@fractalsynapse/dsh-chapters 0.0.0-stage → 0.2.20

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 (195) hide show
  1. package/LICENSE +14 -0
  2. package/README.md +76 -2
  3. package/cordis.patch.yml +363 -0
  4. package/docs/architecture.md +692 -0
  5. package/docs/autorun-guide.md +248 -0
  6. package/docs/backlog.md +2022 -0
  7. package/docs/contract.md +938 -0
  8. package/docs/development.md +990 -0
  9. package/docs/host-compaction-seam.md +225 -0
  10. package/docs/host-protected-head-ask.md +80 -0
  11. package/docs/knowledge-repo.md +1332 -0
  12. package/docs/plans-carriage.md +571 -0
  13. package/docs/project-state.md +642 -0
  14. package/docs/provider.md +98 -0
  15. package/docs/superpowers/plans/2026-10-17-chapters-save.md +198 -0
  16. package/docs/superpowers/plans/2026-11-02-chapter-removal.md +151 -0
  17. package/docs/superpowers/specs/2026-11-02-chapter-removal-design.md +115 -0
  18. package/docs/verify.md +561 -0
  19. package/lib/archive.d.ts +161 -0
  20. package/lib/archive.js +229 -0
  21. package/lib/archive.js.map +1 -0
  22. package/lib/arrival.d.ts +23 -0
  23. package/lib/arrival.js +125 -0
  24. package/lib/arrival.js.map +1 -0
  25. package/lib/artifact-query.d.ts +62 -0
  26. package/lib/artifact-query.js +187 -0
  27. package/lib/artifact-query.js.map +1 -0
  28. package/lib/attach.d.ts +46 -0
  29. package/lib/attach.js +120 -0
  30. package/lib/attach.js.map +1 -0
  31. package/lib/auto-save.d.ts +145 -0
  32. package/lib/auto-save.js +334 -0
  33. package/lib/auto-save.js.map +1 -0
  34. package/lib/aux-message.d.ts +17 -0
  35. package/lib/aux-message.js +20 -0
  36. package/lib/aux-message.js.map +1 -0
  37. package/lib/client.js +1419 -0
  38. package/lib/client.js.map +1 -0
  39. package/lib/codegraph.d.ts +76 -0
  40. package/lib/codegraph.js +190 -0
  41. package/lib/codegraph.js.map +1 -0
  42. package/lib/commands.d.ts +52 -0
  43. package/lib/commands.js +946 -0
  44. package/lib/commands.js.map +1 -0
  45. package/lib/compose.d.ts +30 -0
  46. package/lib/compose.js +185 -0
  47. package/lib/compose.js.map +1 -0
  48. package/lib/continue-core.d.ts +245 -0
  49. package/lib/continue-core.js +405 -0
  50. package/lib/continue-core.js.map +1 -0
  51. package/lib/diag.d.ts +55 -0
  52. package/lib/diag.js +186 -0
  53. package/lib/diag.js.map +1 -0
  54. package/lib/engine-core.d.ts +301 -0
  55. package/lib/engine-core.js +531 -0
  56. package/lib/engine-core.js.map +1 -0
  57. package/lib/engine-note.d.ts +35 -0
  58. package/lib/engine-note.js +32 -0
  59. package/lib/engine-note.js.map +1 -0
  60. package/lib/engine.d.ts +329 -0
  61. package/lib/engine.js +1179 -0
  62. package/lib/engine.js.map +1 -0
  63. package/lib/enrich-queue.d.ts +66 -0
  64. package/lib/enrich-queue.js +126 -0
  65. package/lib/enrich-queue.js.map +1 -0
  66. package/lib/enrich-store.d.ts +31 -0
  67. package/lib/enrich-store.js +103 -0
  68. package/lib/enrich-store.js.map +1 -0
  69. package/lib/enrich-wire.d.ts +163 -0
  70. package/lib/enrich-wire.js +353 -0
  71. package/lib/enrich-wire.js.map +1 -0
  72. package/lib/enrich.d.ts +102 -0
  73. package/lib/enrich.js +267 -0
  74. package/lib/enrich.js.map +1 -0
  75. package/lib/gitops.d.ts +107 -0
  76. package/lib/gitops.js +539 -0
  77. package/lib/gitops.js.map +1 -0
  78. package/lib/index.d.ts +241 -0
  79. package/lib/index.js +1162 -0
  80. package/lib/index.js.map +1 -0
  81. package/lib/indexing.d.ts +98 -0
  82. package/lib/indexing.js +223 -0
  83. package/lib/indexing.js.map +1 -0
  84. package/lib/injections.d.ts +90 -0
  85. package/lib/injections.js +165 -0
  86. package/lib/injections.js.map +1 -0
  87. package/lib/last-resort.d.ts +24 -0
  88. package/lib/last-resort.js +27 -0
  89. package/lib/last-resort.js.map +1 -0
  90. package/lib/log-shape.d.ts +38 -0
  91. package/lib/log-shape.js +93 -0
  92. package/lib/log-shape.js.map +1 -0
  93. package/lib/models-command.d.ts +74 -0
  94. package/lib/models-command.js +100 -0
  95. package/lib/models-command.js.map +1 -0
  96. package/lib/notice.d.ts +74 -0
  97. package/lib/notice.js +92 -0
  98. package/lib/notice.js.map +1 -0
  99. package/lib/plans.d.ts +154 -0
  100. package/lib/plans.js +315 -0
  101. package/lib/plans.js.map +1 -0
  102. package/lib/preset.d.ts +186 -0
  103. package/lib/preset.js +212 -0
  104. package/lib/preset.js.map +1 -0
  105. package/lib/prompt-keys.d.ts +7 -0
  106. package/lib/prompt-keys.js +8 -0
  107. package/lib/prompt-keys.js.map +1 -0
  108. package/lib/prompt-loop.d.ts +73 -0
  109. package/lib/prompt-loop.js +147 -0
  110. package/lib/prompt-loop.js.map +1 -0
  111. package/lib/prompt-push.d.ts +47 -0
  112. package/lib/prompt-push.js +115 -0
  113. package/lib/prompt-push.js.map +1 -0
  114. package/lib/prompt-runner.d.ts +48 -0
  115. package/lib/prompt-runner.js +90 -0
  116. package/lib/prompt-runner.js.map +1 -0
  117. package/lib/prompt-state.d.ts +142 -0
  118. package/lib/prompt-state.js +101 -0
  119. package/lib/prompt-state.js.map +1 -0
  120. package/lib/prompt.d.ts +270 -0
  121. package/lib/prompt.js +408 -0
  122. package/lib/prompt.js.map +1 -0
  123. package/lib/provider.d.ts +44 -0
  124. package/lib/provider.js +66 -0
  125. package/lib/provider.js.map +1 -0
  126. package/lib/redact.d.ts +24 -0
  127. package/lib/redact.js +85 -0
  128. package/lib/redact.js.map +1 -0
  129. package/lib/registry.d.ts +187 -0
  130. package/lib/registry.js +235 -0
  131. package/lib/registry.js.map +1 -0
  132. package/lib/removal.d.ts +159 -0
  133. package/lib/removal.js +556 -0
  134. package/lib/removal.js.map +1 -0
  135. package/lib/render.d.ts +97 -0
  136. package/lib/render.js +530 -0
  137. package/lib/render.js.map +1 -0
  138. package/lib/repair-run.d.ts +76 -0
  139. package/lib/repair-run.js +506 -0
  140. package/lib/repair-run.js.map +1 -0
  141. package/lib/repair.d.ts +208 -0
  142. package/lib/repair.js +357 -0
  143. package/lib/repair.js.map +1 -0
  144. package/lib/repo.d.ts +78 -0
  145. package/lib/repo.js +184 -0
  146. package/lib/repo.js.map +1 -0
  147. package/lib/rules-commands.d.ts +46 -0
  148. package/lib/rules-commands.js +379 -0
  149. package/lib/rules-commands.js.map +1 -0
  150. package/lib/rules.d.ts +267 -0
  151. package/lib/rules.js +478 -0
  152. package/lib/rules.js.map +1 -0
  153. package/lib/save-core.d.ts +72 -0
  154. package/lib/save-core.js +220 -0
  155. package/lib/save-core.js.map +1 -0
  156. package/lib/search.d.ts +112 -0
  157. package/lib/search.js +282 -0
  158. package/lib/search.js.map +1 -0
  159. package/lib/session-rules.d.ts +222 -0
  160. package/lib/session-rules.js +454 -0
  161. package/lib/session-rules.js.map +1 -0
  162. package/lib/signature.d.ts +45 -0
  163. package/lib/signature.js +199 -0
  164. package/lib/signature.js.map +1 -0
  165. package/lib/store.d.ts +156 -0
  166. package/lib/store.js +368 -0
  167. package/lib/store.js.map +1 -0
  168. package/lib/sync.d.ts +220 -0
  169. package/lib/sync.js +810 -0
  170. package/lib/sync.js.map +1 -0
  171. package/lib/tools.d.ts +113 -0
  172. package/lib/tools.js +1090 -0
  173. package/lib/tools.js.map +1 -0
  174. package/lib/treedx/client.d.ts +57 -0
  175. package/lib/treedx/client.js +82 -0
  176. package/lib/treedx/client.js.map +1 -0
  177. package/lib/treedx/provider.d.ts +39 -0
  178. package/lib/treedx/provider.js +479 -0
  179. package/lib/treedx/provider.js.map +1 -0
  180. package/lib/treedx/state.d.ts +27 -0
  181. package/lib/treedx/state.js +65 -0
  182. package/lib/treedx/state.js.map +1 -0
  183. package/lib/types.d.ts +210 -0
  184. package/lib/types.js +31 -0
  185. package/lib/types.js.map +1 -0
  186. package/lib/version.d.ts +9 -0
  187. package/lib/version.js +10 -0
  188. package/lib/version.js.map +1 -0
  189. package/lib/vocabulary.d.ts +41 -0
  190. package/lib/vocabulary.js +118 -0
  191. package/lib/vocabulary.js.map +1 -0
  192. package/lib/warnings.d.ts +10 -0
  193. package/lib/warnings.js +18 -0
  194. package/lib/warnings.js.map +1 -0
  195. package/package.json +151 -4
