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
package/driver/stages.mjs CHANGED
@@ -35,7 +35,7 @@ import { LINE_GROUNDS } from "./hit-list.mjs"; // — the dictation reads the
35
35
  import { marketplaceScopeDirective } from "./jurisdiction-systems.mjs";
36
36
  import { MEANING_SEAT } from "./common-law-receipts.mjs"; // — the seat whose whole dispatch is the meaning sweep
37
37
  import { meaningSweepReceiptsInstruction } from "./connotation-search.mjs"; // M1 — ONE composer; this sentence was authored four times
38
- import { frameworkFor, workedExamplesFor } from "./framework.mjs"; import { methodDictation, inputsShape } from "./framework-method.mjs";
38
+ import { frameworkFor, workedExamplesFor, materialBandPhrase } from "./framework.mjs"; import { methodDictation, inputsShape } from "./framework-method.mjs";
39
39
  import { requiredScriptsFor } from "./registration-scripts.mjs"; // item 21 — which scripts a territory registers marks in
40
40
  import { resolveTerritories, defaultJurisdictionsLine, narrowingOrderLine } from "./effective-scope.mjs"; // the ONE territory ladder (the geography stamp included) + the defaults-never-widen rule (2160)
41
41
  import { editRepairTail } from "./repair-contract.mjs";
@@ -1206,7 +1206,7 @@ export const VARIANT_CATEGORY_BRIEF =
1206
1206
  // on an element a move was supposed to discharge is indistinguishable from a relabel.
1207
1207
  //
1208
1208
  // `tokens` lists the validator failure tokens that SPEAK ABOUT that element. PER STAGE, never global:
1209
- // `too_short` and `missing` come from the shared nonEmpty()/needs() helpers (verify.mjs:123-133) and are
1209
+ // `too_short` and `missing` come from the shared helpers nonEmpty() and needs() in verify.mjs, and are
1210
1210
  // legitimately owned by DIFFERENT elements in matter-frame, clearance-variants and frame-diff. A global
1211
1211
  // token→element map sees several owners for one token and "fixes" a partition that was never violated.
1212
1212
  //
@@ -1287,7 +1287,7 @@ export const STAGES = {
1287
1287
  },
1288
1288
  "Applicant's own & affiliated marks — the self-exclusion set (mandatory)": {
1289
1289
  class: "judgment", tokens: [],
1290
- why: "naming affiliates beyond the seed is judgment; the profile half is already pre-bound — stages.mjs:844 hands the model exclusionSeed verbatim and _driver/instructed-scope.json carries job.customer [citation unverified]",
1290
+ why: "naming affiliates beyond the seed is judgment; the profile half is already pre-bound — this stage's `message` hands the model exclusionSeed verbatim and _driver/instructed-scope.json carries job.customer",
1291
1291
  },
