clearotron 0.3.2-beta.7 → 0.3.2-beta.9

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 (272) hide show
  1. package/.env.example +58 -26
  2. package/CONTRIBUTING.md +8 -8
  3. package/INSTALL.md +148 -81
  4. package/README.md +3 -3
  5. package/SECURITY.md +3 -3
  6. package/bin/brandowner.mjs +3 -3
  7. package/bin/framework-preflight.mjs +1 -1
  8. package/bin/onboard.mjs +637 -216
  9. package/bin/start.mjs +151 -27
  10. package/bin/update.mjs +58 -11
  11. package/build-info.json +2 -2
  12. package/docs/DELIVERY.md +2 -1
  13. package/docs/INTAKE.md +1 -1
  14. package/docs/ONBOARDING.md +1 -1
  15. package/docs/architecture/03-run-lifecycle.md +6 -6
  16. package/docs/architecture/04-configuration-reference.md +32 -14
  17. package/docs/architecture/05-config-governance.md +23 -8
  18. package/docs/architecture/05-customer-profiles.md +2 -2
  19. package/docs/architecture/06-operations-runbook.md +3 -3
  20. package/docs/architecture/08-development-guide.md +6 -6
  21. package/docs/configuration.md +5 -5
  22. package/docs/decisions/0003-credential-model.md +1 -1
  23. package/docs/writing-standard.md +4 -0
  24. package/driver/CHANGELOG.md +124 -0
  25. package/driver/README.md +3 -3
  26. package/driver/band-size.mjs +59 -0
  27. package/driver/binding-layers.mjs +1 -1
  28. package/driver/citation-census.json +3 -3
  29. package/driver/{prelim-variants-record.mjs → clearance-variants-record.mjs} +24 -24
  30. package/driver/common-law-receipts.mjs +2 -2
  31. package/driver/company-bundle.mjs +3 -3
  32. package/driver/compose-read.mjs +8 -14
  33. package/driver/config-inventory.mjs +112 -9
  34. package/driver/consumption-ledger.mjs +2 -2
  35. package/driver/contract-arm2-baseline.json +2 -5
  36. package/driver/contract-dictation-registry.mjs +19 -19
  37. package/driver/contract-e3-backlog.mjs +43 -43
  38. package/driver/contract-e3-baseline.json +14 -14
  39. package/driver/contract-vocabulary.mjs +68 -27
  40. package/driver/deliver-trigger.sh +16 -16
  41. package/driver/demo-container.mjs +3 -3
  42. package/driver/dev-portal.mjs +3 -3
  43. package/driver/disposition-call.mjs +1 -1
  44. package/driver/door-gates.mjs +41 -7
  45. package/driver/doubt-ledger.mjs +2 -2
  46. package/driver/drainer-identity.mjs +34 -8
  47. package/driver/driver.config.mjs +367 -104
  48. package/driver/engine/CONTRACT.md +10 -3
  49. package/driver/engine/README.md +2 -2
  50. package/driver/engine/anthropic-agent.mjs +77 -21
  51. package/driver/engine/auth.mjs +129 -10
  52. package/driver/engine/jx-turn.mjs +7 -6
  53. package/driver/engine/mcp/README.md +1 -1
  54. package/driver/engine/mcp/dispositions-server.mjs +3 -3
  55. package/driver/engine/mcp/gather-config.mjs +9 -9
  56. package/driver/engine/mcp/perplexity-server.mjs +2 -2
  57. package/driver/engine/mcp/recording-server.mjs +18 -5
  58. package/driver/engine/openai-agent.mjs +4 -2
  59. package/driver/engine/probe.mjs +110 -23
  60. package/driver/enqueue-schema.mjs +6 -2
  61. package/driver/findings-model.mjs +6 -3
  62. package/driver/flag-snapshot.mjs +34 -8
  63. package/driver/form-neighbourhood.mjs +54 -7
  64. package/driver/framework.mjs +4 -4
  65. package/driver/gateway.mjs +36 -24
  66. package/driver/jx-lanes.mjs +23 -4
  67. package/driver/jx-units.mjs +7 -4
  68. package/driver/jx.mjs +34 -4
  69. package/driver/knockout-review-record.mjs +56 -4
  70. package/driver/known-conflicts.mjs +1 -1
  71. package/driver/matter-frame-record.mjs +90 -1
  72. package/driver/named-band.mjs +1 -1
  73. package/driver/ordinary-words.mjs +51 -0
  74. package/driver/outbox-backoff.mjs +31 -16
  75. package/driver/package.json +1 -1
  76. package/driver/partial-payload-baseline.json +2 -2
  77. package/driver/phase0.mjs +3 -3
  78. package/driver/pipeline-knockout.mjs +5 -5
  79. package/driver/pipeline.mjs +396 -81
  80. package/driver/placement-form.mjs +77 -1
  81. package/driver/placement-model.mjs +1 -1
  82. package/driver/portal-config-view.mjs +30 -1
  83. package/driver/portal-report.mjs +107 -6
  84. package/driver/portal-service.mjs +80 -14
  85. package/driver/portal-upstream.mjs +1 -1
  86. package/driver/predelivery-lint.mjs +12 -2
  87. package/driver/preserve-merge.mjs +3 -3
  88. package/driver/product-rows.mjs +2 -2
  89. package/driver/products.mjs +1 -1
  90. package/driver/profiles/README.md +3 -3
  91. package/driver/profiles/demo-brand-owner.json +2 -2
  92. package/driver/profiles.mjs +55 -17
  93. package/driver/progress.mjs +18 -8
  94. package/driver/provider-usage.mjs +8 -8
  95. package/driver/publish/index.mjs +154 -8
  96. package/driver/publish/knockout.mjs +39 -5
  97. package/driver/publish/pool-admin.mjs +1 -1
  98. package/driver/publish/publish-inputs.mjs +18 -2
  99. package/driver/publish/render-knockout.mjs +184 -31
  100. package/driver/publish/render.mjs +323 -93
  101. package/driver/publish/report-data.mjs +4 -1
  102. package/driver/publish/report-topbar.mjs +58 -0
  103. package/driver/publish/search-depth.mjs +133 -4
  104. package/driver/publish/templates/report.css +78 -4
  105. package/driver/publish/xlsx.mjs +20 -1
  106. package/driver/queue-order.mjs +2 -2
  107. package/driver/recording-agreement.mjs +1 -1
  108. package/driver/reference-score.mjs +1 -1
  109. package/driver/register-availability.mjs +2 -2
  110. package/driver/register-count.mjs +50 -5
  111. package/driver/register-coverage.mjs +161 -1
  112. package/driver/register-digest-record.mjs +236 -11
  113. package/driver/register-grant-vocabulary.mjs +1 -1
  114. package/driver/register-plan.mjs +189 -2
  115. package/driver/registry-fidelity.mjs +3 -3
  116. package/driver/repair-composers.mjs +1 -1
  117. package/driver/repair-contract.mjs +1 -1
  118. package/driver/replay-archive.mjs +6 -6
  119. package/driver/report-overview-record.mjs +2 -2
  120. package/driver/result-noun-fields.mjs +2 -2
  121. package/driver/run-economics.mjs +41 -10
  122. package/driver/run-requirements.mjs +173 -9
  123. package/driver/runner.mjs +5 -5
  124. package/driver/scope-facts.mjs +20 -5
  125. package/driver/scope-ledger.mjs +5 -5
  126. package/driver/search-policy.mjs +22 -12
  127. package/driver/skills/README.md +15 -15
  128. package/driver/skills/blind-frame/SKILL.md +2 -2
  129. package/driver/skills/case-law-citation/SKILL.md +4 -4
  130. package/driver/skills/case-law-citation/sources/eurlex.md +1 -1
  131. package/driver/skills/{prelim-common-law → clearance-common-law}/SKILL.md +22 -22
  132. package/driver/skills/{prelim-common-law → clearance-common-law}/perplexity-prompts.md +1 -1
  133. package/driver/skills/{prelim-register → clearance-register}/SKILL.md +10 -10
  134. package/driver/skills/{prelim-register → clearance-register}/digest.md +2 -2
  135. package/driver/skills/{prelim-register → clearance-register}/providers/README.md +1 -1
  136. package/driver/skills/{prelim-register → clearance-register}/providers/clarivate.md +37 -35
  137. package/driver/skills/{prelim-register → clearance-register}/providers/corsearch.md +20 -11
  138. package/driver/skills/{prelim-register → clearance-register}/providers/signa.md +5 -5
  139. package/driver/skills/{prelim-register → clearance-register}/register-recipes.md +3 -3
  140. package/driver/skills/{prelim-register → clearance-register}/status-rules.md +2 -2
  141. package/driver/skills/{prelim-register → clearance-register}/stealth-filer-indicators.md +1 -1
  142. package/driver/skills/{prelim-register → clearance-register}/unit.md +2 -2
  143. package/driver/skills/{prelim-search → clearance-search}/SKILL.md +31 -31
  144. package/driver/skills/{prelim-search → clearance-search}/delivery-contract.md +1 -1
  145. package/driver/skills/{prelim-search → clearance-search}/phase2-execution.md +18 -18
  146. package/driver/skills/{prelim-search → clearance-search}/synthesis-rules.md +7 -7
  147. package/driver/skills/{prelim-variants → clearance-variants}/SKILL.md +18 -18
  148. package/driver/skills/{prelim-variants → clearance-variants}/transliteration-scripts.md +5 -5
  149. package/driver/skills/frame-diff/SKILL.md +1 -1
  150. package/driver/skills/knockout-assess/SKILL.md +10 -7
  151. package/driver/skills/matter-frame/SKILL.md +3 -3
  152. package/driver/skills/narrative-refutation/SKILL.md +9 -9
  153. package/driver/skills/placement-inquiry/SKILL.md +5 -5
  154. package/driver/stage-context.mjs +1 -1
  155. package/driver/stages-knockout.mjs +4 -4
  156. package/driver/stages.mjs +65 -61
  157. package/driver/status-snapshot.mjs +2 -2
  158. package/driver/suite-census.json +340 -136
  159. package/driver/surface-exit-verdict.mjs +58 -0
  160. package/driver/systemd/README.md +9 -6
  161. package/driver/systemd/clearotron-worker.service +1 -1
  162. package/driver/terminal-clamp.mjs +109 -1
  163. package/driver/tokens.mjs +169 -3
  164. package/driver/unit-environment.mjs +42 -15
  165. package/driver/unit-inventory.mjs +19 -2
  166. package/driver/usage-ledger.mjs +1 -1
  167. package/driver/variant-manifest-model.mjs +4 -4
  168. package/driver/verify-knockout.mjs +27 -0
  169. package/driver/verify.mjs +94 -6
  170. package/driver/whatif-queue.mjs +1 -1
  171. package/driver/wordlists/en.txt +63906 -0
  172. package/mcp-server/CHANGELOG.md +8 -0
  173. package/mcp-server/README.md +1 -1
  174. package/mcp-server/lib/README.md +1 -1
  175. package/mcp-server/lib/options.mjs +8 -7
  176. package/mcp-server/lib/plan.mjs +18 -2
  177. package/mcp-server/lib/runs.mjs +1 -1
  178. package/mcp-server/lib/usage.mjs +3 -3
  179. package/mcp-server/lib/whatif.mjs +1 -1
  180. package/mcp-server/package.json +1 -1
  181. package/mcp-server/server.mjs +18 -1
  182. package/package.json +12 -11
  183. package/portal-ui/dist/assets/{index-CVOIvdhc.css → index-CtvwLCti.css} +207 -3
  184. package/portal-ui/dist/assets/{index-5UyqAyNM.js → index-EVaSo5-g.js} +1580 -527
  185. package/portal-ui/dist/index.html +2 -2
  186. package/portal-ui/package.json +1 -1
  187. package/providers/README.md +1 -1
  188. package/providers/_shared/enumerate.mjs +6 -6
  189. package/providers/_shared/execute-plan.mjs +3 -3
  190. package/providers/_shared/ledger.mjs +119 -5
  191. package/providers/_shared/provider-text.mjs +2 -2
  192. package/providers/_shared/screen.mjs +2 -2
  193. package/providers/_shared/script-form.mjs +3 -3
  194. package/providers/_shared/territory-codes.mjs +23 -3
  195. package/providers/clarivate/README.md +1 -1
  196. package/providers/clarivate/src/capabilities.js +12 -12
  197. package/providers/clarivate/src/core.js +37 -43
  198. package/providers/corsearch/README.md +1 -1
  199. package/providers/corsearch/src/capabilities.js +5 -5
  200. package/providers/corsearch/src/core.js +3 -3
  201. package/providers/jx/README.md +2 -1
  202. package/providers/jx/src/turn-envelope.mjs +8 -3
  203. package/providers/oauth-mcp-bridge/CHANGELOG.md +8 -0
  204. package/providers/oauth-mcp-bridge/package.json +1 -1
  205. package/providers/perplexity/src/core.js +1 -1
  206. package/providers/signa/README.md +1 -1
  207. package/providers/signa/src/capabilities.js +42 -49
  208. package/providers/signa/src/core.js +106 -29
  209. package/providers/uspto-local/README.md +1 -1
  210. package/providers/uspto-local/src/sync.js +1 -1
  211. package/scripts/README.md +1 -0
  212. package/scripts/ask-ai-render-check.mjs +127 -1
  213. package/scripts/authority-boundary-probe.mjs +8 -6
  214. package/scripts/backfill-started-at.mjs +2 -2
  215. package/scripts/census-merge-driver.mjs +33 -2
  216. package/scripts/citation-anchor-report.mjs +181 -0
  217. package/scripts/dead-names.mjs +1 -1
  218. package/scripts/deprecate-below.mjs +66 -8
  219. package/scripts/drain-preflight.mjs +1 -1
  220. package/scripts/e2e.mjs +174 -0
  221. package/scripts/env-audit.mjs +39 -6
  222. package/scripts/env-classify.mjs +20 -2
  223. package/scripts/freeze-example-run.mjs +61 -18
  224. package/scripts/generated-files-are-current.mjs +69 -4
  225. package/scripts/live-surface-check.mjs +124 -41
  226. package/scripts/markdown-link-check.mjs +1 -1
  227. package/scripts/merge-shape-check.mjs +242 -0
  228. package/scripts/mint-names-in-force.mjs +5 -5
  229. package/scripts/mint-offered-territories.mjs +72 -0
  230. package/scripts/mint-public-residue.mjs +2 -2
  231. package/scripts/mint-reference-strip-backlog.mjs +2 -2
  232. package/scripts/mint-suite-census.mjs +75 -2
  233. package/scripts/mint-writing-standard-backlog.mjs +2 -2
  234. package/scripts/purge-runs.mjs +7 -7
  235. package/scripts/reconcile-runs.mjs +2 -2
  236. package/scripts/release-approve-parked.mjs +20 -2
  237. package/scripts/release-await-cut.mjs +120 -1
  238. package/scripts/release-note-required.mjs +76 -8
  239. package/scripts/report-header-render-check.mjs +164 -0
  240. package/scripts/settings-render-check.mjs +75 -2
  241. package/scripts/test-full.mjs +96 -3
  242. package/scripts/test-run.mjs +10 -0
  243. package/shared/brand.mjs +27 -0
  244. package/shared/connect-clients.mjs +39 -11
  245. package/shared/deployment-box.mjs +7 -2
  246. package/shared/driver-dir.mjs +1 -1
  247. package/shared/env-aliases.mjs +1 -1
  248. package/shared/identifier-scan.mjs +65 -9
  249. package/shared/identifier-sentinels.mjs +22 -0
  250. package/shared/names-in-force.mjs +4 -2
  251. package/shared/offered-territories.json +738 -0
  252. package/shared/pre-rename-spellings.mjs +53 -0
  253. package/shared/reference-guard-classes.mjs +40 -2
  254. package/shared/stdio-connect.mjs +39 -4
  255. package/shared/tree-commit.mjs +48 -0
  256. /package/driver/skills/{prelim-register → clearance-register}/providers/euipo.md +0 -0
  257. /package/driver/skills/{prelim-register → clearance-register}/providers/free-tier.md +0 -0
  258. /package/driver/skills/{prelim-register → clearance-register}/providers/uspto-local.md +0 -0
  259. /package/driver/skills/{prelim-search → clearance-search}/field-doctrine-pharma.md +0 -0
  260. /package/driver/skills/{prelim-search → clearance-search}/firm-wide-reasoning.md +0 -0
  261. /package/driver/skills/{prelim-search → clearance-search}/report-prose.md +0 -0
  262. /package/driver/skills/{prelim-search → clearance-search}/risk-framework-demo.manifest.json +0 -0
  263. /package/driver/skills/{prelim-search → clearance-search}/risk-framework-demo.md +0 -0
  264. /package/driver/skills/{prelim-search → clearance-search}/risk-framework-triage.manifest.json +0 -0
  265. /package/driver/skills/{prelim-search → clearance-search}/risk-framework-triage.md +0 -0
  266. /package/driver/skills/{prelim-search → clearance-search}/risk-framework.manifest.json +0 -0
  267. /package/driver/skills/{prelim-search → clearance-search}/risk-framework.md +0 -0
  268. /package/driver/skills/{prelim-search → clearance-search}/template-formatting.md +0 -0
  269. /package/driver/skills/{prelim-search → clearance-search}/templates/email/generic.md +0 -0
  270. /package/driver/skills/{prelim-search → clearance-search}/templates/search-request-form.html +0 -0
  271. /package/driver/skills/{prelim-search → clearance-search}/worked-examples-demo.md +0 -0
  272. /package/driver/skills/{prelim-search → clearance-search}/worked-examples.md +0 -0