@@ -0,0 +1,353 @@
1
+ /**
2
+ * P2 S6 — enrichment wiring: binds the pure ladder (enrich.ts) and the
3
+ * guarded persistence (enrich-store.ts) to the registry domain and the sync
4
+ * scheduler, per plane.
5
+ *
6
+ * Division of labor (deliberate):
7
+ * - REALM engine owns the AUTO triggers (afterPush/idle/both): it sees the
8
+ * conversation's routed model (requestHeader) and fires after its own
9
+ * pushes/finalizes; it persists the resolved provider/model route and a
10
+ * state heartbeat into the shared settings table.
11
+ * - HOST plane runs the command surface (manual drains, model override,
12
+ * report/status) and reads the same tables; its queue is trigger-manual
13
+ * so auto work never double-runs.
14
+ *
15
+ * The ladder per chapter: build slice -> fetch -> validate; invalid -> ONE
16
+ * retry with a nudge; still invalid -> keep deterministic values (never
17
+ * blocks, never blanks). Frontmatter write goes through the body-hash guard;
18
+ * the registry record mirrors the new fields; a modified file is republished
19
+ * via the scheduler (debounced).
20
+ */
21
+ import fs from 'node:fs';
22
+ import { createEnrichQueue } from "./enrich-queue.js";
23
+ import { buildEnrichInput, buildMineInput, parseEnrichResult, parseMinedRules, applyEnrich } from "./enrich.js";
24
+ import { parseChapterFile, updateChapterFrontmatter } from "./enrich-store.js";
25
+ import { resolveStoredPath } from "./archive.js";
26
+ import { isActiveChapter } from "./registry.js";
27
+ const ROUTE_KEY = 'enrichment.route';
28
+ const STATE_KEY = 'enrichment.state';
29
+ const stripFence = (chunk) => chunk.trim().replace(/^```[a-z]*\n?/, '').replace(/\n?```\s*$/, '').trim();
30
+ /** YAML block for the generated: frontmatter field (newest-first chains) */
31
+ export function renderGeneratedBlock(gen) {
32
+ const lines = [];
33
+ for (const key of ['title', 'summary', 'topics']) {
34
+ const chain = gen[key];
35
+ if (chain === undefined || chain.length === 0)
36
+ continue;
37
+ lines.push(` ${key}:`);
38
+ for (const m of chain) {
39
+ if (m.by === 'model')
40
+ lines.push(` - by: model`, ` model: ${m.model}`, ` at: ${m.at ?? ''}`,
41
+ // #61: which build wrote it. Absent on records from before the field existed — rendering
42
+ // `pluginVersion: undefined` would be a lie about a legacy row.
43
+ ...(m.pluginVersion !== undefined && m.pluginVersion !== '' ? [` pluginVersion: ${m.pluginVersion}`] : []));
44
+ else
45
+ lines.push(` - by: deterministic`);
46
+ }
47
+ }
48
+ return '\n' + lines.join('\n');
49
+ }
50
+ /**
51
+ * The HUMAN bytes of a chapter, and only these. The annotator input splits the
52
+ * body on user-role markers and slices(1) — which leaves every chunk RUNNING ON
53
+ * into the
54
+ * assistant reply that follows it, so it is not a set of user turns. For the
55
+ * verbatim-quote gate (§7.5) that distinction is the whole mechanism: a quote
56
+ * found in assistant prose is the model restating an instruction (the
57
+ * amplification path), never evidence a human gave one. So each chunk is cut at
58
+ * the next role marker before it is offered as evidence.
59
+ */
60
+ export function humanBytesOf(body) {
61
+ const out = [];
62
+ // walk: a role label, then its text until the NEXT label
63
+ const re = /\*\*(User|Assistant)[^*\n]*:\*\*/g;
64
+ let m;
65
+ const marks = [];
66
+ while ((m = re.exec(body)) !== null)
67
+ marks.push({ role: m[1], start: m.index, end: m.index + m[0].length });
68
+ for (let i = 0; i < marks.length; i += 1) {
69
+ if (marks[i].role !== 'User')
70
+ continue;
71
+ const next = i + 1 < marks.length ? marks[i + 1].start : body.length;
72
+ const text = body.slice(marks[i].end, next);
73
+ if (text.trim() !== '')
74
+ out.push(text.trim());
75
+ }
76
+ return out.join('\n');
77
+ }
78
+ /**
79
+ * The ONE "does this chapter still need annotating?" test, used by BOTH the queue and `pendingCount`
80
+ * (#61). They were two hand-written loops over `chaptersOf` that had already drifted in shape, and the
81
+ * missing half was the minimum-content gate: five model calls in the field were spent titling husks
82
+ * ("Empty conversation span with unknown events and zero-byte results") — money thrown at nothing to
83
+ * annotate, and worse, the AI rename replaced a `FRAGMENT_TITLE`-shaped title so `indexing.ts` could no
84
+ * longer stitch adjacent legacy fragments (indexing.ts:43). So an empty chapter is not a candidate, and
85
+ * its deterministic title survives to be stitched.
86
+ */
87
+ export function isPendingChapter(c, modelKey) {
88
+ if ((c.messages ?? 1) === 0)
89
+ return false;
90
+ const top = c.generated?.title?.[0];
91
+ return !(top?.by === 'model' && top.model === modelKey);
92
+ }
93
+ function chaptersOf(state) {
94
+ const c = state?.chapters;
95
+ // #60, widened #255: the enrichment queue reads registry chapters through the ONE predicate, so a
96
+ // repaired-away husk AND an operator-removed stub are never annotated and never re-enter the corpus
97
+ // through the ladder. The old inline `!== 'superseded'` here was a second predicate (#59 shape) —
98
+ // tests/unit/one-predicate.test.ts keeps comparisons against tombstone statuses inside registry.ts.
99
+ return Array.isArray(c) ? c.filter(isActiveChapter) : [];
100
+ }
101
+ export function createEnrichWiring(deps) {
102
+ const resolveRoute = () => {
103
+ const override = deps.store.getSetting('enrichment.model') ?? '';
104
+ const spec = (override !== '' ? override : deps.config.model).trim();
105
+ if (spec !== '' && spec !== 'conversation') {
106
+ const i = spec.indexOf('/');
107
+ if (i > 0)
108
+ return { provider: spec.slice(0, i), model: spec.slice(i + 1) };
109
+ return { provider: deps.conversationRoute()?.provider ?? '', model: spec };
110
+ }
111
+ const persisted = deps.store.getSetting(ROUTE_KEY);
112
+ if (persisted !== undefined) {
113
+ const i = persisted.indexOf('/');
114
+ if (i > 0)
115
+ return { provider: persisted.slice(0, i), model: persisted.slice(i + 1) };
116
+ }
117
+ return deps.conversationRoute();
118
+ };
119
+ const modelKey = () => {
120
+ const r = resolveRoute();
121
+ return r !== null && r.model !== '' ? `${r.provider}/${r.model}` : 'conversation';
122
+ };
123
+ let rememberedCwd;
124
+ const ladder = async (key) => {
125
+ const sep = key.lastIndexOf('#');
126
+ const sid = key.slice(0, sep);
127
+ const num = Number(key.slice(sep + 1));
128
+ const cwd = deps.cwd() ?? rememberedCwd;
129
+ if (cwd === undefined)
130
+ return { ok: false, skipped: 'no workspace cwd yet (a sync or command arms it)' };
131
+ try {
132
+ // Pre-flight read: cheap, and only used to find the file to annotate. The WRITE below never
133
+ // touches this snapshot (#59).
134
+ const state = await deps.store.get(sid);
135
+ const rec = state.chapters.find((c) => c.number === num);
136
+ if (rec === undefined)
137
+ return { ok: false, skipped: 'record gone' };
138
+ const file = resolveStoredPath(cwd, rec.path);
139
+ if (!fs.existsSync(file))
140
+ return { ok: false, skipped: 'chapter file absent' };
141
+ const doc = parseChapterFile(fs.readFileSync(file, 'utf8'));
142
+ // A plan document is a WORK DIRECTIVE: its body is the approved text, and an
143
+ // annotator rewriting its summary is a paraphrase of an order (invariant 4's
144
+ // discipline applied to the ladder). Directives are indexed, cited and searched
145
+ // as they are; only transcript chapters are ever annotated.
146
+ if (doc.fmLines.some((l) => /^kind:\s*plan\s*$/.test(l)))
147
+ return { ok: false, skipped: 'plan documents are directives — never annotated' };
148
+ const body = doc.body;
149
+ const userChunks = body.split(/\*\*User[^*\n]*:\*\*/g).slice(1);
150
+ const asstChunks = body.split(/\*\*Assistant[^*\n]*:\*\*/g).slice(1);
151
+ // Optional CodeGraph structural context: extract code-shaped tokens from
152
+ // the chapter body and explore them against the project index. Fire-and-forget;
153
+ // failure → undefined (buildEnrichInput treats it as zero bytes).
154
+ let codegraphContext;
155
+ try {
156
+ const cg = await import("./codegraph.js");
157
+ const root = cg.findCodegraphRoot(cwd);
158
+ if (root !== undefined) {
159
+ const tokens = cg.extractCodeTokens(body, 5);
160
+ if (tokens.length > 0) {
161
+ codegraphContext = await cg.exploreCodegraph(undefined, root, tokens.join(' '), 800, 15000);
162
+ if (codegraphContext === '')
163
+ codegraphContext = undefined;
164
+ }
165
+ }
166
+ }
167
+ catch { /* CodeGraph unavailable or failed — enrichment proceeds without */ }
168
+ const input = buildEnrichInput({ title: rec.title }, {
169
+ requests: userChunks.slice(-3).map(stripFence),
170
+ ...(asstChunks.length > 0 ? { firstAssistant: stripFence(asstChunks[0]) } : {}),
171
+ ...(asstChunks.length > 1 ? { lastAssistant: stripFence(asstChunks[asstChunks.length - 1]) } : asstChunks.length === 1 && userChunks.length === 0 ? { lastAssistant: stripFence(asstChunks[0]) } : {}),
172
+ }, body.slice(0, 8000), codegraphContext);
173
+ const route = resolveRoute();
174
+ const key2 = modelKey();
175
+ let result = parseEnrichResult(await deps.fetch(input, route));
176
+ if (result === null) {
177
+ // one retry with a nudge; garbage stays non-fatal (record §6.1)
178
+ result = parseEnrichResult(await deps.fetch(input + '\nRemember: reply with ONLY the JSON object, no other text.', route));
179
+ }
180
+ // §7.5 mining, and it happens BEFORE the hash-guarded frontmatter write, so a
181
+ // chapter whose annotation is refused still contributes its standing orders.
182
+ const humanText = humanBytesOf(body);
183
+ let mined = result !== null ? result.rules : [];
184
+ // A dedicated governance model is opt-in; when set, ITS answer is what gets
185
+ // mined and the annotation pass's rules are ignored — two models minting
186
+ // rules for one chapter would just duplicate under different judgement.
187
+ const mineSpec = (deps.store.getSetting('rules.model') ?? deps.config.rulesModel ?? '').trim();
188
+ if (deps.config.mineRules !== false && mineSpec !== '' && mineSpec !== 'conversation') {
189
+ try {
190
+ const sep = mineSpec.indexOf('/');
191
+ const base = resolveRoute();
192
+ const route = sep > 0
193
+ ? { provider: mineSpec.slice(0, sep), model: mineSpec.slice(sep + 1) }
194
+ : { provider: base?.provider ?? '', model: mineSpec };
195
+ if (route.provider !== '') {
196
+ mined = parseMinedRules(await deps.fetch(buildMineInput({ requests: userChunks.map(stripFence) }, body.slice(0, 6000)), route));
197
+ }
198
+ else {
199
+ deps.warn(`rules.model "${mineSpec}" names no provider to route through — mining with the annotation result instead`);
200
+ }
201
+ }
202
+ catch (error) {
203
+ deps.warn(`rule mining pass failed (${String(error?.message ?? error).slice(0, 120)}) — the annotation is unaffected`);
204
+ mined = [];
205
+ }
206
+ }
207
+ if (mined.length > 0) {
208
+ if (deps.config.mineRules === false) {
209
+ deps.log(`rule mining skipped for ${sid}#${num}: ${mined.length} candidate(s) dropped (rulesEnrichment off)`);
210
+ }
211
+ else if (deps.onMinedRules === undefined) {
212
+ deps.warn(`rule mining UNWIRED on this plane: ${mined.length} candidate(s) for ${sid}#${num} were not recorded — the sink owns disk + identity`);
213
+ }
214
+ else {
215
+ try {
216
+ const got = await deps.onMinedRules({
217
+ cwd,
218
+ sessionId: sid,
219
+ chapterNumber: num,
220
+ // The human's own bytes, cut at the next role marker. They decide
221
+ // whether a mined rule is LABELLED `stated` or `inferred` — a warrant
222
+ // shown to the human, not permission to govern (§7.5, 2026-10-21).
223
+ humanText,
224
+ rules: mined,
225
+ max: deps.config.mineCap ?? 3,
226
+ autoActivate: deps.config.rulesAutoActivate !== false,
227
+ });
228
+ if (got.written > 0) {
229
+ deps.log(`rule mining ${sid}#${num}: ${got.written} recorded (${got.stated} stated by you, ${got.inferred} inferred${got.pending > 0 ? `, ${got.pending} held for review` : ', all governing now'} — /chapters-rule list --scope session)`);
230
+ // session rules are LOCAL: nothing is armed on the scheduler (§7.5)
231
+ }
232
+ }
233
+ catch (error) {
234
+ deps.warn(`rule mining failed for ${sid}#${num}: ${String(error?.message ?? error).slice(0, 140)} — the annotation itself is unaffected`);
235
+ }
236
+ }
237
+ }
238
+ const current = { title: rec.title, summary: rec.summary, topics: rec.topics, ...(rec.generated !== undefined ? { generated: rec.generated } : {}) };
239
+ const applied = applyEnrich(current, result, key2, new Date().toISOString());
240
+ if (!applied.changed)
241
+ return { ok: false, skipped: result === null ? 'model output invalid; deterministic kept' : 'already enriched' };
242
+ const v = applied.values;
243
+ const written = updateChapterFrontmatter(file, {
244
+ title: JSON.stringify(v.title),
245
+ summary: JSON.stringify(v.summary),
246
+ topics: `[${v.topics.map((t) => JSON.stringify(t)).join(', ')}]`,
247
+ generated: renderGeneratedBlock(v.generated),
248
+ }, typeof rec.sha256 === 'string' ? rec.sha256 : undefined);
249
+ // #59: this put was built from a row read BEFORE the model call, so every chapter annotated
250
+ // late enough rewound whatever another door had committed in the meantime — the field
251
+ // instance landed at 04:53:52.841 over a compaction commit from 04:53:50.915. The whole
252
+ // remaining step is now ONE section over a fresh read: re-find the record, write the file,
253
+ // re-anchor the row. Nothing derived from a pre-model snapshot survives into the write.
254
+ await deps.store.mutate(sid, (fresh) => {
255
+ const cur = fresh.chapters.find((c) => c.number === num);
256
+ if (cur === undefined)
257
+ return fresh; // record vanished under us: the file write already happened, the row is its own truth
258
+ return {
259
+ ...fresh,
260
+ chapters: fresh.chapters.map((c) => c.number === num
261
+ // re-anchor the registry's whole-file hash after the sanctioned write
262
+ // so the cite-time tamper check stays truthful for every descendant
263
+ ? { ...c, number: c.number, title: v.title, summary: v.summary, topics: v.topics, generated: v.generated, ...(written.changed ? { sha256: written.fileSha256 } : {}) }
264
+ : c),
265
+ };
266
+ });
267
+ // Annotated bytes are new knowledge: arm the push, exactly as before #59 moved the write.
268
+ deps.scheduler?.schedule(cwd, 'archive:enrichment');
269
+ return { ok: true };
270
+ }
271
+ catch (error) {
272
+ deps.warn(`enrichment failed for ${key}: ${String(error?.message ?? error).slice(0, 120)}`);
273
+ return { ok: false, skipped: 'error' };
274
+ }
275
+ };
276
+ const queue = createEnrichQueue({
277
+ listPending: async (modelKey2, cap) => {
278
+ const out = [];
279
+ for (const [sid, st] of deps.store.sessions()) {
280
+ for (const c of chaptersOf(st)) {
281
+ if (!isPendingChapter(c, modelKey2))
282
+ continue;
283
+ out.push({ key: `${sid}#${c.number}`, label: c.title.slice(0, 48) });
284
+ if (out.length >= cap)
285
+ return out;
286
+ }
287
+ }
288
+ return out;
289
+ },
290
+ enrichOne: ladder,
291
+ resolveModel: async () => modelKey(),
292
+ enabled: deps.config.enabled,
293
+ trigger: deps.config.trigger,
294
+ idleMs: deps.config.idleMs,
295
+ batchCap: deps.config.batchCap,
296
+ log: (m) => {
297
+ deps.log(m);
298
+ const r = resolveRoute();
299
+ if (r !== null)
300
+ void deps.store.putSetting(ROUTE_KEY, `${r.provider}/${r.model}`).catch(() => undefined);
301
+ void deps.store.putSetting(STATE_KEY, JSON.stringify({ at: new Date().toISOString(), line: m })).catch(() => undefined);
302
+ },
303
+ ...(deps.setTimer !== undefined ? { setTimer: deps.setTimer } : {}),
304
+ });
305
+ return {
306
+ queue,
307
+ auxRoute: () => resolveRoute(),
308
+ rememberCwd(c) { rememberedCwd = c; },
309
+ async pendingCount() {
310
+ let n = 0;
311
+ const key2 = modelKey();
312
+ for (const [, st] of deps.store.sessions()) {
313
+ for (const c of chaptersOf(st)) {
314
+ if (isPendingChapter(c, key2))
315
+ n += 1;
316
+ }
317
+ }
318
+ return n;
319
+ },
320
+ async runNow(cwd) {
321
+ if (cwd !== undefined)
322
+ rememberedCwd = cwd;
323
+ const processed = await queue.drainNow();
324
+ return { processed, remaining: await this.pendingCount() };
325
+ },
326
+ async setModelOverride(v) {
327
+ if (v === null)
328
+ await deps.store.putSetting('enrichment.model', '');
329
+ else
330
+ await deps.store.putSetting('enrichment.model', v);
331
+ },
332
+ modelOverride() {
333
+ const o = deps.store.getSetting('enrichment.model') ?? '';
334
+ return o === '' ? null : o;
335
+ },
336
+ statusLine() {
337
+ if (!deps.config.enabled)
338
+ return 'enrichment: disabled (signatures-only corpus, fully functional)';
339
+ const override = this.modelOverride();
340
+ const model = override ?? (deps.config.model !== '' ? deps.config.model : 'conversation model');
341
+ const heartbeat = deps.store.getSetting(STATE_KEY);
342
+ let last = '';
343
+ try {
344
+ last = ` · last: ${JSON.parse(heartbeat ?? '{}').line ?? 'idle'}`;
345
+ }
346
+ catch { /* cosmetic */ }
347
+ const mine = deps.config.mineRules === false ? ' · rule mining OFF' : ` · rule mining ON (≤${deps.config.mineCap ?? 3}/chapter, verbatim-quote gated)`;
348
+ return `enrichment: ${deps.config.trigger}, model ${model}${mine}${last}`;
349
+ },
350
+ dispose() { queue.dispose(); },
351
+ };
352
+ }
353
+ //# sourceMappingURL=enrich-wire.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrich-wire.js","sourceRoot":"","sources":["../src/enrich-wire.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * P2 S1 — the enrichment pass, pure core (record §6.1).
3
+ *
4
+ * One structured call per ARCHIVED chapter, input = the cheap slice the user
5
+ * specified (user requests + first/last assistant message, capped, plus the
6
+ * first ~200 tokens of the chapter body), output = validated JSON:
7
+ * {"title": "...", "summary": "...", "topics": ["...", ...], "rules": [{"text","category","quote"}]?}
8
+ *
9
+ * No fs, no harness, no model here — the queue (S2) wires the fetcher. This
10
+ * module guarantees the properties the record stakes:
11
+ * - VALIDATION BEFORE COMMIT: parseEnrichResult accepts nothing malformed;
12
+ * - NEVER BLOCKS OR BLANKS: applyEnrich(null) is a pure no-op — the
13
+ * deterministic title/summary/topics from P1 survive any model failure.
14
+ */
15
+ export interface EnrichSlice {
16
+ requests: string[];
17
+ firstAssistant?: string;
18
+ lastAssistant?: string;
19
+ }
20
+ export interface EnrichResult {
21
+ title: string;
22
+ summary: string;
23
+ topics: string[];
24
+ /**
25
+ * #50 §7.5 — rules mined from this chapter. OPTIONAL: a model that returns the
26
+ * old three-field shape still validates, so every existing stub, fake and tape
27
+ * keeps passing. Each entry carries the human's own words as `quote`, and the
28
+ * quote is what gates activation (`session-rules.quoteIsHuman`) — the pass may
29
+ * PROPOSE a standing order, it may not make one on inference alone.
30
+ */
31
+ rules: MinedRuleOut[];
32
+ }
33
+ export interface MinedRuleOut {
34
+ text: string;
35
+ category: string;
36
+ quote: string;
37
+ /** the model's own claim about its warrant; the plugin re-checks the quote and
38
+ * records `stated` only when the material really contains it (§7.5) */
39
+ basis?: 'stated' | 'inferred' | undefined;
40
+ }
41
+ export type GeneratedMark = {
42
+ by: 'deterministic';
43
+ } | {
44
+ by: 'model';
45
+ model: string;
46
+ at: string;
47
+ pluginVersion?: string | undefined;
48
+ };
49
+ export interface GeneratedProvenance {
50
+ title: GeneratedMark[];
51
+ summary: GeneratedMark[];
52
+ topics: GeneratedMark[];
53
+ }
54
+ export type EnrichableFields = 'title' | 'summary' | 'topics';
55
+ export declare const ENRICH_MAX_TOKENS_DEFAULT = 4000;
56
+ /**
57
+ * Assemble the model input: capped slice, stable order, hard total budget.
58
+ * Deterministic — same chapter material always produces the same prompt,
59
+ * which is what makes the queue's chapter+model idempotency key sound.
60
+ *
61
+ * @param codegraphContext Optional structural context from CodeGraph (symbols,
62
+ * call paths). When present, appended as a bounded block so the enricher can
63
+ * produce more precise topics. Absent → identical output to before this feature.
64
+ */
65
+ export declare function buildEnrichInput(meta: {
66
+ title: string;
67
+ }, slice: EnrichSlice, bodyHead: string, codegraphContext?: string): string;
68
+ /**
69
+ * The validator. Tolerates code fences and surrounding prose (extracts the
70
+ * first JSON object), then requires every field well-shaped. Returns null —
71
+ * never throws — on ANY failure; the retry-then-keep-deterministic ladder is
72
+ * the caller's loop by design.
73
+ */
74
+ export declare function parseEnrichResult(text: string): EnrichResult | null;
75
+ /** The rules-only prompt for a dedicated mining model (§7.5, `rulesModel`). */
76
+ export declare function buildMineInput(slice: EnrichSlice, bodyHead: string): string;
77
+ /**
78
+ * Validate a mining-only answer. Bounds are the same as the annotation path's
79
+ * `rules` field so the two routes cannot produce differently-shaped candidates;
80
+ * an unknown `basis` falls back to the conservative `inferred`.
81
+ */
82
+ export declare function parseMinedRules(text: string): MinedRuleOut[];
83
+ export interface CurrentValues {
84
+ title: string;
85
+ summary: string;
86
+ topics: string[];
87
+ generated?: Partial<GeneratedProvenance>;
88
+ }
89
+ /**
90
+ * Merge an enrichment result into the chapter's model-owned fields.
91
+ * - result === null (ladder bottomed out) → PURE no-op, values + provenance
92
+ * untouched (deterministic P1 values survive forever).
93
+ * - same values AND same newest model author → no-op (idempotent re-run).
94
+ * - otherwise: fields update; each provenance chain grows newest-first, one
95
+ * entry per model (re-annotation by a newer model never erases history).
96
+ * The verbatim BODY is not in this module's universe — callers may only
97
+ * rewrite frontmatter fields (record §6.2), body hash-verified elsewhere.
98
+ */
99
+ export declare function applyEnrich(current: CurrentValues, result: EnrichResult | null, model: string, at: string): {
100
+ values: CurrentValues;
101
+ changed: boolean;
102
+ };