clearotron 0.4.0-beta.0 → 0.4.0-beta.2

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 (293) hide show
  1. package/.env.example +9 -0
  2. package/INSTALL.md +4 -31
  3. package/README.md +5 -5
  4. package/bin/brandowner.mjs +1 -1
  5. package/bin/onboard.mjs +18 -74
  6. package/bin/start.mjs +58 -14
  7. package/bin/update.mjs +10 -2
  8. package/build-info.json +2 -2
  9. package/demo/full-country-search/run/_driver/search-policy.json +1 -1
  10. package/demo/full-country-search/run/status.json +1 -1
  11. package/demo/global-preliminary-search/run/_driver/search-policy.json +1 -1
  12. package/demo/global-preliminary-search/run/status.json +1 -1
  13. package/demo/knockout-search/run/_driver/search-policy.json +1 -1
  14. package/demo/knockout-search/run/status.json +1 -1
  15. package/demo/multi-country-focus-search/run/_driver/search-policy.json +1 -1
  16. package/demo/multi-country-focus-search/run/status.json +1 -1
  17. package/docs/README.md +1 -0
  18. package/docs/SECURITY-OWASP.md +298 -0
  19. package/docs/SECURITY.md +18 -13
  20. package/docs/architecture/02-architecture.md +5 -5
  21. package/docs/architecture/03-run-lifecycle.md +28 -29
  22. package/docs/architecture/04-configuration-reference.md +5 -10
  23. package/docs/architecture/05-config-governance.md +5 -7
  24. package/docs/architecture/06-operations-runbook.md +0 -12
  25. package/docs/architecture/07-quality-and-audit.md +12 -13
  26. package/docs/architecture/09-security-and-data.md +9 -4
  27. package/driver/CHANGELOG.md +70 -0
  28. package/driver/ask-ledger.mjs +4 -2
  29. package/driver/authority-trees.mjs +90 -8
  30. package/driver/band-shape.mjs +13 -13
  31. package/driver/blind-frame-model.mjs +1 -1
  32. package/driver/case-law-ledger.mjs +19 -3
  33. package/driver/claim-liveness.mjs +30 -1
  34. package/driver/clearance-variants-record.mjs +10 -3
  35. package/driver/common-law-receipts.mjs +64 -14
  36. package/driver/commonlaw-carry.mjs +2 -2
  37. package/driver/compare.mjs +2 -2
  38. package/driver/connotation-search.mjs +33 -104
  39. package/driver/contract-arm2-baseline.json +6 -5
  40. package/driver/contract-e3-backlog.mjs +62 -62
  41. package/driver/contract-vocabulary.mjs +38 -31
  42. package/driver/coverage-form-io.mjs +13 -1
  43. package/driver/coverage-form.mjs +42 -4
  44. package/driver/coverage-ledger.mjs +3 -5
  45. package/driver/cross-check-wait.mjs +43 -0
  46. package/driver/declination-call.mjs +34 -10
  47. package/driver/declination-tool.mjs +27 -15
  48. package/driver/deferral-row.mjs +139 -0
  49. package/driver/degraded-parts.mjs +377 -0
  50. package/driver/deliver-trigger.sh +1 -1
  51. package/driver/demo-container.mjs +4 -1
  52. package/driver/dev-portal.mjs +5 -5
  53. package/driver/dispatch-record.mjs +2 -2
  54. package/driver/driver.config.mjs +193 -96
  55. package/driver/e2e/README.md +1 -1
  56. package/driver/effective-scope.mjs +58 -2
  57. package/driver/engine/anthropic-agent.mjs +103 -27
  58. package/driver/engine/auth.mjs +2 -2
  59. package/driver/engine/child-record.mjs +11 -0
  60. package/driver/engine/cli-version.mjs +4 -3
  61. package/driver/engine/common.mjs +17 -2
  62. package/driver/engine/deny-authority-write.mjs +3 -1
  63. package/driver/engine/engine-env.mjs +174 -0
  64. package/driver/engine/engine-spawn.mjs +179 -0
  65. package/driver/engine/mcp/band-server.mjs +1 -1
  66. package/driver/engine/mcp/clarivate-server.mjs +2 -1
  67. package/driver/engine/mcp/codex-config.mjs +112 -3
  68. package/driver/engine/mcp/corsearch-server.mjs +1 -0
  69. package/driver/engine/mcp/declination-server.mjs +9 -8
  70. package/driver/engine/mcp/dispositions-server.mjs +2 -1
  71. package/driver/engine/mcp/euipo-server.mjs +1 -0
  72. package/driver/engine/mcp/fetch-server.mjs +14 -11
  73. package/driver/engine/mcp/free-tier-server.mjs +1 -1
  74. package/driver/engine/mcp/gather-config.mjs +23 -11
  75. package/driver/engine/mcp/perplexity-server.mjs +97 -17
  76. package/driver/engine/mcp/probe-server.mjs +43 -21
  77. package/driver/engine/mcp/public-fetch.mjs +195 -0
  78. package/driver/engine/mcp/recording-server.mjs +79 -14
  79. package/driver/engine/mcp/signa-server.mjs +1 -0
  80. package/driver/engine/mcp/supplemental.mjs +14 -14
  81. package/driver/engine/mcp/unit-note-server.mjs +50 -1
  82. package/driver/engine/mcp/uspto-local-server.mjs +1 -0
  83. package/driver/engine/openai-agent.mjs +109 -28
  84. package/driver/engine/probe.mjs +152 -19
  85. package/driver/enqueue-schema.mjs +5 -5
  86. package/driver/feedback-issues.mjs +1 -1
  87. package/driver/feedback-store.mjs +1 -1
  88. package/driver/findings-model.mjs +67 -16
  89. package/driver/flag-snapshot.mjs +1 -1
  90. package/driver/floor-duty.mjs +23 -7
  91. package/driver/form-neighbourhood.mjs +52 -17
  92. package/driver/frame-diff-model.mjs +3 -3
  93. package/driver/framework-method.mjs +304 -0
  94. package/driver/gateway.mjs +49 -21
  95. package/driver/hand-off-exits.mjs +129 -0
  96. package/driver/jx-lanes.mjs +1 -1
  97. package/driver/jx.mjs +8 -5
  98. package/driver/knockout-assess-record.mjs +7 -1
  99. package/driver/knockout-frame-record.mjs +96 -34
  100. package/driver/knockout-review-record.mjs +7 -2
  101. package/driver/log.mjs +2 -2
  102. package/driver/matter-frame-record.mjs +31 -2
  103. package/driver/methodology-witness.mjs +6 -3
  104. package/driver/named-band.mjs +1 -1
  105. package/driver/owner-use-check.mjs +45 -10
  106. package/driver/package.json +1 -1
  107. package/driver/partial-payload-baseline.json +4 -0
  108. package/driver/phase0.mjs +2 -2
  109. package/driver/pipeline-knockout.mjs +256 -129
  110. package/driver/pipeline.mjs +417 -614
  111. package/driver/placement-carry.mjs +22 -3
  112. package/driver/placement-form-io.mjs +18 -4
  113. package/driver/placement-form.mjs +53 -4
  114. package/driver/placement-union.mjs +32 -5
  115. package/driver/portal-report.mjs +3 -3
  116. package/driver/portal-service.mjs +6 -5
  117. package/driver/portal-static.mjs +11 -18
  118. package/driver/predelivery-lint.mjs +10 -10
  119. package/driver/profile-page.html +5 -5
  120. package/driver/profiles.mjs +5 -5
  121. package/driver/progress.mjs +6 -4
  122. package/driver/provider-usage.mjs +25 -2
  123. package/driver/publish/index.mjs +97 -25
  124. package/driver/publish/knockout.mjs +136 -14
  125. package/driver/publish/profiles-page.mjs +2 -0
  126. package/driver/publish/publish-inputs.mjs +10 -4
  127. package/driver/publish/render-knockout.mjs +48 -21
  128. package/driver/publish/render.mjs +13 -8
  129. package/driver/publish/report-data.mjs +2 -0
  130. package/driver/publish/search-depth.mjs +77 -4
  131. package/driver/publish/templates/report.css +1 -1
  132. package/driver/publish/xlsx.mjs +34 -15
  133. package/driver/reasoning-tripwires.mjs +2 -160
  134. package/driver/recall-receipt.mjs +27 -0
  135. package/driver/recall-reconciliation.mjs +1 -1
  136. package/driver/record-carry.mjs +14 -14
  137. package/driver/recording-agreement.mjs +2 -2
  138. package/driver/reference-score.mjs +169 -47
  139. package/driver/register-count.mjs +61 -4
  140. package/driver/register-digest-record.mjs +14 -1
  141. package/driver/register-plan.mjs +161 -80
  142. package/driver/register-records.mjs +37 -4
  143. package/driver/registration-scripts.mjs +22 -0
  144. package/driver/registry-fidelity.mjs +4 -4
  145. package/driver/repair-composers.mjs +23 -7
  146. package/driver/repair-contract.mjs +1 -1
  147. package/driver/repairs.mjs +5 -2
  148. package/driver/reviewer-open-points.mjs +33 -0
  149. package/driver/rule-shape.mjs +8 -8
  150. package/driver/run-economics.mjs +3 -3
  151. package/driver/run-integrity.mjs +2 -2
  152. package/driver/runner.mjs +17 -5
  153. package/driver/scope-facts.mjs +89 -12
  154. package/driver/score-redaction.mjs +247 -0
  155. package/driver/screen-gate.mjs +1 -1
  156. package/driver/search-policy.mjs +17 -0
  157. package/driver/skills/README.md +2 -2
  158. package/driver/skills/blind-frame/SKILL.md +2 -2
  159. package/driver/skills/clearance-common-law/SKILL.md +29 -36
  160. package/driver/skills/clearance-common-law/perplexity-prompts.md +8 -30
  161. package/driver/skills/clearance-register/SKILL.md +15 -16
  162. package/driver/skills/clearance-register/digest.md +15 -31
  163. package/driver/skills/clearance-register/register-recipes.md +14 -56
  164. package/driver/skills/clearance-register/unit.md +37 -48
  165. package/driver/skills/clearance-search/SKILL.md +6 -8
  166. package/driver/skills/clearance-search/delivery-contract.md +0 -7
  167. package/driver/skills/clearance-search/firm-wide-reasoning.md +5 -4
  168. package/driver/skills/clearance-search/phase2-execution.md +5 -6
  169. package/driver/skills/clearance-search/report-prose.md +5 -5
  170. package/driver/skills/clearance-search/risk-framework-triage.md +2 -2
  171. package/driver/skills/clearance-search/synthesis-rules.md +9 -9
  172. package/driver/skills/clearance-search/template-formatting.md +2 -2
  173. package/driver/skills/clearance-variants/SKILL.md +8 -8
  174. package/driver/skills/clearance-variants/transliteration-scripts.md +2 -2
  175. package/driver/skills/frame-diff/SKILL.md +2 -2
  176. package/driver/skills/knockout-assess/SKILL.md +40 -10
  177. package/driver/skills/knockout-frame/SKILL.md +42 -10
  178. package/driver/skills/matter-frame/SKILL.md +12 -5
  179. package/driver/skills/matter-frame/watchlist-reference.md +1 -1
  180. package/driver/skills/narrative-refutation/SKILL.md +5 -3
  181. package/driver/skills/placement-inquiry/SKILL.md +5 -1
  182. package/driver/stage-context.mjs +27 -6
  183. package/driver/stages-knockout.mjs +92 -79
  184. package/driver/stages.mjs +111 -68
  185. package/driver/stray-artifacts.mjs +9 -5
  186. package/driver/suite-census.json +696 -150
  187. package/driver/synthesis-record.mjs +26 -4
  188. package/driver/systemd/README.md +5 -6
  189. package/driver/systemd/clearotron-client-mcp.service +24 -0
  190. package/driver/systemd/clearotron-mcp-face.service +24 -0
  191. package/driver/systemd/clearotron-portal.service +24 -0
  192. package/driver/systemd/clearotron-worker.service +29 -0
  193. package/driver/tokens.mjs +10 -9
  194. package/driver/turnaround-bands.mjs +1 -1
  195. package/driver/unit-inventory.mjs +24 -43
  196. package/driver/variant-manifest-model.mjs +22 -3
  197. package/driver/verify-knockout.mjs +163 -4
  198. package/driver/verify.mjs +42 -16
  199. package/driver/web-grid.mjs +150 -0
  200. package/driver/whatif-memo-run.mjs +1 -1
  201. package/driver/withheld-families.mjs +113 -4
  202. package/driver/worker-heartbeat.mjs +13 -2
  203. package/mcp-server/CHANGELOG.md +8 -0
  204. package/mcp-server/README.md +1 -1
  205. package/mcp-server/lib/knockout.mjs +1 -1
  206. package/mcp-server/lib/ops.mjs +10 -10
  207. package/mcp-server/lib/scrub.mjs +1 -1
  208. package/mcp-server/lib/trace.mjs +3 -2
  209. package/mcp-server/package.json +1 -1
  210. package/mcp-server/server.mjs +3 -3
  211. package/package.json +1 -1
  212. package/portal-ui/dist/assets/{index-DVtz44vH.js → index-BPAUjcI0.js} +3 -2
  213. package/portal-ui/dist/assets/{index-5CCwiJG7.css → index-D2wrw9cH.css} +18 -2
  214. package/portal-ui/dist/assets/plus-jakarta-sans-BUCHxqJ-.woff2 +0 -0
  215. package/portal-ui/dist/index.html +2 -15
  216. package/portal-ui/package.json +1 -1
  217. package/providers/_shared/README.md +1 -1
  218. package/providers/_shared/answer-memory.mjs +199 -0
  219. package/providers/_shared/enumerate.mjs +155 -50
  220. package/providers/_shared/execute-plan.mjs +62 -16
  221. package/providers/_shared/ledger-path.mjs +1 -1
  222. package/providers/_shared/ledger.mjs +48 -6
  223. package/providers/_shared/plan-guards.mjs +7 -0
  224. package/providers/_shared/script-form.mjs +24 -5
  225. package/providers/_shared/term-shape.mjs +5 -5
  226. package/providers/clarivate/src/capabilities.js +11 -0
  227. package/providers/clarivate/src/core.js +193 -18
  228. package/providers/corsearch/README.md +1 -2
  229. package/providers/corsearch/src/core.js +2 -2
  230. package/providers/jx-subclass/lookup.mjs +1 -1
  231. package/providers/oauth-mcp-bridge/CHANGELOG.md +8 -0
  232. package/providers/oauth-mcp-bridge/README.md +8 -7
  233. package/providers/oauth-mcp-bridge/bridge.mjs +21 -5
  234. package/providers/oauth-mcp-bridge/package.json +1 -1
  235. package/providers/oauth-mcp-bridge/systemd/courtlistener-mcp.service +1 -1
  236. package/providers/oauth-mcp-bridge/warm-server.mjs +16 -5
  237. package/providers/perplexity/src/core.js +246 -21
  238. package/providers/signa/src/capabilities.js +24 -0
  239. package/providers/signa/src/core.js +93 -25
  240. package/scripts/README.md +2 -1
  241. package/scripts/added-reference-check.mjs +2 -1
  242. package/scripts/backup-recall-stores.mjs +5 -5
  243. package/scripts/demo-evidence.mjs +2 -1
  244. package/scripts/deprecate-below.mjs +114 -2
  245. package/scripts/drive-env-check.mjs +2 -1
  246. package/scripts/e2e-first-time.mjs +469 -0
  247. package/scripts/e2e-scenario-ops.mjs +441 -0
  248. package/scripts/e2e.mjs +104 -16
  249. package/scripts/env-audit.mjs +8 -0
  250. package/scripts/freeze-example-run.mjs +7 -7
  251. package/scripts/generated-files-are-current.mjs +2 -1
  252. package/scripts/hand-off-exits-probe.mjs +75 -0
  253. package/scripts/import-cycle-check.mjs +2 -1
  254. package/scripts/merge-shape-check.mjs +2 -1
  255. package/scripts/package-size-budget.mjs +2 -1
  256. package/scripts/record-carry-probe.mjs +1 -1
  257. package/scripts/release-entry-catch-up.mjs +77 -8
  258. package/scripts/release-install-check.mjs +4 -1
  259. package/scripts/release-note-required.mjs +139 -9
  260. package/scripts/release-rehearsal-version.mjs +60 -0
  261. package/scripts/release-sbom.mjs +104 -0
  262. package/scripts/release-visible-check.mjs +7 -5
  263. package/scripts/render-check.mjs +5 -2
  264. package/scripts/report-offline-render-check.mjs +169 -0
  265. package/scripts/score.mjs +79 -8
  266. package/scripts/strip-titles-and-attributions.mjs +2 -1
  267. package/scripts/strip-tracker-citations.mjs +2 -1
  268. package/scripts/test-full.mjs +2 -1
  269. package/scripts/test-run.mjs +10 -3
  270. package/scripts/third-party-notices.mjs +3 -1
  271. package/scripts/travelling-predicates.mjs +1 -1
  272. package/scripts/writing-standard-check.mjs +2 -1
  273. package/shared/brand-fonts.mjs +59 -0
  274. package/shared/brand.mjs +6 -6
  275. package/shared/browser-temp-root.mjs +3 -2
  276. package/shared/doctrine-overlay.mjs +1 -1
  277. package/shared/driver-dir.mjs +47 -11
  278. package/shared/fonts/OFL-fira-code.txt +93 -0
  279. package/shared/fonts/OFL-plus-jakarta-sans.txt +93 -0
  280. package/shared/fonts/README.md +37 -0
  281. package/shared/fonts/fira-code.woff2 +0 -0
  282. package/shared/fonts/plus-jakarta-sans.woff2 +0 -0
  283. package/shared/names-in-force.mjs +2 -0
  284. package/shared/npm-cli.mjs +23 -0
  285. package/shared/os-advice.mjs +14 -2
  286. package/shared/path-seps.mjs +42 -0
  287. package/shared/process-table.mjs +71 -3
  288. package/shared/reference-guard-classes.mjs +30 -6
  289. package/shared/root-doc-commands.mjs +6 -2
  290. package/shared/running-start.mjs +24 -7
  291. package/shared/scope.mjs +2 -2
  292. package/shared/wsl.mjs +1 -1
  293. package/driver/known-conflicts.mjs +0 -327
