@treeseed/dsh-chapters 0.1.23 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +2 -1
  2. package/cordis.patch.yml +54 -1
  3. package/docs/architecture.md +1 -466
  4. package/docs/backlog.md +234 -4
  5. package/docs/contract.md +127 -1
  6. package/docs/development.md +248 -12
  7. package/docs/host-compaction-seam.md +108 -0
  8. package/docs/knowledge-repo.md +532 -16
  9. package/docs/project-state.md +323 -0
  10. package/docs/verify.md +217 -0
  11. package/lib/archive.d.ts +49 -1
  12. package/lib/archive.js +56 -2
  13. package/lib/archive.js.map +1 -1
  14. package/lib/arrival.js +24 -10
  15. package/lib/arrival.js.map +1 -1
  16. package/lib/attach.d.ts +46 -0
  17. package/lib/attach.js +120 -0
  18. package/lib/attach.js.map +1 -0
  19. package/lib/auto-save.d.ts +145 -0
  20. package/lib/auto-save.js +318 -0
  21. package/lib/auto-save.js.map +1 -0
  22. package/lib/client.js +413 -11
  23. package/lib/client.js.map +1 -1
  24. package/lib/commands.d.ts +11 -1
  25. package/lib/commands.js +138 -7
  26. package/lib/commands.js.map +1 -1
  27. package/lib/compose.js +25 -6
  28. package/lib/compose.js.map +1 -1
  29. package/lib/continue-core.d.ts +24 -1
  30. package/lib/continue-core.js +41 -9
  31. package/lib/continue-core.js.map +1 -1
  32. package/lib/diag.d.ts +47 -0
  33. package/lib/diag.js +141 -0
  34. package/lib/diag.js.map +1 -0
  35. package/lib/engine-core.d.ts +51 -1
  36. package/lib/engine-core.js +70 -7
  37. package/lib/engine-core.js.map +1 -1
  38. package/lib/engine.d.ts +93 -0
  39. package/lib/engine.js +477 -36
  40. package/lib/engine.js.map +1 -1
  41. package/lib/enrich-queue.js +28 -2
  42. package/lib/enrich-queue.js.map +1 -1
  43. package/lib/enrich-wire.d.ts +92 -2
  44. package/lib/enrich-wire.js +135 -17
  45. package/lib/enrich-wire.js.map +1 -1
  46. package/lib/enrich.d.ts +27 -2
  47. package/lib/enrich.js +114 -18
  48. package/lib/enrich.js.map +1 -1
  49. package/lib/index.d.ts +59 -0
  50. package/lib/index.js +215 -2
  51. package/lib/index.js.map +1 -1
  52. package/lib/indexing.d.ts +7 -0
  53. package/lib/indexing.js.map +1 -1
  54. package/lib/injections.d.ts +1 -0
  55. package/lib/injections.js +38 -0
  56. package/lib/injections.js.map +1 -1
  57. package/lib/last-resort.d.ts +24 -0
  58. package/lib/last-resort.js +27 -0
  59. package/lib/last-resort.js.map +1 -0
  60. package/lib/prompt.d.ts +130 -0
  61. package/lib/prompt.js +255 -0
  62. package/lib/prompt.js.map +1 -0
  63. package/lib/registry.d.ts +39 -1
  64. package/lib/registry.js +76 -9
  65. package/lib/registry.js.map +1 -1
  66. package/lib/render.d.ts +31 -3
  67. package/lib/render.js +82 -3
  68. package/lib/render.js.map +1 -1
  69. package/lib/repair-run.d.ts +49 -0
  70. package/lib/repair-run.js +423 -0
  71. package/lib/repair-run.js.map +1 -0
  72. package/lib/repair.d.ts +200 -0
  73. package/lib/repair.js +354 -0
  74. package/lib/repair.js.map +1 -0
  75. package/lib/rules-commands.d.ts +22 -0
  76. package/lib/rules-commands.js +177 -20
  77. package/lib/rules-commands.js.map +1 -1
  78. package/lib/rules.d.ts +184 -7
  79. package/lib/rules.js +312 -27
  80. package/lib/rules.js.map +1 -1
  81. package/lib/save-core.d.ts +72 -0
  82. package/lib/save-core.js +220 -0
  83. package/lib/save-core.js.map +1 -0
  84. package/lib/session-rules.d.ts +222 -0
  85. package/lib/session-rules.js +454 -0
  86. package/lib/session-rules.js.map +1 -0
  87. package/lib/store.d.ts +22 -1
  88. package/lib/store.js +94 -17
  89. package/lib/store.js.map +1 -1
  90. package/lib/sync.js +13 -1
  91. package/lib/sync.js.map +1 -1
  92. package/lib/tools.d.ts +14 -0
  93. package/lib/tools.js +341 -91
  94. package/lib/tools.js.map +1 -1
  95. package/lib/types.d.ts +31 -1
  96. package/lib/types.js +12 -0
  97. package/lib/types.js.map +1 -1
  98. package/lib/version.d.ts +9 -0
  99. package/lib/version.js +10 -0
  100. package/lib/version.js.map +1 -0
  101. package/lib/warnings.d.ts +10 -0
  102. package/lib/warnings.js +18 -0
  103. package/lib/warnings.js.map +1 -0
  104. package/package.json +9 -3
