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,1372 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { parse } from "acorn";
5
+
6
+ export const CENSUS_SCHEMA = "N0_GUARD_CENSUS_V2";
7
+ export const SOURCE_EXTENSIONS = new Set([".js", ".mjs", ".cjs"]);
8
+
9
+ function sha256(value) {
10
+ return crypto.createHash("sha256").update(value).digest("hex");
11
+ }
12
+
13
+ function fail(code, detail) {
14
+ const error = new Error(`${code}: ${detail}`);
15
+ error.code = code;
16
+ throw error;
17
+ }
18
+
19
+ function walk(node, visit, parent = null) {
20
+ if (!node || typeof node !== "object") return;
21
+ if (typeof node.type === "string") visit(node, parent);
22
+ for (const [key, value] of Object.entries(node)) {
23
+ if (key === "loc" || key === "start" || key === "end") continue;
24
+ if (Array.isArray(value)) {
25
+ for (const child of value) walk(child, visit, node);
26
+ } else if (value && typeof value === "object" && typeof value.type === "string") {
27
+ walk(value, visit, node);
28
+ }
29
+ }
30
+ }
31
+
32
+ function contains(ancestor, descendant) {
33
+ return ancestor.start <= descendant.start && ancestor.end >= descendant.end;
34
+ }
35
+
36
+ function calleeName(callee) {
37
+ if (callee?.type === "Identifier") return callee.name;
38
+ if (callee?.type === "MemberExpression" && callee.object?.type === "Identifier") {
39
+ const property = !callee.computed && callee.property?.type === "Identifier"
40
+ ? callee.property.name
41
+ : literalString(callee.property);
42
+ if (property) return `${callee.object.name}.${property}`;
43
+ }
44
+ return null;
45
+ }
46
+
47
+ function literalString(node) {
48
+ return node?.type === "Literal" && typeof node.value === "string" ? node.value : null;
49
+ }
50
+
51
+ function atomicTerms(record, expression, atNode = expression, seen = new Set()) {
52
+ if (!expression) return [];
53
+ if (expression.type === "Identifier") {
54
+ const binding = bindingFor(record, expression.name, atNode);
55
+ if (binding?.kind === "const" && binding.init) {
56
+ const key = `${binding.node.start}:${binding.node.end}`;
57
+ if (seen.has(key)) fail("CENSUS_BINDING_CYCLE", `${record.relative}:${expression.name}`);
58
+ return atomicTerms(record, binding.init, binding.node, new Set([...seen, key]));
59
+ }
60
+ }
61
+ if (expression.type === "LogicalExpression") {
62
+ return [...atomicTerms(record, expression.left, atNode, seen), ...atomicTerms(record, expression.right, atNode, seen)];
63
+ }
64
+ return [expression];
65
+ }
66
+
67
+ function sourceFiles(root) {
68
+ const files = [];
69
+ function visit(directory) {
70
+ const entries = fs.readdirSync(directory, { withFileTypes: true })
71
+ .sort((a, b) => a.name.localeCompare(b.name));
72
+ for (const entry of entries) {
73
+ const target = path.join(directory, entry.name);
74
+ if (entry.isDirectory()) visit(target);
75
+ else if (entry.isFile() && SOURCE_EXTENSIONS.has(path.extname(entry.name))) files.push(target);
76
+ else if (entry.isSymbolicLink()) fail("CENSUS_SYMLINK", target);
77
+ }
78
+ }
79
+ visit(root);
80
+ return files;
81
+ }
82
+
83
+ function relativeImport(fromFile, specifier) {
84
+ if (!specifier.startsWith(".")) return null;
85
+ const candidate = path.resolve(path.dirname(fromFile), specifier);
86
+ const options = path.extname(candidate) ? [candidate] : [...SOURCE_EXTENSIONS].map((ext) => `${candidate}${ext}`);
87
+ return options.find((value) => fs.existsSync(value)) ?? candidate;
88
+ }
89
+
90
+ function functionName(node, parent) {
91
+ if (node.type === "FunctionDeclaration" && node.id) return node.id.name;
92
+ if ((node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression")
93
+ && parent?.type === "VariableDeclarator" && parent.id?.type === "Identifier") return parent.id.name;
94
+ return null;
95
+ }
96
+
97
+ function walkWithinFunction(fn, visit) {
98
+ function descend(node, parent = null) {
99
+ if (!node || typeof node !== "object") return;
100
+ if (node !== fn.node && /Function/.test(node.type)) return;
101
+ if (typeof node.type === "string") visit(node, parent);
102
+ for (const [key, value] of Object.entries(node)) {
103
+ if (key === "loc" || key === "start" || key === "end") continue;
104
+ if (Array.isArray(value)) for (const child of value) descend(child, node);
105
+ else if (value && typeof value === "object" && typeof value.type === "string") descend(value, node);
106
+ }
107
+ }
108
+ descend(fn.node);
109
+ }
110
+
111
+ function enclosingFunction(node, functions) {
112
+ let winner = null;
113
+ for (const fn of functions) {
114
+ if (contains(fn.node, node) && (!winner || fn.node.start > winner.node.start)) winner = fn;
115
+ }
116
+ return winner;
117
+ }
118
+
119
+ function bindingFor(record, name, atNode) {
120
+ const owner = enclosingFunction(atNode, record.functions);
121
+ const candidates = record.bindings.filter((binding) => {
122
+ if (binding.name !== name || binding.node.start > atNode.start) return false;
123
+ const bindingOwner = enclosingFunction(binding.node, record.functions);
124
+ return bindingOwner?.key === owner?.key;
125
+ });
126
+ return candidates.sort((a, b) => b.node.start - a.node.start)[0] ?? null;
127
+ }
128
+
129
+ function resolveImmutableExpression(record, expression, atNode = expression, seen = new Set()) {
130
+ if (expression?.type !== "Identifier") return expression;
131
+ const binding = bindingFor(record, expression.name, atNode);
132
+ if (!binding || binding.kind !== "const" || !binding.init) return expression;
133
+ const key = `${binding.node.start}:${binding.node.end}`;
134
+ if (seen.has(key)) fail("CENSUS_BINDING_CYCLE", `${record.relative}:${expression.name}`);
135
+ seen.add(key);
136
+ return resolveImmutableExpression(record, binding.init, binding.node, seen);
137
+ }
138
+
139
+ function returnedStatus(record, node) {
140
+ if (node.type !== "ReturnStatement" || !node.argument) return null;
141
+ const value = resolveImmutableExpression(record, node.argument, node);
142
+ if (value?.type !== "ObjectExpression") return null;
143
+ const statusProperty = value.properties.find((property) => property.type === "Property"
144
+ && !property.computed && ((property.key.type === "Identifier" && property.key.name === "status")
145
+ || literalString(property.key) === "status"));
146
+ return { status: literalString(statusProperty?.value), value };
147
+ }
148
+
149
+ function rejectionEscapes(record, node) {
150
+ let current = node;
151
+ while (current) {
152
+ const parent = record.parents.get(current);
153
+ if (!parent) return true;
154
+ if (parent.type === "TryStatement" && parent.handler && contains(parent.block, node)) {
155
+ const last = parent.handler.body?.body?.at(-1);
156
+ if (last?.type !== "ThrowStatement") return false;
157
+ }
158
+ if (/Function/.test(parent.type)) return true;
159
+ current = parent;
160
+ }
161
+ return true;
162
+ }
163
+
164
+ function normalizedNodeSource(record, node) {
165
+ return record.source.slice(node.start, node.end).replace(/\r\n/g, "\n").trim();
166
+ }
167
+
168
+ function stableNode(record, node, kind, extra = {}) {
169
+ const source = normalizedNodeSource(record, node);
170
+ const shortHash = sha256(source).slice(0, 16);
171
+ const line = node.loc.start.line;
172
+ const column = node.loc.start.column + 1;
173
+ return {
174
+ id: `${record.relative}:${line}:${column}:${kind}:${shortHash}`,
175
+ kind,
176
+ file: record.relative,
177
+ line,
178
+ column,
179
+ nodeType: node.type,
180
+ sourceHash: sha256(source),
181
+ source,
182
+ start: node.start,
183
+ end: node.end,
184
+ ...extra,
185
+ };
186
+ }
187
+
188
+ function parseRecord(root, file) {
189
+ const source = fs.readFileSync(file, "utf8");
190
+ let ast;
191
+ try {
192
+ ast = parse(source, { ecmaVersion: "latest", sourceType: "module", locations: true });
193
+ } catch (error) {
194
+ fail("CENSUS_PARSE", `${path.relative(root, file)}:${error.loc?.line ?? "?"}:${error.loc?.column ?? "?"}: ${error.message}`);
195
+ }
196
+ const record = { root, file, relative: path.relative(root, file).split(path.sep).join("/"), source, ast, parents: new Map(), functions: [], imports: new Map(), bindings: [], nodes: [] };
197
+ walk(ast, (node, parent) => {
198
+ if (parent) record.parents.set(node, parent);
199
+ const name = functionName(node, parent);
200
+ if (name) record.functions.push({ key: `${file}#${name}`, name, file, node, record, directReject: false, rejects: false });
201
+ if (node.type === "VariableDeclarator" && node.id?.type === "Identifier") {
202
+ record.bindings.push({ name: node.id.name, init: node.init, node, declaration: parent, kind: parent?.kind ?? null });
203
+ }
204
+ if (node.type === "ImportDeclaration") {
205
+ const importedFile = relativeImport(file, node.source.value);
206
+ if (node.source.value.startsWith(".") && (!importedFile || !path.resolve(importedFile).startsWith(`${path.resolve(root)}${path.sep}`))) {
207
+ fail("CENSUS_IMPORT_ESCAPE", `${record.relative}: ${node.source.value}`);
208
+ }
209
+ if (node.source.value.startsWith(".") && !fs.existsSync(importedFile)) fail("CENSUS_IMPORT_MISSING", `${record.relative}: ${node.source.value}`);
210
+ for (const specifier of node.specifiers) {
211
+ const imported = specifier.type === "ImportSpecifier" ? specifier.imported.name : "default";
212
+ record.imports.set(specifier.local.name, { file: importedFile, name: imported });
213
+ }
214
+ }
215
+ if (node.type === "ImportExpression") fail("CENSUS_DYNAMIC_IMPORT", record.relative);
216
+ });
217
+ return record;
218
+ }
219
+
220
+ function directOutcome(record, node, parent) {
221
+ if (node.type === "ThrowStatement") return { outcome: "reject", spelling: "throw" };
222
+ if (node.type === "AssignmentExpression" && calleeName(node.left) === "process.exitCode") return { outcome: "exit-status", spelling: "process.exitCode" };
223
+ if (node.type === "ReturnStatement") {
224
+ const returned = returnedStatus(record, node);
225
+ if (node.argument?.type === "Identifier") {
226
+ if (returned?.status === "N0_TEST_CAPABLE") return { outcome: "accept", spelling: "object:N0_TEST_CAPABLE" };
227
+ if (returned?.status === "RED" || returned?.status === "BLOCKED") return { outcome: "reject", spelling: `object:${returned.status}` };
228
+ return { outcome: "candidate", spelling: "returned-binding" };
229
+ }
230
+ }
231
+ if (node.type === "ObjectExpression" && parent?.type === "ReturnStatement") {
232
+ const statusProperty = node.properties.find((property) => property.type === "Property"
233
+ && !property.computed && ((property.key.type === "Identifier" && property.key.name === "status")
234
+ || literalString(property.key) === "status"));
235
+ const status = literalString(statusProperty?.value);
236
+ if (status === "N0_TEST_CAPABLE") return { outcome: "accept", spelling: "object:N0_TEST_CAPABLE" };
237
+ if (status === "RED" || status === "BLOCKED") return { outcome: "reject", spelling: `object:${status}` };
238
+ }
239
+ if (node.type !== "CallExpression") return null;
240
+ const name = calleeName(node.callee);
241
+ if (name === "process.exit") return { outcome: "terminate", spelling: "process.exit" };
242
+ if (["process.kill", "Promise.reject", "assert", "assert.ok"].includes(name)) return { outcome: "reject", spelling: name };
243
+ if (name === "fail") return { outcome: "reject", spelling: "fail" };
244
+ if (name === "verdict") {
245
+ const status = literalString(node.arguments[0]);
246
+ if (status === "N0_TEST_CAPABLE") return { outcome: "accept", spelling: "verdict" };
247
+ if (status === "RED" || status === "BLOCKED") return { outcome: "reject", spelling: `verdict:${status}` };
248
+ return { outcome: "dynamic", spelling: "verdict" };
249
+ }
250
+ if (name === null) return { outcome: "unresolved", spelling: "dynamic-callee" };
251
+ return null;
252
+ }
253
+
254
+ function resolveFunction(recordsByFile, functionsByKey, record, localName) {
255
+ const local = functionsByKey.get(`${record.file}#${localName}`);
256
+ if (local) return local;
257
+ const imported = record.imports.get(localName);
258
+ if (!imported?.file) return null;
259
+ const importedRecord = recordsByFile.get(imported.file);
260
+ if (!importedRecord) return null;
261
+ return functionsByKey.get(`${importedRecord.file}#${imported.name}`) ?? null;
262
+ }
263
+
264
+ function nearestRejectingIf(record, sinkNode) {
265
+ let current = record.parents.get(sinkNode);
266
+ while (current) {
267
+ if (current.type === "IfStatement" && contains(current.consequent, sinkNode)) return current;
268
+ if (/Function/.test(current.type)) return null;
269
+ current = record.parents.get(current);
270
+ }
271
+ return null;
272
+ }
273
+
274
+ function callExpressions(expression) {
275
+ const calls = [];
276
+ walk(expression, (node) => {
277
+ if (node.type === "CallExpression") calls.push(node);
278
+ });
279
+ return calls;
280
+ }
281
+
282
+ function isPureBuiltinCall(call) {
283
+ const name = calleeName(call.callee);
284
+ const method = call.callee?.type === "MemberExpression"
285
+ ? (!call.callee.computed && call.callee.property?.type === "Identifier"
286
+ ? call.callee.property.name : literalString(call.callee.property))
287
+ : null;
288
+ return ["Array.isArray", "Number.isFinite", "Number.isSafeInteger", "path.isAbsolute"].includes(name)
289
+ || ["test", "includes", "startsWith", "endsWith", "some", "every", "isSymbolicLink", "isDirectory", "isFile"].includes(method);
290
+ }
291
+
292
+ function predicateExpressions(fn) {
293
+ const expressions = [];
294
+ walkWithinFunction(fn, (node) => {
295
+ if (node.type === "ReturnStatement" && node.argument
296
+ && !(node.argument.type === "Literal" && typeof node.argument.value === "boolean")) expressions.push(node.argument);
297
+ if (node.type === "IfStatement") expressions.push(node.test);
298
+ });
299
+ return expressions;
300
+ }
301
+
302
+ function looksBoolean(record, expression, context, seen = new Set()) {
303
+ if (!expression) return false;
304
+ const resolved = resolveImmutableExpression(record, expression, expression);
305
+ if (resolved !== expression) return looksBoolean(record, resolved, context, seen);
306
+ if (expression.type === "Literal") return typeof expression.value === "boolean";
307
+ if (expression.type === "UnaryExpression") return expression.operator === "!";
308
+ if (expression.type === "BinaryExpression") return ["==", "!=", "===", "!==", "<", "<=", ">", ">=", "in", "instanceof"].includes(expression.operator);
309
+ if (expression.type === "LogicalExpression") return looksBoolean(record, expression.left, context, seen) && looksBoolean(record, expression.right, context, seen);
310
+ if (expression.type === "ConditionalExpression") return looksBoolean(record, expression.consequent, context, seen) && looksBoolean(record, expression.alternate, context, seen);
311
+ if (expression.type === "CallExpression") {
312
+ const name = calleeName(expression.callee);
313
+ const method = expression.callee?.type === "MemberExpression" && !expression.callee.computed
314
+ && expression.callee.property?.type === "Identifier" ? expression.callee.property.name : name?.split(".").at(-1);
315
+ if (["Array.isArray", "Number.isFinite", "Number.isSafeInteger", "path.isAbsolute"].includes(name)
316
+ || ["test", "includes", "startsWith", "endsWith", "some", "every", "isSymbolicLink", "isDirectory", "isFile"].includes(method)) return true;
317
+ if (expression.callee.type !== "Identifier") return false;
318
+ const target = resolveFunction(context.recordsByFile, context.functionsByKey, record, expression.callee.name);
319
+ if (!target || seen.has(target.key)) return false;
320
+ return functionReturnsBoolean(target, context, new Set([...seen, target.key]));
321
+ }
322
+ return false;
323
+ }
324
+
325
+ function functionReturnsBoolean(fn, context, seen = new Set([fn.key])) {
326
+ const returns = [];
327
+ walkWithinFunction(fn, (node) => {
328
+ if (node.type === "ReturnStatement" && node.argument) returns.push(node.argument);
329
+ });
330
+ return returns.length > 0 && returns.every((expression) => looksBoolean(fn.record, expression, context, seen));
331
+ }
332
+
333
+ function predicateCallContext(record, call, outcomes) {
334
+ let conditional = null;
335
+ let current = call;
336
+ while (current) {
337
+ const parent = record.parents.get(current);
338
+ if (!parent || /Function/.test(parent.type)) break;
339
+ if (parent.type === "IfStatement" && contains(parent.test, call)) {
340
+ conditional = parent;
341
+ break;
342
+ }
343
+ current = parent;
344
+ }
345
+ if (!conditional) return "non-enforcing";
346
+ const owner = enclosingFunction(call, record.functions);
347
+ const branchRejects = (branch) => branch && outcomes.some((outcome) => outcome.record === record
348
+ && ["reject", "terminate", "exit-status"].includes(outcome.outcome)
349
+ && enclosingFunction(outcome.node, record.functions)?.key === owner?.key
350
+ && contains(branch, outcome.node));
351
+ const consequentRejects = branchRejects(conditional.consequent);
352
+ const alternateRejects = branchRejects(conditional.alternate);
353
+ if (!consequentRejects && !alternateRejects) return "non-enforcing";
354
+ if (consequentRejects && alternateRejects) fail("CENSUS_PREDICATE_CONTEXT", `${record.relative}:${call.loc.start.line}: both branches reject`);
355
+
356
+ let callTrueMakesTestTrue = true;
357
+ current = call;
358
+ while (current !== conditional.test) {
359
+ const parent = record.parents.get(current);
360
+ if (!parent) fail("CENSUS_PREDICATE_CONTEXT", `${record.relative}:${call.loc.start.line}: detached call`);
361
+ if (parent.type === "UnaryExpression" && parent.operator === "!") callTrueMakesTestTrue = !callTrueMakesTestTrue;
362
+ else if (parent.type !== "LogicalExpression") {
363
+ fail("CENSUS_PREDICATE_CONTEXT", `${record.relative}:${call.loc.start.line}: unsupported ${parent.type}`);
364
+ }
365
+ current = parent;
366
+ }
367
+ const callTrueRejects = consequentRejects ? callTrueMakesTestTrue : !callTrueMakesTestTrue;
368
+ return callTrueRejects ? "reject-on-true" : "reject-on-false";
369
+ }
370
+
371
+ function sharedContextPredicateProof(records, functions, outcomes, discovered, recordsByFile, functionsByKey, queuedPredicates) {
372
+ const predicateFunctions = new Map(functions.filter((fn) => queuedPredicates.has(fn.key)).map((fn) => [fn.key, fn]));
373
+ for (const record of records) {
374
+ for (const binding of record.bindings) {
375
+ if (binding.init?.type !== "Identifier") continue;
376
+ const target = resolveFunction(recordsByFile, functionsByKey, record, binding.init.name);
377
+ if (target && predicateFunctions.has(target.key)) {
378
+ fail("CENSUS_PREDICATE_ALIAS", `${record.relative}:${binding.node.loc.start.line}:${binding.name}`);
379
+ }
380
+ }
381
+ }
382
+
383
+ const callsByPredicate = new Map([...predicateFunctions.keys()].map((key) => [key, []]));
384
+ for (const record of records) {
385
+ walk(record.ast, (node) => {
386
+ if (node.type !== "CallExpression" || node.callee.type !== "Identifier") return;
387
+ const target = resolveFunction(recordsByFile, functionsByKey, record, node.callee.name);
388
+ if (!target || !predicateFunctions.has(target.key)) return;
389
+ if (node.optional === true) {
390
+ fail("CENSUS_PREDICATE_DYNAMIC_CALL", `${record.relative}:${node.loc.start.line}:${node.callee.name}`);
391
+ }
392
+ const context = predicateCallContext(record, node, outcomes);
393
+ const guardOwners = discovered.filter((entry) => entry.kind === "guard-atom" && entry.file === record.relative
394
+ && entry.start <= node.start && entry.end >= node.end)
395
+ .sort((left, right) => (left.end - left.start) - (right.end - right.start));
396
+ if (context !== "non-enforcing" && guardOwners.length === 0) {
397
+ fail("CENSUS_SHARED_CONTEXT_CALL", `${record.relative}:${node.loc.start.line}: no enforcing guard owner`);
398
+ }
399
+ const callsite = stableNode(record, node, "predicate-call", {
400
+ predicate: target.name,
401
+ context,
402
+ enforcingEntryId: context === "non-enforcing" ? null : guardOwners[0].id,
403
+ });
404
+ callsByPredicate.get(target.key).push(callsite);
405
+ });
406
+ }
407
+
408
+ const proof = [];
409
+ for (const [key, calls] of callsByPredicate) {
410
+ const contexts = [...new Set(calls.map((call) => call.context))].sort();
411
+ if (contexts.length < 2) continue;
412
+ const fn = predicateFunctions.get(key);
413
+ const atomIds = discovered.filter((entry) => entry.kind === "predicate-atom" && entry.predicate === fn.name)
414
+ .map((entry) => entry.id).sort();
415
+ if (atomIds.length === 0) fail("CENSUS_SHARED_CONTEXT_ATOMS", fn.name);
416
+ proof.push({
417
+ predicate: fn.name,
418
+ functionKey: `${fn.record.relative}#${fn.name}`,
419
+ contexts,
420
+ atomIds,
421
+ canonicalAtomMutations: atomIds.map((id) => ({
422
+ id,
423
+ mutation: { operator: "force-owned-condition", value: true },
424
+ })),
425
+ callSites: calls.map(({ id, file, line, column, sourceHash, source, context, enforcingEntryId }) => ({
426
+ id, file, line, column, sourceHash, source, context, enforcingEntryId,
427
+ })).sort((left, right) => left.file.localeCompare(right.file) || left.line - right.line || left.column - right.column),
428
+ });
429
+ }
430
+ return proof.sort((left, right) => left.functionKey.localeCompare(right.functionKey));
431
+ }
432
+
433
+ function sameCodeShadowProof(records, discovered) {
434
+ const proof = [];
435
+ for (const record of records) {
436
+ walk(record.ast, (node) => {
437
+ if (node.type !== "CallExpression" || node.optional === true
438
+ || node.callee.type !== "Identifier" || node.callee.name !== "requireObject") return;
439
+ const parent = record.parents.get(node);
440
+ let statement;
441
+ let validatedSource;
442
+ if (parent?.type === "VariableDeclarator" && parent.init === node && parent.id?.type === "Identifier") {
443
+ statement = record.parents.get(parent);
444
+ validatedSource = parent.id.name;
445
+ if (statement?.type !== "VariableDeclaration") return;
446
+ } else if (parent?.type === "ExpressionStatement") {
447
+ statement = parent;
448
+ validatedSource = normalizedNodeSource(record, node.arguments[0]);
449
+ } else {
450
+ return;
451
+ }
452
+ const block = record.parents.get(statement);
453
+ if (block?.type !== "BlockStatement") return;
454
+ const index = block.body.indexOf(statement);
455
+ const next = index >= 0 ? block.body[index + 1] : null;
456
+ const downstream = next?.type === "ExpressionStatement" ? next.expression : null;
457
+ if (downstream?.type !== "CallExpression" || downstream.optional === true
458
+ || downstream.callee.type !== "Identifier" || downstream.callee.name !== "assertExactKeys"
459
+ || normalizedNodeSource(record, downstream.arguments[0]) !== validatedSource) return;
460
+ const upstreamCode = literalString(node.arguments[1]);
461
+ const downstreamCode = literalString(downstream.arguments[2]);
462
+ if (!upstreamCode || upstreamCode !== downstreamCode) return;
463
+ const entry = discovered.find((candidate) => candidate.kind === "rejecting-helper-call"
464
+ && candidate.file === record.relative && candidate.start === node.start && candidate.end === node.end);
465
+ const downstreamEntry = discovered.find((candidate) => candidate.kind === "rejecting-helper-call"
466
+ && candidate.file === record.relative && candidate.start === downstream.start && candidate.end === downstream.end);
467
+ if (!entry || !downstreamEntry) fail("CENSUS_SHADOW_PROOF", `${record.relative}:${node.loc.start.line}`);
468
+ proof.push({
469
+ entryId: entry.id,
470
+ downstreamEntryId: downstreamEntry.id,
471
+ binding: validatedSource,
472
+ rejectCode: upstreamCode,
473
+ adjacencyHash: sha256(`${entry.sourceHash}:${downstreamEntry.sourceHash}`),
474
+ });
475
+ });
476
+ }
477
+ return proof.sort((left, right) => left.entryId.localeCompare(right.entryId));
478
+ }
479
+
480
+ function downstreamDomainShadowProof(records, functions, outcomes, discovered, recordsByFile, functionsByKey, queuedPredicates) {
481
+ const proof = [];
482
+ for (const fn of functions.filter((candidate) => queuedPredicates.has(candidate.key))) {
483
+ const statements = fn.node.body?.type === "BlockStatement" ? fn.node.body.body : [];
484
+ for (let index = 0; index + 1 < statements.length; index += 1) {
485
+ const guard = statements[index];
486
+ const returned = guard?.type === "IfStatement" && guard.alternate === null
487
+ ? exactReturnStatement(guard.consequent) : null;
488
+ if (!returned || returned.argument?.type !== "Literal" || returned.argument.value !== false
489
+ || guard.test?.type !== "LogicalExpression" || guard.test.operator !== "||") continue;
490
+
491
+ const downstreamTry = statements[index + 1];
492
+ if (downstreamTry?.type !== "TryStatement" || downstreamTry.finalizer
493
+ || downstreamTry.block?.body?.length !== 1 || downstreamTry.handler?.body?.body?.length !== 1) continue;
494
+ const callStatement = downstreamTry.block.body[0];
495
+ const call = callStatement?.type === "ExpressionStatement" ? callStatement.expression : null;
496
+ const catchReturn = exactReturnStatement(downstreamTry.handler.body);
497
+ if (call?.type !== "CallExpression" || call.optional === true || call.callee.type !== "Identifier"
498
+ || !catchReturn || catchReturn.argument?.type !== "Literal" || catchReturn.argument.value !== false) continue;
499
+ const target = resolveFunction(recordsByFile, functionsByKey, fn.record, call.callee.name);
500
+ if (!target?.rejects) continue;
501
+ const downstreamEntry = discovered.find((entry) => entry.kind === "rejecting-helper-call"
502
+ && entry.file === fn.record.relative && entry.start === call.start && entry.end === call.end);
503
+ if (!downstreamEntry) continue;
504
+
505
+ const enforcingCalls = [];
506
+ for (const record of records) {
507
+ walk(record.ast, (node) => {
508
+ if (node.type !== "CallExpression" || node.optional === true || node.callee.type !== "Identifier") return;
509
+ const resolved = resolveFunction(recordsByFile, functionsByKey, record, node.callee.name);
510
+ if (resolved?.key !== fn.key || predicateCallContext(record, node, outcomes) !== "reject-on-false") return;
511
+ const owner = discovered.filter((entry) => entry.kind === "guard-atom" && entry.file === record.relative
512
+ && entry.start <= node.start && entry.end >= node.end)
513
+ .sort((left, right) => (left.end - left.start) - (right.end - right.start))[0];
514
+ if (owner) enforcingCalls.push(owner.id);
515
+ });
516
+ }
517
+ if (enforcingCalls.length === 0) continue;
518
+
519
+ for (const atom of atomicTerms(fn.record, guard.test)) {
520
+ const entry = discovered.find((candidate) => candidate.kind === "predicate-atom"
521
+ && candidate.file === fn.record.relative && candidate.start === atom.start && candidate.end === atom.end);
522
+ if (!entry) fail("CENSUS_DOWNSTREAM_DOMAIN_ATOM", `${fn.record.relative}:${atom.loc.start.line}`);
523
+ const catchAnchor = {
524
+ ...proofAnchor(fn.record, catchReturn, "downstream-domain-catch-return"),
525
+ start: catchReturn.start,
526
+ end: catchReturn.end,
527
+ };
528
+ proof.push({
529
+ entryId: entry.id,
530
+ predicate: fn.name,
531
+ downstreamEntryId: downstreamEntry.id,
532
+ enforcingEntryIds: [...new Set(enforcingCalls)].sort(),
533
+ canonicalMutation: { operator: "force-owned-condition", value: false },
534
+ catchReturn: catchAnchor,
535
+ pathHash: sha256(`${entry.sourceHash}:${downstreamEntry.sourceHash}:${catchAnchor.sourceHash}`),
536
+ });
537
+ }
538
+ }
539
+ }
540
+ return proof.sort((left, right) => left.entryId.localeCompare(right.entryId));
541
+ }
542
+
543
+ function enclosingConditionalTest(record, node) {
544
+ let current = node;
545
+ while (current) {
546
+ const parent = record.parents.get(current);
547
+ if (!parent || /Function/.test(parent.type)) return null;
548
+ if (["IfStatement", "WhileStatement", "DoWhileStatement", "ConditionalExpression"].includes(parent.type)
549
+ && contains(parent.test, node)) return parent;
550
+ current = parent;
551
+ }
552
+ return null;
553
+ }
554
+
555
+ function generatedBinding(record, name, node, recordsByFile, functionsByKey) {
556
+ let current = node;
557
+ while (current) {
558
+ const parent = record.parents.get(current);
559
+ if (!parent) return false;
560
+ if (/Function/.test(parent.type) && Array.isArray(parent.params)
561
+ && parent.params.some((param) => param.type === "Identifier" && param.name === name)) {
562
+ const call = record.parents.get(parent);
563
+ const member = call?.type === "CallExpression" ? call.callee : null;
564
+ const producer = member?.type === "MemberExpression" && !member.computed
565
+ && member.property?.type === "Identifier" && member.property.name === "map"
566
+ ? member.object : null;
567
+ if (producer?.type !== "CallExpression" || producer.callee.type !== "Identifier") return false;
568
+ const target = resolveFunction(recordsByFile, functionsByKey, record, producer.callee.name);
569
+ return Boolean(target && !target.rejects && producer.arguments.length === 0);
570
+ }
571
+ if (parent.type === "ForOfStatement" && parent.left?.type === "VariableDeclaration"
572
+ && parent.left.declarations.some((declaration) => declaration.id?.type === "Identifier" && declaration.id.name === name)) {
573
+ const producer = parent.right;
574
+ if (producer?.type !== "CallExpression" || producer.callee.type !== "Identifier") return false;
575
+ const target = resolveFunction(recordsByFile, functionsByKey, record, producer.callee.name);
576
+ return Boolean(target && !target.rejects && producer.arguments.length === 0);
577
+ }
578
+ current = parent;
579
+ }
580
+ return false;
581
+ }
582
+
583
+ function internallyConstructed(record, expression, atNode, owner, recordsByFile, functionsByKey, seen = new Set()) {
584
+ if (!expression) return false;
585
+ if (["Literal", "ObjectExpression", "ArrayExpression", "TemplateLiteral"].includes(expression.type)) return true;
586
+ if (expression.type === "MemberExpression") return internallyConstructed(record, expression.object, atNode, owner, recordsByFile, functionsByKey, seen);
587
+ if (expression.type !== "Identifier") return false;
588
+ const binding = bindingFor(record, expression.name, atNode);
589
+ if (binding && enclosingFunction(binding.node, record.functions)?.key === owner?.key) {
590
+ const key = `${binding.node.start}:${binding.node.end}`;
591
+ if (seen.has(key)) return false;
592
+ if (binding.kind === "const" && binding.init) {
593
+ return internallyConstructed(record, binding.init, binding.node, owner, recordsByFile, functionsByKey, new Set([...seen, key]));
594
+ }
595
+ }
596
+ return generatedBinding(record, expression.name, atNode, recordsByFile, functionsByKey);
597
+ }
598
+
599
+ function callInsideDefault(record, call) {
600
+ let current = call;
601
+ while (current) {
602
+ const parent = record.parents.get(current);
603
+ if (!parent || /Function/.test(parent.type)) return false;
604
+ if (parent.type === "AssignmentPattern" && contains(parent.right, call)) return true;
605
+ current = parent;
606
+ }
607
+ return false;
608
+ }
609
+
610
+ function rejectionConfinedToDefaults(target, recordsByFile, functionsByKey) {
611
+ if (target.directReject) return false;
612
+ let sawRejectingCall = false;
613
+ let confined = true;
614
+ walkWithinFunction(target, (node) => {
615
+ if (!confined || node.type !== "CallExpression" || node.callee.type !== "Identifier") return;
616
+ const called = resolveFunction(recordsByFile, functionsByKey, target.record, node.callee.name);
617
+ if (!called?.rejects) return;
618
+ sawRejectingCall = true;
619
+ if (!callInsideDefault(target.record, node)) confined = false;
620
+ });
621
+ return sawRejectingCall && confined;
622
+ }
623
+
624
+ function successPathCallProof(records, functions, discovered, recordsByFile, functionsByKey) {
625
+ const proof = [];
626
+ for (const record of records) {
627
+ walk(record.ast, (node) => {
628
+ if (node.type !== "CallExpression" || node.optional === true || node.callee.type !== "Identifier") return;
629
+ const target = resolveFunction(recordsByFile, functionsByKey, record, node.callee.name);
630
+ if (!target?.rejects) return;
631
+ const entry = discovered.find((candidate) => candidate.kind === "rejecting-helper-call"
632
+ && candidate.file === record.relative && candidate.start === node.start && candidate.end === node.end);
633
+ if (!entry) return;
634
+ const owner = enclosingFunction(node, record.functions);
635
+ const conditional = enclosingConditionalTest(record, node);
636
+ let proofKind = null;
637
+ let dischargerEntryIds = [];
638
+ if (!conditional && owner?.node.params.length === 0
639
+ && node.arguments.every((argument) => internallyConstructed(record, argument, node, owner, recordsByFile, functionsByKey))) {
640
+ proofKind = "closed-zero-parameter-construction";
641
+ } else if (!conditional && callInsideDefault(record, node) && node.arguments.length === 0
642
+ && target.node.params.length === 0) {
643
+ proofKind = "closed-default-constructor";
644
+ } else if (!conditional && rejectionConfinedToDefaults(target, recordsByFile, functionsByKey)
645
+ && node.arguments.length >= target.node.params.length
646
+ && node.arguments.every((argument) => argument.type !== "SpreadElement"
647
+ && !(argument.type === "Identifier" && argument.name === "undefined"))) {
648
+ proofKind = "supplied-argument-skips-rejecting-default";
649
+ } else if (conditional && target.name === "renderPrompt" && owner?.name === "validateSpecimen") {
650
+ let loop = node;
651
+ while (loop && loop.type !== "ForOfStatement") loop = record.parents.get(loop);
652
+ const earlierLoop = owner.node.body.body.find((statement) => statement.type === "ForOfStatement"
653
+ && statement.end < loop?.start
654
+ && normalizedNodeSource(record, statement.right) === normalizedNodeSource(record, loop.right));
655
+ if (earlierLoop) {
656
+ const token = /(?:cases|caseSpec|nonce|mailRowId|CASE_|REQUIRED_CASES)/;
657
+ dischargerEntryIds = discovered.filter((candidate) => candidate.file === record.relative
658
+ && candidate.start >= owner.node.start && candidate.end <= node.start
659
+ && ["rejecting-helper-call", "guard-atom", "rejection-site"].includes(candidate.kind)
660
+ && token.test(candidate.source))
661
+ .map((candidate) => candidate.id).sort();
662
+ if (dischargerEntryIds.length > 0) proofKind = "guard-call-dominated-by-owned-dischargers";
663
+ }
664
+ }
665
+ if (!proofKind) return;
666
+ proof.push({
667
+ entryId: entry.id,
668
+ proofKind,
669
+ targetFunctionKey: `${target.record.relative}#${target.name}`,
670
+ conditionalOwnerId: conditional
671
+ ? discovered.find((candidate) => candidate.kind === "guard-atom" && candidate.file === record.relative
672
+ && candidate.start <= node.start && candidate.end >= node.end)?.id ?? null
673
+ : null,
674
+ dischargerEntryIds,
675
+ });
676
+ });
677
+ }
678
+ return proof.sort((left, right) => left.entryId.localeCompare(right.entryId));
679
+ }
680
+
681
+ function exactReturnStatement(statement) {
682
+ if (statement?.type === "ReturnStatement") return statement;
683
+ if (statement?.type === "BlockStatement" && statement.body.length === 1
684
+ && statement.body[0].type === "ReturnStatement") return statement.body[0];
685
+ return null;
686
+ }
687
+
688
+ function proofAnchor(record, node, kind) {
689
+ const anchor = stableNode(record, node, kind);
690
+ return {
691
+ id: anchor.id,
692
+ file: anchor.file,
693
+ line: anchor.line,
694
+ column: anchor.column,
695
+ nodeType: anchor.nodeType,
696
+ sourceHash: anchor.sourceHash,
697
+ source: anchor.source,
698
+ };
699
+ }
700
+
701
+ function delegatedOutcomeCallProof(records, functions, outcomes, discovered, recordsByFile, functionsByKey) {
702
+ const proof = [];
703
+ for (const record of records) {
704
+ walk(record.ast, (node) => {
705
+ if (node.type !== "CallExpression" || node.optional === true || node.callee.type !== "Identifier") return;
706
+ const target = resolveFunction(recordsByFile, functionsByKey, record, node.callee.name);
707
+ if (!target?.rejects || target.directReject) return;
708
+ const entry = discovered.find((candidate) => candidate.kind === "rejecting-helper-call"
709
+ && candidate.file === record.relative && candidate.start === node.start && candidate.end === node.end);
710
+ if (!entry) return;
711
+
712
+ const declarator = record.parents.get(node);
713
+ const declaration = declarator?.type === "VariableDeclarator" && declarator.init === node
714
+ && declarator.id?.type === "Identifier" ? record.parents.get(declarator) : null;
715
+ const block = declaration?.type === "VariableDeclaration" ? record.parents.get(declaration) : null;
716
+ const statementIndex = block?.type === "BlockStatement" ? block.body.indexOf(declaration) : -1;
717
+ const nullGuard = statementIndex >= 0 ? block.body[statementIndex + 1] : null;
718
+ const controlFlow = nullGuard?.type === "IfStatement" && nullGuard.alternate === null
719
+ && nullGuard.test?.type === "UnaryExpression" && nullGuard.test.operator === "!"
720
+ && nullGuard.test.argument?.type === "Identifier"
721
+ && nullGuard.test.argument.name === declarator.id.name
722
+ ? exactReturnStatement(nullGuard.consequent) : null;
723
+ if (!controlFlow || controlFlow.argument !== null) return;
724
+
725
+ const targetDirectOutcomes = outcomes.filter((outcome) => outcome.record.file === target.record.file
726
+ && enclosingFunction(outcome.node, target.record.functions)?.key === target.key
727
+ && ["reject", "terminate", "exit-status"].includes(outcome.outcome));
728
+ if (targetDirectOutcomes.length !== 0) return;
729
+
730
+ const delegatedCalls = [];
731
+ let unresolvedRejectingCall = false;
732
+ walkWithinFunction(target, (candidate) => {
733
+ if (candidate.type !== "CallExpression") return;
734
+ if (candidate.callee.type !== "Identifier") return;
735
+ const delegatedTarget = resolveFunction(recordsByFile, functionsByKey, target.record, candidate.callee.name);
736
+ if (!delegatedTarget?.rejects) return;
737
+ if (!delegatedTarget.directReject) {
738
+ unresolvedRejectingCall = true;
739
+ return;
740
+ }
741
+ const direct = outcomes.filter((outcome) => outcome.record.file === delegatedTarget.record.file
742
+ && enclosingFunction(outcome.node, delegatedTarget.record.functions)?.key === delegatedTarget.key
743
+ && ["reject", "terminate", "exit-status"].includes(outcome.outcome));
744
+ if (direct.length === 0 || direct.some((outcome) => outcome.outcome !== "exit-status")) {
745
+ unresolvedRejectingCall = true;
746
+ return;
747
+ }
748
+ const callStatement = target.record.parents.get(candidate);
749
+ const callBlock = callStatement?.type === "ExpressionStatement" ? target.record.parents.get(callStatement) : null;
750
+ const callIndex = callBlock?.type === "BlockStatement" ? callBlock.body.indexOf(callStatement) : -1;
751
+ const delegatedReturn = callIndex >= 0 ? exactReturnStatement(callBlock.body[callIndex + 1]) : null;
752
+ if (!delegatedReturn || literalString(delegatedReturn.argument) !== null
753
+ || delegatedReturn.argument?.type !== "Literal" || delegatedReturn.argument.value !== null) {
754
+ unresolvedRejectingCall = true;
755
+ return;
756
+ }
757
+ delegatedCalls.push({ candidate, direct });
758
+ });
759
+ if (unresolvedRejectingCall || delegatedCalls.length === 0) return;
760
+
761
+ const internalCallEntryIds = delegatedCalls.map(({ candidate }) => discovered.find((item) =>
762
+ item.kind === "rejecting-helper-call" && item.file === target.record.relative
763
+ && item.start === candidate.start && item.end === candidate.end)?.id ?? null);
764
+ const internalOutcomeEntryIds = delegatedCalls.flatMap(({ direct }) => direct.map((outcome) => discovered.find((item) =>
765
+ item.file === outcome.record.relative && item.start === outcome.node.start && item.end === outcome.node.end
766
+ && ["exit-status-site", "rejection-site"].includes(item.kind))?.id ?? null));
767
+ if (internalCallEntryIds.some((id) => id === null) || internalOutcomeEntryIds.some((id) => id === null)) return;
768
+
769
+ proof.push({
770
+ entryId: entry.id,
771
+ targetFunctionKey: `${target.record.relative}#${target.name}`,
772
+ internalCallEntryIds: [...new Set(internalCallEntryIds)].sort(),
773
+ internalOutcomeEntryIds: [...new Set(internalOutcomeEntryIds)].sort(),
774
+ callerNullGuard: proofAnchor(record, nullGuard.test, "delegated-null-guard"),
775
+ callerControlFlow: proofAnchor(record, controlFlow, "delegated-control-flow"),
776
+ });
777
+ });
778
+ }
779
+ return proof.sort((left, right) => left.entryId.localeCompare(right.entryId));
780
+ }
781
+
782
+ export function analyzeGuardGraph(root) {
783
+ const absoluteRoot = path.resolve(root);
784
+ const files = sourceFiles(absoluteRoot);
785
+ const records = files.map((file) => parseRecord(absoluteRoot, file));
786
+ const recordsByFile = new Map(records.map((record) => [record.file, record]));
787
+ const functions = records.flatMap((record) => record.functions);
788
+ const functionsByKey = new Map(functions.map((fn) => [fn.key, fn]));
789
+ const analysisContext = { recordsByFile, functionsByKey };
790
+ const outcomes = [];
791
+
792
+ for (const record of records) {
793
+ walk(record.ast, (node) => {
794
+ const outcome = directOutcome(record, node, record.parents.get(node));
795
+ if (!outcome) return;
796
+ outcomes.push({ record, node, ...outcome });
797
+ const fn = enclosingFunction(node, record.functions);
798
+ if (fn && ["reject", "terminate", "exit-status"].includes(outcome.outcome) && rejectionEscapes(record, node)) fn.directReject = true;
799
+ });
800
+ }
801
+
802
+ for (const fn of functions) fn.rejects = fn.directReject;
803
+ let changed = true;
804
+ while (changed) {
805
+ changed = false;
806
+ for (const fn of functions) {
807
+ if (fn.rejects) continue;
808
+ walkWithinFunction(fn, (node) => {
809
+ if (node.type !== "CallExpression" || node.callee.type !== "Identifier") return;
810
+ const target = resolveFunction(recordsByFile, functionsByKey, fn.record, node.callee.name);
811
+ if (target?.rejects && rejectionEscapes(fn.record, node)) fn.rejects = true;
812
+ });
813
+ if (fn.rejects) changed = true;
814
+ }
815
+ }
816
+
817
+ for (const record of records) {
818
+ for (const binding of record.bindings) {
819
+ if (binding.init?.type !== "Identifier") continue;
820
+ const target = resolveFunction(recordsByFile, functionsByKey, record, binding.init.name);
821
+ if (target?.rejects || binding.init.name === "fail") {
822
+ fail("CENSUS_REJECT_ALIAS", `${record.relative}:${binding.node.loc.start.line}:${binding.name}`);
823
+ }
824
+ }
825
+ }
826
+
827
+ const discovered = [];
828
+ const predicateQueue = [];
829
+ const queuedPredicates = new Set();
830
+ for (const outcome of outcomes) {
831
+ const kind = outcome.outcome === "accept" ? "success-constructor"
832
+ : outcome.outcome === "terminate" ? "termination-site"
833
+ : outcome.outcome === "exit-status" ? "exit-status-site"
834
+ : outcome.outcome === "dynamic" ? "dynamic-verdict-constructor"
835
+ : outcome.outcome === "candidate" ? "outcome-candidate"
836
+ : outcome.outcome === "unresolved" ? "unresolved-call" : "rejection-site";
837
+ const guard = nearestRejectingIf(outcome.record, outcome.node);
838
+ const owner = enclosingFunction(outcome.node, outcome.record.functions);
839
+ const ownership = guard ? `if:${guard.loc.start.line}` : owner ? `helper-body:${owner.name}` : "module-body";
840
+ discovered.push(stableNode(outcome.record, outcome.node, kind, { spelling: outcome.spelling, ownership }));
841
+ if (!["reject", "terminate", "exit-status"].includes(outcome.outcome)) continue;
842
+ if (!guard) continue;
843
+ const guardAtoms = atomicTerms(outcome.record, guard.test);
844
+ for (const atom of guardAtoms) {
845
+ discovered.push(stableNode(outcome.record, atom, "guard-atom", { ownerSinkLine: outcome.node.loc.start.line }));
846
+ }
847
+ for (const call of guardAtoms.flatMap((atom) => callExpressions(atom))) {
848
+ const name = call.callee.type === "Identifier" ? call.callee.name : null;
849
+ const target = name ? resolveFunction(recordsByFile, functionsByKey, outcome.record, name) : null;
850
+ if (target && functionReturnsBoolean(target, analysisContext) && !queuedPredicates.has(target.key)) {
851
+ queuedPredicates.add(target.key);
852
+ predicateQueue.push(target);
853
+ } else if (!isPureBuiltinCall(call)) {
854
+ discovered.push(stableNode(outcome.record, call, "unresolved-call", { context: "guard", callee: calleeName(call.callee) }));
855
+ }
856
+ }
857
+ }
858
+
859
+ while (predicateQueue.length) {
860
+ const fn = predicateQueue.shift();
861
+ for (const expression of predicateExpressions(fn)) {
862
+ const predicateAtoms = atomicTerms(fn.record, expression);
863
+ for (const atom of predicateAtoms) {
864
+ discovered.push(stableNode(fn.record, atom, "predicate-atom", { predicate: fn.name }));
865
+ }
866
+ for (const call of predicateAtoms.flatMap((atom) => callExpressions(atom))) {
867
+ const name = call.callee.type === "Identifier" ? call.callee.name : null;
868
+ const target = name ? resolveFunction(recordsByFile, functionsByKey, fn.record, name) : null;
869
+ if (target && functionReturnsBoolean(target, analysisContext) && !queuedPredicates.has(target.key)) {
870
+ queuedPredicates.add(target.key);
871
+ predicateQueue.push(target);
872
+ } else if (!isPureBuiltinCall(call)) {
873
+ discovered.push(stableNode(fn.record, call, "unresolved-call", { context: "predicate", callee: calleeName(call.callee) }));
874
+ }
875
+ }
876
+ }
877
+ }
878
+
879
+ for (const record of records) {
880
+ walk(record.ast, (node) => {
881
+ if (node.type !== "CallExpression" || node.callee.type !== "Identifier") return;
882
+ const target = resolveFunction(recordsByFile, functionsByKey, record, node.callee.name);
883
+ if (!target?.rejects || node.callee.name === "fail") return;
884
+ discovered.push(stableNode(record, node, "rejecting-helper-call", { helper: target.name }));
885
+ const guard = nearestRejectingIf(record, node);
886
+ const owner = enclosingFunction(node, record.functions);
887
+ if (guard && !guard.alternate && target.key !== owner?.key) {
888
+ for (const atom of atomicTerms(record, guard.test)) {
889
+ discovered.push(stableNode(record, atom, "guard-atom", { ownerSinkLine: node.loc.start.line }));
890
+ }
891
+ }
892
+ });
893
+ }
894
+
895
+ const byId = new Map();
896
+ for (const entry of discovered) {
897
+ if (byId.has(entry.id)) continue;
898
+ byId.set(entry.id, entry);
899
+ }
900
+ const entries = [...byId.values()].sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line || a.column - b.column || a.kind.localeCompare(b.kind));
901
+ const counts = Object.fromEntries([...new Set(entries.map((entry) => entry.kind))].sort().map((kind) => [kind, entries.filter((entry) => entry.kind === kind).length]));
902
+ const sharedContextPredicates = sharedContextPredicateProof(
903
+ records, functions, outcomes, entries, recordsByFile, functionsByKey, queuedPredicates,
904
+ );
905
+ const sameCodeShadows = sameCodeShadowProof(records, entries);
906
+ const downstreamDomainShadows = downstreamDomainShadowProof(
907
+ records, functions, outcomes, entries, recordsByFile, functionsByKey, queuedPredicates,
908
+ );
909
+ const successPathCalls = successPathCallProof(records, functions, entries, recordsByFile, functionsByKey);
910
+ const delegatedOutcomeCalls = delegatedOutcomeCallProof(records, functions, outcomes, entries, recordsByFile, functionsByKey);
911
+ return { schema: CENSUS_SCHEMA, sourceRoot: path.basename(absoluteRoot), files: records.map((record) => record.relative), counts, sharedContextPredicates, sameCodeShadows, downstreamDomainShadows, successPathCalls, delegatedOutcomeCalls, entries };
912
+ }
913
+
914
+ function identity(entry) {
915
+ const { id, kind, file, line, column, nodeType, sourceHash, source, spelling, ownership, ownerSinkLine, predicate, helper, context, callee } = entry;
916
+ return { id, kind, file, line, column, nodeType, sourceHash, source, spelling, ownership, ownerSinkLine, predicate, helper, context, callee };
917
+ }
918
+
919
+ function migrationKey(entry) {
920
+ return JSON.stringify({
921
+ file: entry.file,
922
+ kind: entry.kind,
923
+ sourceHash: entry.sourceHash,
924
+ spelling: entry.spelling,
925
+ helper: entry.helper,
926
+ predicate: entry.predicate,
927
+ context: entry.context,
928
+ callee: entry.callee,
929
+ });
930
+ }
931
+
932
+ function migratedOwners(graph, prior) {
933
+ const exact = new Map((prior?.entries ?? []).map((entry) => [entry.id, entry]));
934
+ const buckets = new Map();
935
+ for (const entry of prior?.entries ?? []) {
936
+ const key = migrationKey(entry);
937
+ if (!buckets.has(key)) buckets.set(key, []);
938
+ buckets.get(key).push(entry);
939
+ }
940
+ for (const entries of buckets.values()) entries.sort((a, b) => a.line - b.line || a.column - b.column);
941
+ return graph.entries.map((entry) => exact.get(entry.id) ?? buckets.get(migrationKey(entry))?.shift() ?? null);
942
+ }
943
+
944
+ export function mergeManifest(graph, prior = null, projection = null, counterexamples = null) {
945
+ const migrated = migratedOwners(graph, prior);
946
+ const sinkProjection = graph.entries.filter((entry) => entry.kind === "rejection-site"
947
+ && (entry.spelling === "fail" || entry.spelling === "verdict:RED"));
948
+ const priorFloors = prior?.floors?.counts ?? {};
949
+ const floorKinds = [...new Set([...Object.keys(priorFloors), ...Object.keys(graph.counts)])].sort();
950
+ const floors = Object.fromEntries(floorKinds.map((kind) => [
951
+ kind,
952
+ Math.max(graph.counts[kind] ?? 0, priorFloors[kind] ?? 0),
953
+ ]));
954
+ const priorDispositionCeiling = prior?.floors?.maxRedundancyDispositions;
955
+ return {
956
+ schema: CENSUS_SCHEMA,
957
+ sourceRoot: graph.sourceRoot,
958
+ baseline: {
959
+ currentSinkProjection: sinkProjection.length,
960
+ analyzerCounts: {
961
+ fail: sinkProjection.filter((entry) => entry.spelling === "fail").length,
962
+ "verdict:RED": sinkProjection.filter((entry) => entry.spelling === "verdict:RED").length,
963
+ },
964
+ independentProjection: projection,
965
+ counterexampleUniverse: counterexamples,
966
+ sharedContextPredicates: graph.sharedContextPredicates,
967
+ sameCodeShadows: graph.sameCodeShadows,
968
+ downstreamDomainShadows: graph.downstreamDomainShadows,
969
+ successPathCalls: graph.successPathCalls,
970
+ delegatedOutcomeCalls: graph.delegatedOutcomeCalls,
971
+ },
972
+ floors: {
973
+ counts: floors,
974
+ maxRedundancyDispositions: priorDispositionCeiling ?? 0,
975
+ redundancyDispositionReason: prior?.floors?.redundancyDispositionReason ?? null,
976
+ ownershipCounts: prior?.floors?.ownershipCounts ?? null,
977
+ ownershipGrowthReasons: prior?.floors?.ownershipGrowthReasons ?? null,
978
+ sharedContextPredicateAtoms: prior?.floors?.sharedContextPredicateAtoms ?? null,
979
+ sameCodeShadowEntries: prior?.floors?.sameCodeShadowEntries ?? null,
980
+ downstreamDomainShadowEntries: prior?.floors?.downstreamDomainShadowEntries ?? null,
981
+ successPathCalls: prior?.floors?.successPathCalls ?? null,
982
+ delegatedOutcomeCalls: prior?.floors?.delegatedOutcomeCalls ?? null,
983
+ compoundDispositionUnits: prior?.floors?.compoundDispositionUnits ?? null,
984
+ compoundDispositionMembers: prior?.floors?.compoundDispositionMembers ?? null,
985
+ },
986
+ compounds: prior?.compounds ?? [],
987
+ counts: graph.counts,
988
+ entries: graph.entries.map((entry, index) => ({
989
+ ...identity(entry),
990
+ mutation: migrated[index]?.mutation ?? null,
991
+ witness: migrated[index]?.witness ?? null,
992
+ acceptFlipSet: migrated[index]?.acceptFlipSet ?? null,
993
+ rejectDeltaSet: migrated[index]?.rejectDeltaSet ?? null,
994
+ positiveRegressionSet: migrated[index]?.positiveRegressionSet ?? null,
995
+ disposition: migrated[index]?.disposition ?? null,
996
+ classification: migrated[index]?.classification ?? null,
997
+ ownershipRecord: migrated[index]?.ownershipRecord ?? null,
998
+ })),
999
+ };
1000
+ }
1001
+
1002
+ function validateMutationShape(entry) {
1003
+ const mutation = entry.mutation;
1004
+ if (!mutation) return;
1005
+ const keys = Object.keys(mutation).sort().join(",");
1006
+ if (["suppress-thrown-rejection", "force-call-result-status"].includes(mutation.operator)
1007
+ && keys === "operator") return;
1008
+ if (mutation.operator === "bypass-rejection" && keys === "operator") return;
1009
+ if (mutation.operator === "force-owned-condition" && keys === "operator,value" && typeof mutation.value === "boolean") return;
1010
+ if (mutation.operator === "sanitize-first-binding" && keys === "binding,operator,value"
1011
+ && typeof mutation.binding === "string" && mutation.binding.length > 0
1012
+ && typeof mutation.value === "string" && mutation.value.length > 0) return;
1013
+ if (mutation.operator === "sanitize-first-argument" && keys === "operator,value"
1014
+ && typeof mutation.value === "string" && mutation.value.length > 0) return;
1015
+ if (mutation.operator === "drop-reviewed-property" && keys === "operator,target"
1016
+ && typeof mutation.target === "string" && mutation.target.length > 0) return;
1017
+ fail("CENSUS_MUTATION_OPERATOR", `${entry.id}: ${mutation.operator ?? "missing"}`);
1018
+ }
1019
+
1020
+ const MUTATION_OWNERSHIP_KINDS = new Set([
1021
+ "normal-ownership",
1022
+ "reject-preserving-ownership",
1023
+ "mixed-ownership",
1024
+ ]);
1025
+
1026
+ function sortedUniqueById(items) {
1027
+ return Array.isArray(items)
1028
+ && new Set(items.map((item) => item?.id)).size === items.length
1029
+ && items.every((item) => typeof item?.id === "string" && item.id.length > 0)
1030
+ && JSON.stringify([...items].sort((left, right) => left.id.localeCompare(right.id))) === JSON.stringify(items);
1031
+ }
1032
+
1033
+ function validateMutationOwnership(entry) {
1034
+ const accept = entry.acceptFlipSet;
1035
+ const reject = entry.rejectDeltaSet;
1036
+ const regressions = entry.positiveRegressionSet;
1037
+ const kind = entry.ownershipRecord?.kind;
1038
+ if (!MUTATION_OWNERSHIP_KINDS.has(kind)
1039
+ || !sortedUniqueById(accept)
1040
+ || !sortedUniqueById(reject)
1041
+ || !Array.isArray(regressions)
1042
+ || regressions.length !== 0) {
1043
+ fail("CENSUS_MUTATION_OWNERSHIP", entry.id);
1044
+ }
1045
+ if (accept.some((item) => typeof item.rejectCode !== "string" || typeof item.acceptCode !== "string")
1046
+ || reject.some((item) => !item.before || !item.after
1047
+ || typeof item.before.code !== "string" || typeof item.after.code !== "string")) {
1048
+ fail("CENSUS_MUTATION_PARTITION", entry.id);
1049
+ }
1050
+ const expectedKind = accept.length > 0 && reject.length > 0
1051
+ ? "mixed-ownership"
1052
+ : accept.length > 0
1053
+ ? "normal-ownership"
1054
+ : reject.length > 0
1055
+ ? "reject-preserving-ownership"
1056
+ : null;
1057
+ if (kind !== expectedKind) fail("CENSUS_MUTATION_OWNERSHIP", `${entry.id}: ${kind} != ${expectedKind}`);
1058
+ const partition = entry.witness?.partition;
1059
+ const expectedWitness = partition === "acceptFlipSet" && accept.length > 0
1060
+ ? { partition: "acceptFlipSet", ...accept[0] }
1061
+ : partition === "rejectDeltaSet" && reject.length > 0
1062
+ ? {
1063
+ partition: "rejectDeltaSet",
1064
+ id: reject[0].id,
1065
+ beforeCode: reject[0].before.code,
1066
+ afterCode: reject[0].after.code,
1067
+ }
1068
+ : null;
1069
+ if (JSON.stringify(entry.witness) !== JSON.stringify(expectedWitness)) fail("CENSUS_MUTATION_WITNESS", entry.id);
1070
+ }
1071
+
1072
+ export function validateManifest(graph, manifest, {
1073
+ requirePairs = true,
1074
+ requireBaseline = true,
1075
+ projection = null,
1076
+ counterexamples = null,
1077
+ } = {}) {
1078
+ if (manifest?.schema !== CENSUS_SCHEMA) fail("CENSUS_SCHEMA", "manifest schema mismatch");
1079
+ const actual = new Map(graph.entries.map((entry) => [entry.id, identity(entry)]));
1080
+ const owners = new Map();
1081
+ for (const entry of manifest.entries ?? []) {
1082
+ if (owners.has(entry.id)) fail("CENSUS_DUPLICATE_OWNER", entry.id);
1083
+ owners.set(entry.id, entry);
1084
+ }
1085
+ for (const [id, entry] of actual) {
1086
+ const owner = owners.get(id);
1087
+ if (!owner) fail("CENSUS_UNOWNED_NODE", id);
1088
+ if (JSON.stringify(identity(owner)) !== JSON.stringify(entry)) fail("CENSUS_STALE_ANCHOR", id);
1089
+ if (["unresolved-call", "outcome-candidate"].includes(owner.kind)) {
1090
+ if (requirePairs && (!["non-predicate", "non-outcome", "sink-candidate"].includes(owner.classification?.kind)
1091
+ || !owner.classification?.reason)) fail("CENSUS_CLOSED_BUCKET_UNOWNED", id);
1092
+ continue;
1093
+ }
1094
+ if (owner.kind === "success-constructor") {
1095
+ if (requirePairs && (owner.ownershipRecord?.kind !== "owned-success" || owner.mutation || owner.disposition)) fail("CENSUS_SUCCESS_OWNERSHIP", id);
1096
+ continue;
1097
+ }
1098
+ if (owner.ownershipRecord?.kind === "same-code-shadow") {
1099
+ const proof = manifest.baseline?.sameCodeShadows?.find((item) => item.entryId === owner.id);
1100
+ const record = owner.ownershipRecord;
1101
+ if (owner.kind !== "rejecting-helper-call" || owner.mutation || owner.disposition
1102
+ || !proof || record.downstreamEntryId !== proof.downstreamEntryId
1103
+ || record.rejectCode !== proof.rejectCode
1104
+ || record.canonicalMutation?.operator !== "suppress-thrown-rejection"
1105
+ || Object.keys(record.canonicalMutation).join(",") !== "operator"
1106
+ || typeof record.witnessId !== "string" || record.witnessId.length === 0) {
1107
+ fail("CENSUS_SAME_CODE_SHADOW", id);
1108
+ }
1109
+ continue;
1110
+ }
1111
+ if (owner.ownershipRecord?.kind === "compound-member") {
1112
+ if (owner.mutation || owner.disposition || typeof owner.ownershipRecord.compoundId !== "string") {
1113
+ fail("CENSUS_COMPOUND_MEMBER", id);
1114
+ }
1115
+ continue;
1116
+ }
1117
+ if (owner.ownershipRecord?.kind === "success-path-call") {
1118
+ const proof = manifest.baseline?.successPathCalls?.find((item) => item.entryId === owner.id);
1119
+ if (owner.kind !== "rejecting-helper-call" || owner.mutation || owner.disposition
1120
+ || !proof || owner.ownershipRecord.proofKind !== proof.proofKind
1121
+ || JSON.stringify(owner.ownershipRecord.dischargerEntryIds) !== JSON.stringify(proof.dischargerEntryIds)) {
1122
+ fail("CENSUS_SUCCESS_PATH_CALL", id);
1123
+ }
1124
+ continue;
1125
+ }
1126
+ if (owner.ownershipRecord?.kind === "delegated-outcome-call") {
1127
+ const proof = manifest.baseline?.delegatedOutcomeCalls?.find((item) => item.entryId === owner.id);
1128
+ const record = owner.ownershipRecord;
1129
+ if (owner.kind !== "rejecting-helper-call" || owner.mutation || owner.disposition || !proof
1130
+ || JSON.stringify(record.internalCallEntryIds) !== JSON.stringify(proof.internalCallEntryIds)
1131
+ || JSON.stringify(record.internalOutcomeEntryIds) !== JSON.stringify(proof.internalOutcomeEntryIds)
1132
+ || JSON.stringify(record.callerNullGuardOwnership) !== JSON.stringify(proof.callerNullGuard)
1133
+ || JSON.stringify(record.callerControlFlowOwnership) !== JSON.stringify(proof.callerControlFlow)) {
1134
+ fail("CENSUS_DELEGATED_OUTCOME_CALL", id);
1135
+ }
1136
+ continue;
1137
+ }
1138
+ if (owner.ownershipRecord?.kind === "shared-context-predicate") {
1139
+ const proof = manifest.baseline?.sharedContextPredicates?.find((item) => item.predicate === owner.predicate);
1140
+ const canonicalMutation = owner.ownershipRecord?.canonicalMutation;
1141
+ const provedMutation = proof?.canonicalAtomMutations?.find((item) => item.id === owner.id)?.mutation;
1142
+ if (owner.kind !== "predicate-atom" || owner.mutation || owner.disposition
1143
+ || !proof?.atomIds?.includes(owner.id)
1144
+ || JSON.stringify(canonicalMutation) !== JSON.stringify(provedMutation)) {
1145
+ fail("CENSUS_SHARED_CONTEXT_OWNERSHIP", id);
1146
+ }
1147
+ continue;
1148
+ }
1149
+ if (owner.ownershipRecord?.kind === "downstream-domain-shadow") {
1150
+ const proof = manifest.baseline?.downstreamDomainShadows?.find((item) => item.entryId === owner.id);
1151
+ const record = owner.ownershipRecord;
1152
+ if (owner.kind !== "predicate-atom" || owner.mutation || owner.disposition || !proof
1153
+ || record.downstreamEntryId !== proof.downstreamEntryId
1154
+ || typeof record.witnessId !== "string" || record.witnessId.length === 0
1155
+ || record.pathHash !== proof.pathHash
1156
+ || JSON.stringify(record.canonicalMutation) !== JSON.stringify(proof.canonicalMutation)
1157
+ || JSON.stringify(record.catchReturn) !== JSON.stringify(proof.catchReturn)
1158
+ || JSON.stringify(record.enforcingEntryIds) !== JSON.stringify(proof.enforcingEntryIds)) {
1159
+ fail("CENSUS_DOWNSTREAM_DOMAIN_OWNERSHIP", id);
1160
+ }
1161
+ continue;
1162
+ }
1163
+ if (owner.mutation?.kind === "structural-only") fail("CENSUS_STRUCTURAL_ONLY", id);
1164
+ validateMutationShape(owner);
1165
+ const mutable = owner.mutation && MUTATION_OWNERSHIP_KINDS.has(owner.ownershipRecord?.kind);
1166
+ const disposed = owner.disposition?.kind === "not-independently-discriminated"
1167
+ && owner.disposition?.witness && Array.isArray(owner.disposition?.coveredBy);
1168
+ if (requirePairs && Number(Boolean(mutable)) + Number(Boolean(disposed)) !== 1) fail("CENSUS_PAIR_MISSING", id);
1169
+ if (mutable) validateMutationOwnership(owner);
1170
+ }
1171
+ for (const id of owners.keys()) if (!actual.has(id)) fail("CENSUS_UNMATCHED_OWNER", id);
1172
+ const compounds = manifest.compounds;
1173
+ if (!Array.isArray(compounds)) fail("CENSUS_COMPOUNDS", "missing compounds array");
1174
+ const compoundIds = new Set();
1175
+ const compoundMemberIds = new Set();
1176
+ for (const compound of compounds) {
1177
+ if (typeof compound?.id !== "string" || compound.id.length === 0 || compoundIds.has(compound.id)
1178
+ || !Array.isArray(compound.memberIds) || compound.memberIds.length === 0
1179
+ || new Set(compound.memberIds).size !== compound.memberIds.length
1180
+ || !Array.isArray(compound.edits) || compound.edits.length < 2
1181
+ || new Set(compound.edits.map((edit) => edit?.entryId)).size !== compound.edits.length
1182
+ || typeof compound.witness?.id !== "string" || typeof compound.witness?.rejectCode !== "string"
1183
+ || typeof compound.witness?.acceptCode !== "string") {
1184
+ fail("CENSUS_COMPOUND_SHAPE", compound?.id ?? "missing");
1185
+ }
1186
+ compoundIds.add(compound.id);
1187
+ for (const memberId of compound.memberIds) {
1188
+ const member = owners.get(memberId);
1189
+ if (!member || compoundMemberIds.has(memberId)
1190
+ || member.ownershipRecord?.kind !== "compound-member"
1191
+ || member.ownershipRecord.compoundId !== compound.id) {
1192
+ fail("CENSUS_COMPOUND_MEMBER", `${compound.id}:${memberId}`);
1193
+ }
1194
+ compoundMemberIds.add(memberId);
1195
+ }
1196
+ for (const edit of compound.edits) {
1197
+ const target = owners.get(edit.entryId);
1198
+ if (!target || ["success-constructor", "unresolved-call", "outcome-candidate"].includes(target.kind)) {
1199
+ fail("CENSUS_COMPOUND_EDIT", `${compound.id}:${edit.entryId}`);
1200
+ }
1201
+ validateMutationShape({ ...target, mutation: edit.mutation });
1202
+ }
1203
+ if (!compound.memberIds.every((id) => compound.edits.some((edit) => edit.entryId === id))) {
1204
+ fail("CENSUS_COMPOUND_EDIT", `${compound.id}: member lacks edit`);
1205
+ }
1206
+ }
1207
+ for (const owner of owners.values()) {
1208
+ if (owner.ownershipRecord?.kind === "compound-member" && !compoundMemberIds.has(owner.id)) {
1209
+ fail("CENSUS_COMPOUND_MEMBER", `${owner.id}: dangling`);
1210
+ }
1211
+ }
1212
+ const dispositionEdges = new Map();
1213
+ for (const entry of owners.values()) {
1214
+ if (entry.disposition?.kind !== "not-independently-discriminated") continue;
1215
+ if (entry.disposition.coveredBy.length === 0 || new Set(entry.disposition.coveredBy).size !== entry.disposition.coveredBy.length) {
1216
+ fail("CENSUS_DISPOSITION_COVER", entry.id);
1217
+ }
1218
+ for (const covered of entry.disposition.coveredBy) {
1219
+ const target = owners.get(covered);
1220
+ if (!target || covered === entry.id || ["success-constructor", "unresolved-call", "outcome-candidate"].includes(target.kind)) {
1221
+ fail("CENSUS_DISPOSITION_COVER", `${entry.id}->${covered}`);
1222
+ }
1223
+ }
1224
+ dispositionEdges.set(entry.id, entry.disposition.coveredBy.filter((id) => owners.get(id)?.disposition));
1225
+ }
1226
+ const visitDisposition = (id, stack = new Set()) => {
1227
+ if (stack.has(id)) fail("CENSUS_DISPOSITION_CYCLE", id);
1228
+ for (const next of dispositionEdges.get(id) ?? []) visitDisposition(next, new Set([...stack, id]));
1229
+ };
1230
+ for (const id of dispositionEdges.keys()) visitDisposition(id);
1231
+ if ((graph.counts["success-constructor"] ?? 0) !== 1) fail("CENSUS_SUCCESS_COUNT", String(graph.counts["success-constructor"] ?? 0));
1232
+ for (const [kind, floor] of Object.entries(manifest.floors?.counts ?? {})) {
1233
+ if ((graph.counts[kind] ?? 0) < floor) fail("CENSUS_COUNT_REGRESSION", `${kind}: current=${graph.counts[kind] ?? 0} floor=${floor}`);
1234
+ }
1235
+ const dispositions = (manifest.entries ?? []).filter((entry) => entry.disposition?.kind === "not-independently-discriminated").length;
1236
+ const dispositionCeiling = manifest.floors?.maxRedundancyDispositions;
1237
+ if (!Number.isSafeInteger(dispositionCeiling) || dispositionCeiling < 0 || dispositions > dispositionCeiling) {
1238
+ fail("CENSUS_DISPOSITION_GROWTH", `current=${dispositions} ceiling=${dispositionCeiling}`);
1239
+ }
1240
+ if (dispositionCeiling > 0 && !manifest.floors?.redundancyDispositionReason) fail("CENSUS_DISPOSITION_REASON", "missing reviewed reason");
1241
+ if (requirePairs) {
1242
+ const compoundUnitFloor = manifest.floors?.compoundDispositionUnits;
1243
+ if ((compounds.length > 0 || compoundUnitFloor != null)
1244
+ && (!Number.isSafeInteger(compoundUnitFloor) || compoundUnitFloor < 0 || compounds.length !== compoundUnitFloor)) {
1245
+ fail("CENSUS_COMPOUND_UNIT_COUNT", `current=${compounds.length} floor=${compoundUnitFloor}`);
1246
+ }
1247
+ const sharedOwners = manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "shared-context-predicate");
1248
+ const sharedFloor = manifest.floors?.sharedContextPredicateAtoms;
1249
+ if (!Number.isSafeInteger(sharedFloor) || sharedFloor < 0 || sharedOwners.length !== sharedFloor) {
1250
+ fail("CENSUS_SHARED_CONTEXT_COUNT", `current=${sharedOwners.length} floor=${sharedFloor}`);
1251
+ }
1252
+ for (const proof of manifest.baseline?.sharedContextPredicates ?? []) {
1253
+ for (const callsite of proof.callSites.filter((item) => item.context !== "non-enforcing")) {
1254
+ const owner = owners.get(callsite.enforcingEntryId);
1255
+ const independentlyOwned = MUTATION_OWNERSHIP_KINDS.has(owner?.ownershipRecord?.kind)
1256
+ || owner?.disposition?.kind === "not-independently-discriminated";
1257
+ if (!independentlyOwned) fail("CENSUS_SHARED_CONTEXT_ENFORCEMENT", `${proof.predicate}:${callsite.id}`);
1258
+ }
1259
+ }
1260
+ const shadowOwners = manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "same-code-shadow");
1261
+ const shadowFloor = manifest.floors?.sameCodeShadowEntries;
1262
+ if (!Number.isSafeInteger(shadowFloor) || shadowFloor < 0 || shadowOwners.length !== shadowFloor) {
1263
+ fail("CENSUS_SAME_CODE_SHADOW_COUNT", `current=${shadowOwners.length} floor=${shadowFloor}`);
1264
+ }
1265
+ for (const owner of shadowOwners) {
1266
+ const downstreamId = owner.ownershipRecord.downstreamEntryId;
1267
+ const downstream = owners.get(downstreamId);
1268
+ const independentlyOwned = MUTATION_OWNERSHIP_KINDS.has(downstream?.ownershipRecord?.kind)
1269
+ || downstream?.ownershipRecord?.kind === "compound-member"
1270
+ || downstream?.disposition?.kind === "not-independently-discriminated";
1271
+ if (!independentlyOwned) fail("CENSUS_SAME_CODE_SHADOW_COVER", `${owner.id}->${downstreamId}`);
1272
+ }
1273
+ const compoundMembers = manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "compound-member");
1274
+ const compoundFloor = manifest.floors?.compoundDispositionMembers;
1275
+ if (!Number.isSafeInteger(compoundFloor) || compoundFloor < 0 || compoundMembers.length !== compoundFloor) {
1276
+ fail("CENSUS_COMPOUND_COUNT", `current=${compoundMembers.length} floor=${compoundFloor}`);
1277
+ }
1278
+ const downstreamDomainOwners = manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "downstream-domain-shadow");
1279
+ const downstreamDomainFloor = manifest.floors?.downstreamDomainShadowEntries;
1280
+ if (((manifest.baseline?.downstreamDomainShadows?.length ?? 0) > 0 || downstreamDomainFloor != null)
1281
+ && (!Number.isSafeInteger(downstreamDomainFloor) || downstreamDomainFloor < 0
1282
+ || downstreamDomainOwners.length !== downstreamDomainFloor)) {
1283
+ fail("CENSUS_DOWNSTREAM_DOMAIN_COUNT", `current=${downstreamDomainOwners.length} floor=${downstreamDomainFloor}`);
1284
+ }
1285
+ for (const owner of downstreamDomainOwners) {
1286
+ const downstream = owners.get(owner.ownershipRecord.downstreamEntryId);
1287
+ const independentlyOwned = MUTATION_OWNERSHIP_KINDS.has(downstream?.ownershipRecord?.kind)
1288
+ || downstream?.ownershipRecord?.kind === "compound-member"
1289
+ || downstream?.disposition?.kind === "not-independently-discriminated";
1290
+ if (!independentlyOwned) fail("CENSUS_DOWNSTREAM_DOMAIN_COVER", `${owner.id}->${owner.ownershipRecord.downstreamEntryId}`);
1291
+ }
1292
+ const successPathOwners = manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "success-path-call");
1293
+ const successPathFloor = manifest.floors?.successPathCalls;
1294
+ if (!Number.isSafeInteger(successPathFloor) || successPathFloor < 0 || successPathOwners.length !== successPathFloor) {
1295
+ fail("CENSUS_SUCCESS_PATH_CALL_COUNT", `current=${successPathOwners.length} floor=${successPathFloor}`);
1296
+ }
1297
+ for (const owner of successPathOwners) {
1298
+ const proof = manifest.baseline.successPathCalls.find((item) => item.entryId === owner.id);
1299
+ const requiredIds = [...proof.dischargerEntryIds, ...(proof.conditionalOwnerId ? [proof.conditionalOwnerId] : [])];
1300
+ for (const requiredId of requiredIds) {
1301
+ const required = owners.get(requiredId);
1302
+ const independentlyOwned = MUTATION_OWNERSHIP_KINDS.has(required?.ownershipRecord?.kind)
1303
+ || required?.ownershipRecord?.kind === "compound-member"
1304
+ || required?.ownershipRecord?.kind === "same-code-shadow"
1305
+ || required?.disposition?.kind === "not-independently-discriminated";
1306
+ if (!independentlyOwned) fail("CENSUS_SUCCESS_PATH_DISCHARGER", `${owner.id}->${requiredId}`);
1307
+ }
1308
+ }
1309
+ const delegatedOwners = manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "delegated-outcome-call");
1310
+ const delegatedFloor = manifest.floors?.delegatedOutcomeCalls;
1311
+ if (!Number.isSafeInteger(delegatedFloor) || delegatedFloor < 0 || delegatedOwners.length !== delegatedFloor) {
1312
+ fail("CENSUS_DELEGATED_OUTCOME_COUNT", `current=${delegatedOwners.length} floor=${delegatedFloor}`);
1313
+ }
1314
+ for (const owner of delegatedOwners) {
1315
+ const proof = manifest.baseline.delegatedOutcomeCalls.find((item) => item.entryId === owner.id);
1316
+ for (const requiredId of [...proof.internalCallEntryIds, ...proof.internalOutcomeEntryIds]) {
1317
+ const required = owners.get(requiredId);
1318
+ const independentlyOwned = MUTATION_OWNERSHIP_KINDS.has(required?.ownershipRecord?.kind)
1319
+ || required?.ownershipRecord?.kind === "compound-member"
1320
+ || required?.ownershipRecord?.kind === "same-code-shadow"
1321
+ || required?.disposition?.kind === "not-independently-discriminated";
1322
+ if (!independentlyOwned) fail("CENSUS_DELEGATED_OUTCOME_COVER", `${owner.id}->${requiredId}`);
1323
+ }
1324
+ }
1325
+ const ownershipCounts = {
1326
+ rejectPreservingOwnership: manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "reject-preserving-ownership").length,
1327
+ mixedOwnership: manifest.entries.filter((entry) => entry.ownershipRecord?.kind === "mixed-ownership").length,
1328
+ };
1329
+ for (const [name, current] of Object.entries(ownershipCounts)) {
1330
+ const floor = manifest.floors?.ownershipCounts?.[name];
1331
+ if (!Number.isSafeInteger(floor) || floor < 0 || current < floor) {
1332
+ fail("CENSUS_OWNERSHIP_COUNT_REGRESSION", `${name}: current=${current} floor=${floor}`);
1333
+ }
1334
+ if (current > floor && !manifest.floors?.ownershipGrowthReasons?.[name]) {
1335
+ fail("CENSUS_OWNERSHIP_COUNT_GROWTH", `${name}: current=${current} floor=${floor}`);
1336
+ }
1337
+ }
1338
+ }
1339
+ if (requireBaseline) {
1340
+ const sinkProjection = graph.entries.filter((entry) => entry.kind === "rejection-site"
1341
+ && (entry.spelling === "fail" || entry.spelling === "verdict:RED"));
1342
+ const independent = manifest.baseline?.independentProjection;
1343
+ if (!projection || JSON.stringify(independent) !== JSON.stringify(projection)) fail("CENSUS_INDEPENDENT_PROJECTION", "regex projection changed or was not supplied");
1344
+ if (!counterexamples || JSON.stringify(manifest.baseline?.counterexampleUniverse) !== JSON.stringify(counterexamples)) {
1345
+ fail("CENSUS_COUNTEREXAMPLE_UNIVERSE", "named case or positive-corpus set changed or was not supplied");
1346
+ }
1347
+ if (JSON.stringify(manifest.baseline?.sharedContextPredicates) !== JSON.stringify(graph.sharedContextPredicates)) {
1348
+ fail("CENSUS_SHARED_CONTEXT_PROOF", "shared-context predicate proof changed");
1349
+ }
1350
+ if (JSON.stringify(manifest.baseline?.sameCodeShadows) !== JSON.stringify(graph.sameCodeShadows)) {
1351
+ fail("CENSUS_SAME_CODE_SHADOW_PROOF", "same-code shadow proof changed");
1352
+ }
1353
+ if (JSON.stringify(manifest.baseline?.downstreamDomainShadows) !== JSON.stringify(graph.downstreamDomainShadows)) {
1354
+ fail("CENSUS_DOWNSTREAM_DOMAIN_PROOF", "downstream-domain shadow proof changed");
1355
+ }
1356
+ if (JSON.stringify(manifest.baseline?.successPathCalls) !== JSON.stringify(graph.successPathCalls)) {
1357
+ fail("CENSUS_SUCCESS_PATH_PROOF", "success-path call proof changed");
1358
+ }
1359
+ if (JSON.stringify(manifest.baseline?.delegatedOutcomeCalls) !== JSON.stringify(graph.delegatedOutcomeCalls)) {
1360
+ fail("CENSUS_DELEGATED_OUTCOME_PROOF", "delegated-outcome call proof changed");
1361
+ }
1362
+ const analyzerCounts = {
1363
+ fail: sinkProjection.filter((entry) => entry.spelling === "fail").length,
1364
+ "verdict:RED": graph.entries.filter((entry) => entry.kind === "rejection-site" && entry.spelling === "verdict:RED").length,
1365
+ };
1366
+ if (JSON.stringify(analyzerCounts) !== JSON.stringify(independent.counts)
1367
+ || manifest.baseline?.currentSinkProjection !== independent.sites.length) {
1368
+ fail("CENSUS_BASELINE_RECONCILIATION", `analyzer=${JSON.stringify(analyzerCounts)} independent=${JSON.stringify(independent.counts)}`);
1369
+ }
1370
+ }
1371
+ return true;
1372
+ }