@fractalsynapse/dsh-chapters 0.0.0-stage → 0.2.21
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.
- package/LICENSE +14 -0
- package/README.md +76 -2
- package/cordis.patch.yml +363 -0
- package/docs/architecture.md +692 -0
- package/docs/autorun-guide.md +248 -0
- package/docs/backlog.md +2022 -0
- package/docs/contract.md +938 -0
- package/docs/development.md +990 -0
- package/docs/host-compaction-seam.md +225 -0
- package/docs/host-protected-head-ask.md +80 -0
- package/docs/knowledge-repo.md +1332 -0
- package/docs/plans-carriage.md +571 -0
- package/docs/project-state.md +642 -0
- package/docs/provider.md +98 -0
- package/docs/superpowers/plans/2026-10-17-chapters-save.md +198 -0
- package/docs/superpowers/plans/2026-11-02-chapter-removal.md +151 -0
- package/docs/superpowers/specs/2026-11-02-chapter-removal-design.md +115 -0
- package/docs/verify.md +561 -0
- package/lib/archive.d.ts +161 -0
- package/lib/archive.js +229 -0
- package/lib/archive.js.map +1 -0
- package/lib/arrival.d.ts +23 -0
- package/lib/arrival.js +125 -0
- package/lib/arrival.js.map +1 -0
- package/lib/artifact-query.d.ts +62 -0
- package/lib/artifact-query.js +187 -0
- package/lib/artifact-query.js.map +1 -0
- package/lib/attach.d.ts +46 -0
- package/lib/attach.js +120 -0
- package/lib/attach.js.map +1 -0
- package/lib/auto-save.d.ts +145 -0
- package/lib/auto-save.js +334 -0
- package/lib/auto-save.js.map +1 -0
- package/lib/aux-message.d.ts +17 -0
- package/lib/aux-message.js +20 -0
- package/lib/aux-message.js.map +1 -0
- package/lib/client.js +1419 -0
- package/lib/client.js.map +1 -0
- package/lib/codegraph.d.ts +76 -0
- package/lib/codegraph.js +190 -0
- package/lib/codegraph.js.map +1 -0
- package/lib/commands.d.ts +52 -0
- package/lib/commands.js +946 -0
- package/lib/commands.js.map +1 -0
- package/lib/compose.d.ts +30 -0
- package/lib/compose.js +185 -0
- package/lib/compose.js.map +1 -0
- package/lib/continue-core.d.ts +245 -0
- package/lib/continue-core.js +405 -0
- package/lib/continue-core.js.map +1 -0
- package/lib/diag.d.ts +55 -0
- package/lib/diag.js +186 -0
- package/lib/diag.js.map +1 -0
- package/lib/engine-core.d.ts +301 -0
- package/lib/engine-core.js +531 -0
- package/lib/engine-core.js.map +1 -0
- package/lib/engine-note.d.ts +35 -0
- package/lib/engine-note.js +32 -0
- package/lib/engine-note.js.map +1 -0
- package/lib/engine.d.ts +329 -0
- package/lib/engine.js +1179 -0
- package/lib/engine.js.map +1 -0
- package/lib/enrich-queue.d.ts +66 -0
- package/lib/enrich-queue.js +126 -0
- package/lib/enrich-queue.js.map +1 -0
- package/lib/enrich-store.d.ts +31 -0
- package/lib/enrich-store.js +103 -0
- package/lib/enrich-store.js.map +1 -0
- package/lib/enrich-wire.d.ts +163 -0
- package/lib/enrich-wire.js +353 -0
- package/lib/enrich-wire.js.map +1 -0
- package/lib/enrich.d.ts +102 -0
- package/lib/enrich.js +267 -0
- package/lib/enrich.js.map +1 -0
- package/lib/gitops.d.ts +107 -0
- package/lib/gitops.js +539 -0
- package/lib/gitops.js.map +1 -0
- package/lib/index.d.ts +241 -0
- package/lib/index.js +1162 -0
- package/lib/index.js.map +1 -0
- package/lib/indexing.d.ts +98 -0
- package/lib/indexing.js +223 -0
- package/lib/indexing.js.map +1 -0
- package/lib/injections.d.ts +90 -0
- package/lib/injections.js +165 -0
- package/lib/injections.js.map +1 -0
- package/lib/last-resort.d.ts +24 -0
- package/lib/last-resort.js +27 -0
- package/lib/last-resort.js.map +1 -0
- package/lib/log-shape.d.ts +38 -0
- package/lib/log-shape.js +93 -0
- package/lib/log-shape.js.map +1 -0
- package/lib/models-command.d.ts +74 -0
- package/lib/models-command.js +100 -0
- package/lib/models-command.js.map +1 -0
- package/lib/notice.d.ts +74 -0
- package/lib/notice.js +92 -0
- package/lib/notice.js.map +1 -0
- package/lib/plans.d.ts +154 -0
- package/lib/plans.js +315 -0
- package/lib/plans.js.map +1 -0
- package/lib/preset.d.ts +186 -0
- package/lib/preset.js +212 -0
- package/lib/preset.js.map +1 -0
- package/lib/prompt-keys.d.ts +7 -0
- package/lib/prompt-keys.js +8 -0
- package/lib/prompt-keys.js.map +1 -0
- package/lib/prompt-loop.d.ts +73 -0
- package/lib/prompt-loop.js +147 -0
- package/lib/prompt-loop.js.map +1 -0
- package/lib/prompt-push.d.ts +47 -0
- package/lib/prompt-push.js +115 -0
- package/lib/prompt-push.js.map +1 -0
- package/lib/prompt-runner.d.ts +48 -0
- package/lib/prompt-runner.js +90 -0
- package/lib/prompt-runner.js.map +1 -0
- package/lib/prompt-state.d.ts +142 -0
- package/lib/prompt-state.js +101 -0
- package/lib/prompt-state.js.map +1 -0
- package/lib/prompt.d.ts +270 -0
- package/lib/prompt.js +408 -0
- package/lib/prompt.js.map +1 -0
- package/lib/provider.d.ts +44 -0
- package/lib/provider.js +66 -0
- package/lib/provider.js.map +1 -0
- package/lib/redact.d.ts +24 -0
- package/lib/redact.js +85 -0
- package/lib/redact.js.map +1 -0
- package/lib/registry.d.ts +187 -0
- package/lib/registry.js +235 -0
- package/lib/registry.js.map +1 -0
- package/lib/removal.d.ts +159 -0
- package/lib/removal.js +556 -0
- package/lib/removal.js.map +1 -0
- package/lib/render.d.ts +97 -0
- package/lib/render.js +530 -0
- package/lib/render.js.map +1 -0
- package/lib/repair-run.d.ts +76 -0
- package/lib/repair-run.js +506 -0
- package/lib/repair-run.js.map +1 -0
- package/lib/repair.d.ts +208 -0
- package/lib/repair.js +357 -0
- package/lib/repair.js.map +1 -0
- package/lib/repo.d.ts +78 -0
- package/lib/repo.js +184 -0
- package/lib/repo.js.map +1 -0
- package/lib/rules-commands.d.ts +46 -0
- package/lib/rules-commands.js +379 -0
- package/lib/rules-commands.js.map +1 -0
- package/lib/rules.d.ts +267 -0
- package/lib/rules.js +478 -0
- package/lib/rules.js.map +1 -0
- package/lib/save-core.d.ts +72 -0
- package/lib/save-core.js +220 -0
- package/lib/save-core.js.map +1 -0
- package/lib/search.d.ts +112 -0
- package/lib/search.js +282 -0
- package/lib/search.js.map +1 -0
- package/lib/session-rules.d.ts +222 -0
- package/lib/session-rules.js +454 -0
- package/lib/session-rules.js.map +1 -0
- package/lib/signature.d.ts +45 -0
- package/lib/signature.js +199 -0
- package/lib/signature.js.map +1 -0
- package/lib/store.d.ts +156 -0
- package/lib/store.js +368 -0
- package/lib/store.js.map +1 -0
- package/lib/sync.d.ts +220 -0
- package/lib/sync.js +810 -0
- package/lib/sync.js.map +1 -0
- package/lib/tools.d.ts +113 -0
- package/lib/tools.js +1090 -0
- package/lib/tools.js.map +1 -0
- package/lib/treedx/client.d.ts +57 -0
- package/lib/treedx/client.js +82 -0
- package/lib/treedx/client.js.map +1 -0
- package/lib/treedx/provider.d.ts +39 -0
- package/lib/treedx/provider.js +479 -0
- package/lib/treedx/provider.js.map +1 -0
- package/lib/treedx/state.d.ts +27 -0
- package/lib/treedx/state.js +65 -0
- package/lib/treedx/state.js.map +1 -0
- package/lib/types.d.ts +210 -0
- package/lib/types.js +31 -0
- package/lib/types.js.map +1 -0
- package/lib/version.d.ts +9 -0
- package/lib/version.js +10 -0
- package/lib/version.js.map +1 -0
- package/lib/vocabulary.d.ts +41 -0
- package/lib/vocabulary.js +118 -0
- package/lib/vocabulary.js.map +1 -0
- package/lib/warnings.d.ts +10 -0
- package/lib/warnings.js +18 -0
- package/lib/warnings.js.map +1 -0
- package/package.json +151 -3
|
@@ -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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"}
|
package/lib/enrich.d.ts
ADDED
|
@@ -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
|
+
};
|