feat: group verified capsules into offline retrospective reports

Add deterministic grouping for explicitly selected capsules from one task family. Deduplicate identical snapshots and reject conflicting identities without changing input files or exposing payloads and raw IDs. Keep execution and promotion disabled.

Validation: 16 library and 12 CLI checks, scoped scanners, independent code and security review.
This commit is contained in:
Affaan Mustafa
2026-09-11 21:19:19 -04:00
parent 95b9fe157f
commit 472cfa94fb
8 changed files with 393 additions and 3 deletions
+9 -1
View File
@@ -7,6 +7,7 @@
* node scripts/eval-harness.js capsule verify <dir>
* node scripts/eval-harness.js capsule project <dir>
* node scripts/eval-harness.js capsule export <dir> <out-dir>
* node scripts/eval-harness.js capsule group <dir> [<dir> ...]
* node scripts/eval-harness.js gate run <gate.config.json> [--work-dir <dir>] [--capsule <dir>]
* node scripts/eval-harness.js receipt build <capsule-dir> [--artifact <file>] [--gate <gate-receipt.json>] [--out <file>]
* node scripts/eval-harness.js receipt verify <receipt.json> <capsule-dir> [--artifact <file>] [--gate <gate-receipt.json>]
@@ -26,7 +27,7 @@ function usage(message) {
if (message) {
process.stderr.write(`eval-harness: ${message}\n`);
}
const header = fs.readFileSync(__filename, 'utf8').split('\n').slice(3, 15).map((line) => line.replace(/^ \*\s?/, '')).join('\n');
const header = fs.readFileSync(__filename, 'utf8').split('\n').slice(3, 16).map((line) => line.replace(/^ \*\s?/, '')).join('\n');
process.stderr.write(`${header}\n`);
process.exit(2);
}
@@ -64,6 +65,13 @@ function runExample(action) {
function runCapsule(action, rest) {
const dir = rest[0];
if (!dir) usage('capsule commands need a capsule directory');
if (action === 'group') {
if (rest.length > harness.retrospective.MAX_INPUTS || rest.some(arg => !arg.trim() || arg.startsWith('--'))) {
usage(`capsule group needs 1 to ${harness.retrospective.MAX_INPUTS} directory paths and accepts no flags`);
}
print(harness.retrospective.groupCapsules(rest));
return;
}
if (action === 'verify') {
const result = harness.capsule.verify(dir);
print(result);