clearotron 0.4.0 → 0.4.1-beta.1

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 (132) hide show
  1. package/THIRD-PARTY-NOTICES.md +2 -2
  2. package/bin/README.md +1 -1
  3. package/bin/clearotron.mjs +2 -0
  4. package/bin/mcp.mjs +80 -0
  5. package/bin/start.mjs +14 -1
  6. package/build-info.json +2 -2
  7. package/demo/README.md +1 -1
  8. package/docs/SECURITY-OWASP.md +21 -13
  9. package/docs/SECURITY.md +20 -14
  10. package/docs/architecture/04-configuration-reference.md +3 -3
  11. package/docs/architecture/05-config-governance.md +1 -1
  12. package/docs/architecture/06-operations-runbook.md +5 -4
  13. package/docs/architecture/08-development-guide.md +3 -1
  14. package/docs/architecture/09-security-and-data.md +16 -11
  15. package/driver/CHANGELOG.md +29 -0
  16. package/driver/binding-layers.mjs +28 -6
  17. package/driver/citation-census.json +3 -3
  18. package/driver/common-law-coverage-status.mjs +52 -0
  19. package/driver/common-law-receipts.mjs +1 -1
  20. package/driver/compare.mjs +1 -1
  21. package/driver/connotation-search.mjs +5 -5
  22. package/driver/contract-audit.mjs +6 -6
  23. package/driver/contract-dictation-registry.mjs +1 -1
  24. package/driver/contract-e3-backlog.mjs +18 -17
  25. package/driver/contract-vocabulary.mjs +145 -132
  26. package/driver/declination-call.mjs +5 -1
  27. package/driver/degraded-parts.mjs +10 -3
  28. package/driver/dev-portal.mjs +2 -1
  29. package/driver/dispatch-record.mjs +19 -0
  30. package/driver/doubt-closure-tool.mjs +2 -2
  31. package/driver/driver.config.mjs +39 -6
  32. package/driver/engagement-receipt.mjs +1 -1
  33. package/driver/engine/CONTRACT.md +41 -1
  34. package/driver/engine/anthropic-agent.mjs +56 -4
  35. package/driver/engine/mcp/codex-config.mjs +8 -3
  36. package/driver/engine/mcp/coverage-server.mjs +1 -1
  37. package/driver/engine/mcp/gather-config.mjs +1 -1
  38. package/driver/engine/mcp/recording-server.mjs +32 -5
  39. package/driver/engine/mcp/stdio-server.mjs +45 -7
  40. package/driver/engine/mcp/supplemental.mjs +26 -1
  41. package/driver/engine/openai-agent.mjs +113 -20
  42. package/driver/engine/session-record.mjs +223 -0
  43. package/driver/enqueue-schema.mjs +2 -2
  44. package/driver/findings-model.mjs +4 -4
  45. package/driver/flag-snapshot.mjs +2 -1
  46. package/driver/form-neighbourhood.mjs +7 -7
  47. package/driver/frame-diff-model.mjs +3 -3
  48. package/driver/framework.mjs +22 -0
  49. package/driver/gateway.mjs +96 -14
  50. package/driver/jx.mjs +1 -1
  51. package/driver/knockout-review-record.mjs +55 -1
  52. package/driver/named-band.mjs +4 -0
  53. package/driver/owner-screen.mjs +7 -4
  54. package/driver/package.json +1 -1
  55. package/driver/phase0.mjs +13 -2
  56. package/driver/pipeline-knockout.mjs +15 -13
  57. package/driver/pipeline.mjs +132 -48
  58. package/driver/portal-families.mjs +3 -3
  59. package/driver/portal-service.mjs +6 -5
  60. package/driver/predelivery-lint.mjs +19 -19
  61. package/driver/products.mjs +1 -1
  62. package/driver/profiles.mjs +4 -3
  63. package/driver/publish/index.mjs +1 -1
  64. package/driver/publish/knockout.mjs +5 -4
  65. package/driver/publish/office-record-links.mjs +17 -2
  66. package/driver/publish/publish-inputs.mjs +3 -3
  67. package/driver/publish/render-knockout.mjs +17 -5
  68. package/driver/publish/render.mjs +4 -2
  69. package/driver/publish/xlsx.mjs +1 -1
  70. package/driver/record-fold.mjs +177 -0
  71. package/driver/register-count.mjs +20 -3
  72. package/driver/register-coverage.mjs +1 -1
  73. package/driver/register-plan.mjs +83 -18
  74. package/driver/register-records.mjs +7 -0
  75. package/driver/registry-fidelity.mjs +2 -2
  76. package/driver/repairs.mjs +1 -1
  77. package/driver/report-card-record.mjs +4 -4
  78. package/driver/result-noun-fields.mjs +3 -3
  79. package/driver/scope-facts.mjs +11 -3
  80. package/driver/scope-rules.mjs +2 -2
  81. package/driver/search-policy.mjs +20 -1
  82. package/driver/skills/clearance-common-law/SKILL.md +22 -22
  83. package/driver/skills/clearance-register/digest.md +3 -3
  84. package/driver/skills/clearance-register/register-recipes.md +11 -11
  85. package/driver/skills/clearance-register/status-rules.md +1 -1
  86. package/driver/skills/clearance-register/unit.md +1 -1
  87. package/driver/skills/clearance-search/firm-wide-reasoning.md +3 -2
  88. package/driver/skills/clearance-search/phase2-execution.md +6 -5
  89. package/driver/skills/clearance-search/synthesis-rules.md +4 -4
  90. package/driver/skills/clearance-search/worked-examples.md +39 -39
  91. package/driver/skills/clearance-variants/SKILL.md +16 -16
  92. package/driver/skills/frame-diff/SKILL.md +2 -2
  93. package/driver/stage-context.mjs +36 -1
  94. package/driver/stages-knockout.mjs +6 -5
  95. package/driver/stages.mjs +30 -30
  96. package/driver/suite-census.json +259 -55
  97. package/driver/synthesis-record.mjs +5 -0
  98. package/driver/unit-inventory.mjs +17 -28
  99. package/driver/verify.mjs +7 -7
  100. package/mcp-server/CHANGELOG.md +8 -0
  101. package/mcp-server/CONNECT.md +9 -3
  102. package/mcp-server/demo-mode.mjs +10 -0
  103. package/mcp-server/lib/evidence.mjs +8 -8
  104. package/mcp-server/lib/knockout.mjs +1 -1
  105. package/mcp-server/lib/runs.mjs +7 -1
  106. package/mcp-server/lib/scrub.mjs +1 -1
  107. package/mcp-server/package.json +2 -2
  108. package/mcp-server/packs/README.md +1 -1
  109. package/mcp-server/server.mjs +16 -2
  110. package/package.json +4 -3
  111. package/portal-ui/package.json +3 -3
  112. package/providers/_shared/count.mjs +9 -2
  113. package/providers/_shared/enumerate.mjs +125 -41
  114. package/providers/_shared/execute-plan.mjs +15 -4
  115. package/providers/corsearch/src/capabilities.js +1 -1
  116. package/providers/oauth-mcp-bridge/CHANGELOG.md +8 -0
  117. package/providers/oauth-mcp-bridge/package.json +2 -2
  118. package/providers/signa/src/capabilities.js +32 -2
  119. package/providers/signa/src/core.js +262 -36
  120. package/scripts/band-shape-probe.mjs +2 -2
  121. package/scripts/deprecate-below.mjs +28 -4
  122. package/scripts/e2e-first-time.mjs +17 -2
  123. package/scripts/env-audit.mjs +3 -2
  124. package/scripts/freeze-example-run.mjs +10 -10
  125. package/scripts/mcp-registry-listing.mjs +199 -0
  126. package/scripts/mint-plugin-folder.mjs +65 -0
  127. package/scripts/release-version.mjs +44 -0
  128. package/scripts/score.mjs +1 -1
  129. package/shared/register-floor.mjs +19 -0
  130. package/shared/scope.mjs +18 -2
  131. package/shared/trigger-lane.mjs +1 -1
  132. package/skills/clearotron-ops/SKILL.md +81 -24