@@ -0,0 +1,200 @@
1
+ /**
2
+ * The repair engine (#60) — re-derive the archive from the durable log, never edit it.
3
+ *
4
+ * WHY THIS EXISTS (docs/architecture.md § Repair). The durable session log is append-only and complete
5
+ * (invariant 1), which is the only reason the defects measured in the first `chapters`-preset project
6
+ * (`/home/adrian/Projects/saip`, see var/saip-audit/SAIP-CHAPTERS-AUDIT-2026-10-22.md) are recoverable
7
+ * at all: 12 hollow chapters a payload-less read produced, a 203-event completed turn no chapter covers,
8
+ * a 960 KB chapter file its own tree does not cite, two different `015-*.md` from one rewound counter,
9
+ * and two checkpoints citing files that were never written. Nothing in the plugin could see or say any
10
+ * of it. This module is the seeing; `/chapters-repair` is the saying; the fixes run through the SAME
11
+ * save core every other door uses, so a repaired chapter is byte-identical to a normal one.
12
+ *
13
+ * THE CONTRACT, in one line each:
14
+ * 1. **Supersede, never rewrite.** A damaged chapter gets a NEW number carrying `repairs:`, the old
15
+ * record is marked `status: 'superseded'`, and the bad file is COPIED into `.repair-quarantine/`.
16
+ * Nothing is deleted; nothing is edited in place (the body-hash guard is the only sanctioned
17
+ * chapter-file mutation, and repair is not an exception to it).
18
+ * 2. **A dead citation is satisfied, not edited.** A compaction manifest already handed the host its
19
+ * TOC text naming `…/020-<title>.md`. Repair renders that span and writes it AT the cited path with
20
+ * the reserved number, so the committed text becomes true and no log byte moves.
21
+ * 3. **Numbers stay spent.** Releasing a reservation frees its retry key, never its numbers; a counter
22
+ * is raised to `max(spent)+1` and never lowered.
23
+ * 4. **Journalled, therefore reversible.** An applied run writes `<tree>/repairs/<stamp>.json` FIRST —
24
+ * one entry per move with before/after hashes — and `restore <journal-id>` walks it backwards.
25
+ * 5. **One serialized section per row.** Every registry mutation goes through `store.mutate` (#59): a
26
+ * repair that clobbered a live door's commit would be #59 with better intentions.
27
+ */
28
+ import { releaseReservation, type SessionState } from './registry.ts';
29
+ import type { ChapterRecord } from './archive.ts';
30
+ import type { RenderConfig } from './types.ts';
31
+ /** What can be wrong. Each class maps to exactly one remedy; see `REMEDY`. */
32
+ export type FindingClass = 'hollow-payload' | 'empty-artifact' | 'never-archived-span' | 'orphan-file' | 'unregistered-file' | 'duplicate-number' | 'countervalue-drift' | 'ghost-plan-manifest' | 'unreleased-reservation' | 'dead-citation' | 'tampered-file' | 'test-litter' | 'unrecoverable';
33
+ export type Remedy = 'reread-span' | 'materialize-chapter' | 're-register-file' | 'quarantine-file' | 'release-reservation' | 'expire-manifest' | 'raise-counter' | 'report-only';
34
+ export interface RepairFinding {
35
+ class: FindingClass;
36
+ session: string;
37
+ detail: string;
38
+ remedy: Remedy;
39
+ /** The chapter number, seq span or path the remedy acts on — the operator reads this, not prose. */
40
+ target: {
41
+ number?: number;
42
+ path?: string;
43
+ fromSeq?: number;
44
+ toSeq?: number;
45
+ };
46
+ }
47
+ /** What the auditor may ask about the store. The caller owns the filesystem; this stays pure. */
48
+ export interface RepairFileSet {
49
+ exists(path: string): boolean;
50
+ bytes(path: string): number;
51
+ shaMatches(path: string, sha: string): boolean;
52
+ /** Every chapter `.md` present under this session's tree, however it got there. */
53
+ chapterPaths: string[];
54
+ artifactPaths: string[];
55
+ emptyArtifactPaths: string[];
56
+ /** Other session roots sitting in the same store (rig litter shows up here). */
57
+ roots?: string[];
58
+ /**
59
+ * Does this chapter file carry the #58 SHELL signature — `tool: unknown`, `arguments: {}`, a
60
+ * `0 B` result? That signature, not a zero message count, is what a payload-less read leaves behind:
61
+ * a repair split can legitimately produce a part with no prose (turn/step events only), and calling
62
+ * that a husk would report damage that is not damage. `false` when the caller cannot read files.
63
+ */
64
+ looksLikeShell?(path: string): boolean;
65
+ /**
66
+ * FALSE when the caller cannot list a directory — which is the HOST's case: `ArchiveFs` is
67
+ * write/read/exists only (src/archive.ts), so an in-host repair can never discover a file the registry
68
+ * does not cite. Reporting "no orphan files" from a port that cannot see them would be a lie of
69
+ * omission, exactly the class of defect this issue is about; so the audit returns BLIND SPOTS and the
70
+ * command says them out loud. The offline script (`scripts/chapters-repair.mjs`) has `readdir` and
71
+ * leaves this true.
72
+ */
73
+ canScan?: boolean;
74
+ }
75
+ export interface RepairLogFacts {
76
+ /** Every `turn/end` seq in the session — the ONLY authority on completeness (§4.3). */
77
+ turnEndSeqs: number[];
78
+ /** Signed collection spans, for reporting why a span went unsigned. */
79
+ collections: Array<{
80
+ from: number;
81
+ to: number;
82
+ }>;
83
+ }
84
+ export interface AuditInput {
85
+ sessionId: string;
86
+ /** Workspace cwd, so an absolute record path and the same file listed relatively are ONE path (#69). */
87
+ cwd?: string | undefined;
88
+ state: SessionState;
89
+ files: RepairFileSet;
90
+ log: RepairLogFacts;
91
+ }
92
+ /**
93
+ * Compare the three things that can disagree: the log, the files, the records.
94
+ *
95
+ * Deliberately READ-ONLY and pure — the same function serves `audit`, `dry-run` and `apply`, so what an
96
+ * operator sees is exactly what will be done, and a report can never be more optimistic than the run.
97
+ * A clean store must return an EMPTY list: a repair that prints friendly noise is a repair whose output
98
+ * nobody reads.
99
+ */
100
+ export declare function audit(input: AuditInput): {
101
+ findings: RepairFinding[];
102
+ blindSpots: FindingClass[];
103
+ };
104
+ /**
105
+ * A health line from the REGISTRY ALONE (#61), for `/chapters-status` — no log read, no directory scan.
106
+ *
107
+ * `audit()` needs the durable log and the files to judge coverage and orphans; a status command must
108
+ * still say something true at boot, in a project it cannot scan. So this counts only what a row knows
109
+ * about itself, and the caller must say what was NOT checked. A "0 findings" line from a partial check
110
+ * would be a lie of omission, and that is the defect family this issue exists to end.
111
+ */
112
+ export interface RegistryHealth {
113
+ hollow: number;
114
+ duplicate: number;
115
+ drift: number;
116
+ unreleased: number;
117
+ ghost: number;
118
+ superseded: number;
119
+ chapters: number;
120
+ sessions: number;
121
+ }
122
+ export declare function registryHealth(states: readonly SessionState[]): {
123
+ text: string;
124
+ counts: RegistryHealth;
125
+ };
126
+ /**
127
+ * The class names an operator may type, and what each expands to (#60). BOTH `/chapters-repair` and
128
+ * `scripts/chapters-repair.mjs` read this table — two lists is how the command quietly accepted
129
+ * `--apply bogus` and reported "0 moves" as success while the script refused it. Unknown names must
130
+ * fail loudly: a repair that does nothing and says nothing is the defect this whole issue is named for.
131
+ */
132
+ export declare const REPAIR_CLASS_ALIASES: Record<string, string | string[]>;
133
+ /** Resolve operator words into finding classes, or return the unknown names it must refuse. */
134
+ export declare function resolveRepairClasses(input: readonly string[]): {
135
+ classes: FindingClass[];
136
+ unknown: string[];
137
+ };
138
+ /** Every class the auditor can produce — the accept-list for operator words. */
139
+ export declare const FINDING_CLASSES: readonly FindingClass[];
140
+ /**
141
+ * Mark the damaged record superseded and commit its replacement, in ONE pure state transition.
142
+ *
143
+ * The old record KEEPS its number, its seqs and its hash: the watermark is `max(endSeq)+1` and a spent
144
+ * number must never be re-spendable (#59). What changes is that it stops being knowledge — every derived
145
+ * layer reads it through `isActiveChapter`, so it leaves the TOC, the index and the enrichment queue.
146
+ */
147
+ export declare function supersedeChapter(state: SessionState, overNumber: number, replacements: readonly ChapterRecord[], reason: FindingClass, at?: number): SessionState;
148
+ /**
149
+ * Mark a record superseded by a chapter that ALREADY EXISTS — no new bytes (#60).
150
+ *
151
+ * The residue after a project-wide repair: a husk whose span was re-archived correctly by an earlier
152
+ * run, so re-rendering it now is a no-op and `supersedeChapter` (which commits replacements) can never
153
+ * run. The knowledge is safe; only the false record is still circulating. This closes that last step:
154
+ * point the husk at whatever active chapter covers its seqs, and let the derived layers drop it.
155
+ * Refuses (returns the state unchanged with a reason) when nothing covers the span — because silently
156
+ * superseding an uncovered span would delete the only claim that content exists.
157
+ */
158
+ export declare function markSupersededBy(state: SessionState, overNumber: number, byNumber: number, reason: FindingClass, at?: number): {
159
+ state: SessionState;
160
+ problem?: string;
161
+ };
162
+ /**
163
+ * The active chapter whose span fully covers `[from..to]`, if any — the candidate a husk defers to.
164
+ * `exceptNumber` is not cosmetic: the husk covers its OWN span, so without excluding it the search
165
+ * returns the record about to be superseded and `markSupersededBy` would point a chapter at itself
166
+ * (caught by `tests/unit/repair.test.ts`).
167
+ */
168
+ export declare function coveringChapter(state: SessionState, from: number, to: number, exceptNumber?: number): ChapterRecord[];
169
+ /** Raise a counter to the first number nothing has spent. Upward ONLY — never a rewind. */
170
+ export declare function raiseCounters(state: SessionState): SessionState;
171
+ /** Drop a manifest/reservation whose work never landed, keeping every number spent. */
172
+ export declare function expireBookkeeping(state: SessionState, keys: readonly string[]): SessionState;
173
+ export { releaseReservation };
174
+ export interface JournalEntry {
175
+ kind: 'write' | 'quarantine' | 'registry';
176
+ path: string;
177
+ beforeSha: string | null;
178
+ afterSha: string | null;
179
+ /** Quarantine target, registry rev, or the span re-read — whatever `undo` needs. */
180
+ to?: string;
181
+ rev?: number;
182
+ }
183
+ export interface Journal {
184
+ id: string;
185
+ sessionId: string;
186
+ startedAt: number;
187
+ classes: FindingClass[];
188
+ /** Null until the run finishes; an unfinished journal is how `status` knows a run died. */
189
+ completedAt: number | null;
190
+ entries: JournalEntry[];
191
+ findingsBefore: number;
192
+ findingsAfter: number;
193
+ }
194
+ /** How an entry is undone. The inverse is DERIVED, never hand-written, so a journal cannot lie about itself. */
195
+ export declare function journalEntryInverse(e: JournalEntry): {
196
+ undo: 'remove' | 'restore-from-quarantine' | 'restore-registry-rev' | 'unchanged';
197
+ };
198
+ /** Chapter-file frontmatter keys a repair adds. `renderChapter` owns every other byte. */
199
+ export declare function repairFrontmatter(lines: readonly string[], marks: JournalEntry[]): string[];
200
+ export type { RenderConfig };
package/lib/repair.js ADDED
@@ -0,0 +1,354 @@
1
+ /**
2
+ * The repair engine (#60) — re-derive the archive from the durable log, never edit it.
3
+ *
4
+ * WHY THIS EXISTS (docs/architecture.md § Repair). The durable session log is append-only and complete
5
+ * (invariant 1), which is the only reason the defects measured in the first `chapters`-preset project
6
+ * (`/home/adrian/Projects/saip`, see var/saip-audit/SAIP-CHAPTERS-AUDIT-2026-10-22.md) are recoverable
7
+ * at all: 12 hollow chapters a payload-less read produced, a 203-event completed turn no chapter covers,
8
+ * a 960 KB chapter file its own tree does not cite, two different `015-*.md` from one rewound counter,
9
+ * and two checkpoints citing files that were never written. Nothing in the plugin could see or say any
10
+ * of it. This module is the seeing; `/chapters-repair` is the saying; the fixes run through the SAME
11
+ * save core every other door uses, so a repaired chapter is byte-identical to a normal one.
12
+ *
13
+ * THE CONTRACT, in one line each:
14
+ * 1. **Supersede, never rewrite.** A damaged chapter gets a NEW number carrying `repairs:`, the old
15
+ * record is marked `status: 'superseded'`, and the bad file is COPIED into `.repair-quarantine/`.
16
+ * Nothing is deleted; nothing is edited in place (the body-hash guard is the only sanctioned
17
+ * chapter-file mutation, and repair is not an exception to it).
18
+ * 2. **A dead citation is satisfied, not edited.** A compaction manifest already handed the host its
19
+ * TOC text naming `…/020-<title>.md`. Repair renders that span and writes it AT the cited path with
20
+ * the reserved number, so the committed text becomes true and no log byte moves.
21
+ * 3. **Numbers stay spent.** Releasing a reservation frees its retry key, never its numbers; a counter
22
+ * is raised to `max(spent)+1` and never lowered.
23
+ * 4. **Journalled, therefore reversible.** An applied run writes `<tree>/repairs/<stamp>.json` FIRST —
24
+ * one entry per move with before/after hashes — and `restore <journal-id>` walks it backwards.
25
+ * 5. **One serialized section per row.** Every registry mutation goes through `store.mutate` (#59): a
26
+ * repair that clobbered a live door's commit would be #59 with better intentions.
27
+ */
28
+ import { appendChapters, isActiveChapter, releaseReservation } from "./registry.js";
29
+ import { sameStoredPath } from "./archive.js";
30
+ const REMEDY = {
31
+ 'hollow-payload': 'reread-span',
32
+ 'empty-artifact': 'quarantine-file',
33
+ 'never-archived-span': 'reread-span',
34
+ 'orphan-file': 'materialize-chapter',
35
+ 'unregistered-file': 're-register-file',
36
+ 'duplicate-number': 'reread-span',
37
+ 'countervalue-drift': 'raise-counter',
38
+ 'ghost-plan-manifest': 'expire-manifest',
39
+ 'unreleased-reservation': 'release-reservation',
40
+ 'dead-citation': 'materialize-chapter',
41
+ 'tampered-file': 'report-only',
42
+ 'test-litter': 'report-only',
43
+ unrecoverable: 'report-only',
44
+ };
45
+ /**
46
+ * Compare the three things that can disagree: the log, the files, the records.
47
+ *
48
+ * Deliberately READ-ONLY and pure — the same function serves `audit`, `dry-run` and `apply`, so what an
49
+ * operator sees is exactly what will be done, and a report can never be more optimistic than the run.
50
+ * A clean store must return an EMPTY list: a repair that prints friendly noise is a repair whose output
51
+ * nobody reads.
52
+ */
53
+ export function audit(input) {
54
+ const { sessionId, state, files, log, cwd } = input;
55
+ const findings = [];
56
+ const add = (f) => {
57
+ findings.push({ ...f, session: sessionId, remedy: REMEDY[f.class] });
58
+ };
59
+ const active = state.chapters.filter(isActiveChapter);
60
+ // 1. Hollow chapters: the pair that turned 12 recoverable archives into permanent ones (#58).
61
+ for (const c of active) {
62
+ // STRICT equality: `messages` is ABSENT on records written before counts existed, and on every row
63
+ // a repair re-registered from a file whose frontmatter has no such field (render.ts: "absent … never
64
+ // a lying zero"). Coercing undefined to 0 turned 162 legitimate re-registrations into false
65
+ // "hollow-payload" findings on the first real run — an auditor that invents damage is worse than one
66
+ // that misses it, because the operator learns to distrust the report.
67
+ // A record with `messages === 0` is suspect, but not always a wound: a repair that split one enormous
68
+ // turn into event-bounded parts knowingly produced parts holding tool calls and no prose (save-core
69
+ // names each in its warnings). The discriminator is CONTENT, not provenance — my first guess was a
70
+ // `repairs` stamp, and it missed, because parts made by the never-archived-span branch carry no
71
+ // stamp at all, so a healthy repaired tree reported 14 fresh "husks". A #58 shell deferred
72
+ // ZERO-BYTE blobs (its read had no payloads to defer); a real tool-only part has bytes. An empty
73
+ // Evidence, not arithmetic: a payload-less read left EITHER zero-byte deferred blobs (it "archived"
74
+ // 335 empty results) OR the shell signature in the bytes (`tool: unknown`, `arguments: {}`). A bare
75
+ // empty artifact list is NOT evidence — a repair split legitimately produces an empty part (turn and
76
+ // step events only), and three of those were reported as husks until this rule named its evidence.
77
+ const shellSignature = files.looksLikeShell?.(c.path) ?? false;
78
+ const zeroByteBlobs = c.artifacts.length > 0 && c.artifacts.every((a) => a.bytes === 0);
79
+ if (c.messages === 0 && c.endSeq >= c.startSeq && (zeroByteBlobs || shellSignature)) {
80
+ add({ class: 'hollow-payload', detail: `chapter ${c.number} ("${c.title}") has messages 0 over seqs ${c.startSeq}-${c.endSeq} — a payload read that went wrong, not a short conversation`, target: { number: c.number, path: c.path, fromSeq: c.startSeq, toSeq: c.endSeq } });
81
+ }
82
+ else if (!files.exists(c.path)) {
83
+ // 2. A record whose file is gone: knowledge for the reader, a ghost for every tool.
84
+ add({ class: 'orphan-file', detail: `chapter ${c.number} is recorded at ${c.path} but no such file exists — the record is a ghost: re-render it from the log`, target: { number: c.number, path: c.path, fromSeq: c.startSeq, toSeq: c.endSeq } });
85
+ }
86
+ else if (!files.shaMatches(c.path, c.sha256)) {
87
+ add({ class: 'tampered-file', detail: `chapter ${c.number}'s body hash no longer matches ${c.path}`, target: { number: c.number, path: c.path } });
88
+ }
89
+ for (const a of c.artifacts) {
90
+ if (a.bytes === 0 || files.emptyArtifactPaths.includes(a.path)) {
91
+ add({ class: 'empty-artifact', detail: `chapter ${c.number} cites the 0-byte blob ${a.path} (sha ${a.sha256.slice(0, 12)}…) as an artifact`, target: { path: a.path, number: c.number } });
92
+ }
93
+ }
94
+ }
95
+ // 3. Files the registry does not cite — the shape a lost update leaves behind (#59: the 960 KB case).
96
+ // #69: cited-ness is compared with `sameStoredPath`, NEVER string equality — that is how one file at
97
+ // one path became a cited record AND its own unregistered twin, and the auditor reported its own
98
+ // archive as lost knowledge.
99
+ const cited = state.chapters.map((c) => c.path);
100
+ for (const p of files.chapterPaths) {
101
+ if (!cited.some((q) => sameStoredPath(q, p, cwd)) && !p.includes('.repair-quarantine')) {
102
+ const m = /\/(\d{3})-/.exec(p);
103
+ const num = m ? Number(m[1]) : undefined;
104
+ add({ class: 'unregistered-file', detail: `${p} exists on disk and no chapter record cites it — the registry lost its commit${num !== undefined ? ` (number ${num})` : ''}`, ...(num !== undefined ? { target: { path: p, number: num } } : { target: { path: p } }) });
105
+ }
106
+ }
107
+ // 4. Two records on one number (identity is (number, sha256), never number alone).
108
+ const byNumber = new Map();
109
+ for (const c of state.chapters)
110
+ byNumber.set(c.number, [...(byNumber.get(c.number) ?? []), c]);
111
+ for (const [n, list] of byNumber) {
112
+ if (list.length > 1) {
113
+ add({ class: 'duplicate-number', detail: `chapter number ${n} is carried by ${list.length} different records (${list.map((c) => c.path.split('/').pop()).join(', ')}) — a lost update re-spent it`, target: { number: n } });
114
+ }
115
+ }
116
+ // 5. A counter at or below what is already spent: the next door would collide (#59).
117
+ const maxSpent = state.chapters.reduce((m, c) => Math.max(m, c.number), 0);
118
+ if (state.nextChapterNumber <= maxSpent) {
119
+ add({ class: 'countervalue-drift', detail: `nextChapterNumber ${state.nextChapterNumber} is not above the highest spent number ${maxSpent}`, target: { number: maxSpent + 1 } });
120
+ }
121
+ // 6. Coverage: a completed turn inside no chapter. turn/end is the ONLY authority on completeness —
122
+ // the old note inferred "unfinished" from a missing signature and was wrong (#59).
123
+ const covered = new Set();
124
+ for (const c of active)
125
+ for (let s = c.startSeq; s <= c.endSeq; s++)
126
+ covered.add(s);
127
+ const lastEnd = log.turnEndSeqs.length > 0 ? Math.max(...log.turnEndSeqs) : -1;
128
+ let holeStart = -1;
129
+ const flushHole = (to) => {
130
+ if (holeStart >= 0) {
131
+ add({ class: 'never-archived-span', detail: `seqs ${holeStart}-${to} belong to COMPLETED turns and are inside no chapter — signed collections do not cover them`, target: { fromSeq: holeStart, toSeq: to } });
132
+ holeStart = -1;
133
+ }
134
+ };
135
+ for (let s = 0; s <= lastEnd; s++) {
136
+ if (!covered.has(s))
137
+ holeStart = holeStart < 0 ? s : holeStart;
138
+ else
139
+ flushHole(s - 1);
140
+ }
141
+ flushHole(lastEnd);
142
+ // 7. Bookkeeping: manifests the row still carries for work that never landed. The manifest IS the
143
+ // plan the post-commit finalizer was going to execute — `path` is the chapter it promised to
144
+ // commit, `number` its reserved chapter number, `chapters` the bullets it already handed the host
145
+ // as TOC text (src/registry.ts PlanManifest). Read the real shape, not an imagined one.
146
+ for (const [key, plan] of Object.entries(state.plans ?? {})) {
147
+ if (!state.chapters.some((c) => sameStoredPath(c.path, plan.path, cwd)) && !files.exists(plan.path)) {
148
+ add({ class: 'ghost-plan-manifest', detail: `finalize manifest ${key} promises chapter ${plan.number} at ${plan.path}, which never landed`, target: { path: plan.path, number: plan.number } });
149
+ }
150
+ // 8. Dead citations: the manifest's OWN committed TOC bullets naming files that do not exist.
151
+ // The host already holds that text — satisfaction, never editing, is the honest repair (#60).
152
+ for (const ch of plan.chapters ?? []) {
153
+ if (!files.exists(ch.path)) {
154
+ const num = /\/(\d{3})-/.exec(ch.path)?.[1];
155
+ add({
156
+ class: 'dead-citation',
157
+ detail: `a committed checkpoint cites ${ch.path} (number ${num ?? '?'}) and that file was never written — render the span and write it AT that path; do not touch the text`,
158
+ ...(num !== undefined ? { target: { path: ch.path, number: Number(num) } } : { target: { path: ch.path } }),
159
+ });
160
+ }
161
+ }
162
+ }
163
+ for (const [key, numbers] of Object.entries(state.reservations ?? {})) {
164
+ const landed = numbers.every((n) => state.chapters.some((c) => c.number === n));
165
+ if (!landed) {
166
+ add({ class: 'unreleased-reservation', detail: `reservation ${key} holds [${numbers.join(', ')}] and not every number produced a record — its key can never land`, ...(numbers[0] !== undefined ? { target: { number: numbers[0] } } : { target: {} }) });
167
+ }
168
+ }
169
+ // 9. Someone else's data in this store: reported, never decided here.
170
+ for (const root of files.roots ?? []) {
171
+ add({ class: 'test-litter', detail: `the store holds a second root ${root} (not this session's tree); it is not touched automatically — inspect it before removing anything`, target: { path: root } });
172
+ }
173
+ // What we could NOT look at, stated rather than implied. The host port has no directory listing, so
174
+ // unlisted files and stray roots are invisible there; the offline script sees them.
175
+ const blindSpots = files.canScan === false ? ['orphan-file', 'test-litter'] : [];
176
+ return { findings, blindSpots };
177
+ }
178
+ export function registryHealth(states) {
179
+ const counts = { hollow: 0, duplicate: 0, drift: 0, unreleased: 0, ghost: 0, superseded: 0, chapters: 0, sessions: states.length };
180
+ for (const st of states) {
181
+ counts.chapters += st.chapters.length;
182
+ counts.superseded += st.chapters.filter((c) => c.status === 'superseded').length;
183
+ counts.hollow += st.chapters.filter((c) => c.messages === 0 && c.artifacts.every((a) => a.bytes === 0)).length;
184
+ const seen = new Set();
185
+ for (const c of st.chapters) {
186
+ if (seen.has(c.number))
187
+ counts.duplicate += 1;
188
+ seen.add(c.number);
189
+ }
190
+ if (st.chapters.length > 0 && st.nextChapterNumber <= Math.max(...st.chapters.map((c) => c.number)))
191
+ counts.drift += 1;
192
+ for (const [key, nums] of Object.entries(st.reservations ?? {})) {
193
+ if (!nums.every((n) => st.chapters.some((c) => c.number === n)))
194
+ counts.unreleased += 1;
195
+ void key;
196
+ }
197
+ for (const plan of Object.values(st.plans ?? {})) {
198
+ if (!st.chapters.some((c) => c.path === plan.path) && plan.path !== '')
199
+ counts.ghost += 1;
200
+ }
201
+ }
202
+ const parts = Object.keys(counts)
203
+ .filter((k) => k !== 'chapters' && k !== 'sessions')
204
+ .map((k) => `${k}=${counts[k]}`);
205
+ return {
206
+ text: `${counts.sessions} session row(s), ${counts.chapters} chapter record(s) — ${parts.join(' · ')}`,
207
+ counts,
208
+ };
209
+ }
210
+ // ─────────────────────────────────────────────────── operator vocabulary (pure, ONE list)
211
+ /**
212
+ * The class names an operator may type, and what each expands to (#60). BOTH `/chapters-repair` and
213
+ * `scripts/chapters-repair.mjs` read this table — two lists is how the command quietly accepted
214
+ * `--apply bogus` and reported "0 moves" as success while the script refused it. Unknown names must
215
+ * fail loudly: a repair that does nothing and says nothing is the defect this whole issue is named for.
216
+ */
217
+ export const REPAIR_CLASS_ALIASES = {
218
+ hollow: 'hollow-payload',
219
+ gaps: 'never-archived-span',
220
+ citations: 'dead-citation',
221
+ bookkeeping: ['ghost-plan-manifest', 'unreleased-reservation', 'countervalue-drift'],
222
+ files: 'unregistered-file',
223
+ orphans: 'unregistered-file',
224
+ all: 'all',
225
+ };
226
+ /** Resolve operator words into finding classes, or return the unknown names it must refuse. */
227
+ export function resolveRepairClasses(input) {
228
+ if (input.length === 0 || input.includes('all'))
229
+ return { classes: 'all', unknown: [] };
230
+ const expanded = input.flatMap((c) => REPAIR_CLASS_ALIASES[c] ?? c);
231
+ if (expanded.includes('all'))
232
+ return { classes: 'all', unknown: [] };
233
+ const unknown = expanded.filter((c) => !FINDING_CLASSES.includes(c));
234
+ return { classes: expanded, unknown };
235
+ }
236
+ /** Every class the auditor can produce — the accept-list for operator words. */
237
+ export const FINDING_CLASSES = [
238
+ 'hollow-payload', 'empty-artifact', 'never-archived-span', 'orphan-file', 'unregistered-file',
239
+ 'duplicate-number', 'countervalue-drift', 'ghost-plan-manifest', 'unreleased-reservation',
240
+ 'dead-citation', 'tampered-file', 'test-litter', 'unrecoverable',
241
+ ];
242
+ // ─────────────────────────────────────────────────── supersede (pure)
243
+ /**
244
+ * Mark the damaged record superseded and commit its replacement, in ONE pure state transition.
245
+ *
246
+ * The old record KEEPS its number, its seqs and its hash: the watermark is `max(endSeq)+1` and a spent
247
+ * number must never be re-spendable (#59). What changes is that it stops being knowledge — every derived
248
+ * layer reads it through `isActiveChapter`, so it leaves the TOC, the index and the enrichment queue.
249
+ */
250
+ export function supersedeChapter(state, overNumber, replacements, reason, at = Date.now()) {
251
+ const stamped = replacements.map((r) => ({ ...r, repairs: [...(r.repairs ?? []), { class: reason, over: overNumber, at }] }));
252
+ const withMarks = {
253
+ ...state,
254
+ chapters: state.chapters.map((c) => (c.number === overNumber && replacements.length > 0
255
+ ? { ...c, status: 'superseded', supersededBy: replacements[0].number }
256
+ : c)),
257
+ };
258
+ return appendChapters(withMarks, stamped);
259
+ }
260
+ /**
261
+ * Mark a record superseded by a chapter that ALREADY EXISTS — no new bytes (#60).
262
+ *
263
+ * The residue after a project-wide repair: a husk whose span was re-archived correctly by an earlier
264
+ * run, so re-rendering it now is a no-op and `supersedeChapter` (which commits replacements) can never
265
+ * run. The knowledge is safe; only the false record is still circulating. This closes that last step:
266
+ * point the husk at whatever active chapter covers its seqs, and let the derived layers drop it.
267
+ * Refuses (returns the state unchanged with a reason) when nothing covers the span — because silently
268
+ * superseding an uncovered span would delete the only claim that content exists.
269
+ */
270
+ export function markSupersededBy(state, overNumber, byNumber, reason, at = Date.now()) {
271
+ const over = state.chapters.find((c) => c.number === overNumber);
272
+ const by = state.chapters.find((c) => c.number === byNumber);
273
+ if (over === undefined)
274
+ return { state, problem: `no record for chapter ${overNumber}` };
275
+ if (by === undefined)
276
+ return { state, problem: `no covering chapter ${byNumber} to supersede ${overNumber} with` };
277
+ if (byNumber === overNumber)
278
+ return { state, problem: `chapter ${overNumber} cannot supersede itself` };
279
+ // Full coverage is the caller's job (`coveringChapter` returns a SET); this guard only insists the
280
+ // named successor starts no later than the husk, so the citation never claims a partial span.
281
+ if (by.startSeq > over.startSeq) {
282
+ return { state, problem: `chapter ${byNumber} starts at ${by.startSeq}, above ${overNumber}'s span start ${over.startSeq}` };
283
+ }
284
+ return {
285
+ state: {
286
+ ...state,
287
+ chapters: state.chapters.map((c) => (c.number === overNumber
288
+ ? { ...c, status: 'superseded', supersededBy: byNumber, repairs: [...(c.repairs ?? []), { class: reason, over: overNumber, at }] }
289
+ : c)),
290
+ },
291
+ };
292
+ }
293
+ /**
294
+ * The active chapter whose span fully covers `[from..to]`, if any — the candidate a husk defers to.
295
+ * `exceptNumber` is not cosmetic: the husk covers its OWN span, so without excluding it the search
296
+ * returns the record about to be superseded and `markSupersededBy` would point a chapter at itself
297
+ * (caught by `tests/unit/repair.test.ts`).
298
+ */
299
+ export function coveringChapter(state, from, to, exceptNumber) {
300
+ // A REPAIR may have split the span across several chapters, so coverage is a UNION, not one record:
301
+ // insisting on a single coverer left 14 husks unsuperseded in the first full project run, each
302
+ // "not covered" when in fact three chapters carried it between them.
303
+ const pool = state.chapters.filter((c) => isActiveChapter(c) && c.number !== exceptNumber && c.startSeq <= to && c.endSeq >= from);
304
+ const sorted = [...pool].sort((a, b) => a.startSeq - b.startSeq);
305
+ let cursor = from;
306
+ const chosen = [];
307
+ for (const c of sorted) {
308
+ if (c.startSeq > cursor)
309
+ break; // a real hole: nothing reaches `cursor`
310
+ chosen.push(c);
311
+ cursor = Math.max(cursor, c.endSeq + 1);
312
+ if (cursor > to)
313
+ return chosen;
314
+ }
315
+ return [];
316
+ }
317
+ /** Raise a counter to the first number nothing has spent. Upward ONLY — never a rewind. */
318
+ export function raiseCounters(state) {
319
+ const maxChapter = state.chapters.reduce((m, c) => Math.max(m, c.number), 0);
320
+ const maxPlan = state.chapters.flatMap((c) => c.planDocs ?? [])
321
+ .map((d) => /plan-(\d+)-/.exec(d.path)?.[1]).filter((n) => n !== undefined).map(Number)
322
+ .reduce((m, n) => Math.max(m, n), 0);
323
+ return {
324
+ ...state,
325
+ nextChapterNumber: Math.max(state.nextChapterNumber, maxChapter + 1),
326
+ nextPlanNumber: Math.max(state.nextPlanNumber, maxPlan + 1),
327
+ };
328
+ }
329
+ /** Drop a manifest/reservation whose work never landed, keeping every number spent. */
330
+ export function expireBookkeeping(state, keys) {
331
+ const plans = { ...state.plans };
332
+ const reservations = { ...state.reservations };
333
+ for (const k of keys) {
334
+ delete plans[k];
335
+ delete reservations[k];
336
+ }
337
+ return { ...state, plans, reservations };
338
+ }
339
+ export { releaseReservation };
340
+ /** How an entry is undone. The inverse is DERIVED, never hand-written, so a journal cannot lie about itself. */
341
+ export function journalEntryInverse(e) {
342
+ if (e.kind === 'registry')
343
+ return { undo: 'restore-registry-rev' };
344
+ if (e.kind === 'quarantine')
345
+ return { undo: 'restore-from-quarantine' };
346
+ if (e.beforeSha === null)
347
+ return { undo: 'remove' };
348
+ return { undo: 'restore-from-quarantine' };
349
+ }
350
+ /** Chapter-file frontmatter keys a repair adds. `renderChapter` owns every other byte. */
351
+ export function repairFrontmatter(lines, marks) {
352
+ return [...lines, ...marks.map((m) => `repairs: ${m.path}`)];
353
+ }
354
+ //# sourceMappingURL=repair.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repair.js","sourceRoot":"","sources":["../src/repair.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,28 @@ export interface RulesIo {
16
16
  /** provenance of the ADD path: 'manual' for commands, the session id for the tool */