@@ -0,0 +1,298 @@
1
+ # Security mapping: OWASP risks for AI applications
2
+
3
+ *Each risk on OWASP's two lists for AI systems, what Clearotron does about it, and the file on `main`
4
+ where that lives. Where nothing does, the row says so and why.*
5
+
6
+ The two lists are the [OWASP Top 10 for LLM Applications 2025](https://genai.owasp.org/llm-top-10/) and
7
+ the [OWASP Top 10 for Agentic Applications 2026](https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026/).
8
+ Who may see which runs, and how a key is checked, is stated once in [SECURITY.md](SECURITY.md). This page
9
+ links there rather than repeating it.
10
+
11
+ ## How a clearance uses AI
12
+
13
+ A clearance runs as a series of stages. For each stage the driver, which is ordinary code, starts one AI
14
+ program: Anthropic's Claude Code or OpenAI's Codex. The stage gets a written task, the tools named for
15
+ that stage, and its run folder. Code checks every file a stage writes before any other stage reads it.
16
+ The register searches are fixed in a plan before the register stages run, and code runs them. Code also
17
+ renders the report, from the checked files.
18
+
19
+ ## OWASP Top 10 for LLM Applications 2025
20
+
21
+ ### LLM01:2025 Prompt Injection
22
+
23
+ **Here.** Stages read web pages, marketplace listings and register records, and any of them can carry
24
+ text written to steer the model.
25
+
26
+ **What Clearotron does.** Each stage's tools are granted by name. The case-law stage is the exception: it is granted every tool its two case-law services offer. A tool outside that
27
+ grant that needs permission is refused. A Claude stage is offered no tool that runs a command. A Codex stage keeps its shell inside Codex's own sandbox, and Codex approves tool
28
+ calls only for the tool servers Clearotron starts for that stage. The AI program starts with a named list
29
+ of settings rather than the install's settings file, so the key that signs access keys is not in it.
30
+ Codex's page-fetching tool refuses loopback, private, link-local and cloud-metadata addresses. It checks
31
+ the address a name resolves to, and checks again on every redirect.
32
+
33
+ **Where.** `driver/engine/mcp/gather-config.mjs` (the tools each stage holds),
34
+ `driver/engine/anthropic-agent.mjs` (`COMMAND_TOOLS`), `driver/engine/mcp/codex-config.mjs`,
35
+ `driver/engine/engine-env.mjs`, `driver/engine/mcp/public-fetch.mjs`.
36
+
37
+ **Not covered.** Content from the web is not marked as untrusted in the text a stage reads. That text is
38
+ what the engine reasons from, so changing it is a design decision of its own.
39
+
40
+ ### LLM02:2025 Sensitive Information Disclosure
41
+
42
+ **Here.** A report, the portal or a connected assistant shows one company's clearances to another, or
43
+ shows the engine's internals to a company's people.
44
+
45
+ **What Clearotron does.** Every read passes one authorization check, and a person sees only what their
46
+ grant names. A key bound to one run reads that run and writes nothing. The copy of a report a company
47
+ receives drops the staff-only notes. No real company's data is in this repository; run data lives
48
+ in folders the operator owns. CI scans the tree and the built bundle for secrets.
49
+
50
+ **Where.** [SECURITY.md](SECURITY.md) (the access model), `shared/scope.mjs`, `driver/portal-report.mjs`,
51
+ `.gitleaks.toml`, `.github/workflows/ci.yml`.
52
+
53
+ **Not covered.** A company's clearances are kept until the operator deletes them: Clearotron sets no
54
+ retention period, because how long they are held is the operator's policy.
55
+
56
+ ### LLM03:2025 Supply Chain
57
+
58
+ **Here.** A compromised npm package, GitHub Action or engine program.
59
+
60
+ **What Clearotron does.** Dependabot updates the npm packages and the GitHub Actions. Each release is
61
+ published to npm through trusted publishing, with provenance that ties the package to the commit and the
62
+ build that produced it. A stable release is not published while a code-scanning alert is open. Setup
63
+ installs, and `clearotron doctor` accepts, only an engine program at or above the version this release
64
+ needs.
65
+
66
+ **Where.** `.github/dependabot.yml`, `.github/workflows/release.yml`,
67
+ `scripts/release-code-scanning-check.mjs`, `driver/driver.config.mjs` (`ENGINE_BINARIES`, each program's
68
+ `floor`).
69
+
70
+ ### LLM04:2025 Data and Model Poisoning
71
+
72
+ **Here.** Tampering with what the model learns from, so that it concludes wrongly.
73
+
74
+ **What Clearotron does.** Clearotron trains and fine-tunes no model. The instructions every stage reads
75
+ are versioned in this repository. On the Claude engine a check refuses any write by a stage into those
76
+ instructions, into the company profiles, or into the run's own control folder.
77
+
78
+ **Where.** `driver/skills/` (the instructions), `driver/engine/deny-authority-write.mjs`,
79
+ `driver/authority-trees.mjs`.
80
+
81
+ **Not covered.** Codex has no such check. A Codex stage can write anywhere in its run folder, the control
82
+ folder included, because Codex offers no hook at the moment of a write.
83
+
84
+ ### LLM05:2025 Improper Output Handling
85
+
86
+ **Here.** Model output passed on to something that runs or renders it unchecked.
87
+
88
+ **What Clearotron does.** A stage's output is a file, and code checks it against that stage's contract
89
+ before anything uses it. A file that fails is retried or fails the stage; it is never passed on. The
90
+ report is rendered by code from checked files, and no file a stage writes runs on the install's machine.
91
+ The common-law search asks the research service to run a search program, on that service's own servers.
92
+
93
+ **Where.** `driver/gateway.mjs` (`runStage`), `driver/stages.mjs` (each stage's contract),
94
+ `driver/publish/`.
95
+
96
+ ### LLM06:2025 Excessive Agency
97
+
98
+ **Here.** A stage that can do more than its task needs: run commands, spend, write where it should not.
99
+
100
+ **What Clearotron does.** Tools are granted per stage, by name. The case-law stage is the exception: it is granted every tool its two case-law services offer. A Claude
101
+ stage is offered no command tool.
102
+ Register searches beyond the fixed plan go through a proposal that code checks and runs. A key issued for
103
+ automation can be limited to named actions. A what-if requested by a company's people is queued for a
104
+ separate process rather than run by the door that received it.
105
+
106
+ **Where.** `driver/engine/mcp/gather-config.mjs`, `driver/engine/anthropic-agent.mjs`,
107
+ `driver/engine/mcp/supplemental.mjs`, `shared/scope.mjs`, `driver/whatif-worker.mjs`.
108
+
109
+ **Not covered.** As ASI02: the Claude program also offers a stage built-in tools that act without asking.
110
+
111
+ ### LLM07:2025 System Prompt Leakage
112
+
113
+ **Here.** The instructions given to the model leak, and with them anything secret they hold.
114
+
115
+ **What Clearotron does.** The instructions are published in this repository and hold no credential.
116
+ Credentials reach the tool servers through their environment, never through text a model reads.
117
+
118
+ **Where.** `driver/skills/`, `driver/engine/engine-env.mjs`.
119
+
120
+ ### LLM08:2025 Vector and Embedding Weaknesses
121
+
122
+ **Not applicable.** Clearotron keeps no vector store and computes no embeddings. The one search over
123
+ finished runs is a word search.
124
+
125
+ **Where.** `mcp-server/lib/lexsearch.mjs`.
126
+
127
+ ### LLM09:2025 Misinformation
128
+
129
+ **Here.** A report states a conflict that is not there, or misses one that is.
130
+
131
+ **What Clearotron does.** Register counts come from the register, never from the model, and a register
132
+ finding names the register record it rests on. A search that could not run is listed in the report as a gap,
133
+ never reported as a clean result. Before a report is published, separate stages argue against its
134
+ conclusions.
135
+
136
+ **Where.** `driver/register-plan.mjs`, `providers/_shared/execute-plan.mjs`, `driver/stages.mjs`,
137
+ [architecture/07-quality-and-audit.md](architecture/07-quality-and-audit.md).
138
+
139
+ ### LLM10:2025 Unbounded Consumption
140
+
141
+ **Here.** A run that consumes model time or money without limit.
142
+
143
+ **What Clearotron does.** Each stage runs under a stall watchdog and a hard time limit, and a failing
144
+ stage stops retrying once a retry would repeat the same failure. An install runs a set number of
145
+ clearances at a time. The connector doors limit requests per identity.
146
+
147
+ **Where.** `driver/engine/common.mjs`, `driver/engine/anthropic-agent.mjs`, `driver/gateway.mjs`,
148
+ `mcp-server/lib/http-handler.mjs`.
149
+
150
+ **Not covered.** There is no spend ceiling on a search. By policy, no model is given a time, token or cost
151
+ budget.
152
+
153
+ ## OWASP Top 10 for Agentic Applications 2026
154
+
155
+ ### ASI01 Agent Goal Hijack
156
+
157
+ **Here.** Text a stage reads redirects it to a goal that is not the clearance.
158
+
159
+ **What Clearotron does.** The controls under LLM01 above. The stage's task is also fixed by the driver,
160
+ and code checks what the stage hands back against that task's contract.
161
+
162
+ **Where.** As LLM01, and `driver/stages.mjs`.
163
+
164
+ **Not covered.** As LLM01: web content is not marked as untrusted.
165
+
166
+ ### ASI02 Tool Misuse
167
+
168
+ **Here.** A stage uses a legitimate tool for something its task does not need.
169
+
170
+ **What Clearotron does.** Each stage is granted its tools by name. The case-law stage is the exception: it is granted every tool its two case-law services offer. A tool outside
171
+ that grant that needs permission is refused. Codex's approval covers only the tool servers Clearotron starts for the stage, and
172
+ Codex's fetch tool refuses internal addresses. Register
173
+ calls follow the fixed plan or a proposal code checks. Every tool call is written to the run's tool-call
174
+ log, and each stage's attempt record counts the calls made and the calls refused.
175
+
176
+ **Where.** `driver/engine/mcp/gather-config.mjs`, `driver/engine/mcp/codex-config.mjs`,
177
+ `driver/engine/mcp/public-fetch.mjs`, `driver/engine/mcp/stdio-server.mjs` (the tool-call log),
178
+ `driver/gateway.mjs` (`toolGauge`).
179
+
180
+ **Not covered.** The Claude program also offers every stage some of its built-in tools that need no
181
+ permission: starting a subagent, which keeps the stage's restrictions; scheduling a task on the operator's
182
+ Claude account; messaging the account's other sessions; and sending a notification. Clearotron does not
183
+ remove them.
184
+
185
+ ### ASI03 Identity and Privilege Abuse
186
+
187
+ **Here.** A stage acts with more authority than its task, or takes a credential it can reuse.
188
+
189
+ **What Clearotron does.** The AI program starts with a named list of settings, and the key that signs
190
+ access keys is not on it. The worker that starts the AI program does not hold that key either, whether
191
+ the install runs in a terminal or under systemd. Access keys are scoped to a run, a company or named
192
+ actions, and one check enforces the scope. On Claude, a stage's file tools can read nothing outside its run folder, its
193
+ instruction folders and any folder the machine's own Claude settings add. On Codex with its sandbox on, a stage's commands can read nothing outside its run folder, its instruction folders, the temporary
194
+ folders, and the system and program files a command needs to run.
195
+
196
+ **Where.** `driver/engine/engine-env.mjs`, `bin/start.mjs` (`SIGNING_KEY_NAMES`),
197
+ `driver/systemd/clearotron-worker.service`, `shared/scope.mjs`, `driver/engine/anthropic-agent.mjs`
198
+ (`READ_FENCE`), `driver/engine/mcp/codex-config.mjs` (`fenceToml`).
199
+
200
+ **Not covered.** With Codex's sandbox off, a stage's commands run with every permission of the install's
201
+ account and can read any file it can, the settings file included. With it on, the temporary folders are
202
+ shared by every stage of the install, so a stage's commands can read what another stage left there.
203
+
204
+ ### ASI04 Agentic Supply Chain Vulnerabilities
205
+
206
+ **Here.** A tool server or engine component that a stage trusts is compromised.
207
+
208
+ **What Clearotron does.** The tool servers a stage uses are Clearotron's own code in this repository. Two
209
+ of them are bridges Clearotron starts to the case-law services CourtListener and Legal Data Hunter, and
210
+ they pass through the tools those services define. On Codex, the configuration written for each turn lists
211
+ only the servers granted to that stage. The supply-chain controls under LLM03 apply here too.
212
+
213
+ **Where.** `driver/engine/mcp/`, `providers/oauth-mcp-bridge/bridge.mjs`,
214
+ `driver/engine/mcp/codex-config.mjs`.
215
+
216
+ ### ASI05 Unexpected Code Execution
217
+
218
+ **Here.** A stage is talked into running code.
219
+
220
+ **What Clearotron does.** A Claude stage has no tool that runs a command: Bash, PowerShell and Monitor
221
+ are removed by name from every stage. A Codex stage runs its commands inside Codex's own sandbox. They can read nothing outside the stage's own folders, the temporary folders, and the system and program
222
+ files a command needs to run, and write nothing outside its run folder and the temporary folders. Before a search is paid for, a
223
+ check runs one turn through the engine with the settings the search will use.
224
+
225
+ **Where.** `driver/engine/anthropic-agent.mjs` (`COMMAND_TOOLS`), `driver/engine/openai-agent.mjs`
226
+ (`buildCodexArgs`), `driver/engine/mcp/codex-config.mjs` (`fenceToml`), `driver/engine/probe.mjs`.
227
+
228
+ **Not covered.** Where Codex's sandbox cannot start on a machine, the setting
229
+ `CLEAROTRON_CODEX_SANDBOX_BYPASS=1` runs Codex without it, and a stage's commands then run with every
230
+ permission of the install's account. The engine check says when a machine needs it.
231
+
232
+ ### ASI06 Memory and Context Poisoning
233
+
234
+ **Here.** Poisoned content persists and steers later work.
235
+
236
+ **What Clearotron does.** The engine keeps no memory of its own: every stage starts from its task and its
237
+ run folder, and a retried stage resumes only its own session. What does persist between runs is each
238
+ company's configuration, its profile, risk framework and background notes, which every run reads and which
239
+ only people with Manage can edit in the portal. On the Claude engine a stage cannot write to it.
240
+
241
+ **Where.** `driver/gateway.mjs` (`runStage`), `driver/profiles.mjs`, [SECURITY.md](SECURITY.md) (who
242
+ holds Manage), `driver/engine/deny-authority-write.mjs`.
243
+
244
+ **Not covered.** As LLM01: web content that a stage reads, and that a later stage reads in its output, is
245
+ not marked as untrusted.
246
+
247
+ ### ASI07 Insecure Inter-Agent Communication
248
+
249
+ **Not applicable in its usual sense.** Stages do not message each other. The driver passes files from one
250
+ stage to the next, and checks each one first.
251
+
252
+ **Where.** `driver/gateway.mjs`, `driver/stages.mjs`.
253
+
254
+ ### ASI08 Cascading Failures
255
+
256
+ **Here.** One failed stage corrupts the stages after it.
257
+
258
+ **What Clearotron does.** Code checks each stage's output before the next stage reads it. A stage whose
259
+ retries fail the same way twice stops retrying, and a stage whose every tool call was refused stops after
260
+ one attempt. The engine check before a search refuses a machine that would fail every stage.
261
+
262
+ **Where.** `driver/gateway.mjs`, `driver/engine/probe.mjs`, `driver/engine/tool-refusal.mjs`.
263
+
264
+ ### ASI09 Human-Agent Trust Exploitation
265
+
266
+ **Here.** A reader trusts a confident report more than its evidence supports.
267
+
268
+ **What Clearotron does.** A register finding names the register record it rests on, and every search that
269
+ could not run is listed in the report.
270
+
271
+ **Where.** `driver/publish/`, `driver/register-plan.mjs`.
272
+
273
+ ### ASI10 Rogue Agents
274
+
275
+ **Here.** An agent that keeps running, spreads, or acts outside its task.
276
+
277
+ **What Clearotron does.** No agent outlives its stage. Each stage is one process under a watchdog and a
278
+ hard time limit, and the driver stops its whole process group. The driver records every program it
279
+ starts. On the Claude engine a stage cannot write into the instructions it runs from.
280
+
281
+ **Where.** `driver/engine/anthropic-agent.mjs`, `driver/engine/common.mjs`,
282
+ `driver/engine/child-record.mjs`, `driver/engine/deny-authority-write.mjs`.
283
+
284
+ **Not covered.** As LLM04: on Codex, no check refuses a stage's write inside its run folder.
285
+
286
+ ## Repository protections
287
+
288
+ Measured on 2026-09-23 with the GitHub API.
289
+
290
+ | Protection | State |
291
+ |---|---|
292
+ | Secret scanning | On |
293
+ | Push protection | On |
294
+ | CodeQL (Actions, JavaScript and TypeScript) | Configured, and a required check on `main` |
295
+ | Code scanning before a stable release | A stable is not published while an alert is open |
296
+ | Private vulnerability reporting | On |
297
+ | npm provenance | Every release, through trusted publishing |
298
+ | Required checks on `main` | Six; force pushes and branch deletion refused |
package/docs/SECURITY.md CHANGED
@@ -5,6 +5,9 @@
5
5
  What protects what, where it is enforced in code, and what the operator must do. Every statement
6
6
  here corresponds to shipped behavior; when hardening changes, change this file in the same PR.
7
7
 
8
+ Each risk on OWASP's two lists for AI systems, and what Clearotron does about it:
9
+ [SECURITY-OWASP.md](SECURITY-OWASP.md).
10
+
8
11
  ## Surfaces
9
12
 
10
13
  | Surface | Trust | Guard |
@@ -12,7 +15,7 @@ here corresponds to shipped behavior; when hardening changes, change this file i
12
15
  | stdio MCP (`mcp-server/server.mjs`) | local/full ("ops") | OS user boundary — run it AS the operator account; it is the only surface on which `what_if_run` EXECUTES (`visibleTools` keeps what-if out of the HTTP listing for ops, but the CallTool chokepoint gates on `authorize()` alone, which admits it for any ops token not `--verbs`-scoped) |
13
16
  | Client MCP (`mcp-server/http-server-client.mjs`) | a company's signed-in person / their access key | `what_if_run` from an `account` principal ENQUEUES rather than executes (ruling 2026-08-27) — it never imports the engine, and `driver/whatif-worker.mjs` spawns the sandbox from an OS service process. A confirmation token is unsigned, so the call must ALSO name its `runId`: the grant check keys on it, and `whatIfEnqueue` refuses a token naming a different run. The `model` argument is refused on this face. |
14
17
  | HTTP MCP (`mcp-server/http-server.mjs`) | authenticated remote | auth-BEFORE-data; fail-closed construction; inner scoped tokens |
15
- | Report "Ask your AI" links | external report recipients | run-bound `user` tokens minted at publish; the plain-language report tools (`clientSafe`) only |
18
+ | Run-bound keys | a report recipient an operator issues one to | a `user` key from `mint-token.mjs`, read-only and bound to one run; the plain-language report tools (`clientSafe`) only |
16
19
  | Dev portal (`driver/dev-portal.mjs`) | dev only | loopback-only (throws on any other host); never production serving |
17
20
 
18
21
  ## Authentication (the outer gate — both faces)
@@ -121,10 +124,9 @@ with access to everything.
121
124
  what the mechanism guarantees.*
122
125
 
123
126
  - One OPERATOR issuance path: `mint-token.mjs` (prints once, stores nothing; `sub` names the
124
- principal in every audit line; the `jti` printed at mint time is the revocation handle). Two
125
- automatic minters sit beside it on the same `mintToken`: the clearance publisher mints the report
126
- link's run-bound `user` token at publish, and `clearotron start` mints the portal's verb-scoped,
127
- company-capped ops token in memory at every start. Neither prints, and neither is written down.
127
+ principal in every audit line; the `jti` printed at mint time is the revocation handle). Three other callers share the same `mintToken`: `clearotron start` mints the portal's verb-scoped,
128
+ company-capped ops token in memory at every start, and neither prints nor stores it; `clearotron connect`
129
+ and the portal's connect screen each mint a person's key for their own assistant.
128
130
  - **Revocation**: denylist file checked on every verification; missing file = nothing revoked (the
129
131
  denylist can never take all auth down). **Rotation**: two-secret window, flag-day-free.
130
132
  - **Rate limits**: per-identity bucket on every request plus a separate lower per-principal bucket
@@ -132,9 +134,10 @@ what the mechanism guarantees.*
132
134
 
133
135
  ## Audit
134
136
 
135
- Every HTTP tool call appends `{ts, email, sub, tool, args-summary}` to an append-only JSONL
136
- (`TRADEMARK_MCP_AUDIT_LOG`). Audit is written after scope resolution (so the line names the
137
- principal) and before dispatch; it is best-effort and never blocks a request.
137
+ Every HTTP tool call appends one line to an append-only JSONL (`TRADEMARK_MCP_AUDIT_LOG`) when the call
138
+ finishes: `{ts, email, sub, method, tool, runId, status, door}`, where `status` is the outcome. It is
139
+ written after scope resolution, so it names the principal. A request refused before any tool runs is
140
+ written too, with the status `refused`. Writing it is best-effort and never blocks a request.
138
141
 
139
142
  ## Data plane
140
143
 
@@ -143,7 +146,8 @@ principal) and before dispatch; it is best-effort and never blocks a request.
143
146
  companies only. Run data lives in operator-owned directories outside git (`CLEAROTRON_REPORTS_DIR`,
144
147
  workspace root, outbox), backed up by the operator, never committed.
