{"record":{"id":"e39c1d157262d54c","repo":"affaan-m/ECC","slug":"state-reason-capsule","errorCode":null,"errorMessage":"${state.reason}","messagePattern":"\\$\\{state\\.reason\\}","errorType":"exception","errorClass":"CapsuleError","httpStatus":null,"severity":"error","filePath":"scripts/lib/eval-harness/capsule.js","lineNumber":238,"sourceCode":"          offset += written;\n        }\n        fs.fsyncSync(fd);\n      } finally {\n        fs.closeSync(fd);\n      }\n      // These fields remain observable for compatibility, but are never used as\n      // authoritative append state. A preopened handle always reloads above.\n      this.meta = state.meta;\n      this.lastHash = entry.entry_hash;\n      this.nextSeq = entry.seq + 1;\n      return entry;\n    });\n  }\n\n  entries() {\n    const state = readJournal(this.journalPath);\n    if (!state.ok) {\n      throw new CapsuleError(state.code, state.reason, { failed_at: state.failed_at });\n    }\n    return state.entries;\n  }\n}\n\n/**\n * Read and verify a journal file. Never throws for content problems; the\n * result names the first failing entry index and a stable reason code.\n */\nfunction readJournal(journalPath) {\n  if (!fs.existsSync(journalPath)) {\n    return { ok: false, code: 'capsule.missing_journal', reason: 'journal file missing', failed_at: null, entries: [] };\n  }\n  let bytes;\n  try { bytes = fs.readFileSync(journalPath); } catch {\n    return { ok: false, code: 'capsule.unreadable_journal', reason: 'journal file could not be read', failed_at: null, entries: [] };\n  }\n  const raw = bytes.toString('utf8');","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/eval-harness/capsule.js#L220-L256","documentation":"The public entries() method re-reads and verifies the journal via readJournal(); if the journal is missing, truncated, or fails hash verification it throws a CapsuleError with the read's code, message (state.reason), and failed_at offset. Callers get a precise, diagnostic failure instead of a partially verified entry list, since an unverified journal cannot be trusted.","triggerScenarios":"Calling capsule.entries() when the journal file does not exist, ends mid-line (torn write), contains hand-edited lines, or its stored digest/parent-hash chain no longer verifies.","commonSituations":"Reading entries after a process was killed mid-append (partial last line); inspecting a capsule copied with rsync --partial; someone concatenated or trimmed journal files; concurrent readers observing a file during an external (non-locked) modification.","solutions":["Inspect the error's code and failed_at to locate the first bad byte/entry in the journal.","Repair a torn final line by truncating the incomplete trailing line only if you accept losing that entry, then re-verify.","Restore the journal from a backup or rebuild the capsule if earlier entries fail hash verification.","Always use capsule.entries() (locked/verified) rather than reading the JSONL file directly."],"exampleFix":"// before: reading the raw file and choking on a torn line\nconst lines = fs.readFileSync('capsule/journal.jsonl', 'utf8').trim().split('\\n');\n\n// after: use the verified accessor with explicit failure handling\ntry {\n  const entries = capsule.entries();\n} catch (e) {\n  console.error(`journal unreadable at ${e.detail?.failed_at}: ${e.message}; restore from backup`);\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"function canReadJournal(capsule) {\n  const state = readJournal(capsule.journalPath);\n  return state.ok === true;\n}","typeGuard":"function isVerifiedEntryList(state) {\n  return state != null && state.ok === true && Array.isArray(state.entries);\n}","tryCatchPattern":"try {\n  const entries = capsule.entries();\n} catch (e) {\n  if (e instanceof CapsuleError && e.detail?.failed_at != null) {\n    console.error(`journal corrupt from offset ${e.detail.failed_at}: ${e.message}`);\n    // fall back to last known-good snapshot or abort the report\n  }\n  throw e;\n}","preventionTips":["Always read via capsule.entries(), never by parsing journal.jsonl directly.","Verify capsules after any copy/transfer before consuming them.","Avoid concurrent external writers to the same capsule directory.","Snapshot journals (with hash verification) at run completion for later reads."],"tags":["filesystem","data-integrity","journal"],"backgroundTag":"file-read-failed","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}