mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-05-20 07:43:07 +08:00
chore: add release video self-eval gate
This commit is contained in:
committed by
Affaan Mustafa
parent
d135e03da0
commit
f3cd006252
@@ -51,7 +51,7 @@ Tracked repositories in the platform audit were:
|
|||||||
| Release-surface tests | `node tests/docs/ecc2-release-surface.test.js` | 25 passed, 0 failed |
|
| Release-surface tests | `node tests/docs/ecc2-release-surface.test.js` | 25 passed, 0 failed |
|
||||||
| Preview-pack smoke | `npm run preview-pack:smoke -- --format json` | Ready true; digest `bc2bf157616e`; 30 required artifacts; 5 passed, 0 failed |
|
| Preview-pack smoke | `npm run preview-pack:smoke -- --format json` | Ready true; digest `bc2bf157616e`; 30 required artifacts; 5 passed, 0 failed |
|
||||||
| Operator dashboard | `npm run operator:dashboard -- --markdown --write docs/releases/2.0.0-rc.1/operator-readiness-dashboard-2026-05-19.md` | Generated May 19 dashboard with platform audit ready true, 0 tracked PRs, 0 tracked issues, 0 discussion gaps, `$1,728/mo` current MRR, `$10,000/mo` target MRR, and top actions for plugin publication, notifications, release video, outbound approval, AgentShield, and ECC Tools billing |
|
| Operator dashboard | `npm run operator:dashboard -- --markdown --write docs/releases/2.0.0-rc.1/operator-readiness-dashboard-2026-05-19.md` | Generated May 19 dashboard with platform audit ready true, 0 tracked PRs, 0 tracked issues, 0 discussion gaps, `$1,728/mo` current MRR, `$10,000/mo` target MRR, and top actions for plugin publication, notifications, release video, outbound approval, AgentShield, and ECC Tools billing |
|
||||||
| Release video suite | `npm run release:video-suite -- --format json --summary` with `ECC_VIDEO_SOURCE_ROOT` and `ECC_VIDEO_RELEASE_SUITE_ROOT` | Ready true; 15/15 source assets present; 13/13 render, timeline, caption, EDL, and segment artifacts present; primary rough render is 144.759 seconds and 106.78 MB |
|
| Release video suite | `npm run release:video-suite -- --format json --summary` with `ECC_VIDEO_SOURCE_ROOT` and `ECC_VIDEO_RELEASE_SUITE_ROOT` | Ready true; 15/15 source assets present; 13/13 render, timeline, caption, EDL, and segment artifacts present; primary rough render self-eval passed at 144.759 seconds, 1920x1080, 1 audio stream, and 106.78 MB |
|
||||||
| Full local suite | `node tests/run-all.js` | 2544 passed, 0 failed |
|
| Full local suite | `node tests/run-all.js` | 2544 passed, 0 failed |
|
||||||
| PR #1993 CI | GitHub Actions run `26093792219` | Completed successfully for `d9ac22c697d9a8a8771512ab01e6df857c16776d`; all reported checks passed, including lint, validation, security scan, coverage, GitGuardian, and the macOS/Ubuntu/Windows test matrix |
|
| PR #1993 CI | GitHub Actions run `26093792219` | Completed successfully for `d9ac22c697d9a8a8771512ab01e6df857c16776d`; all reported checks passed, including lint, validation, security scan, coverage, GitGuardian, and the macOS/Ubuntu/Windows test matrix |
|
||||||
| Public-path sanitization | `node scripts/ci/validate-no-personal-paths.js` through local suite and CI | Passed |
|
| Public-path sanitization | `node scripts/ci/validate-no-personal-paths.js` through local suite and CI | Passed |
|
||||||
|
|||||||
@@ -153,6 +153,8 @@ npm run release:video-suite -- --format json
|
|||||||
|
|
||||||
Then manually check the final render for:
|
Then manually check the final render for:
|
||||||
|
|
||||||
|
- validator self-eval passes for the primary render: 90-150 seconds, at least
|
||||||
|
1280x720, video stream present, audio stream present, and non-empty output;
|
||||||
- no blank frames or accidental desktop exposure;
|
- no blank frames or accidental desktop exposure;
|
||||||
- no stale repo name, pivot, rename, or Claude-only framing in captions;
|
- no stale repo name, pivot, rename, or Claude-only framing in captions;
|
||||||
- no captions that rewrite speech into a false claim;
|
- no captions that rewrite speech into a false claim;
|
||||||
|
|||||||
@@ -371,8 +371,12 @@ function probeMedia(filePath, skipProbe) {
|
|||||||
const result = {
|
const result = {
|
||||||
sizeBytes: stat.size,
|
sizeBytes: stat.size,
|
||||||
sizeMb: formatBytes(stat.size),
|
sizeMb: formatBytes(stat.size),
|
||||||
|
audioStreams: null,
|
||||||
durationSeconds: null,
|
durationSeconds: null,
|
||||||
|
height: null,
|
||||||
probe: skipProbe ? 'skipped' : 'unavailable',
|
probe: skipProbe ? 'skipped' : 'unavailable',
|
||||||
|
videoStreams: null,
|
||||||
|
width: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (skipProbe) {
|
if (skipProbe) {
|
||||||
@@ -383,7 +387,7 @@ function probeMedia(filePath, skipProbe) {
|
|||||||
'-v',
|
'-v',
|
||||||
'error',
|
'error',
|
||||||
'-show_entries',
|
'-show_entries',
|
||||||
'format=duration',
|
'format=duration:stream=codec_type,width,height',
|
||||||
'-of',
|
'-of',
|
||||||
'json',
|
'json',
|
||||||
filePath,
|
filePath,
|
||||||
@@ -407,9 +411,19 @@ function probeMedia(filePath, skipProbe) {
|
|||||||
const duration = Number(parsed && parsed.format && parsed.format.duration);
|
const duration = Number(parsed && parsed.format && parsed.format.duration);
|
||||||
if (Number.isFinite(duration)) {
|
if (Number.isFinite(duration)) {
|
||||||
result.durationSeconds = Number(duration.toFixed(3));
|
result.durationSeconds = Number(duration.toFixed(3));
|
||||||
result.probe = 'ok';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const streams = Array.isArray(parsed && parsed.streams) ? parsed.streams : [];
|
||||||
|
const videoStreams = streams.filter(stream => stream.codec_type === 'video');
|
||||||
|
const audioStreams = streams.filter(stream => stream.codec_type === 'audio');
|
||||||
|
const firstVideo = videoStreams[0] || {};
|
||||||
|
|
||||||
|
result.audioStreams = audioStreams.length;
|
||||||
|
result.videoStreams = videoStreams.length;
|
||||||
|
result.width = Number.isFinite(Number(firstVideo.width)) ? Number(firstVideo.width) : null;
|
||||||
|
result.height = Number.isFinite(Number(firstVideo.height)) ? Number(firstVideo.height) : null;
|
||||||
|
result.probe = 'ok';
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,6 +534,69 @@ function inspectSuiteArtifacts(suiteRoot, skipProbe) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function evaluatePrimaryRender(suiteArtifacts, skipProbe) {
|
||||||
|
const primary = suiteArtifacts.find(artifact => artifact.id === 'primary-render-v1');
|
||||||
|
|
||||||
|
if (!primary || primary.status !== 'present') {
|
||||||
|
return {
|
||||||
|
status: 'fail',
|
||||||
|
summary: 'primary launch render is missing or outside the duration target',
|
||||||
|
fix: 'Render the primary launch video within the 90-150 second target before release review.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipProbe) {
|
||||||
|
return {
|
||||||
|
status: 'pass',
|
||||||
|
summary: 'primary launch render exists; stream self-eval skipped by --skip-probe',
|
||||||
|
fix: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const failures = [];
|
||||||
|
|
||||||
|
if (primary.probe !== 'ok') {
|
||||||
|
failures.push(`ffprobe ${primary.probe}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Number.isFinite(primary.durationSeconds)
|
||||||
|
|| primary.durationSeconds < 90
|
||||||
|
|| primary.durationSeconds > 150) {
|
||||||
|
failures.push('duration outside 90-150 seconds');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Number.isFinite(primary.sizeMb) || primary.sizeMb < 5) {
|
||||||
|
failures.push('render is unexpectedly small');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Number.isFinite(primary.videoStreams) || primary.videoStreams < 1) {
|
||||||
|
failures.push('no video stream');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Number.isFinite(primary.audioStreams) || primary.audioStreams < 1) {
|
||||||
|
failures.push('no audio stream');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Number.isFinite(primary.width) || !Number.isFinite(primary.height)
|
||||||
|
|| primary.width < 1280 || primary.height < 720) {
|
||||||
|
failures.push('resolution below 1280x720');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failures.length > 0) {
|
||||||
|
return {
|
||||||
|
status: 'fail',
|
||||||
|
summary: `primary launch render failed self-eval: ${failures.join(', ')}`,
|
||||||
|
fix: 'Regenerate the primary launch render with audio, HD video, valid duration, and non-empty output.',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 'pass',
|
||||||
|
summary: `primary launch render self-eval passed: ${primary.durationSeconds}s, ${primary.width}x${primary.height}, ${primary.audioStreams} audio stream(s), ${primary.sizeMb} MB`,
|
||||||
|
fix: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function buildReport(options = {}) {
|
function buildReport(options = {}) {
|
||||||
const rootDir = path.resolve(options.root || process.cwd());
|
const rootDir = path.resolve(options.root || process.cwd());
|
||||||
const sourceRoot = options.sourceRoot ? path.resolve(options.sourceRoot) : '';
|
const sourceRoot = options.sourceRoot ? path.resolve(options.sourceRoot) : '';
|
||||||
@@ -542,6 +619,7 @@ function buildReport(options = {}) {
|
|||||||
const suiteArtifacts = inspectSuiteArtifacts(suiteRoot, skipProbe);
|
const suiteArtifacts = inspectSuiteArtifacts(suiteRoot, skipProbe);
|
||||||
const missingSourceAssets = sourceAssets.filter(asset => asset.status !== 'present');
|
const missingSourceAssets = sourceAssets.filter(asset => asset.status !== 'present');
|
||||||
const missingSuiteArtifacts = suiteArtifacts.filter(artifact => artifact.status !== 'present');
|
const missingSuiteArtifacts = suiteArtifacts.filter(artifact => artifact.status !== 'present');
|
||||||
|
const primaryRenderSelfEval = evaluatePrimaryRender(suiteArtifacts, skipProbe);
|
||||||
|
|
||||||
const checks = [
|
const checks = [
|
||||||
makeCheck(
|
makeCheck(
|
||||||
@@ -598,6 +676,12 @@ function buildReport(options = {}) {
|
|||||||
missing: missingSuiteArtifacts.map(artifact => artifact.relativePath),
|
missing: missingSuiteArtifacts.map(artifact => artifact.relativePath),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
makeCheck(
|
||||||
|
'video-primary-render-self-eval',
|
||||||
|
primaryRenderSelfEval.status,
|
||||||
|
primaryRenderSelfEval.summary,
|
||||||
|
primaryRenderSelfEval.fix
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
const failed = checks.filter(check => check.status !== 'pass');
|
const failed = checks.filter(check => check.status !== 'pass');
|
||||||
|
|||||||
@@ -169,6 +169,10 @@ function runTests() {
|
|||||||
assert.strictEqual(report.ready, true);
|
assert.strictEqual(report.ready, true);
|
||||||
assert.strictEqual(report.mediaPathsRedacted, true);
|
assert.strictEqual(report.mediaPathsRedacted, true);
|
||||||
assert.ok(report.checks.every(check => check.status === 'pass'));
|
assert.ok(report.checks.every(check => check.status === 'pass'));
|
||||||
|
assert.ok(report.checks.some(check => (
|
||||||
|
check.id === 'video-primary-render-self-eval'
|
||||||
|
&& check.summary.includes('skipped by --skip-probe')
|
||||||
|
)));
|
||||||
assert.strictEqual(report.sourceAssets.length, REQUIRED_SOURCE_ASSETS.length);
|
assert.strictEqual(report.sourceAssets.length, REQUIRED_SOURCE_ASSETS.length);
|
||||||
assert.strictEqual(report.suiteArtifacts.length, REQUIRED_SUITE_ARTIFACTS.length);
|
assert.strictEqual(report.suiteArtifacts.length, REQUIRED_SUITE_ARTIFACTS.length);
|
||||||
assert.ok(renderText(report).includes('Ready: yes'));
|
assert.ok(renderText(report).includes('Ready: yes'));
|
||||||
@@ -197,6 +201,7 @@ function runTests() {
|
|||||||
assert.ok(report.top_actions.some(action => action.includes('ECC_VIDEO_RELEASE_SUITE_ROOT')));
|
assert.ok(report.top_actions.some(action => action.includes('ECC_VIDEO_RELEASE_SUITE_ROOT')));
|
||||||
assert.ok(report.checks.some(check => check.id === 'video-source-assets-present' && check.status === 'fail'));
|
assert.ok(report.checks.some(check => check.id === 'video-source-assets-present' && check.status === 'fail'));
|
||||||
assert.ok(report.checks.some(check => check.id === 'video-release-artifacts-present' && check.status === 'fail'));
|
assert.ok(report.checks.some(check => check.id === 'video-release-artifacts-present' && check.status === 'fail'));
|
||||||
|
assert.ok(report.checks.some(check => check.id === 'video-primary-render-self-eval' && check.status === 'fail'));
|
||||||
} finally {
|
} finally {
|
||||||
cleanup(rootDir);
|
cleanup(rootDir);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user