kijito-tools 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +6 -0
  3. package/README.md +220 -0
  4. package/bin/cli.js +34 -0
  5. package/install.sh +161 -0
  6. package/package.json +50 -0
  7. package/providers/_shared/wake-core.mjs +358 -0
  8. package/providers/claude/CLAUDE.md.snippet +31 -0
  9. package/providers/claude/install.sh +186 -0
  10. package/providers/claude/scripts/arm-session.sh +66 -0
  11. package/providers/claude/scripts/claude-armed.sh +101 -0
  12. package/providers/claude/scripts/heartbeat-watchdog.sh +209 -0
  13. package/providers/claude/scripts/inbox-selftest.sh +277 -0
  14. package/providers/claude/scripts/kijito-persona-lib.sh +94 -0
  15. package/providers/claude/scripts/kijito-qa-pass.sh +12 -0
  16. package/providers/claude/scripts/lifecycle-lib.sh +167 -0
  17. package/providers/claude/scripts/myctx.sh +46 -0
  18. package/providers/claude/scripts/self-clear.sh +134 -0
  19. package/providers/claude/scripts/session-autosend.sh +85 -0
  20. package/providers/claude/scripts/session-catchup-hint.sh +330 -0
  21. package/providers/claude/scripts/statusline-context.sh +67 -0
  22. package/providers/claude/skills/kijito-qa-memory/SKILL.md +110 -0
  23. package/providers/claude/skills/kijito-recall/SKILL.md +53 -0
  24. package/providers/claude/skills/kijito-start/SKILL.md +122 -0
  25. package/providers/claude/wiring/README.md +93 -0
  26. package/providers/claude/wiring/kijito-heartbeat@.service +21 -0
  27. package/providers/codex/README.md +75 -0
  28. package/providers/codex/codex-kijito-parity-plan.md +265 -0
  29. package/providers/codex/docs-codex-setup.md +64 -0
  30. package/providers/codex/install.mjs +184 -0
  31. package/providers/codex/n0-capability-probe-protocol.md +472 -0
  32. package/providers/codex/n0-harness/README.md +57 -0
  33. package/providers/codex/n0-harness/cli.mjs +58 -0
  34. package/providers/codex/n0-harness/evidence-manifest.mjs +77 -0
  35. package/providers/codex/n0-harness/fixture.mjs +279 -0
  36. package/providers/codex/n0-harness/lib.mjs +141 -0
  37. package/providers/codex/n0-harness/manifest.mjs +36 -0
  38. package/providers/codex/n0-harness/oracle.mjs +464 -0
  39. package/providers/codex/n0-harness/parser.mjs +200 -0
  40. package/providers/codex/n0-harness/prompt.mjs +43 -0
  41. package/providers/codex/n0-harness/snapshot.mjs +120 -0
  42. package/providers/codex/n0-harness/specimen.mjs +37 -0
  43. package/providers/codex/notify/kijito-notify-count.mjs +117 -0
  44. package/providers/codex/notify/kijito-notify-count.test.mjs +76 -0
  45. package/providers/codex/plans/gate4-battery-log.md +184 -0
  46. package/providers/codex/plans/gate4-battery-protocol.md +43 -0
  47. package/providers/codex/plans/hive-user-first-plan-QA.md +34 -0
  48. package/providers/codex/plans/hive-user-first-plan.md +247 -0
  49. package/providers/codex/release-manifest.json +53 -0
  50. package/providers/codex/same-chat-continuation-plan-gate.md +235 -0
  51. package/providers/codex/same-chat-continuation-plan.md +458 -0
  52. package/providers/codex/skills/kijito-qa-memory/SKILL.md +193 -0
  53. package/providers/codex/skills/kijito-qa-memory/agents/openai.yaml +4 -0
  54. package/providers/codex/skills/kijito-recall/SKILL.md +53 -0
  55. package/providers/codex/skills/kijito-start/SKILL.md +173 -0
  56. package/providers/codex/skills/kijito-start/agents/openai.yaml +4 -0
  57. package/providers/codex/test/n0-cli-refusal.test.mjs +31 -0
  58. package/providers/codex/test/n0-counterexample-matrix.test.mjs +118 -0
  59. package/providers/codex/test/n0-guard-census-core.mjs +1372 -0
  60. package/providers/codex/test/n0-guard-census.json +35479 -0
  61. package/providers/codex/test/n0-guard-census.mjs +31 -0
  62. package/providers/codex/test/n0-guard-census.test.mjs +374 -0
  63. package/providers/codex/test/n0-guard-counterexamples.mjs +1068 -0
  64. package/providers/codex/test/n0-guard-independent-projection.mjs +70 -0
  65. package/providers/codex/test/n0-guard-independent-projection.test.mjs +53 -0
  66. package/providers/codex/test/n0-guard-manifest-author.mjs +424 -0
  67. package/providers/codex/test/n0-guard-mutation-operators.test.mjs +244 -0
  68. package/providers/codex/test/n0-guard-mutation-runner.mjs +599 -0
  69. package/providers/codex/test/n0-guard-remainder-classes.test.mjs +314 -0
  70. package/providers/codex/test/n0-guard-sanitizer-pairs.test.mjs +68 -0
  71. package/providers/codex/test/n0-guard-shared-context-predicates.test.mjs +84 -0
  72. package/providers/codex/test/n0-harness.test.mjs +553 -0
  73. package/providers/codex/test/n0-notable-regressions.test.mjs +70 -0
  74. package/providers/codex/test/n0-subject-boundary.mjs +97 -0
  75. package/providers/codex/test/n0-subject-boundary.test.mjs +72 -0
  76. package/providers/codex/test/same-chat-plan-preflight.sh +167 -0
  77. package/providers/codex/tools/refresh-manifest.mjs +81 -0
  78. package/providers/codex/wake-helper/TRANSPORT-NOTES.md +25 -0
  79. package/providers/codex/wake-helper/integration.test.mjs +285 -0
  80. package/providers/codex/wake-helper/kijito-wake-helper.mjs +488 -0
  81. package/providers/codex/wake-helper/kijito-wake-helper.test.mjs +128 -0
  82. package/providers/codex/wake-helper/mock-daemon.mjs +64 -0
  83. package/providers/codex/wake-helper/status-probe.mjs +45 -0
  84. package/providers/codex/wake-helper/ws-uds.mjs +153 -0
  85. package/providers/monitor/.github/workflows/publish-npm.yml +38 -0
  86. package/providers/monitor/.github/workflows/publish-pypi.yml +30 -0
  87. package/providers/monitor/CHANGELOG.md +465 -0
  88. package/providers/monitor/IMPORT-PROVENANCE.md +68 -0
  89. package/providers/monitor/LICENSE +202 -0
  90. package/providers/monitor/NOTICE +7 -0
  91. package/providers/monitor/OPAQUE-OUTPUT-ENFORCEMENT.md +45 -0
  92. package/providers/monitor/README.md +571 -0
  93. package/providers/monitor/RELEASING.md +125 -0
  94. package/providers/monitor/arm-hive-monitor.sh +13 -0
  95. package/providers/monitor/bin/cli.js +43 -0
  96. package/providers/monitor/com.kijito.inbox-monitor.plist.template +59 -0
  97. package/providers/monitor/docs/DESIGN.md +984 -0
  98. package/providers/monitor/kijito-inbox-monitor@.service.template +95 -0
  99. package/providers/monitor/kijito_inbox_monitor.py +3666 -0
  100. package/providers/monitor/package.json +35 -0
  101. package/providers/monitor/pyproject.toml +42 -0
  102. package/providers/monitor/scripts/mutation-check.py +399 -0
  103. package/providers/monitor/scripts/prepublish-gate.sh +284 -0
  104. package/providers/monitor/test_kijito_monitor.py +5609 -0
