docs(acceptance): record owner PDF visual approval within development scope

This commit is contained in:
cesnimda
2026-10-30 08:39:04 +01:00
parent 214dbd6c4d
commit 39bf430401
4 changed files with 25 additions and 3 deletions
@@ -36,7 +36,7 @@
"unchangedRevisedOracle": { "const": "FAIL" },
"proposedBaselineDiagnostic": { "const": "PASS_OWNER_APPROVED_S01_Y_METRIC" },
"metricDisposition": { "const": "OWNER_APPROVED_S01_METRIC_ONLY" },
"humanVisual": { "const": "NOT_TESTED" },
"humanVisual": { "const": "OWNER_APPROVED_FOR_DEVELOPMENT" },
"actualPrinting": { "const": "NOT_TESTED" }
}
},
@@ -0,0 +1,14 @@
{
"kind": "DIRECT_OWNER_VISUAL_APPROVAL_FOR_DEVELOPMENT",
"receivedLocalDate": "2026-10-30",
"timezone": "Europe/Paris",
"reviewedPublishedCheckpoint": "214dbd6c4d173db72cba18959dd8f81c7fc67f64",
"frozenApplicationCommit": "ba04d817fed26d659bfa2a56b089d6cac851dc34",
"ownerStatement": "I have personally reviewed the revised CV PDFs and am satisfied with their visual appearance.",
"scope": "Current UI and CV/PDF visual presentation for proceeding toward Phase10 development; previously approved S01 metric retained",
"pdfVisualPresentation": "APPROVED_FOR_DEVELOPMENT",
"physicalPrinting": "NOT_TESTED",
"physicalDeviceAndAssistiveTechnology": "NOT_TESTED",
"protectedOrchestratorApproval": "NOT_SIGNED_BY_THIS_RECORD",
"production": "NO-GO"
}
@@ -118,6 +118,10 @@ test('approved S01 cannot conceal a failing revised baseline', () => shadow(base
const bytes = zlib.gzipSync(JSON.stringify(value)); fs.writeFileSync(file, bytes); artifact.sha256 = hash(bytes);
});
}));
test('owner visual approval cannot be broadened to unperformed physical printing', () => shadow(base => {
json(base, 'PDF_VISUAL_APPROVAL', value => { value.physicalPrinting = 'PASS'; });
}));
test('a mandatory entry blocker cannot be self-deferred', () => shadow(base => {
json(base, 'ACCEPTANCE', value => { value.permissibleDeferrals.push('P10-ENTRY-01'); });
}));
@@ -207,7 +207,7 @@ export function validatePackage(base = directory) {
verifyBytes(fs.readFileSync(file), expected);
}
const verifierFiles = JSON.parse(artifact(evidence.verifierSourceArtifactId).toString('utf8'));
const expectedVerifierFiles = ['verify.mjs', 'verify.test.mjs', 'package.test.mjs', 'verify_git.py', 'HANDOFF_SCHEMA.json', 'S01_METRIC_APPROVAL.json'].map(name => 'docs/automation/handoffs/pre-phase10/' + name).sort();
const expectedVerifierFiles = ['verify.mjs', 'verify.test.mjs', 'package.test.mjs', 'verify_git.py', 'HANDOFF_SCHEMA.json', 'S01_METRIC_APPROVAL.json', 'PDF_VISUAL_APPROVAL.json'].map(name => 'docs/automation/handoffs/pre-phase10/' + name).sort();
demand(JSON.stringify(Object.keys(verifierFiles).sort()) === JSON.stringify(expectedVerifierFiles), 'Missing verifier source membership');
for (const [name, expected] of Object.entries(verifierFiles)) {
verifyBytes(fs.readFileSync(path.join(root, name)), expected);
@@ -244,7 +244,11 @@ export function validatePackage(base = directory) {
demand(result.total === 36 && result.passed === 36, 'Approved revised S01 fidelity failed');
revisedS01[platform] = { passed: result.passed, total: result.total };
}
demand(decisions.get('Automated PDF Fidelity') === 'PASS' && decisions.get('PDF Spacing') === 'PARTIAL', 'Scoped PDF or human spacing decision differs');
const visual = JSON.parse(artifact('pdf-visual-approval').toString('utf8'));
verifyBytes(readPackage('PDF_VISUAL_APPROVAL.json'), digest(readSafe('PDF_VISUAL_APPROVAL.json')));
verifyBytes(artifact('pdf-visual-approval'), digest(readSafe('PDF_VISUAL_APPROVAL.json')));
demand(visual.reviewedPublishedCheckpoint === '214dbd6c4d173db72cba18959dd8f81c7fc67f64' && visual.pdfVisualPresentation === 'APPROVED_FOR_DEVELOPMENT' && visual.physicalPrinting === 'NOT_TESTED' && visual.physicalDeviceAndAssistiveTechnology === 'NOT_TESTED' && visual.protectedOrchestratorApproval === 'NOT_SIGNED_BY_THIS_RECORD', 'PDF visual approval scope differs');
demand(decisions.get('Automated PDF Fidelity') === 'PASS' && decisions.get('PDF Spacing') === 'PASS', 'Scoped PDF or human spacing decision differs');
const stages = documents.GATES.stages;
demand(stages.map(item => item.sequence).join(',') === '5,6,7,8,9,10,11' && stages[0].manualApprovals.includes('phase10-development-entry') && stages[0].manualApprovals.includes('candidate-specific-cleanup-scope') && stages.every(item => item.permissibleConditionalDeferrals.length === 0), 'Source-derived stage/approval conditions changed');
const observedLocalCommit = execFileSync('rtk', ['proxy', 'git', 'rev-parse', 'HEAD'], { cwd: root, encoding: 'utf8' }).trim();