affaan-m/ECC · error · RetrospectiveError
retrospective.invalid_capsule
retrospective.invalid_capsule
Error message
capsule at input index ${index} failed verification What it means
readProjection verifies each capsule directory before including it in a retrospective report. When capsule.project(dir) fails — meaning the capsule's journal fails integrity, digest, or structural verification — the error is replaced by a sanitized RetrospectiveError carrying only the input index. Raw reader errors are deliberately swallowed because they can contain private paths or journal content that must not cross the report boundary.
Solutions
- Regenerate the failing capsule snapshot and re-run the retrospective
- Verify the directory is a complete capsule produced by this harness version (check journal and digests)
- Re-copy the capsule directory in full if it was truncated during transfer
- Confirm you passed the directory itself, not a parent or a file path
Example fix
// before node scripts/eval-harness.js capsule group ./random-dir ./capsule-b // after (regenerate the invalid capsule first) node scripts/eval-harness.js capsule group ./.claude/capsules/run-123 ./capsule-b
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check: capsule dir contains a journal before grouping
if (!fs.existsSync(path.join(dir, 'journal.jsonl'))) throw new Error(`${dir} is not a capsule`); Type guard
const looksLikeCapsule = (dir) => typeof dir === 'string' && fs.existsSync(dir) && fs.statSync(dir).isDirectory() && fs.existsSync(path.join(dir, 'journal.jsonl'));
Try / catch
try { report = groupCapsules(dirs); } catch (e) { if (e.code === 'retrospective.invalid_capsule') console.error(`capsule #${e.index} failed verification — regenerate it`); throw e; } Prevention
- Never hand-edit capsule files; regenerate snapshots instead
- Copy capsule directories completely (verify file counts/digests after transfer)
- Pin the harness version used to produce and to read capsules
- Only pass directories produced by eval-harness capsule recording to groupCapsules
When it happens
Trigger: Passing a directory to groupCapsules that is not a valid capsule (missing journal, corrupted hash chain, tampered artifacts, or a non-capsule path). The failing input is identified by its zero-based index in the dirs array.
Common situations: Pointing the tool at an ordinary project directory instead of a capsule snapshot; a capsule truncated by an interrupted copy or sync; editing capsule files by hand so link digests no longer verify; version drift where the capsule format differs from what this harness version projects.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- retrospective.mixed_task_families
- DESTINATION_VERIFICATION_FAILED
- FINAL_VERIFICATION_FAILED
- placement readback mismatch
- retrospective.conflicting_identity
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/2dc03053e6a0dca5.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/eval-harness/retrospective.js:29
const MAX_INPUTS = 100;
const SOURCE_FIELDS = ['entry_count', 'root_hash', 'journal_sha256', 'projection_hash'];
class RetrospectiveError extends Error {
constructor(code, message, inputIndex) {
super(message);
this.name = 'RetrospectiveError';
this.code = code;
if (inputIndex !== undefined) this.input_index = inputIndex;
}
}
function readProjection(dir, index) {
try {
return capsule.project(dir);
} catch {
// Reader errors can contain private paths or journal content. No partial
// report or unchecked diagnostic content crosses the report boundary.
throw new RetrospectiveError('retrospective.invalid_capsule', `capsule at input index ${index} failed verification`, index);
}
}
const compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
const identity = projection => JSON.stringify([projection.run_id, projection.capsule_id]);
function summarizeGroup(harnessVersion, projections) {
const total = keys => Object.fromEntries(keys.map(key => [key, 0]));
const byLineage = total(LINEAGES);
const byEffect = total(EFFECT_CLASSES);
for (const projection of projections) {
for (const key of LINEAGES) byLineage[key] += projection.by_lineage[key];
for (const key of EFFECT_CLASSES) byEffect[key] += projection.by_effect_class[key];
}
return {
harness_version: harnessVersion,
capsule_count: projections.length,
entry_count: projections.reduce((sum, item) => sum + item.entry_count, 0),View on GitHub (pinned to 8321021c54)