@@ -0,0 +1,599 @@
1
+ #!/usr/bin/env node
2
+ import crypto from "node:crypto";
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { spawnSync } from "node:child_process";
7
+ import { fileURLToPath } from "node:url";
8
+ import { parse } from "acorn";
9
+ import { analyzeGuardGraph, validateManifest } from "./n0-guard-census-core.mjs";
10
+ import { counterexampleUniverse, expectedPositiveCases } from "./n0-guard-counterexamples.mjs";
11
+ import { independentProjection } from "./n0-guard-independent-projection.mjs";
12
+
13
+ const here = path.dirname(fileURLToPath(import.meta.url));
14
+ const repo = path.resolve(here, "../../..");
15
+ const manifestPath = path.join(here, "n0-guard-census.json");
16
+ const node = process.execPath;
17
+
18
+ function fail(code, detail) {
19
+ const error = new Error(`${code}: ${detail}`);
20
+ error.code = code;
21
+ throw error;
22
+ }
23
+
24
+ function run(args, cwd, options = {}) {
25
+ const result = spawnSync(args[0], args.slice(1), {
26
+ cwd,
27
+ encoding: "utf8",
28
+ env: { ...process.env, N0_CENSUS_MUTATION_CHILD: "1" },
29
+ timeout: options.timeout ?? 300_000,
30
+ maxBuffer: options.maxBuffer ?? 256 * 1024 * 1024,
31
+ });
32
+ if (result.error) throw result.error;
33
+ return result;
34
+ }
35
+
36
+ function sha256(value) {
37
+ return crypto.createHash("sha256").update(value).digest("hex");
38
+ }
39
+
40
+ function requireGit(result) {
41
+ if (result.status !== 0) fail("MUTATION_PRIMARY_GIT", result.stderr || result.stdout);
42
+ return result.stdout;
43
+ }
44
+
45
+ export function repositorySnapshot(root) {
46
+ const head = requireGit(run(["git", "rev-parse", "HEAD"], root));
47
+ const status = requireGit(run(["git", "status", "--porcelain=v1", "-z", "--untracked-files=all"], root));
48
+ const indexDiff = requireGit(run(["git", "diff", "--cached", "--binary", "--no-ext-diff", "HEAD"], root));
49
+ const worktreeDiff = requireGit(run(["git", "diff", "--binary", "--no-ext-diff"], root));
50
+ const untracked = requireGit(run(["git", "ls-files", "--others", "--exclude-standard", "-z"], root))
51
+ .split("\0")
52
+ .filter(Boolean)
53
+ .sort();
54
+ const untrackedHash = crypto.createHash("sha256");
55
+ for (const relative of untracked) {
56
+ const target = path.join(root, relative);
57
+ const stat = fs.lstatSync(target);
58
+ const kind = stat.isSymbolicLink() ? "symlink" : stat.isFile() ? "file" : "other";
59
+ const content = kind === "symlink" ? fs.readlinkSync(target) : kind === "file" ? fs.readFileSync(target) : "";
60
+ untrackedHash.update(`${Buffer.byteLength(relative)}:${relative}:${kind}:`);
61
+ untrackedHash.update(content);
62
+ untrackedHash.update("\0");
63
+ }
64
+ return {
65
+ head,
66
+ statusSha256: sha256(status),
67
+ indexDiffSha256: sha256(indexDiff),
68
+ worktreeDiffSha256: sha256(worktreeDiff),
69
+ untrackedSha256: untrackedHash.digest("hex"),
70
+ };
71
+ }
72
+
73
+ function primarySnapshot() {
74
+ return repositorySnapshot(repo);
75
+ }
76
+
77
+ function assertPrimary(snapshot) {
78
+ const after = primarySnapshot();
79
+ if (JSON.stringify(after) !== JSON.stringify(snapshot)) fail("MUTATION_PRIMARY_CHANGED", "primary HEAD/index/worktree changed");
80
+ }
81
+
82
+ function copyTree(target) {
83
+ fs.mkdirSync(target, { recursive: true });
84
+ for (const relative of ["package.json", "package-lock.json", "providers"]) {
85
+ fs.cpSync(path.join(repo, relative), path.join(target, relative), { recursive: true, errorOnExist: false });
86
+ }
87
+ const acorn = path.join(repo, "node_modules/acorn");
88
+ if (!fs.existsSync(acorn)) fail("MUTATION_DEPENDENCY", "node_modules/acorn is missing; run npm ci");
89
+ fs.mkdirSync(path.join(target, "node_modules"), { recursive: true });
90
+ fs.cpSync(acorn, path.join(target, "node_modules/acorn"), { recursive: true });
91
+ }
92
+
93
+ function aggregate(cwd) {
94
+ const result = run([node, "providers/codex/n0-harness/manifest.mjs", "--json"], cwd);
95
+ if (result.status !== 0) fail("MUTATION_AGGREGATE", result.stderr);
96
+ return JSON.parse(result.stdout).aggregate;
97
+ }
98
+
99
+ function baseline(cwd, expectedAggregate) {
100
+ if (aggregate(cwd) !== expectedAggregate) fail("MUTATION_COPY_DIGEST", "temp-copy aggregate differs from pinned origin");
101
+ const result = run([node, "--test", "providers/codex/test/n0-harness.test.mjs", "providers/codex/test/n0-cli-refusal.test.mjs"], cwd);
102
+ if (result.status !== 0 || !/^(?:#|ℹ) pass 28$/m.test(result.stdout) || !/^(?:#|ℹ) fail 0$/m.test(result.stdout)) {
103
+ fail("MUTATION_BASELINE", `${result.stdout}\n${result.stderr}`);
104
+ }
105
+ }
106
+
107
+ function matrix(cwd) {
108
+ const result = run([node, "providers/codex/test/n0-guard-counterexamples.mjs", "--all"], cwd);
109
+ if (result.status !== 0) fail("MUTATION_COUNTEREXAMPLE_MATRIX", result.stderr);
110
+ return JSON.parse(result.stdout);
111
+ }
112
+
113
+ export function assertPristineMatrix(pristine, expectedPositive) {
114
+ const actualPositive = {};
115
+ for (const [id, result] of Object.entries(pristine)) {
116
+ if (result?.crashed) fail("MUTATION_PRISTINE_CRASH", `${id}: ${JSON.stringify(result)}`);
117
+ if (result?.accepted === true) actualPositive[id] = result.code;
118
+ else if (result?.accepted !== false || typeof result.code !== "string" || result.code.length === 0) {
119
+ fail("MUTATION_PRISTINE_RESULT", `${id}: ${JSON.stringify(result)}`);
120
+ }
121
+ }
122
+ const orderedActual = Object.fromEntries(Object.entries(actualPositive).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0));
123
+ const orderedExpected = Object.fromEntries(Object.entries(expectedPositive).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0));
124
+ if (JSON.stringify(orderedActual) !== JSON.stringify(orderedExpected)) {
125
+ fail("MUTATION_POSITIVE_CORPUS", `expected=${JSON.stringify(expectedPositive)} actual=${JSON.stringify(actualPositive)}`);
126
+ }
127
+ }
128
+
129
+ function oneExpression(source, label) {
130
+ let expression;
131
+ try {
132
+ const program = parse(source, { ecmaVersion: "latest" });
133
+ if (program.body.length !== 1 || program.body[0].type !== "ExpressionStatement") throw new Error("not one expression");
134
+ expression = program.body[0].expression;
135
+ } catch {
136
+ fail("MUTATION_DIRECTION", `${label}: not one expression`);
137
+ }
138
+ return expression;
139
+ }
140
+
141
+ function originalCall(entry) {
142
+ const expression = oneExpression(entry.source, entry.id);
143
+ if (expression.type !== "CallExpression") fail("MUTATION_DIRECTION", `${entry.id}: sanitizer target is not a call`);
144
+ return expression;
145
+ }
146
+
147
+ const SYNCHRONOUS_REJECTING_CALLEES = new Set([
148
+ "assertExactKeys",
149
+ "main",
150
+ "parseJsonBuffer",
151
+ "readOwnedRegularFile",
152
+ "renderPrompt",
153
+ "requireNonce",
154
+ "requireObject",
155
+ "requirePathInside",
156
+ "requireString",
157
+ "snapshotTree",
158
+ "validateEvidenceMeta",
159
+ ]);
160
+
161
+ function payloadFreeStaticCall(entry, allowedCallees) {
162
+ if (entry.kind !== "rejecting-helper-call") {
163
+ fail("MUTATION_DIRECTION", `${entry.id}: payload-free call operator requires rejecting-helper-call`);
164
+ }
165
+ const call = originalCall(entry);
166
+ if (call.optional === true || call.callee.type !== "Identifier" || !allowedCallees.has(call.callee.name)) {
167
+ fail("MUTATION_DIRECTION", `${entry.id}: payload-free call operator requires an approved static callee`);
168
+ }
169
+ if (entry.helper !== call.callee.name) {
170
+ fail("MUTATION_DIRECTION", `${entry.id}: analyzed callee does not match source`);
171
+ }
172
+ if (call.arguments.some((argument) => argument.type === "SpreadElement")) {
173
+ fail("MUTATION_DIRECTION", `${entry.id}: payload-free call operator forbids spread arguments`);
174
+ }
175
+ return call;
176
+ }
177
+
178
+ function suppressThrownRejection(entry) {
179
+ const call = payloadFreeStaticCall(entry, SYNCHRONOUS_REJECTING_CALLEES);
180
+ const parameters = call.arguments.map((_, index) => `__n0_arg_${index}`);
181
+ const argumentsSource = call.arguments.map((argument) => entry.source.slice(argument.start, argument.end));
182
+ const invoke = `${call.callee.name}(${parameters.join(", ")})`;
183
+ return `((${parameters.join(", ")}) => { try { return ${invoke}; } catch { return void 0; } })(${argumentsSource.join(", ")})`;
184
+ }
185
+
186
+ function forceCallResultStatus(entry) {
187
+ const call = payloadFreeStaticCall(entry, new Set(["evaluateOracle"]));
188
+ return `((__n0_result) => ({ ...__n0_result, status: "N0_TEST_CAPABLE" }))(${entry.source.slice(call.start, call.end)})`;
189
+ }
190
+
191
+ function boundedExpression(source, label) {
192
+ let expression;
193
+ try {
194
+ const program = parse(`(${source})`, { ecmaVersion: "latest" });
195
+ expression = program.body[0]?.expression;
196
+ if (!expression) throw new Error("missing expression");
197
+ } catch {
198
+ fail("MUTATION_DIRECTION", `${label}: not one bounded expression`);
199
+ }
200
+ const forbidden = new Set(["AssignmentExpression", "UpdateExpression", "SequenceExpression", "ImportExpression", "AwaitExpression", "YieldExpression", "FunctionExpression", "ArrowFunctionExpression", "NewExpression"]);
201
+ const stack = [expression];
202
+ while (stack.length) {
203
+ const current = stack.pop();
204
+ if (forbidden.has(current.type)) fail("MUTATION_DIRECTION", `${label}: contains ${current.type}`);
205
+ for (const value of Object.values(current)) {
206
+ if (Array.isArray(value)) stack.push(...value.filter((item) => item && typeof item.type === "string"));
207
+ else if (value && typeof value.type === "string") stack.push(value);
208
+ }
209
+ }
210
+ return expression;
211
+ }
212
+
213
+ export function replacementFor(entry) {
214
+ const mutation = entry.mutation;
215
+ if (["suppress-thrown-rejection", "force-call-result-status"].includes(mutation?.operator)) {
216
+ if (Object.keys(mutation).sort().join(",") !== "operator") {
217
+ fail("MUTATION_DIRECTION", `${entry.id}: payload-free operator contains manifest payload`);
218
+ }
219
+ if (mutation.operator === "suppress-thrown-rejection") return suppressThrownRejection(entry);
220
+ return forceCallResultStatus(entry);
221
+ }
222
+ if (mutation?.operator === "bypass-rejection") {
223
+ if (/^verdict\s*\(/.test(entry.source)) {
224
+ const call = originalCall(entry);
225
+ if (call.callee.type !== "Identifier" || call.callee.name !== "verdict") {
226
+ fail("MUTATION_DIRECTION", `${entry.id}: verdict bypass has a different callee`);
227
+ }
228
+ const status = call.arguments[0];
229
+ if (status?.type !== "Literal" || !["RED", "BLOCKED"].includes(status.value)) {
230
+ fail("MUTATION_DIRECTION", `${entry.id}: verdict bypass does not own a negative status literal`);
231
+ }
232
+ return `${entry.source.slice(0, status.start)}"N0_TEST_CAPABLE"${entry.source.slice(status.end)}`;
233
+ }
234
+ return "void 0";
235
+ }
236
+ if (mutation?.operator === "force-owned-condition" && typeof mutation.value === "boolean") return String(mutation.value);
237
+ if (mutation?.operator === "sanitize-first-binding") {
238
+ const call = originalCall(entry);
239
+ const first = call.arguments[0];
240
+ if (!first) fail("MUTATION_DIRECTION", `${entry.id}: sanitizer call has no first argument`);
241
+ const firstSource = entry.source.slice(first.start, first.end);
242
+ if (mutation.binding !== firstSource) fail("MUTATION_DIRECTION", `${entry.id}: sanitizer binding is not the first argument`);
243
+ if (!["Identifier", "MemberExpression"].includes(first.type) || first.optional === true) {
244
+ fail("MUTATION_DIRECTION", `${entry.id}: sanitizer first argument is not an assignable static binding`);
245
+ }
246
+ boundedExpression(mutation.value, entry.id);
247
+ const replacement = `${mutation.binding} = ${mutation.value}`;
248
+ const assignment = oneExpression(replacement, entry.id);
249
+ if (assignment.type !== "AssignmentExpression" || assignment.operator !== "=") {
250
+ fail("MUTATION_DIRECTION", `${entry.id}: sanitizer did not produce one assignment`);
251
+ }
252
+ return replacement;
253
+ }
254
+ if (mutation?.operator === "sanitize-first-argument") {
255
+ const call = originalCall(entry);
256
+ const first = call.arguments[0];
257
+ if (!first || first.type === "SpreadElement") {
258
+ fail("MUTATION_DIRECTION", `${entry.id}: sanitizer call has no ordinary first argument`);
259
+ }
260
+ boundedExpression(mutation.value, entry.id);
261
+ const replacement = `${entry.source.slice(0, first.start)}${mutation.value}${entry.source.slice(first.end)}`;
262
+ const mutated = originalCall({ ...entry, source: replacement });
263
+ if (mutated.arguments.length !== call.arguments.length
264
+ || replacement.slice(mutated.callee.start, mutated.callee.end) !== entry.source.slice(call.callee.start, call.callee.end)) {
265
+ fail("MUTATION_DIRECTION", `${entry.id}: first-argument sanitizer changed call structure`);
266
+ }
267
+ return replacement;
268
+ }
269
+ if (mutation?.operator === "drop-reviewed-property") {
270
+ const call = originalCall(entry);
271
+ const first = call.arguments[0];
272
+ if (!first) fail("MUTATION_DIRECTION", `${entry.id}: delete call has no first argument`);
273
+ const firstSource = entry.source.slice(first.start, first.end);
274
+ if (!(mutation.target.startsWith(`${firstSource}.`) || mutation.target.startsWith(`${firstSource}[`))) {
275
+ fail("MUTATION_DIRECTION", `${entry.id}: deleted property is not rooted at the first argument`);
276
+ }
277
+ oneExpression(`delete ${mutation.target}`, entry.id);
278
+ return `delete ${mutation.target}`;
279
+ }
280
+ fail("MUTATION_DIRECTION", `${entry.id}: unknown declarative operator`);
281
+ }
282
+
283
+ function canonical(value) {
284
+ if (Array.isArray(value)) return value.map(canonical);
285
+ if (!value || typeof value !== "object") return value;
286
+ return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonical(value[key])]));
287
+ }
288
+
289
+ function changedCases(pristine, mutant) {
290
+ const acceptFlipSet = [];
291
+ const rejectDeltaSet = [];
292
+ const positiveRegressionSet = [];
293
+ for (const id of Object.keys(pristine).sort()) {
294
+ const before = canonical(pristine[id]);
295
+ const after = canonical(mutant[id]);
296
+ if (JSON.stringify(before) === JSON.stringify(after)) continue;
297
+ if (before?.accepted === false && !before?.crashed && after?.accepted === true && !after?.crashed) {
298
+ acceptFlipSet.push({ id, rejectCode: before.code, acceptCode: after.code });
299
+ continue;
300
+ }
301
+ const delta = { id, before, after };
302
+ if (before?.accepted === true) positiveRegressionSet.push(delta);
303
+ else rejectDeltaSet.push(delta);
304
+ }
305
+ return { acceptFlipSet, rejectDeltaSet, positiveRegressionSet };
306
+ }
307
+
308
+ function mutationKey(entry, actual) {
309
+ return JSON.stringify({ file: actual.file, start: actual.start, end: actual.end, replacement: replacementFor(entry) });
310
+ }
311
+
312
+ export function applyMutations(root, edits) {
313
+ const byFile = new Map();
314
+ for (const edit of edits) {
315
+ if (!byFile.has(edit.file)) byFile.set(edit.file, []);
316
+ byFile.get(edit.file).push(edit);
317
+ }
318
+ const originals = new Map();
319
+ for (const [relative, fileEdits] of byFile) {
320
+ const file = path.join(root, "providers/codex/n0-harness", relative);
321
+ let source = fs.readFileSync(file, "utf8");
322
+ originals.set(file, source);
323
+ for (const edit of fileEdits.sort((a, b) => b.start - a.start)) {
324
+ source = `${source.slice(0, edit.start)}${edit.replacement}${source.slice(edit.end)}`;
325
+ }
326
+ fs.writeFileSync(file, source);
327
+ }
328
+ return () => { for (const [file, source] of originals) fs.writeFileSync(file, source); };
329
+ }
330
+
331
+ function graphEntry(graph, id) {
332
+ const entry = graph.entries.find((candidate) => candidate.id === id);
333
+ if (!entry) fail("MUTATION_ANCHOR", id);
334
+ return entry;
335
+ }
336
+
337
+ function ownershipKind(partitions) {
338
+ if (partitions.acceptFlipSet.length > 0 && partitions.rejectDeltaSet.length > 0) return "mixed-ownership";
339
+ if (partitions.acceptFlipSet.length > 0) return "normal-ownership";
340
+ if (partitions.rejectDeltaSet.length > 0) return "reject-preserving-ownership";
341
+ return null;
342
+ }
343
+
344
+ function witnessFor(partitions) {
345
+ if (partitions.acceptFlipSet.length > 0) {
346
+ return { partition: "acceptFlipSet", ...partitions.acceptFlipSet[0] };
347
+ }
348
+ if (partitions.rejectDeltaSet.length > 0) {
349
+ const first = partitions.rejectDeltaSet[0];
350
+ return {
351
+ partition: "rejectDeltaSet",
352
+ id: first.id,
353
+ beforeCode: first.before.code,
354
+ afterCode: first.after.code,
355
+ };
356
+ }
357
+ return null;
358
+ }
359
+
360
+ function exactOwnership(entry, actual) {
361
+ for (const partition of ["acceptFlipSet", "rejectDeltaSet", "positiveRegressionSet"]) {
362
+ if (JSON.stringify(entry[partition]) !== JSON.stringify(actual[partition])) {
363
+ fail("MUTATION_PARTITION_MISMATCH", `${entry.id} ${partition}: declared=${JSON.stringify(entry[partition])} actual=${JSON.stringify(actual[partition])}`);
364
+ }
365
+ }
366
+ if (actual.positiveRegressionSet.length > 0) {
367
+ fail("MUTATION_POSITIVE_REGRESSION", `${entry.id}: ${JSON.stringify(actual.positiveRegressionSet)}`);
368
+ }
369
+ const kind = ownershipKind(actual);
370
+ if (entry.ownershipRecord?.kind !== kind || JSON.stringify(entry.witness) !== JSON.stringify(witnessFor(actual))) {
371
+ fail("MUTATION_ATTRIBUTION", `${entry.id}: ownership mode or witness differs from measured partitions`);
372
+ }
373
+ }
374
+
375
+ export function assertDiscriminatingPair(entry, pristine, mutant) {
376
+ const witness = entry.witness;
377
+ if (witness?.partition !== "acceptFlipSet" || pristine.accepted || pristine.code !== witness.rejectCode) {
378
+ fail("MUTATION_PRISTINE_PAIR", `${entry.id}: ${JSON.stringify(pristine)}`);
379
+ }
380
+ if (!mutant.accepted || mutant.code !== witness.acceptCode) {
381
+ fail("MUTATION_NOT_DISCRIMINATED", `${entry.id}: ${JSON.stringify(mutant)}`);
382
+ }
383
+ }
384
+
385
+ export function assertRedundantDispositionSingle(entry, pristine, single) {
386
+ const witness = entry.disposition?.witness;
387
+ const pristineWitness = pristine[witness?.id];
388
+ if (JSON.stringify(single) !== JSON.stringify(pristine)
389
+ || !pristineWitness || pristineWitness.accepted
390
+ || pristineWitness.code !== witness.rejectCode) {
391
+ fail("MUTATION_DISPOSITION_SINGLE", entry.id);
392
+ }
393
+ }
394
+
395
+ function runBattery() {
396
+ if (process.env.N0_CENSUS_MUTATION_CHILD === "1") fail("MUTATION_RECURSION", "runner cannot run inside a mutation child");
397
+ const derive = process.argv.includes("--derive-flipsets");
398
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
399
+ const sourceRoot = path.join(repo, "providers/codex/n0-harness");
400
+ const originGraph = analyzeGuardGraph(sourceRoot);
401
+ const projection = independentProjection(sourceRoot);
402
+ validateManifest(originGraph, manifest, { requirePairs: !derive, projection, counterexamples: counterexampleUniverse() });
403
+ const primary = primarySnapshot();
404
+ const expectedAggregate = aggregate(repo);
405
+ const temp = fs.mkdtempSync(path.join(os.tmpdir(), "n0-guard-mutation."));
406
+ const derived = new Map();
407
+ let uniqueMutationsExecuted = 0;
408
+ let redundancyDispositionsVerified = 0;
409
+ let compoundUnitsVerified = 0;
410
+ let compoundMembersVerified = 0;
411
+ let sameCodeShadowsVerified = 0;
412
+ let downstreamDomainShadowsVerified = 0;
413
+ try {
414
+ copyTree(temp);
415
+ baseline(temp, expectedAggregate);
416
+ const pristine = matrix(temp);
417
+ assertPristineMatrix(pristine, expectedPositiveCases());
418
+ const cleanGraph = analyzeGuardGraph(path.join(temp, "providers/codex/n0-harness"));
419
+ const mutable = manifest.entries.filter((entry) => entry.mutation);
420
+ const groups = new Map();
421
+ for (const entry of mutable) {
422
+ const actual = graphEntry(cleanGraph, entry.id);
423
+ const key = mutationKey(entry, actual);
424
+ if (!groups.has(key)) groups.set(key, []);
425
+ groups.get(key).push({ entry, actual });
426
+ }
427
+ for (const group of groups.values()) {
428
+ const edits = [{ ...group[0].actual, replacement: replacementFor(group[0].entry) }];
429
+ const restore = applyMutations(temp, edits);
430
+ const mutant = matrix(temp);
431
+ const partitions = changedCases(pristine, mutant);
432
+ uniqueMutationsExecuted += 1;
433
+ for (const { entry } of group) {
434
+ if (derive) derived.set(entry.id, partitions);
435
+ else exactOwnership(entry, partitions);
436
+ }
437
+ restore();
438
+ if (aggregate(temp) !== expectedAggregate) fail("MUTATION_RESTORE", group[0].entry.id);
439
+ }
440
+ if (!derive) {
441
+ for (const entry of manifest.entries.filter((candidate) => candidate.ownershipRecord?.kind === "same-code-shadow")) {
442
+ const actual = graphEntry(cleanGraph, entry.id);
443
+ const witness = pristine[entry.ownershipRecord.witnessId];
444
+ if (!witness || witness.accepted || witness.code !== entry.ownershipRecord.rejectCode) {
445
+ fail("MUTATION_SHADOW_PRISTINE", `${entry.id}:${JSON.stringify(witness)}`);
446
+ }
447
+ const restore = applyMutations(temp, [{
448
+ ...actual,
449
+ replacement: replacementFor({ ...entry, mutation: entry.ownershipRecord.canonicalMutation }),
450
+ }]);
451
+ const mutant = matrix(temp);
452
+ restore();
453
+ if (JSON.stringify(mutant) !== JSON.stringify(pristine)) {
454
+ fail("MUTATION_SHADOW_DELTA", entry.id);
455
+ }
456
+ sameCodeShadowsVerified += 1;
457
+ }
458
+ for (const entry of manifest.entries.filter((candidate) => candidate.ownershipRecord?.kind === "downstream-domain-shadow")) {
459
+ const actual = graphEntry(cleanGraph, entry.id);
460
+ const record = entry.ownershipRecord;
461
+ const witness = pristine[record.witnessId];
462
+ if (!witness || witness.accepted || witness.code !== "CANARY_MISSING") {
463
+ fail("MUTATION_DOWNSTREAM_DOMAIN_PRISTINE", `${entry.id}:${JSON.stringify(witness)}`);
464
+ }
465
+ const canonicalRestore = applyMutations(temp, [{
466
+ ...actual,
467
+ replacement: replacementFor({ ...entry, mutation: record.canonicalMutation }),
468
+ }]);
469
+ const canonical = matrix(temp);
470
+ canonicalRestore();
471
+ if (JSON.stringify(canonical) !== JSON.stringify(pristine)) {
472
+ fail("MUTATION_DOWNSTREAM_DOMAIN_DELTA", entry.id);
473
+ }
474
+ const activeRestore = applyMutations(temp, [
475
+ {
476
+ ...actual,
477
+ replacement: replacementFor({ ...entry, mutation: record.canonicalMutation }),
478
+ },
479
+ {
480
+ file: record.catchReturn.file,
481
+ start: record.catchReturn.start,
482
+ end: record.catchReturn.end,
483
+ replacement: 'throw new Error("N0_DOWNSTREAM_DOMAIN_SHADOW_ACTIVE");',
484
+ },
485
+ ]);
486
+ const active = matrix(temp)[record.witnessId];
487
+ activeRestore();
488
+ if (!active?.crashed || active.code !== "Error" || Object.hasOwn(active, "message")) {
489
+ fail("MUTATION_DOWNSTREAM_DOMAIN_INACTIVE", `${entry.id}:${JSON.stringify(active)}`);
490
+ }
491
+ downstreamDomainShadowsVerified += 1;
492
+ }
493
+ for (const compound of manifest.compounds) {
494
+ const pristineWitness = pristine[compound.witness.id];
495
+ if (!pristineWitness || pristineWitness.accepted || pristineWitness.code !== compound.witness.rejectCode) {
496
+ fail("MUTATION_COMPOUND_PRISTINE", `${compound.id}:${JSON.stringify(pristineWitness)}`);
497
+ }
498
+ for (const edit of compound.edits) {
499
+ const target = manifest.entries.find((entry) => entry.id === edit.entryId);
500
+ const actual = graphEntry(cleanGraph, edit.entryId);
501
+ const restore = applyMutations(temp, [{
502
+ ...actual,
503
+ replacement: replacementFor({ ...target, mutation: edit.mutation }),
504
+ }]);
505
+ const single = matrix(temp)[compound.witness.id];
506
+ restore();
507
+ if (JSON.stringify(single) !== JSON.stringify(pristineWitness)) {
508
+ fail("MUTATION_COMPOUND_SINGLE", `${compound.id}:${edit.entryId}:${JSON.stringify(single)}`);
509
+ }
510
+ }
511
+ const edits = compound.edits.map((edit) => {
512
+ const target = manifest.entries.find((entry) => entry.id === edit.entryId);
513
+ const actual = graphEntry(cleanGraph, edit.entryId);
514
+ return { ...actual, replacement: replacementFor({ ...target, mutation: edit.mutation }) };
515
+ });
516
+ const restore = applyMutations(temp, edits);
517
+ const combined = matrix(temp)[compound.witness.id];
518
+ restore();
519
+ if (!combined.accepted || combined.code !== compound.witness.acceptCode) {
520
+ fail("MUTATION_COMPOUND_PAIR", `${compound.id}:${JSON.stringify(combined)}`);
521
+ }
522
+ compoundUnitsVerified += 1;
523
+ compoundMembersVerified += compound.memberIds.length;
524
+ }
525
+ for (const entry of manifest.entries.filter((candidate) => candidate.disposition?.kind === "not-independently-discriminated")) {
526
+ const actual = graphEntry(cleanGraph, entry.id);
527
+ const singleRestore = applyMutations(temp, [{ ...actual, replacement: replacementFor({ ...entry, mutation: entry.disposition.mutation }) }]);
528
+ const single = matrix(temp);
529
+ singleRestore();
530
+ assertRedundantDispositionSingle(entry, pristine, single);
531
+ const compoundEntries = [entry, ...entry.disposition.coveredBy.map((id) => manifest.entries.find((candidate) => candidate.id === id))];
532
+ const edits = compoundEntries.map((candidate) => {
533
+ if (!candidate) fail("MUTATION_DISPOSITION_COVER", entry.id);
534
+ const candidateActual = graphEntry(cleanGraph, candidate.id);
535
+ const mutation = candidate.id === entry.id ? entry.disposition.mutation : candidate.mutation;
536
+ return { ...candidateActual, replacement: replacementFor({ ...candidate, mutation }) };
537
+ });
538
+ const restore = applyMutations(temp, edits);
539
+ const compound = matrix(temp)[entry.disposition.witness.id];
540
+ restore();
541
+ if (!compound.accepted || compound.code !== entry.disposition.witness.acceptCode) fail("MUTATION_DISPOSITION_COMPOUND", entry.id);
542
+ redundancyDispositionsVerified += 1;
543
+ }
544
+ }
545
+ baseline(temp, expectedAggregate);
546
+ assertPrimary(primary);
547
+ } finally {
548
+ try {
549
+ fs.rmSync(temp, { recursive: true, force: true });
550
+ } finally {
551
+ assertPrimary(primary);
552
+ }
553
+ }
554
+ if (derive) {
555
+ const positiveRegressionEntries = [...derived.entries()]
556
+ .filter(([, partitions]) => partitions.positiveRegressionSet.length > 0)
557
+ .map(([id, partitions]) => ({ id, positiveRegressionSet: partitions.positiveRegressionSet }));
558
+ if (positiveRegressionEntries.length > 0) {
559
+ fail("MUTATION_POSITIVE_REGRESSION", JSON.stringify(positiveRegressionEntries));
560
+ }
561
+ for (const entry of manifest.entries) {
562
+ if (!derived.has(entry.id)) continue;
563
+ const partitions = derived.get(entry.id);
564
+ entry.acceptFlipSet = partitions.acceptFlipSet;
565
+ entry.rejectDeltaSet = partitions.rejectDeltaSet;
566
+ entry.positiveRegressionSet = partitions.positiveRegressionSet;
567
+ entry.witness = witnessFor(partitions);
568
+ const kind = ownershipKind(partitions);
569
+ entry.ownershipRecord = kind ? { kind } : null;
570
+ }
571
+ const derivedCounts = {
572
+ rejectPreservingOwnership: manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "reject-preserving-ownership").length,
573
+ mixedOwnership: manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "mixed-ownership").length,
574
+ };
575
+ manifest.floors.ownershipCounts ??= derivedCounts;
576
+ manifest.floors.ownershipGrowthReasons ??= {};
577
+ fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
578
+ const normalOwnership = manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "normal-ownership").length;
579
+ const rejectPreservingOwnership = derivedCounts.rejectPreservingOwnership;
580
+ const mixedOwnership = derivedCounts.mixedOwnership;
581
+ const zeroDeltaEntries = [...derived.values()].filter((result) => ownershipKind(result) === null).length;
582
+ const successOwnershipRecords = manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "owned-success").length;
583
+ process.stdout.write(`N0_GUARD_PARTITION_AUTHOR_GREEN normalOwnership=${normalOwnership} rejectPreservingOwnership=${rejectPreservingOwnership} mixedOwnership=${mixedOwnership} successOwnershipRecords=${successOwnershipRecords} zeroDeltaEntries=${zeroDeltaEntries} uniqueMutationsExecuted=${uniqueMutationsExecuted}\n`);
584
+ return;
585
+ }
586
+ const normalOwnership = manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "normal-ownership").length;
587
+ const rejectPreservingOwnership = manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "reject-preserving-ownership").length;
588
+ const mixedOwnership = manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "mixed-ownership").length;
589
+ const successOwnershipRecords = manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "owned-success").length;
590
+ process.stdout.write(`N0_GUARD_MUTATION_GREEN normalOwnership=${normalOwnership} rejectPreservingOwnership=${rejectPreservingOwnership} mixedOwnership=${mixedOwnership} successOwnershipRecords=${successOwnershipRecords} sameCodeShadowsVerified=${sameCodeShadowsVerified} downstreamDomainShadowsVerified=${downstreamDomainShadowsVerified} compoundUnitsVerified=${compoundUnitsVerified} compoundMembersVerified=${compoundMembersVerified} uniqueMutationsExecuted=${uniqueMutationsExecuted} redundancyDispositionsVerified=${redundancyDispositionsVerified} aggregate=${expectedAggregate}\n`);
591
+ }
592
+
593
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
594
+ try { runBattery(); }
595
+ catch (error) {
596
+ process.stderr.write(`${error?.stack ?? error}\n`);
597
+ process.exitCode = 1;
598
+ }
599
+ }