@@ -111,3 +111,55 @@ export function recordCoverageStatus(spec, received, { now = () => new Date().to
111
111
  if (refused.length) lines.push("Refused — send these again, corrected:", ...refused.map((x) => `- ${x}`));
112
112
  return { ok: refused.length === 0, text: lines.join("\n") };
113
113
  }
114
+
115
+ /** The status code records for a ledger row whose findings gave none of the three words. */
116
+ export const NOT_STATED = "not stated";
117
+
118
+ /**
119
+ * THE STATUSES A FINDINGS FILE STATES, RECORDED BY CODE (Krzys, 2026-10-01). A seat whose findings carry
120
+ * a coverage ledger but made no `record_coverage_status` call is accepted, not re-run: a re-run for this
121
+ * was a full stage re-run, and nothing is added to what the model reads. Each ledger row's status is read
122
+ * from the row as the findings wrote it — one of the three words, else "not stated" — and recorded in the
123
+ * same file the tool writes, marked `source: "findings"`. A record the seat made through the tool is never
124
+ * overwritten; a record code made earlier is replaced, so it follows the latest findings after a re-run.
125
+ * Returns the record written, or null when nothing was written. Never throws.
126
+ */
127
+ export function recordStatusesFromFindings(findingsPath, { half = null, now = () => new Date().toISOString() } = {}) {
128
+ if (!findingsPath) return null;
129
+ const file = coverageStatusPath(findingsPath);
130
+ let existing = null;
131
+ try { existing = JSON.parse(readFileSync(file, "utf8")); } catch { existing = null; }
132
+ if (existing && existing.source !== "findings") return null; // the seat recorded its own statuses
133
+ let text;
134
+ try { text = readFileSync(String(findingsPath), "utf8"); } catch { return null; }
135
+ const record = { coverage_status: ledgerStatuses(text), half, source: "findings", recorded_at: now() };
136
+ try {
137
+ mkdirSync(dirname(file), { recursive: true });
138
+ writeFileSync(file, JSON.stringify(record, null, 2) + "\n");
139
+ } catch { return null; }
140
+ return record;
141
+ }
142
+
143
+ /**
144
+ * Each coverage-ledger row's unit and status, as the findings file wrote them: the first table under the
145
+ * Coverage ledger heading, its header and separator rows skipped. A row with none of the three words
146
+ * reads "not stated"; a ledger with no rows reads as one unit, "coverage ledger", not stated. PURE.
147
+ */
148
+ export function ledgerStatuses(text) {
149
+ const lines = String(text ?? "").split("\n");
150
+ const at = lines.findIndex((l) => /^#{1,4}\s+[^\n]*coverage[\s-]ledger/i.test(l));
151
+ const isSeparator = (l) => /^\|?(\s*:?-{2,}:?\s*\|)+\s*:?-{0,}:?\s*\|?$/.test(String(l ?? "").trim());
152
+ const out = {};
153
+ if (at >= 0) {
154
+ for (let i = at + 1; i < lines.length; i++) {
155
+ const l = lines[i].trim();
156
+ if (/^#{1,6}\s/.test(l)) break;
157
+ if (!l.startsWith("|")) { if (Object.keys(out).length) break; continue; }
158
+ if (isSeparator(l) || isSeparator(lines[i + 1])) continue; // the separator, and the header above it
159
+ const unit = l.replace(/^\|/, "").split("|")[0].trim();
160
+ if (!unit) continue;
161
+ out[unit] = COMMON_LAW_COVERAGE_STATUSES.find((s) => new RegExp(`(^|[^a-z-])${s}([^a-z-]|$)`, "i").test(l)) ?? NOT_STATED;
162
+ }
163
+ }
164
+ return Object.keys(out).length ? out : { "coverage ledger": NOT_STATED };
165
+ }
@@ -166,7 +166,7 @@ export function countMatrixCells(findingsContent) {
166
166
  /**
167
167
  * The shared shortfall ladder over a `cellsOf(term) → count` accessor. A variant is satisfied by:
168
168
  * its own floor; " / "-packed ALTERNATES each meeting the floor (one manifest cell, two renderings —
169
- * "丝绸与铁 / 席尔克": each alternate is its own search term with its own grid — the copper-conduit worker
169
+ * "缎与钢 / 萨汀": each alternate is its own search term with its own grid — the copper-conduit worker
170
170
  * keyed the split forms with full receipts while the validator demanded the compound key, 2026-06-12);
171
171
  * or WORD-BOUNDARY substring coverage (a fully-receipted variant covers a LONGER variant containing it
172
172
  * as a whole-word phrase — "Foxglade Legends II: Oak & Ember" ⊃ "Oak & Ember"; a marketplace phrase
@@ -212,7 +212,7 @@ export function compareCmd(opts) {
212
212
  if (isEntrypoint(import.meta.url)) {
213
213
  let a;
214
214
  //: the refusal must print the usage, or "unknown flag --experiement" leaves the reader guessing
215
- // which spelling was wanted. Same wiring as enqueue.mjs:155.
215
+ // which spelling was wanted. Same wiring as main() in enqueue.mjs.
216
216
  try { a = parseArgv(process.argv.slice(2)); }
217
217
  catch (e) { console.error(`error: ${e.message}\n\n${USAGE}`); process.exit(2); }
218
218
  try {
@@ -300,14 +300,14 @@ export const normText = (s) => foldPunct(String(s ?? "").toLowerCase()).replace(
300
300
 
301
301
  // (2026-08-04, the terminal R2 run of that round) — LANGUAGE EDITIONS OF ONE DOCUMENT ARE ONE RECEIPT.
302
302
  // The recurrence floor demanded the model cite the SAME dictionary lemma twice, under two language editions.
303
- // Attempts 2, 6 and 8 died on https://fr.wiktionary.org/wiki/δελφίς; the model then cited it verbatim; attempt
304
- // 9 died on https://en.wiktionary.org/wiki/δελφίς and the run went terminal — ~37 minutes of model work, no
303
+ // Attempts 2, 6 and 8 died on https://fr.wiktionary.org/wiki/βελτρίν; the model then cited it verbatim; attempt
304
+ // 9 died on https://en.wiktionary.org/wiki/βελτρίν and the run went terminal — ~37 minutes of model work, no
305
305
  // artifact. Both editions cleared the floor independently (en 8 owning queries, fr 5, floor 4) and their
306
306
  // titles diverge before TITLE_PREFIX ("Wiktionary, the free dictionary" / "Wiktionnaire, le dictionnaire
307
307
  // libre"), so citing one PROVABLY could not satisfy the other and no attempt could have converged.
308
308
  // Folding the leading language-edition host label weakens the compare's contract not at all: the contract is
309
- // "the model quoted something it could only have got by opening the receipt", and fr.wiktionary.org/wiki/δελφίς
310
- // proves exactly that for en.wiktionary.org/wiki/δελφίς. BOUNDED two ways — only a leading 2-3 letter (or
309
+ // "the model quoted something it could only have got by opening the receipt", and fr.wiktionary.org/wiki/βελτρίν
310
+ // proves exactly that for en.wiktionary.org/wiki/βελτρίν. BOUNDED two ways — only a leading 2-3 letter (or
311
311
  // xx-yy) label, and only when a PATH follows, because folding a BARE host would let any URL on the domain
312
312
  // satisfy a demand for one specific page. Measured on the evidence receipts: 274 distinct results → 266,
313
313
  // and the load-bearing-by-recurrence set is the same 7, only re-keyed.
@@ -438,7 +438,7 @@ const QUOTE_MIN = 24;
438
438
  // that it could not have been produced without reading the snippet. 24 Latin characters buy that. 24
439
439
  // HANZI buy several times as much, because a Chinese character carries a morpheme where a Latin
440
440
  // character carries a letter — so this constant asked the CJK lane for a passage far longer than the
441
- // rule requires, and a 克罗玛 row failed on exactly that.
441
+ // rule requires, and a 维尔特林 row failed on exactly that.
442
442
  //
443
443
  // IT CUT BOTH WAYS, which is why both sites move together or neither does. The same constant decides
444
444
  // `usableSnippet` — which rows are ELIGIBLE to be quote-required at all — so a CJK snippet under 24
@@ -158,14 +158,14 @@ const ARROW_TOKEN_RE = /=>\s*[`"']([a-z][a-z0-9]*(?:_[a-z0-9]+)+)/g;
158
158
  const REASON_TOKEN_RE = /reason:\s*[`"']([a-z][a-z0-9]*(?:_[a-z0-9]+)+)/g;
159
159
 
160
160
  // A CITED SITE MUST BE A MINT. The extractor records the FIRST line a pattern matched, and the
161
- // patterns read comment text as readily as code: `no_status` was cited at coverage-form.mjs:802, the
162
- // JSDoc `@returns {Array<{reason:"no_status"|"form_damaged", …` annotation seventeen lines above the line
163
- // that writes it. Every such ruling cites its mint, so a citation drawn from a sentence about the code
164
- // is a ruling about a sentence.
161
+ // patterns read comment text as readily as code: `no_status` was cited at the JSDoc `@returns
162
+ // {Array<{reason:"no_status"|"form_damaged", …` annotation of findCoverageFormViolations() in coverage-form.mjs,
163
+ // seventeen lines above the line that writes it. Every such ruling cites its mint, so a citation drawn
164
+ // from a sentence about the code is a ruling about a sentence.
165
165
  //
166
166
  // Comment-ONLY lines, never a trailing `//` after code — a token minted on a line that also carries a
167
167
  // comment is still minted there. Measured before it was trusted: across all 30 covered sources this moves
168
- // exactly one citation (coverage-form.mjs:802 -> :828) and loses NO token, so the census does not shrink.
168
+ // exactly one citation (`no_status`'s, annotation -> mint) and loses NO token, so the census does not shrink.
169
169
  // That measurement is the load-bearing half: a filter that quietly dropped a comment-only token would
170
170
  // take its coverage obligation with it, and the tripwire would read the absence as clean.
171
171
  const COMMENT_ONLY_LINE = /^\s*(?:\/\/|\*|\/\*)/;
@@ -265,7 +265,7 @@ export const E3_KINDS = ["literal-json-skeleton", "exactly-these-keys", "dictate
265
265
  *
266
266
  * other — the dictate is not in the text being linted. Two shapes found: a stage message that
267
267
  * DELEGATES its whole envelope to a skill file ("dictated keys + closed enums per the skill",
268
- * stages.mjs:974 for blind-frame — a lint reading the message sees nothing and the skeleton
268
+ * blind-frame's message until 2026-08-17 — a lint reading the message sees nothing and the skeleton
269
269
  * escapes); and a field DICTATED THEN OVERWRITTEN, where the instruction annotates its own
270
270
  * fields as driver-replaced in the model's own reading (delivery-contract.md:34-37).
271
271
  *
@@ -131,7 +131,7 @@ export const TOOL_ORDER_BACKLOG = [
131
131
  closes: "#865 — same shared file, same split grant." },
132
132
  { stage: "register-digest", tool: "register_batch_screen", site: "driver/skills/clearance-register/digest.md",
133
133
  closes: "#865 — the digest's OWN doctrine, not a shared file: this one is the stage being told to "
134
- + "batch-screen with a tool its grant does not carry. gather-config.mjs:196 already records that "
134
+ + "batch-screen with a tool its grant does not carry. toolGroupsForStage() in gather-config.mjs already records that "
135
135
  + "this stage's prompt once ordered live register checks; the order outlived the note." },
136
136
  { stage: "register-unit", tool: "band_record", site: "driver/skills/clearance-register/SKILL.md",
137
137
  closes: "#865 — same shared file, same split grant." },
@@ -106,11 +106,11 @@ export const E3_BACKLOG = [
106
106
  // Two `literal-json-skeleton` and two `exactly-these-keys`, all four stamped "NOTHING ON THE PLAN
107
107
  // REMOVES THIS". The conversion removed them:
108
108
  //
109
- // stages.mjs:926 the dispatch dictated variant-manifest.json key by key and enum by enum;
109
+ // stages.mjs (message) the dispatch dictated variant-manifest.json key by key and enum by enum;
110
110
  // `record_clearance_variants`'s schema IS that shape now, so the key-set and
111
111
  // enum families are unreachable from a typed call rather than caught after
112
112
  // the file is written.
113
- // stages.mjs:774-808 the same skeleton's category enum, same fate.
113
+ // stages.mjs (message) the same skeleton's category enum, same fate.
114
114
  // clearance-variants SKILL.md the `### Scope ledger` markdown table and its column contract. The rows
115
115
  // arrive typed; the driver renders the table AND serialises
116
116
  // scope-ledger.json from them through one shared function.
@@ -152,7 +152,7 @@ export const E3_BACKLOG = [
152
152
  where: "driver/skills/blind-frame/SKILL.md:62-83",
153
153
  surface: "skill-file",
154
154
  evidence: "A JSON OBJECT with EXACTLY these keys:\\n```json\\n{\\n \"schema_version\": 1,\\n \"dominant_element\": \"the spine, verbatim\",\\n \"variants\": [{\"value\": \"KORPHI\", \"direction\": \"drop\", \"rationale\": \"…\"}],\\n \"fields\": […],\\n \"sources\": […],\\n \"ranking_basis\": \"goods-overlap\"\\n}\\n``` … `direction` is EXACTLY on",
155
- reparsedBy: "driver/verify.mjs validators.blindFrame — emits invalid_file:…:blindframe_* on an off-enum or missing key (stages.mjs:952-957 doc block)",
155
+ reparsedBy: "driver/verify.mjs validators.blindFrame — emits invalid_file:…:blindframe_* on an off-enum or missing key (the blind-frame stage's doc block in stages.mjs)",
156
156
  removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
157
157
  },
158
158
  // ── DISCHARGED 2026-08-17 by, and the row said this could not happen ──────────────────────────
@@ -180,8 +180,8 @@ export const E3_BACKLOG = [
180
180
  {
181
181
  stage: "common-law-half",
182
182
  kind: "dictated-line-shape",
183
- // CONSOLIDATED 2026-08-16 from THREE rows (common-law stages.mjs:1031, common-law-half :1112 and
184
- // :1146). Those three existed because the dictation was AUTHORED at three sites in stages.mjs. M1 made
183
+ // CONSOLIDATED 2026-08-16 from THREE rows (one in common-law's message in stages.mjs, two in
184
+ // common-law-half's). Those three existed because the dictation was AUTHORED at three sites in stages.mjs. M1 made
185
185
  // it one: authored once in renderConnotationObligations, and reaching the seat through the perplexity
186
186
  // MCP server (`tellObligations` in driver/engine/mcp/perplexity-server.mjs) rather than a stage message. Three rows
187
187
  // pointing at one block would fabricate two authored sites the surface does not have.
@@ -211,7 +211,7 @@ export const E3_BACKLOG = [
211
211
  kind: "literal-json-skeleton",
212
212
  where: "driver/skills/clearance-common-law/SKILL.md:123-170",
213
213
  surface: "skill-file",
214
- evidence: "### Format\\n```markdown\\n# Common-law findings — Dawn: Legends of Thornmantle (2026-05-11)\\n\\n## Summary\\n\\n- Perplexity calls executed: 4 …",
214
+ evidence: "### Format\\n```markdown\\n# Common-law findings — Dusk: Tales of Thornmantle (2026-05-11)\\n\\n## Summary\\n\\n- Perplexity calls executed: 4 …",
215
215
  reparsedBy: "driver/publish/audit-from-spine.mjs:14 parseTables → parseSpineFindingBlocks (audit-from-spine.mjs:123) re-parses the common-law finding tables into audit.md",
216
216
  removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
217
217
  },
@@ -295,7 +295,7 @@ export const E3_BACKLOG = [
295
295
  where: "driver/stages.mjs:2351-2353",
296
296
  surface: "stage-message",
297
297
  evidence: "PLACEMENT FORM (MANDATORY): record every placement in <path> — {\"rows\":[…]} … · A REGISTER candidate: {\"select\":\"<one record URI it holds>\",\"tier\":\"…\",\"reason\":\"…\"} (+ optional \"borderline\":true) … · A COMMON-LAW candidate …: {\"kind\":\"seat\",\"mark\",\"owner\",\"jurisdiction\",\"records\":[],\"tier\",\"reason\"}",
298
- reparsedBy: "driver/placement-form.mjs (SELECT_ROW_FIELDS at placement-form.mjs:93, the seat-row contract at 97-105, formRowKey/rowIsSettled/renderEntry at 117-141) via validators.placement. The same field list is ALSO carried in the driver-written form's own seat_row_contract, so the shape exists twice",
298
+ reparsedBy: "driver/placement-form.mjs (SELECT_ROW_FIELDS at placement-form.mjs:93, the seat-row contract SEAT_ROW_CONTRACT, formRowKey/rowIsSettled/renderEntry) via validators.placement. The same field list is ALSO carried in the driver-written form's own seat_row_contract, so the shape exists twice",
299
299
  removedByMove: "M1 removes the opaque `select` URI (ordinal selection) — it does not remove the JSON skeleton, the retract shape, or the kind:\"seat\" row",
300
300
  },
301
301
  {
@@ -313,7 +313,7 @@ export const E3_BACKLOG = [
313
313
  where: "driver/skills/placement-inquiry/SKILL.md:58-66",
314
314
  surface: "skill-file",
315
315
  evidence: "**2. The structured mirror** `…/placements.json` … `{\"schema_version\":1,\"placements\":[...]}`, ONE object per placed candidate, keys EXACTLY `{\"mark\",\"owner\",\"jurisdiction\",\"records\",\"tier\",\"reason\"}` plus the optional `\"borderline\"` … `tier` — EXACTLY one of `headline-candidate` / `sheet-2` / `watch",
316
- reparsedBy: "driver/placement-model.mjs. AND IT IS STALE: #562 made placements.json driver-rendered, and stages.mjs:2409 says \"DO NOT WRITE placements.json (the driver renders it from this form)\" — the skill file the stage is ordered to \"read and follow exactly\" dictates the key set of a file the message forbids it to write. Two contracts in one dispatch",
316
+ reparsedBy: "driver/placement-model.mjs. AND IT IS STALE: #562 made placements.json driver-rendered, and placement-inquiry's message in stages.mjs says \"DO NOT WRITE placements.json (the driver renders it from this form)\" — the skill file the stage is ordered to \"read and follow exactly\" dictates the key set of a file the message forbids it to write. Two contracts in one dispatch",
317
317
  removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
318
318
  },
319
319
  {
@@ -322,13 +322,14 @@ export const E3_BACKLOG = [
322
322
  where: "driver/skills/placement-inquiry/SKILL.md:42",
323
323
  surface: "skill-file",
324
324
  evidence: "Use these section headings, in this order: **Band reconciliation** …, the four placement tiers (**Headline candidates**, **Sheet 2 / register watch**, **Watchlist annex**, **Out-of-scope / filtered**), **Disagreements / flags surfaced to downstream**, **Coverage rulings & open questions** …, and **O",
325
- reparsedBy: "driver/pipeline.mjs — the PLACEMENT RULINGS TAIL block handed to register-digest is lifted from these named sections (stages.mjs:2561 references it); driver/skills/clearance-register/digest.md:342-352 re-parses the Disagreements section into its own table",
325
+ reparsedBy: "driver/pipeline.mjs — the PLACEMENT RULINGS TAIL block handed to register-digest is lifted from these named sections (register-digest's message in stages.mjs references it); driver/skills/clearance-register/digest.md:342-352 re-parses the Disagreements section into its own table",
326
326
  removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
327
327
  },
328
328
  // RETIRED 2026-08-16 — register-digest's no-form arm. M6 DELETED THE DICTATION ON 2026-08-14 AND THIS
329
329
  // ROW OUTLIVED IT BY TWO DAYS. Verified at source rather than from the epitaph: the arm is absent from
330
330
  // the composed message, `git grep "NO coverage form"` on origin/main returns exactly ONE hit and it is
331
- // the COMMENT recording the deletion (stages.mjs:2195), and skill-contract-enumerations.test.mjs
331
+ // the COMMENT recording the deletion ("A NO-FORM arm stood here until M6", in register-digest's message in
332
+ // stages.mjs), and skill-contract-enumerations.test.mjs
332
333
  // composes the dispatch under both stamp states and asserts the two texts are equal.
333
334
  //
334
335
  // The surviving prose arms in verify.mjs are NOT dead code and must not be tidied away with it: they
@@ -447,7 +448,7 @@ export const E3_BACKLOG = [
447
448
  where: "driver/skills/frame-diff/SKILL.md:44-48",
448
449
  surface: "skill-file",
449
450
  evidence: "A directive may carry a structured `remedy`:\\n```json\\n\"remedy\": { \"terms\": [\"TROPICAL WAVO\", \"ISLAND WAVO\"], \"nice_classes\": [\"5\", \"32\"], \"regions\": [] }\\n```",
450
- reparsedBy: "driver/pipeline.mjs runSupplementalSweeps — the remedy lint refuses a label-shaped term; stages.mjs:2827 restates the same shape in the message (\"THE ASK CONTRACT, stated at BOTH levels\")",
451
+ reparsedBy: "driver/pipeline.mjs runSupplementalSweeps — the remedy lint refuses a label-shaped term; frame-diff's message in stages.mjs restates the same shape (\"THE ASK CONTRACT, stated at BOTH levels\")",
451
452
  removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
452
453
  },
453
454
  {
@@ -524,7 +525,7 @@ export const E3_BACKLOG = [
524
525
  where: "driver/stages.mjs:3283",
525
526
  surface: "stage-message",
526
527
  evidence: "use_check = {\"source\",\"quality\"}: … quality: OPTIONAL, EXACTLY one of owner-site / independent / register-mirror … own_rights = {\"source\"}",
527
- reparsedBy: "driver/verify.mjs:988 checkFindingsSibling (finding_use_check_missing); driver/own-rights.mjs:19-22",
528
+ reparsedBy: "driver/verify.mjs checkFindingsSibling (finding_use_check_missing); driver/own-rights.mjs:19-22",
528
529
  removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
529
530
  },
530
531
  {
@@ -593,7 +594,7 @@ export const E3_BACKLOG = [
593
594
  where: "driver/stages.mjs:3115 (restated at driver/skills/clearance-search/synthesis-rules.md:428)",
594
595
  surface: "stage-message",
595
596
  evidence: "END that finding's actual-use line with a literal \"- **Use-check source:** <result URL | \"perplexity_research — no result\">\" line",
596
- reparsedBy: "driver/verify.mjs validators.narrative (spec-11 hard reject); the repair hint re-dictates the literal at driver/gateway.mjs:2153",
597
+ reparsedBy: "driver/verify.mjs validators.narrative (spec-11 hard reject); the repair hint re-dictates the literal in correctionHint() in gateway.mjs",
597
598
  removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
598
599
  },
599
600
  {
@@ -602,7 +603,7 @@ export const E3_BACKLOG = [
602
603
  where: "driver/stages.mjs:3128 (restated at driver/skills/clearance-search/synthesis-rules.md:475)",
603
604
  surface: "stage-message",
604
605
  evidence: "END that finding's reasoning with a literal \"- **Own-rights source:** <record URI(s) | \"no applicant-owned registrations in the searched register material\">\" line",
605
- reparsedBy: "driver/own-rights.mjs:19-22 — \"This module only requires the 'Own-rights source:' line to exist\"; repair hint at driver/gateway.mjs:2370 (the `own_rights_missing` branch; re-verified 2026-08-29 — the old :1736 predated this branch and pointed into the A4 repeat-signature block)",
606
+ reparsedBy: "driver/own-rights.mjs, in its header — \"This module only requires the 'Own-rights source:' line to exist\"; repair hint in correctionHint() in gateway.mjs (the `own_rights_missing` branch; re-verified 2026-08-29 — the old :1736 predated this branch and pointed into the A4 repeat-signature block)",
606
607
  removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
607
608
  },
608
609
  {
@@ -629,7 +630,7 @@ export const E3_BACKLOG = [
629
630
  where: "driver/stages.mjs:3502",
630
631
  surface: "stage-message",
631
632
  evidence: "ALSO write the RETRIEVAL RECORD to <path> — a JSON OBJECT with EXACTLY these keys: {\"schema_version\":2,\"queries\":[{\"query\":\"<the search you dispatched, verbatim>\",\"jurisdiction\":\"…\",\"results\":<how many hits it returned, or null when the query never reached a source — never 0 for a query you could not send>}, …],\"citations\":[{\"proceeding\":\"…\",\"forum\":\"…\",\"jurisdiction\":\"…\",\"decided\":\"…\"",
632
- reparsedBy: "driver/verify.mjs validators.caseLaw — the ledger arm, armed by the stage-contract marker `citations` (stages.mjs:1822)",
633
+ reparsedBy: "driver/verify.mjs validators.caseLaw — the ledger arm, armed by the stage-contract marker `citations` (the case-law stage's `contract: { citations: 1 }` in stages.mjs)",
633
634
  removedByMove: "M5 moves `queries[]` to the call log (and is itself blocked: tool-calls.jsonl records no arguments); the envelope, schema_version, `read` enum and `citations[]` skeleton survive M5 entirely",
634
635
  },
635
636
  {
@@ -638,7 +639,7 @@ export const E3_BACKLOG = [
638
639
  where: "driver/stages.mjs:3510",
639
640
  surface: "stage-message",
640
641
  evidence: "EVERY \"Grounded profile\" section MUST start its body with the line \"- ord: <N>\" naming which finding it grounds (use the ordinal from this list; a profile that grounds no listed finding omits the line)",
641
- reparsedBy: "driver/publish/parse.mjs:339, parseCaseLawProfiles() in parse.mjs (\"the optional '- ord: <N>' first body line … gives an EXACT join\"); driver/findings-model.mjs:274 /^-\\s*ord:\\s*(\\d+)\\s*$/m; driver/publish/index.mjs:778 runOrigins",
642
+ reparsedBy: "driver/publish/parse.mjs:339, parseCaseLawProfiles() in parse.mjs (\"the optional '- ord: <N>' first body line … gives an EXACT join\"); driver/findings-model.mjs:274 /^-\\s*ord:\\s*(\\d+)\\s*$/m; driver/publish/index.mjs publishReport (joinCaseLawProfiles)",
642
643
  removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
643
644
  },
644
645
  {
@@ -697,7 +698,7 @@ export const E3_BACKLOG = [
697
698
  // `[on: -]` case went from a value to an ABSENCE — you omit the field — which is the one part a
698
699
  // reader could get wrong from the old wording, since there is no value meaning "no finding".
699
700
  evidence: "**AND EVERY FLAG CARRIES WHICH FINDING IT IS ABOUT** — the `on` field, an array of ordinals. Same rule as `kind`: you send the values, the driver renders the token.",
700
- reparsedBy: "driver/verify.mjs:864 CORRECTION_ON_RE = /\\[on:\\s*([0-9,\\s-]*?)\\s*\\]/i. SKILL-FILE ONLY — the stage message at stages.mjs:1844-1877 never mentions `[on:]`. This is #850's \"the element shape is in the skill file, not the stage message\" in its purest form: an E3 lint reading stages.mjs alone sees the [kind:] token and misses its twin",
701
+ reparsedBy: "driver/verify.mjs:864 CORRECTION_ON_RE = /\\[on:\\s*([0-9,\\s-]*?)\\s*\\]/i. SKILL-FILE ONLY — the stage message (narrative-refutation's, in stages.mjs) never mentions `[on:]`. This is #850's \"the element shape is in the skill file, not the stage message\" in its purest form: an E3 lint reading stages.mjs alone sees the [kind:] token and misses its twin",
701
702
  removedByMove: "NOTHING ON THE #850 PLAN REMOVES THIS",
702
703
  },
703
704
  {