diff --git a/docs/plans/igneum-2.0-test-registry.json b/docs/plans/igneum-2.0-test-registry.json index 48c5aa27f..8264e181d 100644 --- a/docs/plans/igneum-2.0-test-registry.json +++ b/docs/plans/igneum-2.0-test-registry.json @@ -52,7 +52,7 @@ "run_status": "NOT RUN", "evidence_path": "docs/plans/igneum-2.0-f0-manifest.md; build-4:/srv/builds/igneum-wt-f03-201/vendor/igneum-node/packaging/pow-freeze.txt; build-4:/srv/builds/igneum-wt-f03-201", "run_id": "f03-manifest-20261008-01", - "updated": "2026-10-08T20:35:51.764Z", + "updated": "2026-10-08T20:43:50.473Z", "evidence_record": { "requirement_id": "GOV-01", "decision": "NOT RUN", @@ -73,7 +73,7 @@ }, "claim_impact": "F03's first rung: one manifest, one build, no unpublished vendor tree; the same-work rung (R02) and the transition rung (R03) stay NOT RUN until the readers run on the job context", "reviewer": "", - "at": "2026-10-08T20:35:51.764Z" + "at": "2026-10-08T20:43:50.473Z" }, "in_progress_since": "2026-10-08T19:32:50.856Z", "approvals": { @@ -103,7 +103,7 @@ }, "claim_impact": "F03's first rung: one manifest, one build, no unpublished vendor tree; the same-work rung (R02) and the transition rung (R03) stay NOT RUN until the readers run on the job context", "reviewer": "", - "at": "2026-10-08T20:35:51.764Z" + "at": "2026-10-08T20:43:50.473Z" } } }, @@ -11188,7 +11188,7 @@ ], "run_id": "f03-manifest-20261008-01", "evidence_path": "build-1:/srv/artefacts/tas/f03-manifest-20261008-01/build-from-manifest-c30ab32c-build4.log; build-4:/srv/builds/igneum-wt-f03-201; tools/ci/build-from-manifest.sh; tools/ci/release-manifest-check.sh", - "updated": "2026-10-08T20:35:51.764Z", + "updated": "2026-10-08T20:43:50.473Z", "evidence_record": { "requirement_id": "R2-F03-R01", "decision": "PASS", @@ -11209,7 +11209,31 @@ }, "claim_impact": "F03's first rung: one manifest, one build, no unpublished vendor tree; the same-work rung (R02) and the transition rung (R03) stay NOT RUN until the readers run on the job context", "reviewer": "", - "at": "2026-10-08T20:35:51.764Z" + "at": "2026-10-08T20:43:50.473Z" + }, + "evidence_records": { + "harness:release-manifest": { + "requirement_id": "R2-F03-R01", + "decision": "PASS", + "method": "static", + "cell": "harness:release-manifest", + "manifest_sha": "c30ab32c", + "run_id": "f03-manifest-20261008-01", + "evidence": "build-1:/srv/artefacts/tas/f03-manifest-20261008-01/build-from-manifest-c30ab32c-build4.log; build-4:/srv/builds/igneum-wt-f03-201; tools/ci/build-from-manifest.sh; tools/ci/release-manifest-check.sh", + "in_progress": false, + "coverage": "full for the components the tree builds (node, miner, pool, app, prove-host from one manifest, no unpublished vendor tree); the GPU workers are the kit's cross-build and read under the shipper's kit-isa line, not this cell", + "release_identity": { + "commit": "c30ab32c", + "lockfile": "the release tree's Cargo.lock files at c30ab32c", + "binary": "cargo check only: no binary is claimed by this cell; the fleet binaries are the shipper's kit on aa0e0f45", + "network_object": "igneum-devnet-4, chain id 4465", + "activation": "none (a build fact)", + "profile_hashes": "release-manifest-check: every component's own pin equals packaging/release-manifest.json" + }, + "claim_impact": "F03's first rung: one manifest, one build, no unpublished vendor tree; the same-work rung (R02) and the transition rung (R03) stay NOT RUN until the readers run on the job context", + "reviewer": "", + "at": "2026-10-08T20:43:50.473Z" + } }, "approvals": { "scope_approved": null, diff --git a/tools/ci/int-suite.mjs b/tools/ci/int-suite.mjs index 3f31534c7..ea3c3af1d 100644 --- a/tools/ci/int-suite.mjs +++ b/tools/ci/int-suite.mjs @@ -24,7 +24,7 @@ export function suite(tr) { return { code: 'INT', title: 'INT: the master edition\'s integration gates (R1, the full-system review)', source: 'docs/plans/igneum-2.0-master/traceability.json integration_gates', gate: 'Integration gates closed', owner: 'the owner lanes per the coordinator\'s crosswalk', fixtures: ['F0', 'F5'], summary: `${tests.length} integration gates; each reads NOT RUN until its owner lane records a run`, tests }; } export function merge(reg, s) { const old = (reg.suites || []).find((x) => x.code === s.code); const live = new Map((old?.tests || []).map((t) => [t.id, t])); - for (const t of s.tests) { const o = live.get(t.id); if (o) for (const k of ['run_status', 'run_id', 'evidence_path', 'updated', 'evidence_record', 'in_progress_since', 'deferral_note', 'approvals']) if (k in o) t[k] = o[k]; } + for (const t of s.tests) { const o = live.get(t.id); if (o) for (const k of ['run_status', 'run_id', 'evidence_path', 'updated', 'evidence_record', 'evidence_records', 'blocked_on', 'method_recorded', 'in_progress_since', 'deferral_note', 'approvals']) if (k in o) t[k] = o[k]; } if (old?.notes) s.notes = old.notes; reg.suites = [...(reg.suites || []).filter((x) => x.code !== s.code), s]; return reg; } const canon = (o) => JSON.stringify(o, (k, v) => (v && typeof v === 'object' && !Array.isArray(v)) ? Object.fromEntries(Object.keys(v).sort().map((x) => [x, v[x]])) : v); function mapReasons(map, s) { const mapped = new Set(Object.values(map.cells || {}).flatMap((c) => c.cases || [])); map.not_run = map.not_run || {}; let n = 0; @@ -33,8 +33,8 @@ if (args.includes('--self-test')) { let fails = 0; const tr = { integration_gates: [{ id: 'INT-01', requirement: 'r one', status: 'PROPOSED / NOT RUN', source: 'R1' }, { id: 'INT-05', requirement: 'r five', status: 'x', source: 'R1' }, { id: 'INT-07', requirement: 'r seven', status: 'x', source: 'R1' }] }; const s = suite(tr); if (!(s.tests[2].definition && /V6-12/.test(s.tests[2].definition) && s.tests[2].accept === 'r seven')) { console.log('self-test failed: INT-07 does not carry V6-12 as a definition beside its verbatim requirement'); fails = 1; } if (!(s.tests.length === 3 && s.tests[0].id === 'INT-01' && s.tests[0].accept === 'r one' && /proving/.test(s.tests[0].owner_lane) && /node/.test(s.tests[1].owner_lane) && s.tests[0].run_status === 'NOT RUN' && s.tests[0].source[0] === 'R1')) { console.log('self-test failed: the INT cases are not shaped from the gates with the crosswalk owners'); fails = 1; } - const reg = { suites: [{ code: 'INT', notes: [{ text: 'n' }], tests: [{ id: 'INT-01', run_status: 'NOT RUN', in_progress_since: 't', run_id: 'r' }] }] }; const m = merge(reg, s); const i = m.suites.find((x) => x.code === 'INT'); - if (!(i.tests[0].in_progress_since === 't' && i.tests[1].run_status === 'NOT RUN' && i.notes?.length === 1)) { console.log('self-test failed: regenerating lost live fields or notes'); fails = 1; } + const reg = { suites: [{ code: 'INT', notes: [{ text: 'n' }], tests: [{ id: 'INT-01', run_status: 'NOT RUN', in_progress_since: 't', evidence_records: { 'c:x': { decision: 'PASS' } }, run_id: 'r' }] }] }; const m = merge(reg, s); const i = m.suites.find((x) => x.code === 'INT'); + if (!(i.tests[0].in_progress_since === 't' && i.tests[0].evidence_records?.['c:x']?.decision === 'PASS' && i.tests[1].run_status === 'NOT RUN' && i.notes?.length === 1)) { console.log('self-test failed: regenerating lost live fields or notes'); fails = 1; } const map = { cells: { c: { cases: ['INT-01'] } }, not_run: {} }; if (!(mapReasons(map, s) === 2 && !map.not_run['INT-01'] && /node lane/.test(map.not_run['INT-05']) && /CI steward/.test(map.not_run['INT-07']))) { console.log('self-test failed: the map reasons'); fails = 1; } if (!fails) console.log('self-test passed: one INT case per integration gate, the requirement verbatim, source R1, NOT RUN, the owner from the crosswalk; regenerating keeps live fields and notes; unmapped gates get a NOT RUN reason naming the owner'); process.exit(fails); } diff --git a/tools/ci/review-suite.mjs b/tools/ci/review-suite.mjs index 41c86bf9b..06f27ec00 100644 --- a/tools/ci/review-suite.mjs +++ b/tools/ci/review-suite.mjs @@ -36,7 +36,7 @@ function suite(findings, dispatchMd, prefix, sourceNote, master) { } function merge(reg, s) { // replace the suite of the same code, keeping live fields of cases that already exist const old = (reg.suites || []).find((x) => x.code === s.code); const live = new Map((old?.tests || []).map((t) => [t.id, t])); - for (const t of s.tests) { const o = live.get(t.id); if (o) for (const k of ['run_status', 'run_id', 'evidence_path', 'updated', 'evidence_record', 'in_progress_since', 'deferral_note', 'approvals']) if (k in o) t[k] = o[k]; } + for (const t of s.tests) { const o = live.get(t.id); if (o) for (const k of ['run_status', 'run_id', 'evidence_path', 'updated', 'evidence_record', 'evidence_records', 'blocked_on', 'method_recorded', 'in_progress_since', 'deferral_note', 'approvals']) if (k in o) t[k] = o[k]; } reg.suites = [...(reg.suites || []).filter((x) => x.code !== s.code), s]; return reg; } if (args.includes('--self-test')) { @@ -49,9 +49,9 @@ if (args.includes('--self-test')) { if (!(s.tests[0].title === 'r one' && s.tests[0].accept === 'r one')) { console.log('self-test failed: the title and accept are not the regression line verbatim'); fails = 1; } if (!(s.tests[0].owner_lane === 'lane x, lane y' && s.tests[2].owner_lane === 'lane z')) { console.log(`self-test failed: owners not read from the dispatch table: ${s.tests.map((t) => t.owner_lane)}`); fails = 1; } if (!(s.tests[0].finding === 'R2-F01' && s.tests[0].priority === 'P0' && s.tests[0].run_status === 'NOT RUN' && s.tests[0].method.includes('Automated'))) { console.log('self-test failed: finding, priority, NOT RUN or method missing'); fails = 1; } - const reg = { suites: [{ code: 'GOV', tests: [] }, { code: 'REV', tests: [{ id: 'R2-F01-R01', run_status: 'NOT RUN', in_progress_since: 't', run_id: 'r9' }] }] }; + const reg = { suites: [{ code: 'GOV', tests: [] }, { code: 'REV', tests: [{ id: 'R2-F01-R01', run_status: 'NOT RUN', in_progress_since: 't', evidence_records: { 'c:x': { decision: 'PASS' } }, run_id: 'r9' }] }] }; const m = merge(JSON.parse(JSON.stringify(reg)), s); const rev = m.suites.find((x) => x.code === 'REV'); - if (!(m.suites.length === 2 && rev.tests.length === 3 && rev.tests[0].in_progress_since === 't' && rev.tests[0].run_id === 'r9' && rev.tests[1].run_status === 'NOT RUN')) { console.log('self-test failed: a regenerated suite did not keep the existing case\'s live fields or dropped another suite'); fails = 1; } + if (!(m.suites.length === 2 && rev.tests.length === 3 && rev.tests[0].in_progress_since === 't' && rev.tests[0].evidence_records?.['c:x']?.decision === 'PASS' && rev.tests[0].run_id === 'r9' && rev.tests[1].run_status === 'NOT RUN')) { console.log('self-test failed: a regenerated suite did not keep the existing case\'s live fields or dropped another suite'); fails = 1; } const map = { cells: { c1: { cases: ['R2-F01-R01'] } }, not_run: { 'REV-F02-1': 'old' } }; const n = mapReasons(map, s); if (!(n === 2 && !('R2-F01-R01' in map.not_run) && /lane z/.test(map.not_run['REV-F02-1']) && /lane x/.test(map.not_run['REV-F01-2']))) { console.log(`self-test failed: the map's NOT RUN reasons: ${JSON.stringify(map.not_run)} n=${n}`); fails = 1; } if (!fails) console.log('self-test passed: one case per required regression with the id --, the line verbatim as title and accept, the owner from the dispatch table, finding and priority carried, NOT RUN; regenerating keeps live fields and the other suites; every unmapped case gets a NOT RUN reason naming its owner lane in the map, a mapped one loses it');