@@ -0,0 +1,51 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright 2026 Cordillera Sàrl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md
3
+ // ordinary-words.mjs — the impure edge of the one-letter neighbourhood rule: it reads the word list off disk.
4
+ //
5
+ // form-neighbourhood.mjs is PURE and takes the list as a Set; this is the one place that turns the file into
6
+ // that Set, so there is one reading of it and not one per caller. The file's own header states its source,
7
+ // its date and its licence; lines starting with `#` are that header and are skipped.
8
+ //
9
+ // A LIST THAT WILL NOT LOAD REMOVES NOTHING. The rule only ever takes queries away, so the safe failure is an
10
+ // empty Set — every neighbour searched, exactly as before the rule existed — and the caller is told, so the
11
+ // run record can say the rule did not apply rather than read as a mark with no ordinary-word neighbours.
12
+
13
+ import { readFileSync } from "node:fs";
14
+ import { dirname, join } from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+
17
+ const HERE = dirname(fileURLToPath(import.meta.url));
18
+
19
+ /** Where each language's list lives. English only; other markets add a file and a key. */
20
+ export const WORD_LIST_PATHS = Object.freeze({ en: join(HERE, "wordlists", "en.txt") });
21
+
22
+ /** Parse a list file's text into a Set of lowercase words. PURE. */
23
+ export function parseWordList(text) {
24
+ const out = new Set();
25
+ for (const line of String(text ?? "").split("\n")) {
26
+ const w = line.trim();
27
+ if (!w || w.startsWith("#")) continue;
28
+ out.add(w.toLowerCase());
29
+ }
30
+ return out;
31
+ }
32
+
33
+ const cache = new Map();
34
+
35
+ /**
36
+ * The ordinary-word Set for a language, read once per process.
37
+ * @returns {{ words: Set<string>, error: string|null }}
38
+ */
39
+ export function loadOrdinaryWords(lang = "en") {
40
+ if (cache.has(lang)) return cache.get(lang);
41
+ const p = WORD_LIST_PATHS[lang];
42
+ let r;
43
+ if (!p) r = { words: new Set(), error: `no word list for language "${lang}"` };
44
+ else {
45
+ try { r = { words: parseWordList(readFileSync(p, "utf8")), error: null }; }
46
+ catch (e) { r = { words: new Set(), error: `word list ${lang} unreadable: ${String(e?.message ?? e).slice(0, 120)}` }; }
47
+ if (!r.error && !r.words.size) r = { words: r.words, error: `word list ${lang} holds no words` };
48
+ }
49
+ cache.set(lang, r);
50
+ return r;
51
+ }
@@ -15,7 +15,7 @@
15
15
  // sendPending with no .sent, so a lost/given-up marker (or an overnight finish) is retried