1292
1292
  "Campaign shape (stated) — the intake's campaign facts retyped from the `Stated campaign shape` line the dispatch already carries": {
1293
1293
  class: "mechanical:code-rendered", tokens: [],
@@ -1436,7 +1436,7 @@ export const STAGES = {
1436
1436
  },
1437
1437
  "mark — \"<the mark verbatim>\"": {
1438
1438
  class: "mechanical:pre-bound", tokens: ["variantmodel_mark_missing"],
1439
- why: "_driver/instructed-scope.json.marks holds it and stage-context.mjs:175 binds that file to this stage. variant-manifest-model.mjs:225-231 already concedes the field is not the model's: it is excluded from the term-shape gate because \"the stage is told to emit it VERBATIM, and it arrives from the job… a value this stage CANNOT restate\" [citation unverified]",
1439
+ why: "_driver/instructed-scope.json.marks holds it and VALIDATOR_SIDECARS declared in stage-context.mjs binds that file to this stage. variantTermShapeGaps() in variant-manifest-model.mjs already concedes the field is not the model's: it is excluded from the term-shape gate because \"the stage is told to emit it VERBATIM, and it arrives from the job… a value this stage CANNOT restate\"",
1440
1440
  },
1441
1441
  "dominant_element — the distinctive anchor the sweep enumerates": {
1442
1442
  class: "judgment", tokens: ["variantmodel_dominant_element_missing"],
@@ -1456,7 +1456,7 @@ export const STAGES = {
1456
1456
  },
1457
1457
  "variants[].value — the search terms themselves": {
1458
1458
  class: "judgment", tokens: ["variantmodel_term_markup"],
1459
- why: "the repo forbids code from minting a search term twice over — stages.mjs:771-773 and variant-manifest-model.mjs:387 (\"VALIDATES, NEVER GENERATES… the moment code mints a search term, judgment has moved into the funnel\"). variantmodel_term_markup is therefore a shape rule that stays model-facing BY DESIGN; do not reclassify it mechanical to satisfy E6. It also walks dominant_element and elements[].value (variantTermShapeGaps), which is why they carry no token of their own [citation unverified]",
1459
+ why: "the repo forbids code from minting a search term twice over — scriptFloorDirective() in stages.mjs and variantCompletenessGaps() in variant-manifest-model.mjs (\"VALIDATES, NEVER GENERATES… the moment code mints a search term, judgment has moved into the funnel\"). variantmodel_term_markup is therefore a shape rule that stays model-facing BY DESIGN; do not reclassify it mechanical to satisfy E6. It also walks dominant_element and elements[].value (variantTermShapeGaps), which is why they carry no token of their own",
1460
1460
  },
1461
1461
  "variants[].category — one of core|phonetic|visual|transliteration|numeric|composite|other": {
1462
1462
  class: "judgment", tokens: [],
@@ -1472,7 +1472,7 @@ export const STAGES = {
1472
1472
  },
1473
1473
  "Family completeness — at minimum one core, one phonetic and one visual variant, plus a transliteration variant when the mark, the dominant element or any elements[] value is non-Latin": {
1474
1474
  class: "judgment", tokens: ["variantmodel_family_incomplete", "variantmodel_variants_empty"],
1475
- why: "structural completeness of the family the plan compiles from; code refuses but must never mint the missing member (variant-manifest-model.mjs:387). variantmodel_family_incomplete carries THREE arms — category:<cat>, script:<term> and script-coverage:<script>:<territories> — and owns all three here, including the per-script arm declared below [citation unverified]",
1475
+ why: "structural completeness of the family the plan compiles from; code refuses but must never mint the missing member (variantCompletenessGaps() in variant-manifest-model.mjs). variantmodel_family_incomplete carries THREE arms — category:<cat>, script:<term> and script-coverage:<script>:<territories> — and owns all three here, including the per-script arm declared below",
1476
1476
  },
1477
1477
  "Per-script coverage — at least one rendering of the mark in each script the in-scope territories register marks in, as a transliteration variant carrying its romanization": {
1478
1478
  class: "judgment", tokens: [],
@@ -1516,7 +1516,7 @@ export const STAGES = {
1516
1516
  },
1517
1517
  "### Scope ledger rows — {Layer, Item, Status: applied|dropped, Reason, Reopen trigger} across variant / field / source / jurisdiction": {
1518
1518
  class: "judgment", tokens: [],
1519
- why: "defending an omission with the concrete observation that should reopen it is the whole judgment, and frame-diff diffs it against the blind re-derivation. The ROW SHAPE is mechanical — scope-ledger.mjs:123-126 parses the table into scope-ledger.json — and the jurisdiction rows are largely a re-carry of the matter frame's own Scope-jurisdictions line [citation unverified]",
1519
+ why: "defending an omission with the concrete observation that should reopen it is the whole judgment, and frame-diff diffs it against the blind re-derivation. The ROW SHAPE is mechanical — renderScopeLedgerJson() in scope-ledger.mjs parses the table into scope-ledger.json — and the jurisdiction rows are largely a re-carry of the matter frame's own Scope-jurisdictions line",
1520
1520
  },
1521
1521
  "Prose variant-table category token — translit-<script>, and for Chinese translit-zh-meaning vs translit-zh-phonetic": {
1522
1522
  class: "judgment", tokens: [],
@@ -1531,7 +1531,7 @@ export const STAGES = {
1531
1531
  },
1532
1532
  "Per-jurisdiction sub-queries": {
1533
1533
  class: "judgment", tokens: [],
1534
- why: "a per-territory search decision no artifact holds — the dispatch names the deliverable and no file the model reads says what one looks like. coverage-ledger.mjs:139-140 shows a downstream consumer that expects them (\"the per-jurisdiction sub-query belongs to primary-sweep\") [citation unverified]",
1534
+ why: "a per-territory search decision no artifact holds — the dispatch names the deliverable and no file the model reads says what one looks like. normalizeAxis() in coverage-ledger.mjs shows a downstream consumer that expects them (\"the per-jurisdiction sub-query belongs to primary-sweep\")",
1535
1535
  },
1536
1536
  "Verify? ✅ column on every transliteration row of the prose Variants table": {
1537
1537
  class: "mechanical:code-rendered", tokens: [],
@@ -1807,7 +1807,7 @@ export const STAGES = {
1807
1807
  },
1808
1808
  "PR / reputational section — the readings the meaning sweep surfaced, per form, each labelled benign or loaded": {
1809
1809
  class: "judgment", tokens: ["connotation_search_missing"],
1810
- why: "The semantic read of a surfaced passage is the model's. `connotation_search_missing` (verify.mjs:362) fires when the ledger recorded no meaning query at all. [citation unverified]",
1810
+ why: "The semantic read of a surfaced passage is the model's. `connotation_search_missing` (commonLawEvidence() in verify.mjs) fires when the ledger recorded no meaning query at all.",
1811
1811
  },
1812
1812
  "`Connotation-search source: <URL | \"perplexity_research — no result\">` line on a clean PR row": {
1813
1813
  class: "mechanical:code-extracted", tokens: ["connotation_search_missing"],
@@ -1970,7 +1970,7 @@ export const STAGES = {
1970
1970
  },
1971
1971
  "disposition form `note` — one line saying what the receipt says and why it reads that way": {
1972
1972
  class: "judgment", tokens: ["connotation_no_ruling"],
1973
- why: "#850 keeps it. The empty-note state lands in the `no_ruling` residual (connotation-search.mjs:2129-2133). [citation unverified]",
1973
+ why: "#850 keeps it. The empty-note state lands in the `no_ruling` residual (findConnotationViolations() in connotation-search.mjs).",
1974
1974
  },
1975
1975
  "disposition form `receipt_index` — the 1-based POSITION of the candidate you ruled on, in that row's own list": {
1976
1976
  class: "mechanical:pre-bound", tokens: ["connotation_form_damaged", "connotation_cite_absent"],
@@ -2102,7 +2102,7 @@ export const STAGES = {
2102
2102
  contractElements: {
2103
2103
  "execute the frozen plan — ONE register_execute_plan call with {plan_path, axis, output_path}": {
2104
2104
  class: "mechanical:tool-written", tokens: ["named_band_missing", "tool_timeout"],
2105
- why: "All three args are driver values interpolated into the message; the tool writes every band block. #850 calls this already right. Note #793: `named_band_missing` and `tool_timeout` are one evidence state with two causes, and registerPlanCallKilled (verify.mjs:1291) separates them from the call log, not from the model. [citation unverified]",
2105
+ why: "All three args are driver values interpolated into the message; the tool writes every band block. #850 calls this already right. Note #793: `named_band_missing` and `tool_timeout` are one evidence state with two causes, and registerPlanCallKilled() in tool-calls.mjs separates them from the call log, not from the model.",
2106
2106
  },
2107
2107
  "the dictated entry list — qid, predicate, terms, owner, nice_classes, regions, when-guard, expected_kind, covered_by": {
2108
2108
  class: "mechanical:pre-bound", tokens: [],
@@ -2126,11 +2126,11 @@ export const STAGES = {
2126
2126
  },
2127
2127
  "named-band block envelope — {state: enumerated|incomplete, query, total_hits, records|fetched+sample+reason}": {
2128
2128
  class: "mechanical:tool-written", tokens: ["named_band_unparseable", "named_band_block_invalid", "named_band_state_invalid", "band_block_unplanned", "named_band_invalid"],
2129
- why: "#850: M (envelope), tool-written blocks. `band_block_unplanned` (verify.mjs:1297) is the backstop that kills a hand-authored qid-less block — a token that exists only because the legacy lane still offers the duty in the same message. [citation unverified]",
2129
+ why: "#850: M (envelope), tool-written blocks. `band_block_unplanned` (validators.registerUnit in verify.mjs) is the backstop that kills a hand-authored qid-less block — a token that exists only because the legacy lane still offers the duty in the same message.",
2130
2130
  },
2131
2131
  "enumerated block records carried verbatim — record_id, mark_text, classes, status, owner_name, owner_country, application_date, registration_date, expiry_date, jurisdictions, screen_verdict": {
2132
2132
  class: "mechanical:tool-written", tokens: ["named_band_collapsed"],
2133
- why: "register_enumerate already returns each record batch-screened; carrying it is transcription. `named_band_collapsed` (verify.mjs:1325, findCollapsedBands) is exactly the recall loss that transcription produces — a slice claiming total_hits with zero records reaching the band. [citation unverified]",
2133
+ why: "register_enumerate already returns each record batch-screened; carrying it is transcription. `named_band_collapsed` (validators.registerUnit in verify.mjs, findCollapsedBands) is exactly the recall loss that transcription produces — a slice claiming total_hits with zero records reaching the band.",
2134
2134
  },
2135
2135
  "per-axis prose digest — the SHORT AUDIT NOTE at register-units/<axis>.md": {
2136
2136
  class: "judgment", tokens: ["too_short"],
@@ -2142,7 +2142,7 @@ export const STAGES = {
2142
2142
  },
2143
2143
  "axis applicability — decide the axis has no work in this manifest and write a one-line \"not applicable\" band block": {
2144
2144
  class: "judgment", tokens: ["band_block_unplanned"],
2145
- why: "The applicability call is the model's; the block is not. Under the supplemental lane a seat obeying unit.md:89-91 writes exactly the qid-less block verify.mjs:1297 kills. The skill file and the stage message contradict each other on the one path the skill offers for an empty axis. [citation unverified]",
2145
+ why: "The applicability call is the model's; the block is not. Under the supplemental lane a seat obeying unit.md's \"not applicable\" rule ('write a single block … so the file always lands') writes exactly the qid-less block validators.registerUnit in verify.mjs kills. The skill file and the stage message contradict each other on the one path the skill offers for an empty axis.",
2146
2146
  },
2147
2147
  "reading the band back and judging it — keep proposing until the axis's dangerous named band is covered": {
2148
2148
  class: "judgment", tokens: [],
@@ -2150,7 +2150,7 @@ export const STAGES = {
2150
2150
  },
2151
2151
  "layer-execution declaration — whether the prose says the register layer / provider tools were not executed or not bound": {
2152
2152
  class: "mechanical:code-extracted", tokens: ["declared_not_executed"],
2153
- why: "_driver/plan-execution.json and the tool-call log already hold whether the call ran — registerPlanCallKilled (verify.mjs:1291) reads exactly that to settle the same question one arm below. This arm still decides it from the model's sentence. [citation unverified]",
2153
+ why: "_driver/plan-execution.json and the tool-call log already hold whether the call ran — registerPlanCallKilled() in tool-calls.mjs reads exactly that to settle the same question one arm below. This arm still decides it from the model's sentence.",
2154
2154
  },
2155
2155
  "`CROSS-CHECK REQUIRED: <what> — <why>` — the check that is needed and why": {
2156
2156
  class: "judgment", tokens: [],
@@ -2364,7 +2364,7 @@ export const STAGES = {
2364
2364
  },
2365
2365
  "reason — the short paragraph carrying the stated ground for the tier (owner characterisation, customer/channel read, decisive ground, Stage-2 mitigant)": {
2366
2366
  class: "judgment", tokens: ["placement_reason_missing", "placement_reason_bare"],
2367
- why: "Four downstream stages adopt or counter-reason BY ARGUING WITH THIS TEXT (stages.mjs:2485-2489). It is authored reasoning, not a value any artifact holds. [citation unverified]",
2367
+ why: "Four downstream stages adopt or counter-reason BY ARGUING WITH THIS TEXT (the B2 comment in this stage's `message` says so). It is authored reasoning, not a value any artifact holds.",
2368
2368
  },
2369
2369
  "borderline: true — the declaration that the promotion question could be argued either way on this record": {
2370
2370
  class: "judgment", tokens: ["placement_borderline_invalid"],
@@ -2372,7 +2372,7 @@ export const STAGES = {
2372
2372
  },
2373
2373
  "select — one record URI of the register candidate being placed": {
2374
2374
  class: "mechanical:code-extracted", tokens: [],
2375
- why: "buildSelectionIndex() in placement-form.mjs already holds every selectable record, built from _driver/register-positions.json plus the band shape's floors, and resolves any URI of a family to the canonical row. #850 M1: the model should return the 1-based index into that driver-written list; code resolves index→id. WHICH candidate to place stays judgment — the row existing at all is the judgment; only the pointing token is mechanical. NO VALIDATOR TOKEN speaks about it: an unresolved select is recorded on the form as `unresolved[]` (placement-union.mjs:134) and handed back in the next dispatch, never a fail. [citation unverified]",
2375
+ why: "buildSelectionIndex() in placement-form.mjs already holds every selectable record, built from _driver/register-positions.json plus the band shape's floors, and resolves any URI of a family to the canonical row. #850 M1: the model should return the 1-based index into that driver-written list; code resolves index→id. WHICH candidate to place stays judgment — the row existing at all is the judgment; only the pointing token is mechanical. NO VALIDATOR TOKEN speaks about it: an unresolved select is recorded on the form as `unresolved[]` (pushSelection() in placement-union.mjs) and handed back in the next dispatch, never a fail.",
2376
2376
  },
2377
2377
  "seat rows for candidates the register does not hold — mark / owner / jurisdiction / records: [] written in full": {
2378
2378
  class: "judgment", tokens: ["placement_mark_missing", "placement_owner_missing", "placement_jurisdiction_invalid", "placement_records_invalid"],
@@ -2384,7 +2384,7 @@ export const STAGES = {
2384
2384
  },
2385
2385
  "the identifier half of each `cleared:` / `material-gap:` line — the axis, the named slice and its count": {
2386
2386
  class: "mechanical:code-extracted", tokens: [],
2387
- why: "The band's `incomplete` crowd descriptor carries query, total_hits, fetched and reason, and the driver already writes one coverage-form row per unaccounted crowd block with the qid, hit count and unaccounted classes/terms computed (coverage-form.mjs; digest.md:196-201). The MATERIALITY CALL is judgment and stays in the element above; the descriptor's identity and count are transcription of the driver's own numbers.",
2387
+ why: "The band's `incomplete` crowd descriptor carries query, total_hits, fetched and reason, and the driver already writes one coverage-form row per unaccounted crowd block with the qid, hit count and unaccounted classes/terms computed (coverage-form.mjs; digest.md, 'Coverage ledger'). The MATERIALITY CALL is judgment and stays in the element above; the descriptor's identity and count are transcription of the driver's own numbers.",
2388
2388
  },
2389
2389
  "the md's four tier sections — one per-candidate entry restating that candidate's tier and reasoning": {
2390
2390
  class: "mechanical:code-rendered", tokens: ["missing", "too_short"],
@@ -2404,7 +2404,7 @@ export const STAGES = {
2404
2404
  },
2405
2405
  "retract: <row_id> — withdrawing a seat row already on the form": {
2406
2406
  class: "judgment", tokens: [],
2407
- why: "Whether a placed candidate should come off is a call only the model makes. The row_id it names is driver-assigned (shortId 'PS'/'PR', placement-form.mjs:205/273), so the HANDLE is code-assigned even though the act is judgment. [citation unverified]",
2407
+ why: "Whether a placed candidate should come off is a call only the model makes. The row_id it names is driver-assigned (shortId 'PS'/'PR', in seatRows() and buildSelectionIndex() in placement-form.mjs), so the HANDLE is code-assigned even though the act is judgment.",
2408
2408
  },
2409
2409
  "return payload — the absolute output path plus a 2-3 line summary": {
2410
2410
  class: "mechanical:pre-bound", tokens: [],
@@ -2490,7 +2490,7 @@ export const STAGES = {
2490
2490
  },
2491
2491
  "seat-added coverage rows — the decision to add one, and the axis it is filed under (expressed in the `unit` label)": {
2492
2492
  class: "judgment", tokens: ["coverage_form_axis_invalid"],
2493
- why: "The shipped code rules it judgment in its own words: 'THE AXIS IS PART OF THE JUDGMENT, and on a SEAT row it is the one identifier the seat still supplies' and normalizeAxis 'repair[s] formatting, never invent[s] an axis' (coverage-form.mjs:519-524). The driver cannot know which axis a coverage unit it never planned belongs under. [citation unverified]",
2493
+ why: "The shipped code rules it judgment in its own words: 'THE AXIS IS PART OF THE JUDGMENT, and on a SEAT row it is the one identifier the seat still supplies' and normalizeAxis 'repair[s] formatting, never invent[s] an axis' (rowIsSettled() in coverage-form.mjs). The driver cannot know which axis a coverage unit it never planned belongs under.",
2494
2494
  },
2495
2495
  "the seat row's duplicate `axis` cell (the same token already typed as the leading segment of `unit`)": {
2496
2496
  class: "mechanical:code-extracted", tokens: ["coverage_form_axis_invalid"],
@@ -2502,7 +2502,7 @@ export const STAGES = {
2502
2502
  },
2503
2503
  "the compulsory dominant-element crowd row's `unit` cell — the dictated grammar `<axis> / dominant-element crowd (<N> members): <label>` and the bare integer N": {
2504
2504
  class: "mechanical:code-rendered", tokens: [],
2505
- why: "The driver computes the denominator: it groups screened-live dominant-element records by _driver/register-positions.json, counts the positions the digest did not individually end, verifies N and re-verifies after every rewrite (digest.md:132-164). The model is asked to retype a number the driver already checks it against — the frame_scope_missing loop restated. The RULING (why crowd membership ends this residual class) is judgment and lives in `reason`. No verify.mjs token: the reconciliation gate is a delivery block in pipeline.mjs, not this stage's validator.",
2505
+ why: "The driver computes the denominator: it groups screened-live dominant-element records by _driver/register-positions.json, counts the positions the digest did not individually end, verifies N and re-verifies after every rewrite (digest.md, 'Dominant-element reconciliation'). The model is asked to retype a number the driver already checks it against — the frame_scope_missing loop restated. The RULING (why crowd membership ends this residual class) is judgment and lives in `reason`. No verify.mjs token: the reconciliation gate is a delivery block in pipeline.mjs, not this stage's validator.",
2506
2506
  },
2507
2507
  "rolled-up coverage judgment — `sufficient: <true|false>`": {
2508
2508
  class: "mechanical:code-extracted", tokens: [],
@@ -2542,7 +2542,7 @@ export const STAGES = {
2542
2542
  },
2543
2543
  "Audit trail — per-unit search/detail-fetch counts, per-jurisdiction `_query` attribution": {
2544
2544
  class: "mechanical:tool-written", tokens: [],
2545
- why: "CONVERTED (conversion 11): the driver renders the Audit trail table from the same artifacts as the Summary counts, plus `_query` which digest.md:388 says 'the driver stamps at merge' — carrying that forward was transcription of a driver stamp. The judgment half — flagging a unit that shortcut its axis — stays in the findings-prose element.",
2545
+ why: "CONVERTED (conversion 11): the driver renders the Audit trail table from the same artifacts as the Summary counts, plus `_query` which digest.md says 'the driver stamps at merge' — carrying that forward was transcription of a driver stamp. The judgment half — flagging a unit that shortcut its axis — stays in the findings-prose element.",
2546
2546
  },
2547
2547
  "INSTRUCTED CHECKS — the answer to each requester ask the register owns": {
2548
2548
  class: "judgment", tokens: ["registerdigest_instructed_incomplete"],
@@ -2703,11 +2703,11 @@ export const STAGES = {
2703
2703
  },
2704
2704
  "the escalation decision — which register axes carry a material, unresolved, genuinely closeable gap, and the one-line reason for each": {
2705
2705
  class: "judgment", tokens: [],
2706
- why: "Whether a documented coverage-limited row, a capability-gap deferral or a fresh concern on a confirmed-clean row warrants spending a re-run. The driver hands the coverage/execution truth in as a computed table (stages.mjs:1479; skepticDeferralExtra) precisely so this is a call over data rather than a re-derivation — but the call itself is nobody else's. [citation unverified]",
2706
+ why: "Whether a documented coverage-limited row, a capability-gap deferral or a fresh concern on a confirmed-clean row warrants spending a re-run. The driver hands the coverage/execution truth in as a computed table (skepticDeferralExtra() in pipeline.mjs) precisely so this is a call over data rather than a re-derivation — but the call itself is nobody else's.",
2707
2707
  },
2708
2708
  "escalation decisions — one {axis, reason} per axis that must be re-run, sent through record_skeptic": {
2709
2709
  class: "mechanical:code-rendered", tokens: [],
2710
- why: "#850 rules the line shape M: typed rows, code renders. The axis is one of the closed list the driver wrote into the same message (`Valid axes: ${axes}`, stages.mjs:2628), and the parse at skeptic-record.mjs:49-53 recognises only /ESCALATE:\\s*<axis>\\b/i per known axis — the em-dash, the reason, the section title and the literal 'none' are parsed by nothing. NO TOKEN: skepticFlags never inspects these lines, so a malformed ESCALATE line is a silent no-escalation, not a failure. [citation unverified]",
2710
+ why: "#850 rules the line shape M: typed rows, code renders. The axis is one of the closed list the driver wrote into the same message (`Valid axes: ${axes}`), and the parse in escalatedAxes() in skeptic-record.mjs recognises only /ESCALATE:\\s*<axis>\\b/i per known axis — the em-dash, the reason, the section title and the literal 'none' are parsed by nothing. NO TOKEN: skepticFlags never inspects these lines, so a malformed ESCALATE line is a silent no-escalation, not a failure.",
2711
2711
  },
2712
2712
  "the verbatim ESCALATE string dictated for a `translit-too-generic` unit digest": {
2713
2713
  class: "mechanical:code-rendered", tokens: [],
@@ -2715,7 +2715,7 @@ export const STAGES = {
2715
2715
  },
2716
2716
  "the `risk: <category>` field inside that dictated ESCALATE line": {
2717
2717
  class: "mechanical:code-rendered", tokens: [],
2718
- why: "IT HAS NO CONSUMER AT ALL. stages.mjs:333-336 records that the risk-category filter was deleted, and pipeline.mjs states 'spec-48 D3 — the escalation-risk SHADOW loop (risk-tag parse + would-skip telemetry for the never-enabled CLEAROTRON_ESCALATION_FILTER) is DELETED' at the parse site (envelopeDecision() in pipeline.mjs). The doc block at envelopeDecision() in pipeline.mjs that describes reading the field is a stale header left standing over envelopeDecision — the function it documented is gone. Classed code-rendered because it is not judgment; the correct move is deletion from the skill file. [citation unverified]",
2718
+ why: "IT HAS NO CONSUMER AT ALL. The D3 note in stages.mjs (\"the escalation-risk SHADOW apparatus … is DELETED\") records that the risk-category filter was deleted, and pipeline.mjs states 'spec-48 D3 — the escalation-risk SHADOW loop (risk-tag parse + would-skip telemetry for the never-enabled CLEAROTRON_ESCALATION_FILTER) is DELETED' at the parse site (envelopeDecision() in pipeline.mjs). The doc block at envelopeDecision() in pipeline.mjs that describes reading the field is a stale header left standing over envelopeDecision — the function it documented is gone. Classed code-rendered because it is not judgment; the correct move is deletion from the skill file.",
2719
2719
  },
2720
2720
  "return payload — a 2-3 line summary; the audit itself rides record_skeptic": {
2721
2721
  class: "mechanical:tool-written", tokens: ["skeptic_"],
@@ -2839,7 +2839,7 @@ export const STAGES = {
2839
2839
  // demands. Stating it only in skills/frame-diff/SKILL.md would leave this line inviting the exact
2840
2840
  // shape the parse throws on — enforcement without a matching invitation, which is how the
2841
2841
  // 2026-07-29 run raised four omissions nothing could search.
2842
- `A FIRING variant directive (severity dominant-element or material) MUST be dispatchable: either its "item" is ITSELF a single mark-shaped search term (TAKIS, AXIOS, CORAL MAGIC), or it carries remedy: {terms:["<mark-shaped term>", …], nice_classes:["<class>", …]} saying WHAT to search. A label — a parenthetical, an enumeration, more than about four words ("TAKIS (famous CPG snack, one-keystroke neighbour)") — dispatches as a nil search that reads CLEAN, so the driver REFUSES the file and asks you to restate it in-turn. Every offending directive is named at once: fix them ALL in one re-save. Never delete a directive or downgrade it to "minor" to get past this — a real omission must still be raised, it just has to say what the search IS.`,
2842
+ `A FIRING variant directive (severity dominant-element or material) MUST be dispatchable: either its "item" is ITSELF a single mark-shaped search term (WAVA, ORBEXA, CORAL MAGIC), or it carries remedy: {terms:["<mark-shaped term>", …], nice_classes:["<class>", …]} saying WHAT to search. A label — a parenthetical, an enumeration, more than about four words ("WAVA (famous CPG snack, one-keystroke neighbour)") — dispatches as a nil search that reads CLEAN, so the driver REFUSES the file and asks you to restate it in-turn. Every offending directive is named at once: fix them ALL in one re-save. Never delete a directive or downgrade it to "minor" to get past this — a real omission must still be raised, it just has to say what the search IS.`,
2843
2843
  `field and source directives are NOT under that rule: an un-classed field directive and a source channel are disclosed rather than swept blind, which is a principled ending for those layers. A remedy is welcome on them whenever you know the exact re-search, and any remedy you supply is linted the same way wherever it rides.`,
2844
2844
  `Set dominant_element_gap true when the dominant element is not fully enumerated (the crowd not yet counted worldwide, a spine neighbour unsearched). The driver holds the dominant element and re-checks this against it — do not rely on it to hide a spine omission.`,
2845
2845
  //, third conversion — THE WRITE DICTATION AND BOTH PATHS ARE GONE. This dispatch used to end
@@ -3112,7 +3112,7 @@ export const STAGES = {
3112
3112
  // WS2 (spec 11) — ENFORCED, not advisory: validators.narrative HARD-REJECTS this file if a
3113
3113
  // use-dependent finding above the framework's lowest band asserts a use-negative without a searched
3114
3114
  // source line. So actually run the query.
3115
- `USE-CHECK (enforced): for EVERY finding whose mitigant/verdict turns on the ABSENCE of use (regardless of its band) ("not in actual use", "unused", "no marketplace use found", non-use revocation/cancellation as the mitigant, "owner's use unknown"), run ONE scoped \`perplexity_research\` query (owner + mark + the goods/field) and END that finding's actual-use line with a literal "- **Use-check source:** <result URL | "perplexity_research — no result">" line. Mirror the result into the matching # Actions item (the deferred "confirm the owner's use" becomes a stated result). NEVER assert a use-negative you did not search — an inference from the owner's profile is not a searched result. On a perplexity outage write "- **Use-check source:** perplexity_research — no result" and proceed (the run still delivers). ALSO populate that finding's use_check field in findings.json: {"source": "<the result URL | perplexity_research — no result>"} — the structured field is the authoritative cite the report renders from (the prose line is for narrative readability).`,
3115
+ `USE-CHECK (enforced): run the scoped use check (phase2-execution.md Step 3.5) on EVERY finding banded ${(framework && materialBandPhrase(framework)) || "medium risk or higher"} — the rungs this framework rates medium risk or higher; a lower rung is not checked — and ask in the SAME query for the owner's enforcement record (oppositions, disputes or court actions over this mark or a similar one). After the search, use is "confirmed" or "not-confirmed", never "unknown". What the query finds about enforcement is a LEAD under ENFORCEMENT AUTHORITY below: enforcer basis "inferred-from-signal", its URL cited inline in that finding's prose; where it finds none, the enforcer is "low" with basis "inferred-from-signal" and the finding says the search found no enforcement record. ALSO, for EVERY finding whose mitigant/verdict turns on the ABSENCE of use (regardless of its band) ("not in actual use", "unused", "no marketplace use found", non-use revocation/cancellation as the mitigant, "owner's use unknown"), run ONE scoped \`perplexity_research\` query (owner + mark + the goods/field) and END that finding's actual-use line with a literal "- **Use-check source:** <result URL | "perplexity_research — no result">" line. Mirror the result into the matching # Actions item (the deferred "confirm the owner's use" becomes a stated result). NEVER assert a use-negative you did not search — an inference from the owner's profile is not a searched result. On a perplexity outage write "- **Use-check source:** perplexity_research — no result" and proceed (the run still delivers). ALSO populate that finding's use_check field in findings.json: {"source": "<the result URL | perplexity_research — no result>"} — the structured field is the authoritative cite the report renders from (the prose line is for narrative readability).`,
3116
3116
  // Spec-v3 A4 — ENFORCED the same way (validators.narrative): own-rights reliance needs its evidence.
3117
3117
  // PR-8 review fix: synthesis holds the FROZEN band, not the live register — and the band is class-
3118
3118
  // and mark-text-scoped to this matter's dispatched slices, so the client's OWN house-mark
@@ -3280,7 +3280,7 @@ export const STAGES = {
3280
3280
  // beside it is caught only if the prose form itself trips SCOPE_NUMBER_RE — which the narrative's
3281
3281
  // own phrasings routinely dodge. Prompt-only per §7; the fix is to stop authoring the duplicate.
3282
3282
  `COVERAGE PROSE (the lane that runs longest — hold it to the house budgets): the register coverage line a reader sees is COMPUTED from this run's own record and STAMPED BY CODE as front-matter (the proportion, the class states, the searched registers). Do NOT re-type its numbers anywhere in prose — not in a coverage[] note, not in the coverage_judgment reason, not in the narrative. Nothing catches the duplicate for you (the code-stamped line sits outside the prose checks precisely because ITS numbers are the authoritative ones), so a re-typed count does not disagree with the record — it silently drifts from it a redelivery later. Carry the SUBSTANCE and drop the number: "the remaining forms are non-Latin script" says the useful half; the code says how many. State each coverage fact ONCE, in ONE place — an area's state belongs in its coverage[] row, the sufficiency read belongs in coverage_judgment.reason, and neither is re-narrated in the other or in the findings. And say WHICH KIND of negative you hold every time: a source this run actually queried and got nothing from reads "searched — none found"; a source it did not reach reads "not searched this run" or "could not be searched — <the reason>". The same source must never wear both readings in one report.`,
3283
- `- use_check / own_rights: OPTIONAL per-finding objects; populate per the USE-CHECK / OWN-RIGHTS rules above. use_check = {"source","quality"}: source is the cite of record the report renders — MANDATORY (spec-48 A4, symmetric) for ANY ASSERTED use status (token "confirmed" OR "not-confirmed") on a finding banded ABOVE the framework's lowest band, not only use-negatives (the validator rejects an asserted use with no receipt: finding_use_check_missing); "unknown" needs none. quality: OPTIONAL, EXACTLY one of owner-site / independent / register-mirror — your read of what KIND of page the source is (the code re-derives its own classification and wins; a register mirror is never evidence of use). own_rights = {"source"} — MANDATORY for any own-rights-reliant finding.`,
3283
+ `- use_check / own_rights: OPTIONAL per-finding objects; populate per the USE-CHECK / OWN-RIGHTS rules above. use_check = {"source","quality"}: source is the cite of record the report renders — MANDATORY (spec-48 A4, symmetric) for ANY ASSERTED use status (token "confirmed" OR "not-confirmed") on a finding banded ${(framework && materialBandPhrase(framework)) || "medium risk or higher"}, not only use-negatives (the validator rejects an asserted use with no receipt: finding_use_check_missing); "unknown" needs none. quality: OPTIONAL, EXACTLY one of owner-site / independent / register-mirror — your read of what KIND of page the source is (the code re-derives its own classification and wins; a register mirror is never evidence of use). own_rights = {"source"} — MANDATORY for any own-rights-reliant finding.`,
3284
3284
  // U3 (probative grading) — a risk-RAISING signal must say what it proves about THIS conflict.
3285
3285
  `- bears_on: a string, MANDATORY whenever this finding's enforcer meter is "high" (and good practice for any other risk-RAISING adjustment): one line on what the fact proves about THIS mark against THIS owner's rights on the disputed element — e.g. "owner has asserted <element> against comparable <goods>", NOT a bare "aggressive enforcer". A default win on a different element, or against an obvious copycat, does not count: if you cannot say why it bears on this confusion, the fact is annotation and the enforcer meter is not "high".`,
3286
3286
  // doc-35 T1 (authority grounding — fetch-before-cite, like use_check/own_rights): an enforcement AUTHORITY
@@ -3707,7 +3707,7 @@ export const STAGES = {
3707
3707
  },
3708
3708
  "actions.checks_we_ran[].source_link (the `([source](<url>))` URL in each bullet)": {
3709
3709
  class: "mechanical:code-rendered", tokens: [],
3710
- why: "A URL the run already fetched, retyped by hand: the same 127-URI transcription class #850 rules M for synthesis. findings.json carries the typed source.resolved_link (findings-model.mjs:616, render.mjs:1858 fullDetail) and the coverage rows carry theirs; code can render the link once the model names the check. [citation unverified]",
3710
+ why: "A URL the run already fetched, retyped by hand: the same 127-URI transcription class #850 rules M for synthesis. findings.json carries the typed source.resolved_link (validateSource() in findings-model.mjs, fullDetail() in render.mjs) and the coverage rows carry theirs; code can render the link once the model names the check.",
3711
3711
  },
3712
3712
  // RETIRED BY CONVERSION 4 — `actions.only_you_can_close_these[]`. buildOnlyYouSection already
3713
3713
  // replaced any authored section wholesale, so this row described an ask the driver overwrote. The
@@ -3724,7 +3724,7 @@ export const STAGES = {
3724
3724
  },
3725
3725
  "lint_contracts.withdrawn_findings_excluded (a withdrawn finding 'DOES NOT EXIST for this report')": {
3726
3726
  class: "mechanical:pre-bound", tokens: [],
3727
- why: "`withdrawn` is a typed disposition (findings-model.mjs:61 DISPOSITIONS) and fullProseOrdinals already filters it (fullProseOrdinals in pipeline.mjs). The driver can hand a filtered findings view instead of handing the whole file plus a prohibition. [citation unverified]",
3727
+ why: "`withdrawn` is a typed disposition (DISPOSITIONS declared in findings-model.mjs) and fullProseOrdinals already filters it (fullProseOrdinals in pipeline.mjs). The driver can hand a filtered findings view instead of handing the whole file plus a prohibition.",
3728
3728
  },
3729
3729
  // RETIRED BY CONVERSION 4 — the `::p::` MARKER. Which note is internal is still the model's call
3730
3730
  // and rides `internal: true` on the entry; the marker itself is a rendering instruction the driver