17
17
  sourceSession?: string;
18
18
  now: () => Date;
19
+ /**
20
+ * #50 §7.5: the current session's ancestor path (root-first), so `active`,
21
+ * `list --scope session` and `conflicts` can tell which session rules bind.
22
+ * Absent ⇒ the session tier is reported as unresolved, never guessed.
23
+ */
24
+ ancestors?: () => Promise<ReadonlySet<string>>;
25
+ /** #52: true when the ancestry walk hit its cap (delegation or continuation). */
26
+ ancestryTruncated?: () => Promise<boolean>;
27
+ /** #50 §7.7: ONE bounded model call, report-only. Absent ⇒ the verb refuses. */
28
+ ask?: (prompt: string) => Promise<string>;
29
+ /** §7.3/§7.4 numbers the answer is measured with — the SAME config the doors
30
+ * render from, so `active` cannot report a view the head will not show. */
31
+ budgetTokens?: number;
32
+ projectCap?: number;
33
+ sessionCap?: number;
34
+ /** §7.5: reported by `active`, and drives whether mined rules govern on arrival */
35
+ autoActivate?: boolean | undefined;
36
+ /** the shared settings table (`rules.model` lives beside `enrichment.model`) */
37
+ settings?: {
38
+ get(key: string): string | undefined;
39
+ put(key: string, value: string): Promise<void>;
40
+ } | undefined;
19
41
  }
20
42
  export interface RulesReply {
21
43
  kind: 'success' | 'error';