@smartmemory/stratum 0.3.3 → 0.4.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.
- package/dist/cli/guard.js +63 -6
- package/dist/cli/guard.js.map +1 -1
- package/dist/cli/learn.js +226 -0
- package/dist/cli/learn.js.map +1 -0
- package/dist/cli/query_gate.js +2 -1
- package/dist/cli/query_gate.js.map +1 -1
- package/dist/cli/stratum.js +5 -2
- package/dist/cli/stratum.js.map +1 -1
- package/dist/connectors/background.js +58 -10
- package/dist/connectors/background.js.map +1 -1
- package/dist/connectors/base.js +16 -0
- package/dist/connectors/base.js.map +1 -1
- package/dist/connectors/cancellation.js +119 -0
- package/dist/connectors/cancellation.js.map +1 -0
- package/dist/connectors/claude-bg-worker.js +9 -1
- package/dist/connectors/claude-bg-worker.js.map +1 -1
- package/dist/connectors/claude.js +179 -86
- package/dist/connectors/claude.js.map +1 -1
- package/dist/connectors/codex.js +289 -61
- package/dist/connectors/codex.js.map +1 -1
- package/dist/connectors/runner.js +44 -3
- package/dist/connectors/runner.js.map +1 -1
- package/dist/contracts/events.json +34 -1
- package/dist/contracts/guard-signers.allowed +36 -0
- package/dist/contracts/mcp-surface.json +1097 -104
- package/dist/engine/checkpoint.js +8 -1
- package/dist/engine/checkpoint.js.map +1 -1
- package/dist/engine/engine.js +508 -42
- package/dist/engine/engine.js.map +1 -1
- package/dist/engine/evaluate.js +61 -0
- package/dist/engine/evaluate.js.map +1 -0
- package/dist/engine/ledger.js +12 -0
- package/dist/engine/ledger.js.map +1 -1
- package/dist/engine/receipts.js +91 -0
- package/dist/engine/receipts.js.map +1 -0
- package/dist/engine/state.js +51 -1
- package/dist/engine/state.js.map +1 -1
- package/dist/guard/authorization.js +71 -0
- package/dist/guard/authorization.js.map +1 -0
- package/dist/guard/descriptors.js +248 -0
- package/dist/guard/descriptors.js.map +1 -0
- package/dist/guard/errors.js +12 -0
- package/dist/guard/errors.js.map +1 -1
- package/dist/guard/evidence.js +24 -3
- package/dist/guard/evidence.js.map +1 -1
- package/dist/guard/sshsig.js +264 -0
- package/dist/guard/sshsig.js.map +1 -0
- package/dist/guard/store.js +13 -0
- package/dist/guard/store.js.map +1 -1
- package/dist/guard/transition.js +484 -33
- package/dist/guard/transition.js.map +1 -1
- package/dist/guard/trust.js +78 -0
- package/dist/guard/trust.js.map +1 -0
- package/dist/ir/schema.js +8 -1
- package/dist/ir/schema.js.map +1 -1
- package/dist/ir/validate.js +3 -1
- package/dist/ir/validate.js.map +1 -1
- package/dist/judge/judged.js +1 -1
- package/dist/judge/pricing.js +1 -0
- package/dist/judge/pricing.js.map +1 -1
- package/dist/learn/apply.js +600 -0
- package/dist/learn/apply.js.map +1 -0
- package/dist/learn/candidate.js +186 -0
- package/dist/learn/candidate.js.map +1 -0
- package/dist/learn/classify.js +181 -0
- package/dist/learn/classify.js.map +1 -0
- package/dist/learn/harvest.js +138 -0
- package/dist/learn/harvest.js.map +1 -0
- package/dist/learn/smartmemory_egress.js +330 -0
- package/dist/learn/smartmemory_egress.js.map +1 -0
- package/dist/mcp/server.js +155 -24
- package/dist/mcp/server.js.map +1 -1
- package/dist/policy/bundle.js +195 -0
- package/dist/policy/bundle.js.map +1 -0
- package/dist/policy/events.js +51 -0
- package/dist/policy/events.js.map +1 -0
- package/dist/policy/smartmemory_client.js +332 -0
- package/dist/policy/smartmemory_client.js.map +1 -0
- package/dist/policy/types.js +2 -0
- package/dist/policy/types.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { mkdir, readFile, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { dirname, join, resolve, sep } from "node:path";
|
|
5
|
+
import { guardTransition, noteLegacyDigestMatch, payloadDigestForVersion, registerGuard } from "../guard/transition.js";
|
|
6
|
+
import { loadRegistry, readLedger, resourceDir } from "../guard/store.js";
|
|
7
|
+
import { resourceLock } from "../guard/lock.js";
|
|
8
|
+
/**
|
|
9
|
+
* The write half of the loop: admission, then a journalled, ledger-committed apply,
|
|
10
|
+
* then compare-and-swap revert.
|
|
11
|
+
*
|
|
12
|
+
* Default OFF. With the flag unset nothing here writes anything.
|
|
13
|
+
*
|
|
14
|
+
* The single commit point is the guard LEDGER, not the journal. The journal is a plain
|
|
15
|
+
* file this module writes, so "journal says applied" is only a claim about intent; the
|
|
16
|
+
* ledger is hash-chained and is already the authorization record. Recovery therefore
|
|
17
|
+
* asks the ledger what happened and treats the target and the journal as reconstructible.
|
|
18
|
+
*/
|
|
19
|
+
export class ApplyError extends Error {
|
|
20
|
+
}
|
|
21
|
+
export class ApplyRefused extends ApplyError {
|
|
22
|
+
}
|
|
23
|
+
function isEnabled(options) {
|
|
24
|
+
if (options.enabled === true)
|
|
25
|
+
return true;
|
|
26
|
+
return process.env.STRATUM_LEARN_APPLY_ENABLED === "1";
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Instructions that are damaging, irreversible, or that bypass a control. Deterministic
|
|
30
|
+
* on purpose: this is the critic that must not depend on a model being available, and
|
|
31
|
+
* the class of harm it catches is the one the other two provably miss.
|
|
32
|
+
*/
|
|
33
|
+
const HAZARDS = [
|
|
34
|
+
[/git\s+checkout\s+--\s/i, "discards uncommitted work (git checkout --)"],
|
|
35
|
+
[/git\s+reset\s+--hard/i, "discards committed work (git reset --hard)"],
|
|
36
|
+
[/git\s+clean\s+-[a-z]*f/i, "deletes untracked files (git clean -f)"],
|
|
37
|
+
[/git\s+push\s+--force/i, "rewrites published history (git push --force)"],
|
|
38
|
+
[/\brm\s+-[a-z]*r[a-z]*f\b/i, "recursive force delete (rm -rf)"],
|
|
39
|
+
[/curl[^\n]*\|\s*(ba)?sh/i, "pipes remote content into a shell"],
|
|
40
|
+
[/\b(api[_-]?key|secret|token|password|credential)s?\b/i, "handles credentials"],
|
|
41
|
+
[/ts\/src\/(guard|judge)\//i, "instructs a write to the immutable core"],
|
|
42
|
+
[/docs\/judgment\//i, "instructs a write that bypasses the judgment tools"],
|
|
43
|
+
[/\.stratum\.yaml/i, "instructs a spec edit"],
|
|
44
|
+
[/guard\s+(registry|ledger)/i, "instructs a write to guard state"],
|
|
45
|
+
];
|
|
46
|
+
function structuralValidity(candidate) {
|
|
47
|
+
const findings = [];
|
|
48
|
+
const content = candidate.rendered.content;
|
|
49
|
+
if (content.trim().length === 0)
|
|
50
|
+
findings.push("rendered content is empty");
|
|
51
|
+
if (content.length > 4000)
|
|
52
|
+
findings.push("rendered content is implausibly large for a note");
|
|
53
|
+
if (/^#{1,6}\s/m.test(content))
|
|
54
|
+
findings.push("content injects a heading into the target document");
|
|
55
|
+
if (candidate.targetKind !== "memory")
|
|
56
|
+
findings.push(`target kind ${candidate.targetKind} is not memory`);
|
|
57
|
+
if (candidate.evidence.length === 0)
|
|
58
|
+
findings.push("candidate carries no evidence");
|
|
59
|
+
return { critic: "structural-validity", passes: findings.length === 0, findings };
|
|
60
|
+
}
|
|
61
|
+
function behavioralHarmlessness(candidate) {
|
|
62
|
+
const findings = [];
|
|
63
|
+
for (const [pattern, description] of HAZARDS) {
|
|
64
|
+
if (pattern.test(candidate.rendered.content))
|
|
65
|
+
findings.push(description);
|
|
66
|
+
}
|
|
67
|
+
return { critic: "behavioral-harmlessness", passes: findings.length === 0, findings };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Does the note generalize what its evidence shows, and no more? Recurrence COUNT does
|
|
71
|
+
* not license generalization SCOPE — conflating the two is the failure this catches.
|
|
72
|
+
*/
|
|
73
|
+
function semanticConsistency(candidate) {
|
|
74
|
+
const findings = [];
|
|
75
|
+
const content = candidate.rendered.content;
|
|
76
|
+
if (/\b(all|every|any)\s+(agent\s+)?(steps?|projects?|flows?|pipelines?)\b/i.test(content)) {
|
|
77
|
+
findings.push(`claim is unscoped; evidence spans ${candidate.scope.stepIds.length} step(s) in 1 workspace`);
|
|
78
|
+
}
|
|
79
|
+
if (!content.includes(candidate.scope.flowName)) {
|
|
80
|
+
findings.push("note does not name the flow its evidence came from");
|
|
81
|
+
}
|
|
82
|
+
const cited = new Set(candidate.evidence.map((record) => record.runId));
|
|
83
|
+
if (cited.size !== candidate.recurrence.distinctRuns) {
|
|
84
|
+
findings.push(`recurrence claims ${candidate.recurrence.distinctRuns} runs, evidence carries ${cited.size}`);
|
|
85
|
+
}
|
|
86
|
+
return { critic: "semantic-consistency", passes: findings.length === 0, findings };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* What does this add that the pool does not already carry? Per-candidate critics cannot
|
|
90
|
+
* see the pool, and a pool of individually-clean but overlapping notes is still a bad
|
|
91
|
+
* pool. Memory-class candidates are NOT exempt from this: notes are read together by a
|
|
92
|
+
* working agent even when neither influenced the other's authoring.
|
|
93
|
+
*/
|
|
94
|
+
function subsetMarginalGain(candidate, pool) {
|
|
95
|
+
const findings = [];
|
|
96
|
+
const marker = `learn:${candidate.clusterId.slice(0, 12)}`;
|
|
97
|
+
if (pool.includes(marker))
|
|
98
|
+
findings.push("pool already carries this lesson");
|
|
99
|
+
else if (pool.includes(candidate.rendered.content.trim()))
|
|
100
|
+
findings.push("pool already carries this text");
|
|
101
|
+
else {
|
|
102
|
+
// Overlap beyond identical text: a note about the same field of the same flow is
|
|
103
|
+
// covered by, or contradicts, what is already there. Either way it is not a
|
|
104
|
+
// marginal gain and a human should decide which one is right.
|
|
105
|
+
const subject = noteSubject(candidate.rendered.content);
|
|
106
|
+
if (subject !== null) {
|
|
107
|
+
for (const line of pool.split("\n")) {
|
|
108
|
+
if (line.includes(marker))
|
|
109
|
+
continue;
|
|
110
|
+
if (noteSubject(line) === subject) {
|
|
111
|
+
findings.push(`pool already carries a note about ${subject}; resolve which is right`);
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return { critic: "subset-marginal-gain", passes: findings.length === 0, findings };
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* `<flow>/<field>` — the thing a note is about. Deliberately coarse: it catches
|
|
121
|
+
* overlap and same-subject contradiction, and it does NOT catch two notes that conflict
|
|
122
|
+
* while naming different subjects. Genuine semantic conflict detection is specified in
|
|
123
|
+
* ../STRAT-ADMIT and is not implemented here.
|
|
124
|
+
*/
|
|
125
|
+
function noteSubject(line) {
|
|
126
|
+
const match = /recurring \w+ failure on ([\w.]+)\*\* — In flow `([^`]+)`/.exec(line);
|
|
127
|
+
return match === null ? null : `${match[2]}/${match[1]}`;
|
|
128
|
+
}
|
|
129
|
+
/** The bytes must be the bytes the revision id names. */
|
|
130
|
+
export function verifyIdentity(candidate) {
|
|
131
|
+
const expected = sha([
|
|
132
|
+
candidate.clusterId,
|
|
133
|
+
candidate.rendered.templateVersion,
|
|
134
|
+
candidate.rendered.content,
|
|
135
|
+
candidate.targetPath,
|
|
136
|
+
candidate.rendered.insertion.mode,
|
|
137
|
+
candidate.rendered.insertion.section,
|
|
138
|
+
].join("\u0000"));
|
|
139
|
+
if (expected !== candidate.revisionId) {
|
|
140
|
+
throw new ApplyError("candidate identity does not match its content; the sidecar row was edited after staging");
|
|
141
|
+
}
|
|
142
|
+
const runs = new Set(candidate.evidence.map((record) => record.runId)).size;
|
|
143
|
+
if (runs !== candidate.recurrence.distinctRuns) {
|
|
144
|
+
throw new ApplyError(`candidate claims ${candidate.recurrence.distinctRuns} distinct runs but carries ${runs}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export async function admit(candidate, pool) {
|
|
148
|
+
const verdicts = [
|
|
149
|
+
structuralValidity(candidate),
|
|
150
|
+
behavioralHarmlessness(candidate),
|
|
151
|
+
semanticConsistency(candidate),
|
|
152
|
+
subsetMarginalGain(candidate, pool),
|
|
153
|
+
];
|
|
154
|
+
return {
|
|
155
|
+
admitted: verdicts.every((verdict) => verdict.passes),
|
|
156
|
+
verdicts,
|
|
157
|
+
candidateDigest: sha(candidate.rendered.content),
|
|
158
|
+
poolDigest: sha(pool),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
export function journalDir(workspaceRoot) {
|
|
162
|
+
return join(workspaceRoot, ".stratum", "learn", "applies");
|
|
163
|
+
}
|
|
164
|
+
export function journalPath(workspaceRoot, applyId) {
|
|
165
|
+
return join(journalDir(workspaceRoot), `${applyId}.json`);
|
|
166
|
+
}
|
|
167
|
+
export async function readJournal(workspaceRoot) {
|
|
168
|
+
let names;
|
|
169
|
+
try {
|
|
170
|
+
names = (await readdir(journalDir(workspaceRoot))).filter((n) => n.endsWith(".json")).sort();
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
const out = [];
|
|
176
|
+
for (const name of names) {
|
|
177
|
+
try {
|
|
178
|
+
out.push(JSON.parse(await readFile(join(journalDir(workspaceRoot), name), "utf8")));
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// A corrupt journal record must not hide the others.
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return out;
|
|
185
|
+
}
|
|
186
|
+
async function writeJournal(workspaceRoot, entry) {
|
|
187
|
+
const path = journalPath(workspaceRoot, entry.applyId);
|
|
188
|
+
await mkdir(dirname(path), { recursive: true });
|
|
189
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
190
|
+
await writeFile(temporary, JSON.stringify(entry, null, 2), "utf8");
|
|
191
|
+
await rename(temporary, path);
|
|
192
|
+
}
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
// Apply
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
/**
|
|
197
|
+
* G4: the target must sit inside the project's own learn directory — checked against the
|
|
198
|
+
* REAL path, not the lexical one. `resolve()` alone collapses `..` but follows no
|
|
199
|
+
* symlinks, so a symlinked `.stratum/learn` would place the write outside the allowlist
|
|
200
|
+
* while passing a purely lexical check.
|
|
201
|
+
*/
|
|
202
|
+
async function assertAllowlisted(workspaceRoot, targetPath) {
|
|
203
|
+
const target = resolve(targetPath);
|
|
204
|
+
if (!target.endsWith(".md"))
|
|
205
|
+
throw new ApplyError(`target is not a note file: ${target}`);
|
|
206
|
+
const realRoot = await realpathOrSelf(resolve(workspaceRoot));
|
|
207
|
+
const allowed = await realpathOrSelf(join(realRoot, ".stratum", "learn"));
|
|
208
|
+
// The allowlist DIRECTORY must itself be inside the workspace. Without this, a
|
|
209
|
+
// symlinked `.stratum/learn` makes `allowed` and the target agree on a path outside
|
|
210
|
+
// the project entirely, and the prefix test below passes happily.
|
|
211
|
+
if (allowed !== realRoot && !allowed.startsWith(realRoot + sep)) {
|
|
212
|
+
throw new ApplyError(`learn directory resolves outside the workspace: ${allowed}`);
|
|
213
|
+
}
|
|
214
|
+
// The file (and its parents) may not exist yet, so resolve the nearest EXISTING
|
|
215
|
+
// ancestor and re-attach the remaining components. Resolving only the immediate
|
|
216
|
+
// parent leaves an unresolved path when the parent is itself missing, which both
|
|
217
|
+
// misses symlinks higher in the chain and, on macOS, fails to normalize /var.
|
|
218
|
+
const real = await realpathThroughMissing(target);
|
|
219
|
+
if (real !== allowed && !real.startsWith(allowed + sep)) {
|
|
220
|
+
throw new ApplyError(`target is outside the memory allowlist: ${real}`);
|
|
221
|
+
}
|
|
222
|
+
return real;
|
|
223
|
+
}
|
|
224
|
+
async function realpathOrSelf(path) {
|
|
225
|
+
try {
|
|
226
|
+
return await realpath(path);
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
return path;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/** realpath of the deepest existing ancestor, with the missing tail re-attached. */
|
|
233
|
+
async function realpathThroughMissing(path) {
|
|
234
|
+
const tail = [];
|
|
235
|
+
let current = resolve(path);
|
|
236
|
+
for (;;) {
|
|
237
|
+
try {
|
|
238
|
+
return join(await realpath(current), ...tail);
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
const parent = dirname(current);
|
|
242
|
+
// Reached the filesystem root without finding anything real.
|
|
243
|
+
if (parent === current)
|
|
244
|
+
return resolve(path);
|
|
245
|
+
tail.unshift(current.slice(parent.length + 1));
|
|
246
|
+
current = parent;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/** `after` is a pure function of before + rendered content + insertion. */
|
|
251
|
+
export function renderAfter(before, candidate) {
|
|
252
|
+
const { content, insertion } = candidate.rendered;
|
|
253
|
+
if (insertion.mode === "create" || before.trim().length === 0) {
|
|
254
|
+
return `${insertion.section}\n\n${content}\n`;
|
|
255
|
+
}
|
|
256
|
+
if (!before.includes(insertion.section)) {
|
|
257
|
+
return `${before.replace(/\n*$/, "\n")}\n${insertion.section}\n\n${content}\n`;
|
|
258
|
+
}
|
|
259
|
+
// Append INSIDE the section: appending at end-of-document drops the note under
|
|
260
|
+
// whatever heading happens to come last.
|
|
261
|
+
const lines = before.replace(/\n*$/, "\n").split("\n");
|
|
262
|
+
const start = lines.findIndex((line) => line.trim() === insertion.section.trim());
|
|
263
|
+
let end = lines.length;
|
|
264
|
+
for (let i = start + 1; i < lines.length; i += 1) {
|
|
265
|
+
if (/^#{1,6}\s/.test(lines[i] ?? "")) {
|
|
266
|
+
end = i;
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
while (end > start + 1 && (lines[end - 1] ?? "").trim() === "")
|
|
271
|
+
end -= 1;
|
|
272
|
+
lines.splice(end, 0, content);
|
|
273
|
+
return lines.join("\n").replace(/\n*$/, "\n");
|
|
274
|
+
}
|
|
275
|
+
export async function applyCandidate(candidate, options) {
|
|
276
|
+
if (!isEnabled(options)) {
|
|
277
|
+
throw new ApplyRefused("learn apply is disabled; enable it explicitly (STRATUM_LEARN_APPLY_ENABLED=1)");
|
|
278
|
+
}
|
|
279
|
+
verifyIdentity(candidate);
|
|
280
|
+
const workspaceRoot = candidate.scope.workspaceRoot;
|
|
281
|
+
const target = await assertAllowlisted(workspaceRoot, candidate.targetPath);
|
|
282
|
+
// Serialize on the TARGET, not the apply: two candidates racing on one file could
|
|
283
|
+
// otherwise both snapshot the same `before`, both pass the digest check, overwrite
|
|
284
|
+
// each other, and both commit — leaving one ledger entry describing bytes that are
|
|
285
|
+
// no longer on disk.
|
|
286
|
+
return resourceLock(`learn-target-${sha(target).slice(0, 32)}`, async () => {
|
|
287
|
+
// An unreconciled journal means the target's true state is unknown; applying on top
|
|
288
|
+
// would bury the ambiguity.
|
|
289
|
+
for (const entry of await readJournal(workspaceRoot)) {
|
|
290
|
+
if (entry.targetPath === target && (entry.state === "prepared" || entry.state === "applying")) {
|
|
291
|
+
throw new ApplyError(`target has an unreconciled apply (${entry.applyId}); reconcile first`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const { content: before, existed } = await readTarget(target);
|
|
295
|
+
const admission = await admit(candidate, before);
|
|
296
|
+
if (!admission.admitted) {
|
|
297
|
+
const failed = admission.verdicts.filter((v) => !v.passes);
|
|
298
|
+
throw new ApplyRefused(`admission refused: ${failed.map((v) => `${v.critic} (${v.findings.join("; ")})`).join(", ")}`);
|
|
299
|
+
}
|
|
300
|
+
const after = renderAfter(before, candidate);
|
|
301
|
+
// UNIQUE PER ATTEMPT. A deterministic id would reuse the guard resource when the
|
|
302
|
+
// same revision is applied again after a revert, colliding with that resource's
|
|
303
|
+
// terminal state and its spent idempotency keys.
|
|
304
|
+
const applyId = sha(randomUUID()).slice(0, 32);
|
|
305
|
+
// 1. Prepare.
|
|
306
|
+
const entry = {
|
|
307
|
+
applyId,
|
|
308
|
+
state: "prepared",
|
|
309
|
+
clusterId: candidate.clusterId,
|
|
310
|
+
revisionId: candidate.revisionId,
|
|
311
|
+
targetPath: target,
|
|
312
|
+
before,
|
|
313
|
+
beforeDigest: sha(before),
|
|
314
|
+
after,
|
|
315
|
+
afterDigest: sha(after),
|
|
316
|
+
existedBefore: existed,
|
|
317
|
+
evidence: candidate.evidence,
|
|
318
|
+
verdicts: admission.verdicts,
|
|
319
|
+
at: new Date().toISOString(),
|
|
320
|
+
};
|
|
321
|
+
await writeJournal(workspaceRoot, entry);
|
|
322
|
+
// 2. Transition to `applying`, committing the ledger to this journal record.
|
|
323
|
+
const resourceId = guardResource(applyId);
|
|
324
|
+
await registerGuard(resourceId,
|
|
325
|
+
// `applied` is NOT terminal: revert is a legal, ledger-recorded edge out of it.
|
|
326
|
+
// Registering it terminal made every revert an illegal transition that threw and
|
|
327
|
+
// was swallowed, leaving the ledger claiming `applied` over reverted bytes.
|
|
328
|
+
{ staged: ["applying", "aborted"], applying: ["applied", "aborted"], applied: ["reverted"], aborted: [], reverted: [] }, {}, "staged", ["aborted", "reverted"]);
|
|
329
|
+
await guardTransition(resourceId, "staged", "applying", {
|
|
330
|
+
artifacts: { journal_digest: sha(JSON.stringify(entry)), revision_id: candidate.revisionId },
|
|
331
|
+
idempotencyKey: `${applyId}:applying`,
|
|
332
|
+
});
|
|
333
|
+
await writeJournal(workspaceRoot, { ...entry, state: "applying" });
|
|
334
|
+
// 3. Write, only if the target still holds what we snapshotted.
|
|
335
|
+
const current = await readTarget(target);
|
|
336
|
+
if (sha(current.content) !== entry.beforeDigest) {
|
|
337
|
+
throw new ApplyError("target changed between snapshot and write; aborting");
|
|
338
|
+
}
|
|
339
|
+
await atomicWriteFile(target, after);
|
|
340
|
+
// 4. Commit. This ledger append is the moment the apply becomes real.
|
|
341
|
+
const committed = await guardTransition(resourceId, "applying", "applied", {
|
|
342
|
+
artifacts: { after_digest: entry.afterDigest },
|
|
343
|
+
modifiedFiles: [target],
|
|
344
|
+
idempotencyKey: `${applyId}:applied`,
|
|
345
|
+
});
|
|
346
|
+
// 5. Finish. Bookkeeping; its loss is not a correctness problem, because recovery
|
|
347
|
+
// reads the LEDGER rather than this field.
|
|
348
|
+
await writeJournal(workspaceRoot, { ...entry, state: "applied", ledgerRef: committed.ledger_ref });
|
|
349
|
+
return { applyId, ledgerRef: committed.ledger_ref, targetPath: target };
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* What the LEDGER says about an apply, bound to THIS journal record.
|
|
354
|
+
*
|
|
355
|
+
* A state string alone is not enough: it would let a modified journal borrow an
|
|
356
|
+
* unrelated `applied` receipt and write different bytes, or a different allowlisted
|
|
357
|
+
* target, under it. So the receipt must match the transition payload we would have
|
|
358
|
+
* committed for exactly this entry.
|
|
359
|
+
*/
|
|
360
|
+
export function ledgerReceipt(entry) {
|
|
361
|
+
const resource = guardResource(entry.applyId);
|
|
362
|
+
let entries;
|
|
363
|
+
try {
|
|
364
|
+
entries = readLedger(resource);
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
// Corruption must never be read as "nothing committed" — that answer authorizes a
|
|
368
|
+
// destructive rollback. Diverge instead. Every read failure is treated this way,
|
|
369
|
+
// not just LedgerCorrupt: an unexpected error tells us just as little.
|
|
370
|
+
return { kind: "unreadable" };
|
|
371
|
+
}
|
|
372
|
+
// readLedger TRUNCATES at a malformed trailing line rather than throwing (a partial
|
|
373
|
+
// append is normal). Truncation and "nothing was ever written" are indistinguishable
|
|
374
|
+
// from the returned array, and only one of them may authorize a rollback — so compare
|
|
375
|
+
// against the raw line count.
|
|
376
|
+
let rawLines = 0;
|
|
377
|
+
try {
|
|
378
|
+
const raw = readFileSync(join(resourceDir(resource), "ledger.jsonl"), "utf8");
|
|
379
|
+
rawLines = raw.split("\n").filter((line) => line.trim().length > 0).length;
|
|
380
|
+
}
|
|
381
|
+
catch {
|
|
382
|
+
rawLines = 0; // no ledger file at all
|
|
383
|
+
}
|
|
384
|
+
if (rawLines > entries.length)
|
|
385
|
+
return { kind: "unreadable" };
|
|
386
|
+
if (entries.length === 0)
|
|
387
|
+
return { kind: "absent" };
|
|
388
|
+
let policyChecksum;
|
|
389
|
+
try {
|
|
390
|
+
const registry = loadRegistry(resource);
|
|
391
|
+
if (registry === null)
|
|
392
|
+
return { kind: "unreadable" };
|
|
393
|
+
policyChecksum = registry.checksum;
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
return { kind: "unreadable" };
|
|
397
|
+
}
|
|
398
|
+
let receipt = { kind: "absent" };
|
|
399
|
+
for (const row of entries) {
|
|
400
|
+
const dict = row.toDict();
|
|
401
|
+
const appliedDigest = payloadDigestForVersion("applying", "applied", { after_digest: entry.afterDigest }, [entry.targetPath], "agent", policyChecksum, row.payload_digest_version);
|
|
402
|
+
const revertedDigest = payloadDigestForVersion("applied", "reverted", { reverted_to: entry.beforeDigest }, [entry.targetPath], "agent", policyChecksum, row.payload_digest_version);
|
|
403
|
+
if (dict.to_state === "applied" && dict.payload_digest === appliedDigest) {
|
|
404
|
+
if (row.payload_digest_version === 1)
|
|
405
|
+
noteLegacyDigestMatch(resource);
|
|
406
|
+
receipt = { kind: "committed", state: "applied" };
|
|
407
|
+
}
|
|
408
|
+
if (dict.to_state === "reverted" && dict.payload_digest === revertedDigest) {
|
|
409
|
+
if (row.payload_digest_version === 1)
|
|
410
|
+
noteLegacyDigestMatch(resource);
|
|
411
|
+
// A revert receipt wins: it is strictly later in this resource's lifecycle.
|
|
412
|
+
return { kind: "committed", state: "reverted" };
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return receipt;
|
|
416
|
+
}
|
|
417
|
+
/** The guard's current state, for choosing a legal abort edge. */
|
|
418
|
+
function guardState(applyId) {
|
|
419
|
+
try {
|
|
420
|
+
const entries = readLedger(guardResource(applyId));
|
|
421
|
+
const last = entries[entries.length - 1];
|
|
422
|
+
return last === undefined ? "staged" : last.toDict().to_state;
|
|
423
|
+
}
|
|
424
|
+
catch {
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
// ---------------------------------------------------------------------------
|
|
429
|
+
// Revert (compare-and-swap)
|
|
430
|
+
// ---------------------------------------------------------------------------
|
|
431
|
+
export async function revertApply(applyId, workspaceRoot, options) {
|
|
432
|
+
if (!isEnabled(options))
|
|
433
|
+
throw new ApplyRefused("learn apply is disabled");
|
|
434
|
+
const entry = (await readJournal(workspaceRoot)).find((e) => e.applyId === applyId);
|
|
435
|
+
if (entry === undefined)
|
|
436
|
+
throw new ApplyError(`no apply journal for ${applyId}`);
|
|
437
|
+
if (entry.state !== "applied")
|
|
438
|
+
throw new ApplyError(`apply ${applyId} is ${entry.state}, not applied`);
|
|
439
|
+
// Revalidate the journalled path: a journal is a plain file, and revert writes to
|
|
440
|
+
// whatever it names.
|
|
441
|
+
const target = await assertAllowlisted(workspaceRoot, entry.targetPath);
|
|
442
|
+
await resourceLock(`learn-target-${sha(target).slice(0, 32)}`, async () => {
|
|
443
|
+
const current = await readTarget(target);
|
|
444
|
+
// Compare-and-swap. Restoring a snapshot over content we did not write destroys
|
|
445
|
+
// whatever landed after this apply — a data-loss bug dressed as a safety feature.
|
|
446
|
+
if (sha(current.content) !== entry.afterDigest) {
|
|
447
|
+
throw new ApplyError(`target has changed since apply ${applyId} (out-of-band edit or a stacked apply); ` +
|
|
448
|
+
"revert refused — resolve explicitly or revert the newer apply first");
|
|
449
|
+
}
|
|
450
|
+
// `reverting` is durable BEFORE either the ledger or the bytes move, so every crash
|
|
451
|
+
// window below lands on a journal state reconciliation can actually see.
|
|
452
|
+
await writeJournal(workspaceRoot, { ...entry, state: "reverting" });
|
|
453
|
+
await guardTransition(guardResource(applyId), "applied", "reverted", {
|
|
454
|
+
artifacts: { reverted_to: entry.beforeDigest },
|
|
455
|
+
modifiedFiles: [target],
|
|
456
|
+
idempotencyKey: `${applyId}:reverted`,
|
|
457
|
+
});
|
|
458
|
+
await restore(target, entry);
|
|
459
|
+
await writeJournal(workspaceRoot, { ...entry, state: "reverted" });
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
/** Restore the target to its pre-apply state — including not existing at all. */
|
|
463
|
+
async function restore(target, entry) {
|
|
464
|
+
if (!entry.existedBefore) {
|
|
465
|
+
// The apply created this file. Leaving an empty one behind is not a restore.
|
|
466
|
+
await rm(target, { force: true });
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
await atomicWriteFile(target, entry.before);
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Drive every non-terminal journal to a terminal state, using the LEDGER as the
|
|
473
|
+
* authority and refusing to mutate whenever the evidence is ambiguous.
|
|
474
|
+
*/
|
|
475
|
+
export async function reconcile(workspaceRoot, options) {
|
|
476
|
+
if (!isEnabled(options))
|
|
477
|
+
throw new ApplyRefused("learn apply is disabled");
|
|
478
|
+
const report = { completed: 0, rolledBack: 0, reverted: 0, diverged: 0 };
|
|
479
|
+
for (const entry of await readJournal(workspaceRoot)) {
|
|
480
|
+
const terminal = entry.state === "applied" || entry.state === "aborted" || entry.state === "reverted";
|
|
481
|
+
// `applied` is included below only when its receipt is missing — see the revert
|
|
482
|
+
// crash window, where the ledger says reverted but the journal still says applied.
|
|
483
|
+
if (terminal && entry.state !== "applied")
|
|
484
|
+
continue;
|
|
485
|
+
let target;
|
|
486
|
+
try {
|
|
487
|
+
target = await assertAllowlisted(workspaceRoot, entry.targetPath);
|
|
488
|
+
}
|
|
489
|
+
catch {
|
|
490
|
+
report.diverged += 1;
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
const receipt = ledgerReceipt(entry);
|
|
494
|
+
if (receipt.kind === "unreadable") {
|
|
495
|
+
// A corrupt ledger tells us nothing, and "nothing" must not authorize a write.
|
|
496
|
+
report.diverged += 1;
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
if (entry.state === "applied" && receipt.kind === "committed" && receipt.state === "applied") {
|
|
500
|
+
continue; // settled
|
|
501
|
+
}
|
|
502
|
+
const current = await readTarget(target);
|
|
503
|
+
const digest = sha(current.content);
|
|
504
|
+
// The revert committed. Finish it, whatever the journal claims.
|
|
505
|
+
if (receipt.kind === "committed" && receipt.state === "reverted") {
|
|
506
|
+
if (digest === entry.beforeDigest && current.existed === entry.existedBefore) {
|
|
507
|
+
await writeJournal(workspaceRoot, { ...entry, state: "reverted" });
|
|
508
|
+
report.reverted += 1;
|
|
509
|
+
}
|
|
510
|
+
else if (digest === entry.afterDigest) {
|
|
511
|
+
await restore(target, entry);
|
|
512
|
+
await writeJournal(workspaceRoot, { ...entry, state: "reverted" });
|
|
513
|
+
report.reverted += 1;
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
report.diverged += 1;
|
|
517
|
+
}
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
if (receipt.kind === "committed" && receipt.state === "applied") {
|
|
521
|
+
if (digest === entry.afterDigest) {
|
|
522
|
+
await writeJournal(workspaceRoot, { ...entry, state: "applied" });
|
|
523
|
+
report.completed += 1;
|
|
524
|
+
}
|
|
525
|
+
else if (digest === entry.beforeDigest) {
|
|
526
|
+
// The commit happened; the write did not survive. Redo it.
|
|
527
|
+
await atomicWriteFile(target, entry.after);
|
|
528
|
+
await writeJournal(workspaceRoot, { ...entry, state: "applied" });
|
|
529
|
+
report.completed += 1;
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
report.diverged += 1;
|
|
533
|
+
}
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
// No receipt. A `reverting` or `applied` journal here means the revert never
|
|
537
|
+
// committed, so the apply stands.
|
|
538
|
+
if (entry.state === "reverting" || entry.state === "applied") {
|
|
539
|
+
if (digest === entry.afterDigest) {
|
|
540
|
+
await writeJournal(workspaceRoot, { ...entry, state: "applied" });
|
|
541
|
+
report.completed += 1;
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
report.diverged += 1;
|
|
545
|
+
}
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
if (digest === entry.afterDigest) {
|
|
549
|
+
await restore(target, entry);
|
|
550
|
+
await abort(workspaceRoot, entry);
|
|
551
|
+
report.rolledBack += 1;
|
|
552
|
+
}
|
|
553
|
+
else if (digest === entry.beforeDigest) {
|
|
554
|
+
await abort(workspaceRoot, entry);
|
|
555
|
+
report.rolledBack += 1;
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
// Neither state. Guessing here is how a recovery routine destroys data.
|
|
559
|
+
report.diverged += 1;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
return report;
|
|
563
|
+
}
|
|
564
|
+
async function abort(workspaceRoot, entry) {
|
|
565
|
+
// Terminating the journal alone would leave the guard non-terminal forever, and state
|
|
566
|
+
// is derived from the ledger. The legal edge depends on where the guard actually is:
|
|
567
|
+
// a crash right after registration leaves it at `staged`, not `applying`.
|
|
568
|
+
const from = guardState(entry.applyId);
|
|
569
|
+
if (from === "staged" || from === "applying") {
|
|
570
|
+
await guardTransition(guardResource(entry.applyId), from, "aborted", {
|
|
571
|
+
artifacts: { aborted: "reconcile" },
|
|
572
|
+
idempotencyKey: `${entry.applyId}:aborted`,
|
|
573
|
+
}).catch(() => {
|
|
574
|
+
// Idempotent by key; a racing reconcile must not block the rollback.
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
await writeJournal(workspaceRoot, { ...entry, state: "aborted" });
|
|
578
|
+
}
|
|
579
|
+
// ---------------------------------------------------------------------------
|
|
580
|
+
function guardResource(applyId) {
|
|
581
|
+
return `learn-apply-${applyId}`;
|
|
582
|
+
}
|
|
583
|
+
async function readTarget(path) {
|
|
584
|
+
try {
|
|
585
|
+
return { content: await readFile(path, "utf8"), existed: true };
|
|
586
|
+
}
|
|
587
|
+
catch {
|
|
588
|
+
return { content: "", existed: false };
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
async function atomicWriteFile(path, content) {
|
|
592
|
+
await mkdir(dirname(path), { recursive: true });
|
|
593
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
594
|
+
await writeFile(temporary, content, "utf8");
|
|
595
|
+
await rename(temporary, path);
|
|
596
|
+
}
|
|
597
|
+
function sha(value) {
|
|
598
|
+
return createHash("sha256").update(value).digest("hex");
|
|
599
|
+
}
|
|
600
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/learn/apply.ts"],"names":[],"mappings":"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"}
|