145
148
  - Secrets enter only via environment (`.env` on the host); the repo carries `.env*.example` files
146
- with placeholders. CI runs a secret scan (gitleaks) on every push.
149
+ with placeholders. CI runs a secret scan (gitleaks) over the tree and the built bundle on every pull request and every
150
+ push to `main`.
147
151
  - Dev instances are isolated by CONFIGURATION and nothing else: a test instance and a live one are the
148
152
  same code with different environment — no build flag, no profile constant, no mode switch in the
149
153
  source — so the separation holds exactly as far as the operator gives it its own
@@ -160,7 +164,9 @@ Each pipeline stage shells the configured engine binary as the operator account
160
164
  picks the adapter install-wide (`anthropic-agent` spawns `claude -p`, `openai-agent` spawns
161
165
  `codex exec` with a per-run `CODEX_HOME`), with no per-stage engine and no fallback between them —
162
166
  with run-scoped `--add-dir` access and per-provider gather MCP servers whose credentials come from the
163
- environment. Stage outputs are judged by file-truth validators — the engine's own success claims
167
+ environment. The program starts with a named list of settings rather than the whole environment, so the
168
+ key that signs access keys never reaches it (`driver/engine/engine-env.mjs`). A stage on Claude is
169
+ offered no tool that runs a command; a stage on Codex runs its commands inside Codex's own sandbox. Stage outputs are judged by file-truth validators — the engine's own success claims
164
170
  are never trusted. Delivery is a self-contained packet couriered by the integrator; the engine sends