16
16
  // on the prelim-outbox.timer cadence independent of heartbeat activeHours.
17
17
  //
18
- // TIGHT-LOOP INVARIANT (load-bearing): prelim-outbox.path is PathExistsGlob=…/prelim-outbox/*.pending —
18
+ // TIGHT-LOOP INVARIANT (load-bearing): prelim-outbox.path is PathExistsGlob=…/clearance-outbox/*.pending —
19
19
  // level-triggered, so a RETAINED marker re-triggers the service the moment it deactivates. The backoff
20
20
  // sidecars therefore live in <outbox>/backoff/ — a subdirectory the glob can never match (`*` does not
21
21
  // cross `/`, and "backoff" has no .pending suffix; inotify on the outbox dir doesn't recurse either) —
@@ -26,7 +26,7 @@
26
26
  // ("due" / "retry 300") — a broken helper must degrade to retried wakes, never to lost deliveries.
27
27
 
28
28
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
29
- import { join, basename } from "node:path";
29
+ import { join, basename } from "node:path"; import { studioDirFor } from "../shared/pre-rename-spellings.mjs";
30
30
  import { fileURLToPath } from "node:url";
31
31
  import { config } from "./driver.config.mjs";
32
32
  import { atomicWrite } from "./progress.mjs";
@@ -130,20 +130,35 @@ export function settleWake(agent, { code, stdout }, now = Date.now()) {
130
130
  // Which *.pending markers currently route to <agent>? Mirrors deliver-trigger.sh's grouping exactly: a
131
131
  // JSON packet carries an "agent" field; a legacy delivered marker's first-line body IS the agent id.
132
132
  export function markersForAgent(agent) {
133
- let names = [];
134
- try { names = readdirSync(config.outboxDir).filter((f) => f.endsWith(".pending")); } catch { return []; }
133
+ // BOTH DIRECTORIES, AND THE OLD ONE IS NOT OPTIONAL. The default outbox was renamed with the `clearance`
134
+ // identifier; a box that never pinned `CLEAROTRON_OUTBOX_DIR` still has markers under the old name.
135
+ // Reading only the new directory would leave them there for ever, and each one is a report a client
136
+ // is owed — with nothing to see, because an outbox nobody reads looks exactly like an empty one.
137
+ // Each marker keeps the path it was found at, so an ack removes the file that actually exists.
135
138
  const out = [];
136
- for (const file of names.sort()) {
137
- let raw;
138
- try { raw = readFileSync(join(config.outboxDir, file), "utf8"); } catch { continue; } // raced an ack — skip
139
- let who = null, kind = "delivered";
140
- if (raw.trimStart().startsWith("{")) {
141
- try { const j = JSON.parse(raw); who = j.agent != null ? String(j.agent) : null; kind = j.kind != null ? String(j.kind) : "delivered"; }
142
- catch { who = null; }
143
- } else {
144
- who = raw.split("\n")[0].trim();
139
+ // THE SECOND DIRECTORY IS SKIPPED WHEN IT IS THE FIRST ONE. The two accessors answered the same path
140
+ // once, and this loop then listed every marker twice — the same file handed out as two pieces of work,
141
+ // with the strike count that quarantines a stuck marker counting each wake twice. A guard rather than a
142
+ // dedupe at the end: two directories that are the same directory is a configuration fact worth costing
143
+ // nothing, and a dedupe would also hide a genuine duplicate filename across two real directories.
144
+ const seen = new Set();
145
+ for (const dir of [config.outboxDir, config.legacyOutboxDir]) {
146
+ if (!dir || seen.has(dir)) continue;
147
+ seen.add(dir);
148
+ let names = [];
149
+ try { names = readdirSync(dir).filter((f) => f.endsWith(".pending")); } catch { continue; }
150
+ for (const file of names.sort()) {
151
+ let raw;
152
+ try { raw = readFileSync(join(dir, file), "utf8"); } catch { continue; } // raced an ack — skip
153
+ let who = null, kind = "delivered";
154
+ if (raw.trimStart().startsWith("{")) {
155
+ try { const j = JSON.parse(raw); who = j.agent != null ? String(j.agent) : null; kind = j.kind != null ? String(j.kind) : "delivered"; }
156
+ catch { who = null; }
157
+ } else {
158
+ who = raw.split("\n")[0].trim();
159
+ }
160
+ if (who === agent) out.push({ file, path: join(dir, file), kind });
145
161
  }
146
- if (who === agent) out.push({ file, path: join(config.outboxDir, file), kind });
147
162
  }
148
163
  return out;
149
164
  }
@@ -188,7 +203,7 @@ function* eachRunDir() {
188
203
  let workspaces = [];
189
204
  try { workspaces = readdirSync(config.workspaceRoot).filter((n) => n.startsWith("workspace-")); } catch { return; }
190
205
  for (const ws of workspaces) {
191
- const studio = join(config.workspaceRoot, ws, "studio", "prelim-search");
206
+ const studio = studioDirFor(join(config.workspaceRoot, ws));
192
207
  let slugs = [];
193
208
  try { slugs = readdirSync(studio); } catch { continue; }
194
209
  for (const slug of slugs) {
@@ -311,7 +326,7 @@ export function rescanOwedRuns() {
311
326
  let workspaces = [];
312
327
  try { workspaces = readdirSync(config.workspaceRoot).filter((n) => n.startsWith("workspace-")); } catch { return dropped; }
313
328
  for (const ws of workspaces) {
314
- const studio = join(config.workspaceRoot, ws, "studio", "prelim-search");
329
+ const studio = studioDirFor(join(config.workspaceRoot, ws));
315
330
  let slugs = [];
316
331
  try { slugs = readdirSync(studio); } catch { continue; }
317
332
  for (const slug of slugs) {
@@ -2,7 +2,7 @@
2
2
  "name": "clearotron-driver",
3
3
  "private": true,
4
4
  "type": "module",
5
- "version": "0.3.2-beta.7",
5
+ "version": "0.3.2-beta.9",
6
6
  "license": "AGPL-3.0-only",
7
7
  "description": "Deterministic driver for the trademark clearance workflow: orchestration in code (fan-out, fan-in barrier, gating, retries); the model does judgment leaves only, through a reasoning CLI spawned per stage.",
8
8
  "engines": {
@@ -59,7 +59,7 @@
59
59
  "why": "a caption-only call renders 149B, clears the 120-char floor, and ships a SECTION OF THE CLIENT'S ONE REPORT without the 'Checks we ran' bullets, the methodology or the handling note. Traced: report-overview.md is the head of report.md (assembleReportMd() in pipeline.mjs) which renders to the HTML (publish/index.mjs:649 publishReport). The 'Only you can close these' register is NOT lost — it is code-built from findings.json under spec 64's 'code wins' ruling."
60
60
  },
61
61
  {
62
- "tool": "record_prelim_variants",
62
+ "tool": "record_clearance_variants",
63
63
  "fields": [
64
64
  "incumbent_classes",
65
65
  "watchlist_owners",
@@ -84,7 +84,7 @@
84
84
  "why": "the schema the seat is handed declares `fields` REQUIRED and acceptBlindFrame takes a call without it — the goods/on-field half of the cold threat model"
85
85
  },
86
86
  {
87
- "tool": "record_prelim_variants",
87
+ "tool": "record_clearance_variants",
88
88
  "fields": [
89
89
  "elements",
90
90
  "scope_ledger"
package/driver/phase0.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: AGPL-3.0-only
2
2
  // Copyright 2026 Cordillera Sàrl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md
3
3
  // Phase 0 — PURE CODE (no LLM): derive the slug, codename, run-dir, calendar date, and customer template.
4
- // Mirrors prelim-search/SKILL.md Phase 0 + Phase 1 slug derivation.
4
+ // Mirrors clearance-search/SKILL.md Phase 0 + Phase 1 slug derivation.
5
5
 
6
6
  import { existsSync, appendFileSync, readFileSync, mkdirSync } from "node:fs";
7
7
  import { join, dirname } from "node:path";
@@ -108,7 +108,7 @@ export function archiveDirFor({ slug, date, codename, archiveRoot = config.archi
108
108
 
109
109
  // ── — THE RUN KEY MUST BE UNIQUE IN THE SCOPE IT IS READ IN, NOT ONLY IN ITS OWN ROOT ────────
110
110
  //
111
- // `prelim-<slug>-<codename>-` is not just a directory name. It is the ONLY thing separating one run's
111
+ // `clearance-<slug>-<codename>-` is not just a directory name. It is the ONLY thing separating one run's
112
112
  // rows from another's in the shared call ledger, and `pipeline.mjs`'s screen gate reads that ledger to
113
113
  // build the fetched universe it judges goods-drops against:
114
114
  //
@@ -148,7 +148,7 @@ export function archiveDirFor({ slug, date, codename, archiveRoot = config.archi
148
148
  export const codenameRegistryPath = () => join(dirname(ledgerPath("call")), "run-codenames.jsonl");
149
149
 
150
150
  /**
151
- * Claim `prelim-<slug>-<codename>-` for this run, and report whether we got it.
151
+ * Claim `clearance-<slug>-<codename>-` for this run, and report whether we got it.
152
152
  *
153
153
  * FIRST WRITER WINS, decided by re-reading rather than by locking: append the claim, read every claim
154
154
  * back, and the earliest line for this slug+date+codename is the owner. Two runs that append in the same
@@ -73,7 +73,7 @@ import { envFrom } from "../shared/env-aliases.mjs"; // — resolves EITHER sp
73
73
  import { ownersOwedACheck, runOwnerChecks } from "./owner-use-check.mjs";
74
74
 
75
75
  const DRIVER_DIR = dirname(fileURLToPath(import.meta.url));
76
- export const TRIAGE_FRAMEWORK = "skills/prelim-search/risk-framework-triage.md";
76
+ export const TRIAGE_FRAMEWORK = "skills/clearance-search/risk-framework-triage.md";
77
77
 
78
78
  // sentinel/archive mirror pipeline.mjs's private helpers (cross-referenced there) — byte-faithful.
79
79
  const sentinel = (runDir, name, obj) => atomicWrite(join(runDir, name), JSON.stringify({ ts: new Date().toISOString(), ...obj }, null, 2) + "\n");
@@ -151,7 +151,7 @@ export function readBackLadder(ctx, sidecarPath, { minted }) { // exported for
151
151
  if (ladder.length) return;
152
152
  const detail = `${sidecarPath} does not read back as a band ladder, so knockoutAssessChunk's three band checks would pass every rating unchecked`;
153
153
  if (minted) throw new Error(`knockout_ladder_unreadable: ${detail} — the driver wrote this file itself from a parsed manifest, so this is a driver fault and no seat can fix it`);
154
- // THE RECORDING CANNOT BE WHAT STOPS THE RUN. `runLog` → `appendLine` (log.mjs:11) does an unguarded
154
+ // THE RECORDING CANNOT BE WHAT STOPS THE RUN. `runLog` → appendLine() in log.mjs (:11) does an unguarded
155
155
  // mkdirSync + appendFileSync: on EACCES or a full disk it THROWS. Everywhere else in the driver that is
156
156
  // the accepted behaviour, but not here — this branch exists precisely to keep a pre-existing run alive,
157
157
  // and a throw out of it would take down the run it is written to spare, for a reason unrelated to
@@ -250,7 +250,7 @@ async function koStage(name, ctx, { chunkNo = null, msgCtx = {} } = {}) {
250
250
  agent: ctx.agent,
251
251
  message: def.message({ ...ctx, K, chunkNo, ...msgCtx }),
252
252
  model, thinking: def.thinking,
253
- sessionKey: `prelim-${ctx.run.slug}-${ctx.run.codename}-${label}`,
253
+ sessionKey: `clearance-${ctx.run.slug}-${ctx.run.codename}-${label}`,
254
254
  timeoutSec: def.timeoutSec, stallSec: def.stallSec,
255
255
  expectFile: out, validate: def.validate, runDir: ctx.paths.runDir,
256
256
  });
@@ -494,7 +494,7 @@ export async function knockoutInner(ctx, job, opts = {}) {
494
494
  const caps = capabilitiesFor(REGISTER_PROVIDER);
495
495
  countExec = resolveCountExecutor({
496
496
  counter: opts?.countExecutor ?? null, adapter: registerAdapter,
497
- agentId: agent, sessionKey: `prelim-${run.slug}-${run.codename}`,
497
+ agentId: agent, sessionKey: `clearance-${run.slug}-${run.codename}`,
498
498
  recordLog: runRecordLogPath(run.runDir),
499
499
  // FROM THE JOB, not the environment. Whether this run calls a real register
500
500
  // is a fact about the run, so it arrives with the run and lands on its record.
@@ -684,7 +684,7 @@ export async function knockoutInner(ctx, job, opts = {}) {
684
684
  // Every failure lands as a recorded reason on the surfaces instead.
685
685
  const recExec = resolveRecordExecutor({
686
686
  lister: opts?.recordLister ?? null, adapter: activeProvider(),
687
- agentId: agent, sessionKey: `prelim-${run.slug}-${run.codename}`,
687
+ agentId: agent, sessionKey: `clearance-${run.slug}-${run.codename}`,
688
688
  // — this run's record log, not the box's. The knockout lane never reads the record bodies
689
689
  // its batch-screen hydration writes; before this they were pure growth on a global file.
690
690
  recordLog: runRecordLogPath(run.runDir),