165
171
  no messages and holds no channel credentials.
166
172
 
@@ -178,9 +184,8 @@ no messages and holds no channel credentials.
178
184
  ## Reporting
179
185
 
180
186
  **[`../SECURITY.md`](../SECURITY.md) is the disclosure path** — the channel, what is in scope, and
181
- what to expect. It is the only file that names the channel — a monitored `security@` mailbox and
182
- GitHub's private vulnerability reporting, either one — so there is one place to change if a channel
183
- ever moves.
187
+ what to expect. It is the only file that names the channels, so there is one place to change if one ever
188
+ moves.
184
189
 
185
190
  If you run your own deployment, reports about *your* configuration — your auth proxy, your TLS, your
186
191
  keys — go to you. This file describes what the code guarantees; it cannot speak for how a given
@@ -214,9 +214,9 @@ mode via `CLEAROTRON_AI_BILLING=api-key` — the scale setting ([04](04-configur
214
214
 
215
215
  **The second engine** (`engine/openai-agent.mjs`) spawns `codex exec` per stage on the shared
216
216
  `engine/common.mjs` substrate: prompt on stdin, `--json` event stream, `--skip-git-repo-check` with a neutral non-repo
217
- cwd, `--sandbox workspace-write --add-dir <runDir>`, and a per-run `CODEX_HOME` holding a rendered
218
- `config.toml` (MCP servers + developer instructions) plus, under subscription billing, a seeded
219
- `auth.json`. It is single-provider like the anthropic engine — one run's stages all execute as GPT —
217
+ cwd, `--add-dir <runDir>`, and a per-run `CODEX_HOME` holding a rendered `config.toml` (MCP servers,
218
+ developer instructions and, with Codex's sandbox on, a permission profile that limits what the stage's
219
+ commands can read and write) plus, under subscription billing, a seeded `auth.json`. It is single-provider like the anthropic engine — one run's stages all execute as GPT —
220
220
  so telemetry's model provenance needs no cross-provider bookkeeping. Its abstract tiers all resolve
221
221
  to one model id by default; [04](04-configuration-reference.md) records why, and why lowering them
222
222
  is not a cost saving.
@@ -254,7 +254,7 @@ primitive is a filesystem primitive chosen for its atomicity:
254
254
  | pid+starttime sidecars | claim liveness, slot ownership | survives pid reuse; positive-evidence death only |
255
255
 
256
256
  The run directory ([03 §7](03-run-lifecycle.md#7--run-directory-anatomy)) is the unit of truth;
257
- the queue dirs, the known-conflicts store, the outbox, and the publish pool are the only shared
257
+ the queue dirs, the outbox, and the publish pool are the only shared
258
258
  locations, and each has a single writer role. This is why horizontal
259
259
  scaling is credible: a second driver on a second host needs sharded queues and a shared pool,
260
260
  nothing else.
@@ -286,7 +286,7 @@ All paths relative to [`driver/`](../../driver/). The load-bearing seven are mar
286
286
  | `rule-shape.mjs` · `reasoning-tripwires.mjs` · `gate-metrics.mjs` | Anti-threshold guard, integrity tripwires (observe-only), gate telemetry. |
287
287
  | `predelivery-lint.mjs` · `close-verify.mjs` · `screen-gate.mjs` | Pre-delivery checks, envelope close verification, screen-gate detection. |
288
288
  | `common-law-receipts.mjs` · `engagement-receipt.mjs` · `scope-ledger.mjs` | Receipt models for the marketplace grid, engagement, scope. |
289
- | `senior-rights.mjs` · `own-rights.mjs` · `use-check.mjs` · `known-conflicts.mjs` | Rights closure, self-exclusion, use analysis, recall store. |
289
+ | `senior-rights.mjs` · `own-rights.mjs` · `use-check.mjs` | Rights closure, self-exclusion, use analysis. |
290
290
  | `publish/` | Deterministic publication: HTML render, Excel audit workbook, pool admin, regions. |
291
291
  | `repairs.mjs` · `repair-digest.mjs` | Recovery decisions, repair budgets, repair digests. |
292
292
  | `tokens.mjs` · `provider-usage.mjs` · `progress.mjs` · `status-snapshot.mjs` · `run-activity.mjs` | Token rollup (successor to the deleted `cost.mjs`), billing-grade provider ledger, status surfaces. |
@@ -178,7 +178,7 @@ seeding. Frozen sidecars are never silently re-derived; a corrupt one crashes lo
178
178
  flowchart TD
179
179
  subgraph HEAD["Phase 1-2 head (fatal)"]
180
180
  MF[matter-frame] --> PV[clearance-variants]
181
- PV --> DER["code derivations:<br/>scope ledger · form neighbourhood ·<br/>register plan freeze · recall probes"]
181
+ PV --> DER["code derivations:<br/>scope ledger · form neighbourhood ·<br/>register plan freeze"]
182
182
  end
183
183
  DER --> GRID["grid spec dictated by code<br/>(terms × platforms × connotation; A1 split)"]
184
184
  subgraph GATHER["Gather fan-out (concurrency = CLEAROTRON_GATHER_CONCURRENCY)"]
@@ -189,18 +189,17 @@ flowchart TD
189
189
  GRID --> GATHER
190
190
  GATHER --> FANIN{{"fan-in barrier (code):<br/>quarantines · must() · half-merge ·<br/>named-band gate · taint chain ·<br/>plan⇄band identity join · grid-ledger gate"}}
191
191
  FANIN --> CLOSURE["coverage closure pass<br/>(one supplementary sweep, non-fatal)"]
192
- CLOSURE --> PI[placement-inquiry] --> RD[register-digest]
192
+ CLOSURE --> FD["frame-diff vs blind frame<br/>+ bounded reopen (non-fatal block)"] --> PI[placement-inquiry] --> RD[register-digest]
193
193
  RD --> SK["skeptic (non-fatal)"]
194
194
  SK --> ESC{"ESCALATE: axis tokens?"}
195
195
  ESC -- yes --> RERUN["re-run flagged axes warm ·<br/>byte-diff · one re-digest"] --> ENV
196
196
  ESC -- no --> ENV["deadline envelope:<br/>close deferred floors if time allows"]
197
197
  ENV --> SG{{"screen-gate: dropped LIVE mark<br/>without fetched record?<br/>fetch → re-digest → else FATAL"}}
198
- SG --> FD["frame-diff vs blind frame<br/>+ bounded reopen (non-fatal block)"]
199
- FD --> SYN[synthesis]
198
+ SG --> SYN[synthesis]
200
199
  SYN --> PAR["case-law ∥ narrative-refutation<br/>(case-law non-fatal)"]
201
200
  PAR --> VG{"verdict gate:<br/>parseVerdict(review)"}
202
201
  VG -- "CONDITIONAL / BLOCKING" --> CORR["corrective re-synthesis (fatal) ·<br/>corrections freshness gate ·<br/>verdict re-check (warm)"] --> VG2{"still BLOCKING?"}
203
- VG2 -- yes --> FAIL[["FATAL StageFailure('verdict')"]]
202
+ VG2 -- yes --> DELIV["report DELIVERS (ruling 2026-08-26) ·<br/>runLog verdict-blocking-delivered ·<br/>open points recorded beside the review,<br/>for the reviewing lawyer (ruling 2026-09-24)"] --> CLAMP
204
203
  VG2 -- no --> CLAMP
205
204
  VG -- CLEAR --> CLAMP["code clamps (raise-only):<br/>legal actions · coverage · frame residual ·<br/>screen gate · register gap · deadline gap"]
206
205
  CLAMP --> VS["verdict sidecar _driver/verdict.json<br/>(single label authority; write failure = fatal)"]
@@ -212,7 +211,7 @@ flowchart TD
212
211
  PUB --> HANDOFF["delivery packet _driver/delivery.json ·<br/>outbox <runId>.pending · .delivered · archive"]
213
212
 
214
213
  classDef fatal stroke:#c0392b,stroke-width:2px
215
- class MF,PV,PI,RD,SYN,FAIL,VS,CG fatal
214
+ class MF,PV,PI,RD,SYN,VS,CG fatal
216
215
  ```
217
216
 
218
217
  Reading order for the phases, with what code decides at each:
@@ -222,8 +221,7 @@ Reading order for the phases, with what code decides at each:
222
221
  generates the complete mechanical variant floor), freezes the register plan
223
222
  (`_driver/register-plan.json`, frozen for the life of *this run* — a resume never re-plans, and a
224
223
  fresh run always mints; reproducibility comes from the compiler being pure, not from a store of
225
- prior plans), and folds in **recall probes** — prior confirmed conflicts for this mark from the
226
- workspace store become deterministic plan entries (cap 10).
224
+ prior plans).
227
225
  2. **Grid dictation** — code writes `_driver/grid-spec.json`: exact terms × platforms, connotation
228
226
  queries, batch size, `ledger_required: true`. With ≥2 terms the grid is split across three
229
227
  seats — unconditionally since item 8 deleted the rollback switch: halves`a` and `b` take
@@ -244,29 +242,29 @@ Reading order for the phases, with what code decides at each:
244
242
  persistent repair ledger (`_driver/repairs.json`) so no ladder is ever bought twice.
245
243
  5. **Coverage closure** — one supplementary sweep for closable coverage-limited cells, idempotent
246
244
  by receipt; survivors become a front-matter coverage note, not a halt.
247
- 6. **Placement → register-digest** — both fatal. Every digest pass (fresh, escalation, envelope,
245
+ 6. **Frame-diff + bounded reopen** — the blind frame is diffed against the run's own framing;
246
+ directives (including deterministic mechanical form-gap directives) can reopen register and
247
+ source arms once, under a fetch ceiling (`CLEAROTRON_REOPEN_MAX_FETCH`, default 150), with
248
+ per-directive closure verification. The whole block is non-fatal; unclosed directives demote to
249
+ disclosed deferrals that later clamp the verdict.
250
+ 7. **Placement → register-digest** — both fatal. Every digest pass (fresh, escalation, envelope,
248
251
  late-bind, stale-repair) goes through the single `runDigest` chokepoint, which drops stale ledgers,
249
252
  renders the coverage ledger from the driver-written coverage form the seat submits through
250
253
  `record_coverage` — the prose `## Coverage ledger` table and the machine-readable JSON are both
251
254
  renders of that one form, so neither can be the thing that drifts (prose parsing survives only as
252
255
  the fallback when the derivation throws) — and quarantines rather than ships a ledger that fails
253
256
  its validator.
254
- 7. **Skeptic + escalation** — the skeptic is deliberately non-fatal (a checker outage must not bin
257
+ 8. **Skeptic + escalation** — the skeptic is deliberately non-fatal (a checker outage must not bin
255
258
  a completed gather). Escalation is triggered only by structured `ESCALATE: <axis>` tokens; an
256
259
  axis whose every owned ledger row is `coverage-limited` is skipped (documented accepted limit);
257
260
  flagged axes re-run warm on their winning session keys, byte-diff guards skip unchanged units,
258
261
  then exactly one re-digest. A digest lock forbids escalation after synthesis exists on a resume.
259
- 8. **Deadline envelope** — pure arithmetic: if the deadline leaves room after an estimated close
262
+ 9. **Deadline envelope** — pure arithmetic: if the deadline leaves room after an estimated close
260
263
  cost plus a one-hour delivery reserve, deferred floors get one warm close attempt, verified by
261
264
  re-running the detectors; unverifiable closes are disclosed, never claimed.
262
- 9. **Screen-gate** — an in-scope *live* mark dropped on goods/field grounds without a fetched
263
- record is repaired (code fetches the record, one warm re-digest) or the run dies: an
264
- unexaminable drop is not shippable.
265
- 10. **Frame-diff + bounded reopen** — the blind frame is diffed against the run's own framing;
266
- directives (including deterministic mechanical form-gap directives) can reopen register and
267
- source arms once, under a fetch ceiling (`CLEAROTRON_REOPEN_MAX_FETCH`, default 150), with
268
- per-directive closure verification. The whole block is non-fatal; unclosed directives demote to
269
- disclosed deferrals that later clamp the verdict.
265
+ 10. **Screen-gate** — an in-scope *live* mark dropped on goods/field grounds without a fetched
266
+ record is repaired (code fetches the record, one warm re-digest) or the run dies: an
267
+ unexaminable drop is not shippable.
270
268
  11. **Synthesis** — fatal. Malformed findings get one warm re-emit naming exactly the defective
271
269
  objects; still-malformed findings after the ladder are terminal (the old quarantine-and-continue
272
270
  is retired). Schema and actions[] upgrades are demanded warm on runs where synthesis actually ran.
@@ -275,12 +273,16 @@ Reading order for the phases, with what code decides at each:
275
273
  verdict is parsed by code; a parse failure is **BLOCKING** (fail-safe). CONDITIONAL/BLOCKING
276
274
  triggers corrective re-synthesis (fatal if it fails), a freshness gate proving the named
277
275
  corrections reached `findings.json`, and a warm verdict re-check. A still-BLOCKING verdict
278
- after the degenerate-artifact repair is a fatal run failure — "delivered with open questions"
279
- is retired.
276
+ after the degenerate-artifact repair does **not** fail the run. Ruling 2026-08-26, verbatim:
277
+ "Deliver always, with open points printed. The refusal on a blocking review goes." The run
278
+ logs `verdict-blocking-delivered` and carries on to the clamps. Ruling 2026-09-24 settled
279
+ where the points go: reviewer notes never reach the client page, and a report the reviewer
280
+ still refuses ships with its rating and nothing added — the open points are recorded beside
281
+ the review in the run record, for the reviewing lawyer.
280
282
  13. **Code clamps** — the coverage floor (`applyCoverageFloor`) only ever *raises* CLEAR to
281
283
  CONDITIONAL: typed condition actions, the lawyer's explicit `coverage_judgment.sufficient ===
282
- false`, frame residuals, screen-gate gaps, register gaps (from the taint-relabelled ledger),
283
- deadline-carry gaps. Execution facts clamp in code regardless of the model's self-report. The
284
+ false`, frame residuals, screen-gate gaps, register gaps (from the taint-relabelled ledger).
285
+ Execution facts clamp in code regardless of the model's self-report. The
284
286
  **verdict sidecar** (`_driver/verdict.json`) then becomes the single verdict authority for
285
287
  everything downstream; failing to write it is fatal.
286
288
  14. **Delivery phase** — report overview (fatal), per-finding report cards (fan-out, individually
@@ -292,7 +294,7 @@ Reading order for the phases, with what code decides at each:
292
294
  reasoning-integrity receipt (observability only, never a gate — an explicit Goodhart guard).
293
295
  15. **Client-gate + publish + handoff** — the client gate is evaluated fail-closed *before*
294
296
  anything touches the pool. Publish is deterministic code, idempotent via `.published`. Then the
295
- delivery handoff (§4), known-conflicts store upsert, `status.json` flip to `delivered`,
297
+ delivery handoff (§4), `status.json` flip to `delivered`,
296
298
  archive (the run dir is renamed into the archive tree), and the `.delivered` sentinel.
297
299
 
298
300
  **Fatal vs note-and-continue.** The full lists live in `pipeline.mjs` (the outer catch), but the shape is:
@@ -465,7 +467,7 @@ needs is in it:
465
467
  │ ├── profile.json · framework.json · register-plan.json # frozen per-run config (never re-derived)
466
468
  │ ├── grid-spec.json (+ .half-a/b, .supp-*) # code-dictated search specs
467
469
  │ ├── coverage-enum.json · plan-execution.json # fail-closed enum sentinel · execution receipt
468
- │ ├── register-recall.json · register-xcheck.json # recall probes · cross-check receipts
470
+ │ ├── register-xcheck.json # cross-check receipt (a run before 2026-09-24 may also carry register-recall.json, its recall-search receipt)
469
471
  │ ├── register-taint.json · escalation-state.json # taint chain · escalation/envelope outcome
470
472
  │ ├── coverage-closure.json · frame-reopen.json # closure + reopen receipts
471
473
  │ ├── intake-asks.json · instructed-scope.json # intake derivations (code-authoritative scope)
@@ -486,7 +488,4 @@ needs is in it:
486
488
  └── (delivered runs move whole to <archive>/<YYYY-MM>/<slug>/)
487
489
  ```
488
490
 
489
- Outside the run dir, a run touches the workspace known-conflicts store
490
- (`_known-conflicts/<mark>.json` — human-editable; code only adds
491
- rows, and rewrites exactly one machine field, `terminal`, when a delivered run confirms a leg an
492
- earlier failed attempt recorded), the outbox (`<runId>.pending`), and the publish pool.
491
+ Outside the run dir, a run touches the outbox (`<runId>.pending`) and the publish pool.
@@ -85,7 +85,7 @@ does after the stage's full retry ladder fails ([03 §5](03-run-lifecycle.md#5--
85
85
  | 10 | `frame-diff` | sonnet · low | 600 / — | `frame-diff.md` + `frame-diff.json` | non-fatal (no reopen) |
86
86
  | 11 | `synthesis` | `CLEAROTRON_SYNTHESIS_MODEL` \|\| opus · high | 2500 / 900 | `narrative.md` + **`findings.json`** (schema v7 — `FINDINGS_SCHEMA_VERSION`, interpolated into the contract the stage message dictates: `findings`, `coverage`, `mark_assessment`, `four_answers`, `actions`, `coverage_judgment` and `rated_under_framework`, plus `context_notes` / `ask_answers` where they apply) | quasi-fatal: unrepaired finding defects are terminal; corrective re-synthesis is fatal on failure |
87
87
  | 12 | `case-law` | sonnet · adaptive | 900 / — | `case-law-findings.md` | non-fatal; conditional on the PRODUCT — `decideCaseLaw` (`pipeline.mjs`) runs it on **every** `full-country-search`, because the case-law and opposition reading is what that product IS and `policy.caseLaw` is set from the product spec. A narrative that turns on a precedent or an opposition is the second, redundant arm there; on any other product that reading is recorded as `declined`, never run |
88
- | 13 | `narrative-refutation` | opus · high | 900 / 600 | `senior-eye-review.md` (verdict on first line) | fatal |
88
+ | 13 | `narrative-refutation` | opus · high | 900 / 600 | `senior-eye-review.md` (verdict on first line) | fatal: the STAGE failing to produce a review. Its **verdict** is not — a still-BLOCKING verdict delivers (ruling 2026-08-26), see [03](03-run-lifecycle.md) step 12 |
89
89
  | 14 | `report-overview` | sonnet · low | 900 / — | `report-overview.md` (shell only; cards + "Only you can close these" are code-built) | fatal |
90
90
  | 15 | `report-card` | sonnet · low | 600 / — | `report-cards/<ord>.md` | non-fatal per card (structured-only fallback) |
91
91
  | 16 | `doubt-closure` | sonnet · low | 300 / — | `doubt-closure.md` (dictated `SETTLED`/`IMMATERIAL`/`OPEN` lines; code re-verifies every quote) | non-fatal (the open doubts and asks ship `OPEN`, as they would without the stage) |
@@ -138,12 +138,6 @@ id is what a dispatch row and a token-rollup row carry as the model *asked for*;
138
138
  the turn is recorded beside it, and the report names that. A version here would be a claim about a
139
139
  request nobody made, and wrong the day a newer model of the tier shipped.
140
140
 
141
- One consequence, accepted when this was decided: per-model totals are keyed on what was asked for,
142
- and the native-language lanes call the API directly, where a model id is required and a tier word is
143
- not accepted. So one model reached by a stage and by those lanes appears under two keys —
144
- `anthropic/claude-haiku` and `anthropic/claude-haiku-4-5`. They are different requests, and the split
145
- says so.
146
-
147
141
  The bottom four are **legacy names that no stage declares and no engine can run** — they resolve at
148
142
  level 1 and then throw at level 2 (below). They are catalogue entries, not available tiers.
149
143
 
@@ -199,7 +193,7 @@ timeout shot, warm patch, backoff), the lane-wedge re-dispatch, and the rate-lim
199
193
  | `CLEAROTRON_OPENAI_MODEL_JUDGMENT` / `CLEAROTRON_OPENAI_MODEL_SWEEP` / `CLEAROTRON_OPENAI_MODEL_CHEAP` | `gpt-5.6-sol` / `gpt-5.6-terra` / `gpt-5.6-luna`. | Maps the driver's abstract `opus`/`sonnet`/`haiku` tiers onto the codex ladder, the way the anthropic engine maps onto its own (ruling 2026-09-02, superseding the single-model mapping). A tier that cannot hold its stage contract announces itself at that stage — `missing:negative-results`, `no_coverage_status_row`, `named_band_missing` in `_driver/<stage>.jsonl` — not at delivery. |
200
194
  | ↳ why they are three, and what the old measurement still says | superseded 2026-09-02, not erased | The three defaulted to `sol` alone on a MEASUREMENT, never a placeholder: on 2026-08-11/12, with `SWEEP=gpt-5.6-terra` / `CHEAP=gpt-5.6-luna`, every codex clearance died on structural-output gates — `missing:negative-results`, `no_coverage_status_row`, `named_band_missing` — over 2 scenarios × 3 stage families, **byte-identically on retry**, so no retry budget rescued it. That measurement stands for the code and the codex CLI **of that date**, and it is why the judgment tier keeps `sol`. Three weeks of stage-contract work and several codex minor versions sit between it and the 2026-09-02 ruling that split the three. **The symptom to match against this cause is unchanged**: those same three gates, as a fail row in`_driver/<stage>.jsonl`, inside the first few dispatches of a clearance and identical on every retry — a model incapable of a contract is not flaky at it. It reads as an engine bug when the only fault is this configuration. A cheap-tier experiment still belongs in the three constants in `driver/engine/openai-agent.mjs` where a reviewer sees it, not in an untraceable env line. |
201
195
  | `CLEAROTRON_DATABASE` | **REQUIRED — no default.** `corsearch` \| `clarivate` \| `signa` \| `euipo` \| `uspto-local` \| `free-tier` | Active register provider — one per run, set in the environment the deploy carries, in every environment including production. There is **no default**: unset resolves to `null` and every use of it throws, so a run refuses at start rather than calling a vendor nobody chose (the removed `corsearch` fallback named a vendor the deployment did not choose). Three are paid global sweeps; `euipo` (EU) and `uspto-local` (US) are free single-office sources, and `free-tier` composes those two as one register. Choosing a free value makes every territory outside its coverage a disclosed *deferred* row. Unknown ids throw loudly, and the gather layer throws at stage time for any provider without a built MCP server. |
202
- | `CLEAROTRON_CODEX_SANDBOX_BYPASS` | unset | `1` runs `codex exec` with its own sandbox helper bypassed, for hosts where that helper cannot spawn or refuses every tool call (setup and `doctor --probe-engine` report the refusal). It removes a defence: with it set, the run dir is writable by the seat and only the deny-hook stands between a stage and `_driver/`. Set it because the host forces it, never for convenience. |
196
+ | `CLEAROTRON_CODEX_SANDBOX_BYPASS` | unset | `1` runs `codex exec` with its own sandbox bypassed, for hosts where that sandbox cannot run (setup and `doctor --probe-engine` report it). It removes a defence: with it set, a stage's commands run with every permission of the account Clearotron runs as, not only in the run folder. Codex has no guard against a stage writing into the run's `_driver/` folder, with the sandbox or without it. Set it because the host forces it, never for convenience. |
203
197
 
204
198
  ## Environment variable reference
205
199
 
@@ -248,6 +242,8 @@ deployment may override (verify live values per deployment).
248
242
  | `CLEAROTRON_MAX_CLAIM_AGE_MS` | 172800000 (48 h; 0 disables) | Hard ceiling on a claim's age (from the `.pid` sidecar mtime) — beyond it, re-claim regardless of liveness. |
249
243
  | `CLEAROTRON_KNOCKOUT_VARIANT_CAP` | unset (⇒ the lane's own cap) | Ceiling on variants a knockout screens per name. Set only to bound an unusually wide batch; absent means the lane decides. |
250
244
  | `CLEAROTRON_KNOCKOUT_RECORD_CAP` | unset (⇒ the lane's own cap) | Ceiling on records a knockout fetches per hit. Same shape as the variant cap: absent is the normal state. |
245
+ | `CLEAROTRON_SIGNA_ANSWER_MEMORY` | `off` | On the Signa register, whether a run reuses an answer it already holds instead of asking again. `off` asks every time. `watch` also asks every time, and records whether a held answer would have matched. `on` reuses held answers. |
246
+ | `CLEAROTRON_CLARIVATE_ANSWER_MEMORY` | `on` | On the Clarivate register, whether a run reuses a count, a search, an owner lookup or a record it already holds instead of asking again. `off` asks every time. |
251
247
 
252
248
  ### Retries, timeouts, watchdogs
253
249
 
@@ -281,10 +277,9 @@ unrecognised policy value that leaves the default behaviour standing.
281
277
 
282
278
  | Var | Gates |
283
279
  |---|---|
284
- | `CLEAROTRON_RECALL_PROBES` / `CLEAROTRON_RECALL_TRIPWIRE` | Prior-confirmed-conflict plan probes / recall store reads + regression check. |
285
280
  | `CLEAROTRON_PLAN_DISPATCH` (`0` or `off` disables) | Pure-code provider `executePlan` repairs at fan-in and reopen. **Never silently inert:** every entry in `PROVIDERS` ships an `executePlan` adapter, and `preflightCredentials` refuses the run before any spend under one that does not — a credential is not a capability. §5.4 of [05-config-governance.md](05-config-governance.md) still lists `signa` as the exception to that and has not been updated since its two missing tools were mounted. |
286
281
  | `CLEAROTRON_FRAME_REOPEN` (+ `CLEAROTRON_FRAME_REOPEN_MAX`, default 1) | The bounded frame-diff reopen. |
287
- | `CLEAROTRON_REGISTER_GAP_CLAMP` | The registerGap + deadline-carry verdict clamp arms. |
282
+ | `CLEAROTRON_REGISTER_GAP_CLAMP` | The registerGap verdict clamp arm. |
288
283
  | `CLEAROTRON_REOPEN_MAX_FETCH` (default 150) | Detail-fetch ceiling inside the reopen closure pass. |
289
284
  | `CLEAROTRON_UNREACHABLE_SENIOR` (`open-item` \| `clamp`, default `open-item`) | Policy when a verdict-driving senior right can't be retrieved. |
290
285