clearotron 0.3.2-beta.8 → 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 (238) hide show
  1. package/.env.example +34 -3
  2. package/CONTRIBUTING.md +8 -8
  3. package/INSTALL.md +6 -6
  4. package/SECURITY.md +3 -3
  5. package/bin/brandowner.mjs +3 -3
  6. package/bin/framework-preflight.mjs +1 -1
  7. package/bin/start.mjs +18 -4
  8. package/build-info.json +2 -2
  9. package/docs/DELIVERY.md +2 -1
  10. package/docs/INTAKE.md +1 -1
  11. package/docs/ONBOARDING.md +1 -1
  12. package/docs/architecture/03-run-lifecycle.md +6 -6
  13. package/docs/architecture/04-configuration-reference.md +6 -3
  14. package/docs/architecture/05-config-governance.md +6 -1
  15. package/docs/architecture/05-customer-profiles.md +2 -2
  16. package/docs/architecture/06-operations-runbook.md +3 -3
  17. package/docs/architecture/08-development-guide.md +6 -6
  18. package/docs/configuration.md +5 -5
  19. package/docs/decisions/0003-credential-model.md +1 -1
  20. package/docs/writing-standard.md +4 -0
  21. package/driver/CHANGELOG.md +48 -0
  22. package/driver/README.md +3 -3
  23. package/driver/binding-layers.mjs +1 -1
  24. package/driver/citation-census.json +3 -3
  25. package/driver/{prelim-variants-record.mjs → clearance-variants-record.mjs} +24 -24
  26. package/driver/common-law-receipts.mjs +2 -2
  27. package/driver/company-bundle.mjs +3 -3
  28. package/driver/compose-read.mjs +8 -14
  29. package/driver/consumption-ledger.mjs +2 -2
  30. package/driver/contract-arm2-baseline.json +2 -3
  31. package/driver/contract-dictation-registry.mjs +19 -19
  32. package/driver/contract-e3-backlog.mjs +19 -19
  33. package/driver/contract-e3-baseline.json +14 -14
  34. package/driver/contract-vocabulary.mjs +24 -17
  35. package/driver/deliver-trigger.sh +16 -16
  36. package/driver/demo-container.mjs +3 -3
  37. package/driver/dev-portal.mjs +3 -3
  38. package/driver/disposition-call.mjs +1 -1
  39. package/driver/doubt-ledger.mjs +2 -2
  40. package/driver/drainer-identity.mjs +34 -8
  41. package/driver/driver.config.mjs +95 -45
  42. package/driver/engine/mcp/README.md +1 -1
  43. package/driver/engine/mcp/dispositions-server.mjs +3 -3
  44. package/driver/engine/mcp/gather-config.mjs +9 -9
  45. package/driver/engine/mcp/perplexity-server.mjs +2 -2
  46. package/driver/engine/mcp/recording-server.mjs +5 -5
  47. package/driver/enqueue-schema.mjs +6 -2
  48. package/driver/findings-model.mjs +5 -2
  49. package/driver/flag-snapshot.mjs +6 -3
  50. package/driver/form-neighbourhood.mjs +54 -7
  51. package/driver/framework.mjs +4 -4
  52. package/driver/gateway.mjs +12 -6
  53. package/driver/jx-lanes.mjs +2 -2
  54. package/driver/jx-units.mjs +1 -1
  55. package/driver/jx.mjs +30 -2
  56. package/driver/knockout-review-record.mjs +56 -4
  57. package/driver/known-conflicts.mjs +1 -1
  58. package/driver/named-band.mjs +1 -33
  59. package/driver/ordinary-words.mjs +51 -0
  60. package/driver/outbox-backoff.mjs +31 -16
  61. package/driver/package.json +1 -1
  62. package/driver/partial-payload-baseline.json +2 -2
  63. package/driver/phase0.mjs +3 -3
  64. package/driver/pipeline-knockout.mjs +5 -5
  65. package/driver/pipeline.mjs +206 -68
  66. package/driver/placement-form.mjs +77 -1
  67. package/driver/placement-model.mjs +1 -1
  68. package/driver/portal-report.mjs +92 -5
  69. package/driver/portal-service.mjs +34 -8
  70. package/driver/portal-upstream.mjs +1 -1
  71. package/driver/preserve-merge.mjs +3 -3
  72. package/driver/product-rows.mjs +2 -2
  73. package/driver/products.mjs +1 -1
  74. package/driver/profiles/README.md +3 -3
  75. package/driver/profiles/demo-brand-owner.json +2 -2
  76. package/driver/profiles.mjs +55 -17
  77. package/driver/progress.mjs +18 -8
  78. package/driver/provider-usage.mjs +8 -8
  79. package/driver/publish/index.mjs +110 -5
  80. package/driver/publish/knockout.mjs +29 -4
  81. package/driver/publish/pool-admin.mjs +1 -1
  82. package/driver/publish/publish-inputs.mjs +18 -2
  83. package/driver/publish/render-knockout.mjs +115 -24
  84. package/driver/publish/render.mjs +153 -34
  85. package/driver/publish/search-depth.mjs +133 -4
  86. package/driver/publish/templates/report.css +60 -3
  87. package/driver/publish/xlsx.mjs +8 -1
  88. package/driver/queue-order.mjs +2 -2
  89. package/driver/recording-agreement.mjs +1 -1
  90. package/driver/reference-score.mjs +1 -1
  91. package/driver/register-count.mjs +50 -5
  92. package/driver/register-coverage.mjs +67 -0
  93. package/driver/register-grant-vocabulary.mjs +1 -1
  94. package/driver/register-plan.mjs +19 -2
  95. package/driver/registry-fidelity.mjs +3 -3
  96. package/driver/repair-composers.mjs +1 -1
  97. package/driver/repair-contract.mjs +1 -1
  98. package/driver/replay-archive.mjs +6 -6
  99. package/driver/report-overview-record.mjs +2 -2
  100. package/driver/run-requirements.mjs +3 -3
  101. package/driver/runner.mjs +2 -2
  102. package/driver/scope-facts.mjs +20 -5
  103. package/driver/scope-ledger.mjs +5 -5
  104. package/driver/search-policy.mjs +22 -12
  105. package/driver/skills/README.md +15 -15
  106. package/driver/skills/blind-frame/SKILL.md +2 -2
  107. package/driver/skills/case-law-citation/SKILL.md +4 -4
  108. package/driver/skills/case-law-citation/sources/eurlex.md +1 -1
  109. package/driver/skills/{prelim-common-law → clearance-common-law}/SKILL.md +22 -22
  110. package/driver/skills/{prelim-common-law → clearance-common-law}/perplexity-prompts.md +1 -1
  111. package/driver/skills/{prelim-register → clearance-register}/SKILL.md +10 -10
  112. package/driver/skills/{prelim-register → clearance-register}/digest.md +2 -2
  113. package/driver/skills/{prelim-register → clearance-register}/providers/README.md +1 -1
  114. package/driver/skills/{prelim-register → clearance-register}/providers/clarivate.md +37 -35
  115. package/driver/skills/{prelim-register → clearance-register}/providers/corsearch.md +20 -11
  116. package/driver/skills/{prelim-register → clearance-register}/providers/signa.md +5 -5
  117. package/driver/skills/{prelim-register → clearance-register}/register-recipes.md +3 -3
  118. package/driver/skills/{prelim-register → clearance-register}/status-rules.md +2 -2
  119. package/driver/skills/{prelim-register → clearance-register}/stealth-filer-indicators.md +1 -1
  120. package/driver/skills/{prelim-register → clearance-register}/unit.md +2 -2
  121. package/driver/skills/{prelim-search → clearance-search}/SKILL.md +31 -31
  122. package/driver/skills/{prelim-search → clearance-search}/delivery-contract.md +1 -1
  123. package/driver/skills/{prelim-search → clearance-search}/phase2-execution.md +18 -18
  124. package/driver/skills/{prelim-search → clearance-search}/synthesis-rules.md +7 -7
  125. package/driver/skills/{prelim-variants → clearance-variants}/SKILL.md +18 -18
  126. package/driver/skills/{prelim-variants → clearance-variants}/transliteration-scripts.md +5 -5
  127. package/driver/skills/frame-diff/SKILL.md +1 -1
  128. package/driver/skills/knockout-assess/SKILL.md +10 -7
  129. package/driver/skills/matter-frame/SKILL.md +3 -3
  130. package/driver/skills/narrative-refutation/SKILL.md +9 -9
  131. package/driver/skills/placement-inquiry/SKILL.md +5 -5
  132. package/driver/stage-context.mjs +1 -1
  133. package/driver/stages-knockout.mjs +4 -4
  134. package/driver/stages.mjs +53 -53
  135. package/driver/status-snapshot.mjs +2 -2
  136. package/driver/suite-census.json +218 -92
  137. package/driver/surface-exit-verdict.mjs +58 -0
  138. package/driver/systemd/README.md +2 -2
  139. package/driver/systemd/clearotron-worker.service +1 -1
  140. package/driver/terminal-clamp.mjs +2 -0
  141. package/driver/usage-ledger.mjs +1 -1
  142. package/driver/variant-manifest-model.mjs +4 -4
  143. package/driver/verify-knockout.mjs +27 -0
  144. package/driver/verify.mjs +67 -6
  145. package/driver/whatif-queue.mjs +1 -1
  146. package/driver/wordlists/en.txt +63906 -0
  147. package/mcp-server/CHANGELOG.md +4 -0
  148. package/mcp-server/README.md +1 -1
  149. package/mcp-server/lib/README.md +1 -1
  150. package/mcp-server/lib/options.mjs +8 -7
  151. package/mcp-server/lib/plan.mjs +18 -2
  152. package/mcp-server/lib/runs.mjs +1 -1
  153. package/mcp-server/lib/usage.mjs +3 -3
  154. package/mcp-server/lib/whatif.mjs +1 -1
  155. package/mcp-server/package.json +1 -1
  156. package/mcp-server/server.mjs +3 -0
  157. package/package.json +12 -11
  158. package/portal-ui/dist/assets/{index-CVOIvdhc.css → index-CtvwLCti.css} +207 -3
  159. package/portal-ui/dist/assets/{index-6jzO9HiX.js → index-EVaSo5-g.js} +1459 -482
  160. package/portal-ui/dist/index.html +2 -2
  161. package/portal-ui/package.json +1 -1
  162. package/providers/README.md +1 -1
  163. package/providers/_shared/enumerate.mjs +6 -6
  164. package/providers/_shared/execute-plan.mjs +3 -3
  165. package/providers/_shared/ledger.mjs +119 -5
  166. package/providers/_shared/provider-text.mjs +2 -2
  167. package/providers/_shared/screen.mjs +2 -2
  168. package/providers/_shared/script-form.mjs +3 -3
  169. package/providers/_shared/territory-codes.mjs +23 -3
  170. package/providers/clarivate/README.md +1 -1
  171. package/providers/clarivate/src/capabilities.js +12 -12
  172. package/providers/clarivate/src/core.js +37 -43
  173. package/providers/corsearch/README.md +1 -1
  174. package/providers/corsearch/src/capabilities.js +5 -5
  175. package/providers/corsearch/src/core.js +3 -3
  176. package/providers/oauth-mcp-bridge/CHANGELOG.md +4 -0
  177. package/providers/oauth-mcp-bridge/package.json +1 -1
  178. package/providers/perplexity/src/core.js +1 -1
  179. package/providers/signa/README.md +1 -1
  180. package/providers/signa/src/capabilities.js +42 -49
  181. package/providers/signa/src/core.js +106 -29
  182. package/providers/uspto-local/src/sync.js +1 -1
  183. package/scripts/README.md +1 -0
  184. package/scripts/ask-ai-render-check.mjs +127 -1
  185. package/scripts/authority-boundary-probe.mjs +4 -4
  186. package/scripts/backfill-started-at.mjs +2 -2
  187. package/scripts/census-merge-driver.mjs +33 -2
  188. package/scripts/citation-anchor-report.mjs +181 -0
  189. package/scripts/dead-names.mjs +1 -1
  190. package/scripts/deprecate-below.mjs +66 -8
  191. package/scripts/drain-preflight.mjs +1 -1
  192. package/scripts/e2e.mjs +174 -0
  193. package/scripts/env-audit.mjs +27 -0
  194. package/scripts/env-classify.mjs +20 -2
  195. package/scripts/freeze-example-run.mjs +20 -10
  196. package/scripts/live-surface-check.mjs +124 -41
  197. package/scripts/markdown-link-check.mjs +1 -1
  198. package/scripts/merge-shape-check.mjs +242 -0
  199. package/scripts/mint-names-in-force.mjs +5 -5
  200. package/scripts/mint-offered-territories.mjs +72 -0
  201. package/scripts/mint-public-residue.mjs +2 -2
  202. package/scripts/mint-reference-strip-backlog.mjs +2 -2
  203. package/scripts/mint-suite-census.mjs +75 -2
  204. package/scripts/mint-writing-standard-backlog.mjs +2 -2
  205. package/scripts/purge-runs.mjs +7 -7
  206. package/scripts/reconcile-runs.mjs +2 -2
  207. package/scripts/release-approve-parked.mjs +20 -2
  208. package/scripts/release-await-cut.mjs +120 -1
  209. package/scripts/release-note-required.mjs +76 -8
  210. package/scripts/report-header-render-check.mjs +164 -0
  211. package/shared/brand.mjs +27 -0
  212. package/shared/connect-clients.mjs +39 -11
  213. package/shared/env-aliases.mjs +1 -1
  214. package/shared/identifier-scan.mjs +65 -9
  215. package/shared/identifier-sentinels.mjs +22 -0
  216. package/shared/names-in-force.mjs +3 -1
  217. package/shared/offered-territories.json +738 -0
  218. package/shared/pre-rename-spellings.mjs +53 -0
  219. package/shared/reference-guard-classes.mjs +40 -2
  220. package/shared/stdio-connect.mjs +39 -4
  221. package/shared/tree-commit.mjs +48 -0
  222. /package/driver/skills/{prelim-register → clearance-register}/providers/euipo.md +0 -0
  223. /package/driver/skills/{prelim-register → clearance-register}/providers/free-tier.md +0 -0
  224. /package/driver/skills/{prelim-register → clearance-register}/providers/uspto-local.md +0 -0
  225. /package/driver/skills/{prelim-search → clearance-search}/field-doctrine-pharma.md +0 -0
  226. /package/driver/skills/{prelim-search → clearance-search}/firm-wide-reasoning.md +0 -0
  227. /package/driver/skills/{prelim-search → clearance-search}/report-prose.md +0 -0
  228. /package/driver/skills/{prelim-search → clearance-search}/risk-framework-demo.manifest.json +0 -0
  229. /package/driver/skills/{prelim-search → clearance-search}/risk-framework-demo.md +0 -0
  230. /package/driver/skills/{prelim-search → clearance-search}/risk-framework-triage.manifest.json +0 -0
  231. /package/driver/skills/{prelim-search → clearance-search}/risk-framework-triage.md +0 -0
  232. /package/driver/skills/{prelim-search → clearance-search}/risk-framework.manifest.json +0 -0
  233. /package/driver/skills/{prelim-search → clearance-search}/risk-framework.md +0 -0
  234. /package/driver/skills/{prelim-search → clearance-search}/template-formatting.md +0 -0
  235. /package/driver/skills/{prelim-search → clearance-search}/templates/email/generic.md +0 -0
  236. /package/driver/skills/{prelim-search → clearance-search}/templates/search-request-form.html +0 -0
  237. /package/driver/skills/{prelim-search → clearance-search}/worked-examples-demo.md +0 -0
  238. /package/driver/skills/{prelim-search → clearance-search}/worked-examples.md +0 -0
@@ -1,11 +1,11 @@
1
1
  ---
2
- name: prelim-register
3
- description: Register-side execution for the v3 preliminary trademark search workflow. **Invoked exclusively by the `prelim-search` orchestrator** — do not call directly. Runs in one of two modes the orchestrator selects via the spawn task. **Unit mode (the FUNNEL — Layer A):** execute ONE register search axis (saturation / primary-sweep / transliteration-numeric / incumbent-class) against the variant manifest — ENUMERATE each named query to completion via `register_enumerate` (the completeness primitive that owns the page loop), describe saturation crowds as count-only incomplete descriptors, and write the COMPLETE NAMED BAND (`register-units/<axis>-band.json`) carrying every record with its status; the funnel decides NOTHING about relevance / sufficiency / prioritisation and never samples or self-accepts; only the raw character-noise pile dies in this session. **Digest mode (judgment — Layer B):** read the complete merged band through the band tools (`band_shape` / `band_lookup` / `band_record` — every call on the run's reading audit; never by slicing band files), run the cross-cutting judgment (relevance, identical-match + cross-class merchandising, owner aggregation, watchlists, stealth-filer + Option-D cross-checks, opposition), decide sufficiency, and hand the register-side findings back as typed rows — the driver renders the document the orchestrator synthesises from; the seat writes no file.
2
+ name: clearance-register
3
+ description: Register-side execution for the v3 preliminary trademark search workflow. **Invoked exclusively by the `clearance-search` orchestrator** — do not call directly. Runs in one of two modes the orchestrator selects via the spawn task. **Unit mode (the FUNNEL — Layer A):** execute ONE register search axis (saturation / primary-sweep / transliteration-numeric / incumbent-class) against the variant manifest — ENUMERATE each named query to completion via `register_enumerate` (the completeness primitive that owns the page loop), describe saturation crowds as count-only incomplete descriptors, and write the COMPLETE NAMED BAND (`register-units/<axis>-band.json`) carrying every record with its status; the funnel decides NOTHING about relevance / sufficiency / prioritisation and never samples or self-accepts; only the raw character-noise pile dies in this session. **Digest mode (judgment — Layer B):** read the complete merged band through the band tools (`band_shape` / `band_lookup` / `band_record` — every call on the run's reading audit; never by slicing band files), run the cross-cutting judgment (relevance, identical-match + cross-class merchandising, owner aggregation, watchlists, stealth-filer + Option-D cross-checks, opposition), decide sufficiency, and hand the register-side findings back as typed rows — the driver renders the document the orchestrator synthesises from; the seat writes no file.
4
4
  ---
5
5
 
6
6
  ## Spawned session
7
7
 
8
- Invoked from `prelim-search` (the orchestrator) as an **isolated depth-2 worker**, in one of two
8
+ Invoked from `clearance-search` (the orchestrator) as an **isolated depth-2 worker**, in one of two
9
9
  modes. **This skill never spawns sub-agents** — the orchestrator owns all dispatch. (This is
10
10
  deliberate: the announce/completion chain supports one nesting level — `main → orchestrator →
11
11
  workers` — so every register worker is a flat depth-2 sibling of the common-law worker, not a nested
@@ -26,16 +26,16 @@ Two modes, chosen by the orchestrator and stated in the spawn `task`:
26
26
  band. The worker reads that COMPLETE band **through the band tools** (`band_shape` first, then
27
27
  `band_lookup` / `band_record` — every call lands in the reading audit; never by opening or slicing band
28
28
  files), performs all cross-cutting judgment (relevance, owner aggregation, opposition, Option-D),
29
- DECIDES SUFFICIENCY, and writes `studio/prelim-search/<slug>/<date>/register-findings.md`.
29
+ DECIDES SUFFICIENCY, and writes `studio/clearance-search/<slug>/<date>/register-findings.md`.
30
30
 
31
- Reads (both modes): the variant manifest at `studio/prelim-search/<slug>/<date>/variant-manifest.md` (archetype + risk
32
- theory), the `matter-context.md` at `studio/prelim-search/<slug>/<date>/matter-context.md` (Phase 0 strategic anchor — names materially-matters jurisdictions, watchlist-owner seeds, off-field sectors), the request context, the active **provider**. The **watchlist-owner seeds are enrichment / additive-surfacing context, not a search or priority filter** — an in-class identical/near-identical incumbent surfaces on field-relevance alone whether or not its owner is named (see `digest.md` Step 5).
31
+ Reads (both modes): the variant manifest at `studio/clearance-search/<slug>/<date>/variant-manifest.md` (archetype + risk
32
+ theory), the `matter-context.md` at `studio/clearance-search/<slug>/<date>/matter-context.md` (Phase 0 strategic anchor — names materially-matters jurisdictions, watchlist-owner seeds, off-field sectors), the request context, the active **provider**. The **watchlist-owner seeds are enrichment / additive-surfacing context, not a search or priority filter** — an in-class identical/near-identical incumbent surfaces on field-relevance alone whether or not its owner is named (see `digest.md` Step 5).
33
33
 
34
- **Digest mode also reads**: `placement-recommendations.md` at `studio/prelim-search/<slug>/<date>/placement-recommendations.md` (Touchpoint 2 per-candidate placements — informs digest tiering), and its structured mirror `placements.json` beside it (one `{mark, owner, jurisdiction, records, tier, reason}` entry per candidate; when present, the authoritative per-candidate tier record — the md carries the rulings tail as prose).
34
+ **Digest mode also reads**: `placement-recommendations.md` at `studio/clearance-search/<slug>/<date>/placement-recommendations.md` (Touchpoint 2 per-candidate placements — informs digest tiering), and its structured mirror `placements.json` beside it (one `{mark, owner, jurisdiction, records, tier, reason}` entry per candidate; when present, the authoritative per-candidate tier record — the md carries the rulings tail as prose).
35
35
 
36
36
  Writes:
37
- - Unit mode — TWO artifacts, both gate-checked, neither optional. `studio/prelim-search/<slug>/<date>/register-units/<axis>.md` is the stage's DECLARED OUTPUT: the driver fails the pass outright when it is absent, and the digest worker reads it as an input. `studio/prelim-search/<slug>/<date>/register-units/<axis>-band.json` is the COMPLETE named band — a JSON array of `enumerated` / `incomplete` blocks (see `unit.md` → *Named-band artifact*) — carrying every record and no clearance verdict. The md narrates and proves nothing on its own: an md narrating a completed sweep while the band its plan entries call for is missing is refused as `named_band_missing`. In plan mode `register_execute_plan` writes the band itself and you never hand-write its blocks.
38
- - Digest mode: `studio/prelim-search/<slug>/<date>/register-findings.md`. Coverage statuses are NOT a file you write: they ride the `record_coverage` tool into a driver-held record, and the driver renders the `## Coverage ledger` table and its JSON mirror from it (see *Coverage ledger* below and `digest.md` → *Coverage ledger*). Optional: `register-details/` snapshots inside the run-dir.
37
+ - Unit mode — TWO artifacts, both gate-checked, neither optional. `studio/clearance-search/<slug>/<date>/register-units/<axis>.md` is the stage's DECLARED OUTPUT: the driver fails the pass outright when it is absent, and the digest worker reads it as an input. `studio/clearance-search/<slug>/<date>/register-units/<axis>-band.json` is the COMPLETE named band — a JSON array of `enumerated` / `incomplete` blocks (see `unit.md` → *Named-band artifact*) — carrying every record and no clearance verdict. The md narrates and proves nothing on its own: an md narrating a completed sweep while the band its plan entries call for is missing is refused as `named_band_missing`. In plan mode `register_execute_plan` writes the band itself and you never hand-write its blocks.
38
+ - Digest mode: `studio/clearance-search/<slug>/<date>/register-findings.md`. Coverage statuses are NOT a file you write: they ride the `record_coverage` tool into a driver-held record, and the driver renders the `## Coverage ledger` table and its JSON mirror from it (see *Coverage ledger* below and `digest.md` → *Coverage ledger*). Optional: `register-details/` snapshots inside the run-dir.
39
39
 
40
40
  Returns to the orchestrator: your **final session message** — a 2–3 line summary (counts + the
41
41
  absolute path of the file you wrote). Keep raw character-noise records out of the message and out of any
@@ -50,7 +50,7 @@ Companion files:
50
50
 
51
51
  ## Trigger
52
52
 
53
- Called by `prelim-search` after `prelim-variants` has produced the manifest. The orchestrator spawns
53
+ Called by `clearance-search` after `clearance-variants` has produced the manifest. The orchestrator spawns
54
54
  the unit-mode workers and the common-law worker together, then spawns the digest-mode worker once the
55
55
  unit digests exist. Not invoked directly by operators.
56
56
 
@@ -1,4 +1,4 @@
1
- # prelim-register — MODE B (DIGEST)
1
+ # clearance-register — MODE B (DIGEST)
2
2
 
3
3
  > Read `SKILL.md` first (the shared spine). This file is the DIGEST-mode procedure + the register-findings output format. **Do NOT read `unit.md`.**
4
4
 
@@ -470,7 +470,7 @@ for the same URI across fields or sources, OR an EUIPO cross-check disagrees wit
470
470
  owner identity, OR a portfolio-size signal (many filings clustering under a normalised owner) would
471
471
  materially change the enforcement-appetite read, do NOT silently pick one. Surface both readings in the
472
472
  findings row and set `Verify? ✅` with reason "owner-identity conflict — confirm before enforcement
473
- read." Owner identity drives enforcer-profiling (see `prelim-search/firm-wide-reasoning.md`, *Enforcer profiling*
473
+ read." Owner identity drives enforcer-profiling (see `clearance-search/firm-wide-reasoning.md`, *Enforcer profiling*
474
474
  rule) — a wrong owner is a wrong risk read.
475
475
 
476
476
  ### Step 4 — Proactive competitor + aggressive-enforcer sweep
@@ -10,7 +10,7 @@ This boundary is enforced by `test/provider-neutral-prose.test.mjs` — it fails
10
10
 
11
11
  ```bash
12
12
  # manual equivalent
13
- grep -rnE "corsearch_|clarivate_|signa_" ../../prelim-{register,variants,search}/*.md
13
+ grep -rnE "corsearch_|clarivate_|signa_" ../../clearance-{register,variants,search}/*.md
14
14
  # should return zero hits OUTSIDE this providers/ directory
15
15
  ```
16
16
 
@@ -44,35 +44,37 @@ claimed. Booleans, parentheses and wildcards are parsed **inside `searchFields[]
44
44
 
45
45
  | `match_mode` | Field + value shape | Semantics | Probe |
46
46
  |---|---|---|---|
47
- | `default` | `WORD_MARK_SPECIFICATION` = `*TERM*` | **A TRUE CONTAINS** — the substring band | `*NIK*` = 806 |
48
- | `exact` | `EXACT_WORD_MARK_SPECIFICATION` = `TERM` | Full-string, case-insensitive, **punctuation-sensitive** (punctuation is stripped client-side for you) | `NIKE` = 34 on CH |
49
- | `wildcard` | `WORD_MARK_SPECIFICATION` = your pattern, untouched | `*` and `?` are native | `NIK*` = 128, `*NIKE` = 36, `NIK?` = 48 |
50
- | `starts_with` | `WORD_MARK_SPECIFICATION` = `TERM*` | prefix | `NIK*` = 128 |
51
- | `ends_with` | `WORD_MARK_SPECIFICATION` = `*TERM` | suffix | `*NIKE` = 36 |
47
+ | `default` | `WORD_MARK_SPECIFICATION` = `*TERM*` | **A TRUE CONTAINS** — the substring band | `*TERM*` |
48
+ | `exact` | `EXACT_WORD_MARK_SPECIFICATION` = `TERM` | Full-string, case-insensitive, **punctuation-sensitive** (punctuation is stripped client-side for you) | `TERM` |
49
+ | `wildcard` | `WORD_MARK_SPECIFICATION` = your pattern, untouched | `*` and `?` are native | `TERM*`, `*TERM`, `TER?` |
50
+ | `starts_with` | `WORD_MARK_SPECIFICATION` = `TERM*` | prefix | `TERM*` |
51
+ | `ends_with` | `WORD_MARK_SPECIFICATION` = `*TERM` | suffix | `*TERM` |
52
52
  | `phonetic` | `PHONETIC_WORD_MARK_SPECIFICATION` = `TERM` | Native server-side sound-alike. Opaque — no variant list. | — |
53
53
 
54
54
  `contains` is accepted as an alias of `default` and produces the identical query. There is no separate
55
55
  "contains mode" to reach for any more.
56
56
 
57
- **Booleans are explicit and native.** `"NIKE OR ADIDAS"` = 38 = 34 + 4 exactly. `AND` works. `NOT` works
58
- (`"NIK* NOT NIKE"` = 94 = 128 − 34). Parentheses group. Regex is not supported (`/NIK./` = 0) despite
59
- what the field description hints.
57
+ **Booleans are explicit and native**, and they are evaluated as real set operations rather than as text.
58
+ An `OR` stack answers the union of its legs — on two names that share no marks that is the two totals
59
+ added, and on names that overlap it is less, because nothing is counted twice. `AND` and `NOT` compose the
60
+ same way. Parentheses group. Regex is not supported despite what the field description hints: a regex
61
+ value matches nothing rather than erroring.
60
62
 
61
- **Multi-word terms work — pass them normally.** A bare space is an implicit *AND*
62
- (`*KESTREL BEVERAGE*` = `*KESTREL* AND *BEVERAGE*` = 75, and it is order-blind: `*CORAL PUP*` =
63
- `*PUP CORAL*` = 11), so the tool compiles your phrase to the **ADJ** adjacency operator instead —
64
- `*CORAL ADJ PUP*`, an ordered phrase match (11 hits; reversed = 0). You write the term the way a
63
+ **Multi-word terms work — pass them normally.** A bare space is an implicit *AND*, and it is order-blind,
64
+ so the tool compiles your phrase to the **ADJ** adjacency operator instead — an ordered phrase match,
65
+ which matches only the order you write it in. You write the term the way a
65
66
  lawyer would say it; the tool does the translation. This applies to `default`/`contains`/`wildcard`/
66
67
  `starts_with`/`ends_with`/`phonetic` alike.
67
68
 
68
69
  Two things to know when you read the results:
69
70
 
70
71
  - **A multi-word `starts_with`/`ends_with` is not anchored.** No string anchor exists on this provider
71
- (`BEGINS_WITH "ALPINE SPRING"` = 9 vs the phrase's 7), so it runs as a phrase-*contains* — a superset
72
- of what you asked. Extra hits, never fewer. Screen them as usual.
72
+ (`BEGINS_WITH` on a multi-word value degrades to a per-token AND, which is a superset of the ordered
73
+ phrase), so it runs as a phrase-*contains* — a superset of what you asked. Extra hits, never fewer.
74
+ Screen them as usual.
73
75
  - **`exact` is still the tightest read** — `EXACT_WORD_MARK_SPECIFICATION` is an ordered whole-string
74
- match ("KESTREL BEVERAGE" = 4, "BEVERAGE KESTREL" = 0). Use it when you want the mark itself, not the
75
- neighbourhood.
76
+ match — the whole string as written, so the same words in another order are a different string. Use it
77
+ when you want the mark itself, not the neighbourhood.
76
78
 
77
79
  **A term you pass is never silently re-parsed.** Parentheses, or (outside `wildcard`) a stray `*`/`?`,
78
80
  are **REJECTED** with a plain-English error and the slice defers — there is no escape syntax for those.
@@ -80,9 +82,9 @@ An operator word *inside* a phrase is handled for you: "BLACK AND DECKER" goes o
80
82
  `*BLACK ADJ A?D ADJ DECKER*` (the `?` stops the parser reading AND as an operator). The one term that
81
83
  still defers is a bare two-letter operator word — `OR` alone has no interior character to wildcard.
82
84
 
83
- `names[]` (an OR-stack) becomes ONE value joined with explicit ` OR `. The safe width is **500 terms**
84
- (80/200/500 all fine; 1000 → HTTP 500 *"Document nesting depth (1001) exceeds the maximum allowed"*).
85
- `register_enumerate` chunks wider stacks for you at that bound.
85
+ `names[]` (an OR-stack) becomes ONE value joined with explicit ` OR `. The safe width is **500 terms** —
86
+ the bound is the JSON parser's document-nesting cap, which the register names in the refusal it answers a
87
+ wider stack with. `register_enumerate` chunks wider stacks for you at that bound.
86
88
 
87
89
  ## Filters
88
90
 
@@ -99,8 +101,8 @@ still defers is a bare two-letter operator word — `OR` alone has no interior c
99
101
 
100
102
  ### Multi-class is ONE call — the fan-out is gone
101
103
 
102
- `INT_CLASS_NUMBER` value `"9 OR 28 OR 41 OR 42"` returns **18** — identical to the deduplicated union of
103
- four per-class calls (`"9,28,41,42"` also = 18). The old per-class fan-out and its `warnings[]` cost
104
+ `INT_CLASS_NUMBER` value `"9 OR 28 OR 41 OR 42"` returns the deduplicated union of what four per-class
105
+ calls returned — the comma form `"9,28,41,42"` is the same. The old per-class fan-out and its `warnings[]` cost
104
106
  breakdown have been **deleted from the core**. N classes cost one call; budget accordingly, and ignore
105
107
  any older guidance that told you to size a class fan-out.
106
108
 
@@ -113,8 +115,8 @@ becomes a `deferred` coverage row — it is never quietly dropped from the filte
113
115
 
114
116
  ### Owner search — resolve first, and never emit CONTAINS
115
117
 
116
- `APPLICANT_NAME` supports `EQUALS` (156 hits), `BEGINS_WITH` (159), wildcards (`"NIKE*"` with EQUALS =
117
- 159, i.e. equivalent to BEGINS_WITH), and `OR`. **`CONTAINS` is a hard HTTP 400** —
118
+ `APPLICANT_NAME` supports `EQUALS`, `BEGINS_WITH`, wildcards (a trailing `*` with EQUALS is equivalent to
119
+ `BEGINS_WITH`), and `OR`. **`CONTAINS` is a hard HTTP 400** —
118
120
  *"Operator CONTAINS is not supported for search field APPLICANT_NAME"* — and is never emitted anywhere.
119
121
 
120
122
  This provider has something Corsearch does not: **`POST /resolution/company`** returns confidence-scored
@@ -125,13 +127,12 @@ a narrower one. The result carries an `owner_resolution` note; cite it when the
125
127
 
126
128
  ## Completeness, crowds and the ceiling
127
129
 
128
- `/search` has **no pagination** and needs none: it returns the whole guid set (128 guids for a count of
129
- 128; 806 for 806). Past 30 000 it **fails loud**: HTTP 400 *"tooManyResults — The search returned 209012
130
- results. Maximum number of results is 30000."*
130
+ `/search` has **no pagination** and needs none: it returns one guid for every hit the count reports, at
131
+ any size below the ceiling. **The ceiling is 30 000**, and past it the search **fails loud** with a
132
+ `tooManyResults` HTTP 400 naming that maximum and how many results the search reached.
131
133
 
132
134
  `register_enumerate` therefore probes `POST /count` first. `/count` is cheap, takes the same body, works
133
- at **any** magnitude, and returns per-office counts in one call
134
- (`{"counts":{"CH":34,"EM":60,"WO":7,"CN":14345,"GB":91,"US":138}}`).
135
+ at **any** magnitude, and returns a `counts` object keyed by office code in one call.
135
136
 
136
137
  **A `tooManyResults` / over-ceiling band is `state:"incomplete"` — a CROWD DESCRIPTOR, never an error and
137
138
  never a clean negative.** It is dilution the lawyer reads. On this provider the crowd block also carries
@@ -156,7 +157,7 @@ identical-match is class-agnostic.
156
157
 
157
158
  ## Records — `register_record_fetch` / `register_batch_screen`
158
159
 
159
- `/text` takes **exactly 100 ids** per call (101+ → HTTP 400); the adapter chunks at 100. Response splits
160
+ `/text` takes **exactly 100 ids** per call and refuses a longer list; the adapter chunks at 100. Response splits
160
161
  into `trademarks[]` and `nonTrademarks[]` (design-only / bookkeeping artefacts — generally skip, but
161
162
  sanity-check it if results look sparse).
162
163
 
@@ -205,16 +206,17 @@ silently omit the dimension.
205
206
  - **No regex** — wildcards and booleans cover the plan vocabulary.
206
207
  - **No cross-language single query** — run the variant manifest per script.
207
208
  - **No native-script search — send the ROMANISATION instead.** This index holds non-Latin marks by
208
- their transliteration and does not hold the characters at all. `华威豹` answers **0**; its own
209
- transliteration `HUA WEI BAO` answers **32**, and those 32 include 华威豹. Same for `小米` (0) vs
210
- `XIAOMI` (57632). Universal — every non-Latin record sampled across CN/TW/JP/KR/TH/GR/UA/EG/SA/IL
209
+ their transliteration and does not hold the characters at all. A native-script term answers nothing;
210
+ its own transliteration answers records that carry those very characters. Universal — every non-Latin
211
+ record sampled across CN/TW/JP/KR/TH/GR/UA/EG/SA/IL
211
212
  carried a populated `markTransliteration`. A native term you send is REFUSED client-side (a 0 here
212
213
  would read as clean), so send the romanised form and say in the report that the register was
213
214
  searched by transliteration. Two rules that come with it:
214
215
  - use **contains, not `exact`** — the office writes its own spacing and trailing tokens, so
215
- `exact` on a transliteration is a silent zero (GR 0/10, EG 0/7);
216
- - the romanisation is **broader than the characters, not narrower** — it catches homophone
217
- variants (`HUA WEI BAO` → 华威豹, 华味宝, 华为爆破), which is the shape most Chinese squatting takes.
216
+ `exact` on a transliteration can be a silent zero where the same term under contains answers;
217
+ - the romanisation is **broader than the characters, not narrower** — the search key is the
218
+ romanisation, so it returns every character set filed under that pronunciation and not only the one
219
+ you meant, which is the shape most Chinese squatting takes.
218
220
 
219
221
  Each of these, when it blocks a dictated slice, is a **`deferred` coverage row** — escalate and disclose.
220
222
  Never substitute a weaker query under the same heading.
@@ -22,17 +22,26 @@ Auth: `CORSEARCH_SESSION_KEY` environment variable, supplied from the deployment
22
22
 
23
23
  Corsearch's supremesearch API uses single-character prefixes on field names. All field values must be **backtick-quoted** (the plugin handles this).
24
24
 
25
- | Match mode | API prefix | Semantics | Hit volume (NIKE benchmark) |
25
+ | Match mode | API prefix | Semantics | Budget as |
26
26
  |---|---|---|---|
27
- | `default` | (none) | Exact-token, case-insensitive — catches tokenisation splits and case variations | ~15,083 |
28
- | `exact` | `=` | Strictest — full-string match | ~3,014 |
29
- | `phrase` | `"` | Ordered phrase match | ~10,075 |
30
- | `starts_with` | `^` | Prefix | ~7,681 |
31
- | `ends_with` | `$` | Suffix | ~8,248 |
32
- | `phonetic` | `*` (or `P`) | Server-side phoneme match; extend with `phonetic_variants[]` | ~5,854 bare / ~6,022 with variants |
33
- | `fuzzy` | `~` | Approximate (diacritics, transliterations) | ~143,184 |
27
+ | `default` | (none) | Exact-token, case-insensitive — catches tokenisation splits and case variations | a read |
28
+ | `exact` | `=` | Strictest — full-string match | a read |
29
+ | `phrase` | `"` | Ordered phrase match | a read |
30
+ | `starts_with` | `^` | Prefix | a read |
31
+ | `ends_with` | `$` | Suffix | a read |
32
+ | `phonetic` | `*` (or `P`) | Server-side phoneme match; extend with `phonetic_variants[]` | a read |
33
+ | `fuzzy` | `~` | Approximate (diacritics, transliterations) | **a crowd** |
34
34
  | `not` | `!` (or `-`) | Complement; useful in compound queries | — |
35
- | `must` | `&` | Force AND within same-field stacking | ~433 (NIKE + ADIDAS) |
35
+ | `must` | `&` | Force AND within same-field stacking | a read |
36
+
37
+ Two facts about size, and no more than two, because a mode's breadth is a fact about the mark you send and
38
+ not about the mode: **`fuzzy` answers an order of magnitude wider than anything else here** — budget it as
39
+ a crowd unless you have narrowed it another way — and **`must` and `exact` are the two narrowest**, which
40
+ is what to reach for when a band has to be read rather than screened.
41
+
42
+ No mode's results contain another's. A prefix and a suffix each hold marks the other does not, a
43
+ sound-alike need not begin with your letters, and an intersection is not a subset of either half — so
44
+ running the wider one does not cover the narrower one, and a leg you drop is a leg nobody searched.
36
45
 
37
46
  **Critical:** No explicit `AND` / `OR` keywords — those return HTTP 400. Composition is space-separated. Repeated fields = implicit OR. Use `must` prefix for AND within same field. Repeated `nice-class:` fields are therefore an implicit-OR union — `nice_classes:[9,28,41,42]` correctly scopes to *any of* those classes.
38
47
 
@@ -150,7 +159,7 @@ Capture VERBATIM in the register findings file's "Opposition history" section. D
150
159
 
151
160
  Corsearch supports phoneme expansion via `register_expand_phoneme`. Returns `{ base, aiVariants[] }`. Use the variants as `phonetic_variants[]` in `register_search` with `match_mode: "phonetic"`.
152
161
 
153
- Declared languages: `en_US` (~29 variants per word), `de_DE` (~29), `fr_FR` (~49). Other languages (`it_IT`, `es_ES`) are supported by the API but UNDECLARED here — treat them as a stated unknown, not as unavailable.
162
+ Declared languages: `en_US`, `de_DE`, `fr_FR` — each returns a few dozen variants for a typical word. Other languages (`it_IT`, `es_ES`) are supported by the API but UNDECLARED here — treat them as a stated unknown, not as unavailable.
154
163
 
155
164
  **Usage pattern:** for multi-language jurisdictions, call expand-phoneme once per relevant language, concatenate `aiVariants[]`, pass to a single search call. Don't run multiple separate phonetic searches — costs more, returns largely overlapping results.
156
165
 
@@ -165,7 +174,7 @@ Only invoke for marks where `markFeature: "Figurative"` or `markFeature: "Stylis
165
174
  Be aware these capabilities are missing, so the skill doesn't promise them:
166
175
 
167
176
  - **POCA scoring** — not available through this adapter. Skill returns `null`
168
- - **Cross-language search within one query** — Corsearch doesn't support "search this mark in Japanese AND English in one query." Skill handles this by generating transliteration variants in `prelim-variants` and querying each separately.
177
+ - **Cross-language search within one query** — Corsearch doesn't support "search this mark in Japanese AND English in one query." Skill handles this by generating transliteration variants in `clearance-variants` and querying each separately.
169
178
  - **Server-side stem-folding** — present but not configurable (the default match-mode tokenizer catches LEGEND ↔ LEGENDS). The variant manifest's `plural-root` category encodes this — search the root form to catch inflected forms.
170
179
 
171
180
  ## Provider-specific behaviour
@@ -125,8 +125,8 @@ difference is not a margin. On the same term:
125
125
 
126
126
  | request | national | regional | madrid |
127
127
  |---|---|---|---|
128
- | `filters.offices: ["inpi-fr"]` | 6898 | 0 | 0 |
129
- | `filters.jurisdictions: ["FR"]`, protection | 6898 | 10000+ | 2708 |
128
+ | `filters.offices: ["inpi-fr"]` | yes | **none** | **none** |
129
+ | `filters.jurisdictions: ["FR"]`, protection | yes | yes | yes |
130
130
 
131
131
  **So an EU trade mark that blocks use in France is now found**, and it never appears in the French
132
132
  register. Every covered territory reaches its Madrid layer this way and the EU members additionally reach
@@ -154,10 +154,10 @@ French national marks. On the same term:
154
154
 
155
155
  | what the executor sends | national | regional | Madrid |
156
156
  |---|---|---|---|
157
- | `filters.offices: ["inpi-fr"]` (the shape this doc used to describe) | 6898 | 0 | 0 |
158
- | `filters.jurisdictions: ["FR"]`, `territory_match: "protection"` | 6898 | 10000+ | 2708 |
157
+ | `filters.offices: ["inpi-fr"]` (the shape this doc used to describe) | yes | **none** | **none** |
158
+ | `filters.jurisdictions: ["FR"]`, `territory_match: "protection"` | yes | yes | yes |
159
159
 
160
- It is ONE call, not three. A territory under no regional register — Switzerland — returns regional 0 either
160
+ It is ONE call, not three. A territory under no regional register — Switzerland — gains no regional rows either
161
161
  way and still reaches its Madrid layer, which is what shows `protection` adds a LAYER rather than just more
162
162
  rows.
163
163
 
@@ -26,7 +26,7 @@ sufficiency, and prioritisation. See [unit.md](unit.md).
26
26
  > match-mode, never "all classes". The ONLY all-class enumerate is the exact-IDENTICAL cross-class merch check
27
27
  > (`match_mode:exact`, `nice_classes:[25]`). `fuzzy` is never an enumerate mode.
28
28
 
29
- **Execution note:** `prelim-register` now runs as a worker that decomposes these axes into isolated
29
+ **Execution note:** `clearance-register` now runs as a worker that decomposes these axes into isolated
30
30
  search **units** (saturation-probe / primary-sweep / transliteration-numeric / incumbent-class /
31
31
  merch-sweep), each executing one axis and writing its named-band array (`register-units/<axis>-band.json`).
32
32
  If you are a unit, run only your assigned axis from the recipe below; the judgment worker (Layer B) performs
@@ -190,7 +190,7 @@ For each transliteration variant in the manifest:
190
190
  → transliteration plausibility is a verification flag for the lawyer (Verify? ✅)
191
191
  ```
192
192
 
193
- **Important:** transliteration hits are NOT confirmed without senior-lawyer sign-off. Claude generates plausible transliterations but Korean/Arabic/etc native speakers must confirm. The `Verify? ✅` flag from `prelim-variants` carries through to the band so judgment surfaces it. The funnel does not decide a transliteration is wrong — it enumerates and passes the record with its flag.
193
+ **Important:** transliteration hits are NOT confirmed without senior-lawyer sign-off. Claude generates plausible transliterations but Korean/Arabic/etc native speakers must confirm. The `Verify? ✅` flag from `clearance-variants` carries through to the band so judgment surfaces it. The funnel does not decide a transliteration is wrong — it enumerates and passes the record with its flag.
194
194
 
195
195
  **Breadth note (this recipe shares a unit with the per-jurisdiction named queries).** Both the script-group enumerations here and the material-jurisdiction named queries are owned by the `transliteration-numeric` unit, and **both are enumerated** — there is no "yield one to fund the other" sufficiency trade any more. `register_enumerate` owns each query's page loop; the unit runs every variant query the manifest declares. If a query genuinely cannot run (provider error), that surfaces as an `incomplete` block, not a silently-dropped sweep.
196
196
 
@@ -331,7 +331,7 @@ by goods **words**. The everyday-word saturation is the trigger to **scope the n
331
331
  class)** — never to drop the token, re-narrow it to a more specific concept, or swap it for the phonetic form. The
332
332
  saturated meaning token is enumerated like any other named slice; the lawyer reads it. (This is the register half
333
333
  of the variant-stage everyday-word-first rule — see
334
- [transliteration-scripts.md](../prelim-variants/transliteration-scripts.md): the everyday word is kept upstream,
334
+ [transliteration-scripts.md](../clearance-variants/transliteration-scripts.md): the everyday word is kept upstream,
335
335
  class-scoped and enumerated here.) Reuse steps 1–2 above with the class-scoped meaning token as the `register_enumerate` predicate.
336
336
 
337
337
  **Expected output:** on a saturated field, the complete enumerated near-exact in-class band (live + dead with status) the ranker's top-N paging would have buried, plus the phonetic-fringe band — each as an `enumerated` block, or an `incomplete` descriptor where a slice was a genuine crowd. On a non-saturated field this recipe does not fire.
@@ -1,6 +1,6 @@
1
1
  # Status rules — status classification, Madrid handling, non-Latin status strings
2
2
 
3
- Cross-referenced from [prelim-register/SKILL.md](SKILL.md) — the canonical entry point. The provider files and stealth-filer indicators link here for the status-classification rules; the orchestrator never reads this file directly.
3
+ Cross-referenced from [clearance-register/SKILL.md](SKILL.md) — the canonical entry point. The provider files and stealth-filer indicators link here for the status-classification rules; the orchestrator never reads this file directly.
4
4
 
5
5
  > **Funnel vs judgment (read this first).** Under the two-layer split, the **funnel (Layer A) does NOT drop
6
6
  > records on status** — `register_enumerate` carries **every** record forward (live AND dead) **with its
@@ -226,7 +226,7 @@ For owner country:
226
226
 
227
227
  If after the full fallback chain the owner is still empty, set owner column to `(unknown — confirm)` and add to Open verification flags.
228
228
 
229
- **Owner-identity conflict.** If two fields in the chain (or an EUIPO cross-check vs the vendor record) yield *materially different* owner names for the same URI, do NOT silently pick the first — record both candidate names in the owner field and set `Verify? ✅` with reason "owner-identity conflict — confirm before enforcement read." Likewise, when a portfolio-size signal (many filings clustering under one normalised owner) would change the enforcement-appetite read, surface it. Owner identity drives enforcer-profiling (`prelim-search/firm-wide-reasoning.md`, *Enforcer profiling*) — a wrong owner is a wrong risk read.
229
+ **Owner-identity conflict.** If two fields in the chain (or an EUIPO cross-check vs the vendor record) yield *materially different* owner names for the same URI, do NOT silently pick the first — record both candidate names in the owner field and set `Verify? ✅` with reason "owner-identity conflict — confirm before enforcement read." Likewise, when a portfolio-size signal (many filings clustering under one normalised owner) would change the enforcement-appetite read, surface it. Owner identity drives enforcer-profiling (`clearance-search/firm-wide-reasoning.md`, *Enforcer profiling*) — a wrong owner is a wrong risk read.
230
230
 
231
231
  ### USPTO extended country codes
232
232
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Detect "law firm as owner" (i.e., the registered owner is a legal-services entity rather than the underlying client) via the following regex / substring patterns. Any match flags the row as a candidate stealth filing — surface this in the Findings sheet and feed it into Option D Trigger 2 (one common-law query for the underlying client's marketplace use).
4
4
 
5
- Canonical entry point: [prelim-register/SKILL.md](SKILL.md) lists this file and `status-rules.md` as siblings; this file references back to `status-rules.md` only for the owner-extraction fallback chain it depends on.
5
+ Canonical entry point: [clearance-register/SKILL.md](SKILL.md) lists this file and `status-rules.md` as siblings; this file references back to `status-rules.md` only for the owner-extraction fallback chain it depends on.
6
6
 
7
7
  ## Indicator patterns
8
8
 
@@ -1,4 +1,4 @@
1
- # prelim-register — MODE A (UNIT)
1
+ # clearance-register — MODE A (UNIT)
2
2
 
3
3
  > Read `SKILL.md` first (the shared spine: Spawned session, Model, Provider, Tool call budget, the band-block coverage model, Failure fallback). This file is the UNIT-mode procedure only. **Do NOT read `digest.md`** — that is digest-mode judgment a unit must never run.
4
4
 
@@ -52,7 +52,7 @@ You were spawned to run exactly ONE axis named in your task. Read the manifest +
52
52
  - **off-field-drop on goods** — brand-json has no goods/services text; an in-scope-class live record is carried forward and the lawyer decides on its actual goods/services. (`screen_verdict` is enrichment for judgment, not a funnel drop authority.)
53
53
  - **sample or self-accept** — no top-N, no "narrow to tractable and stop", no per-jurisdiction 3-fetch ceiling, no switch-to-exact-standalone-as-enumeration. Those were funnel sufficiency calls; they are **deleted**. The tool enumerates or reports incomplete — there is no in-between for you to author.
54
54
  6. **Surface dead records WITH their status — no funnel date-cutoff.** Carry every record `register_enumerate` returns **with its `status`** (live / lapsed / expired / lapse-date in the record's dates). You do **NOT** apply a recency/date threshold and you do **NOT** drop dead-except-identical. **`recently-dead` is a STATUS for judgment**, not a funnel filter: whether a recently-lapsed near-identical matters (revival window, field history, non-use vulnerability) is the lawyer's call (Layer B), made on the status + lapse date you passed through. Volume is handled by the completeness contract (step 3): if the dead-inclusive named band is bounded, `register_enumerate` returns it `enumerated`; if it is a crowd, it returns `incomplete` → descriptor. You pass the fact; judgment weighs it. (The old D4 ≤5y date-cutoff drop is **removed** — it was a funnel-side judgment.)
55
- 7. **Write the band artifact, then return.** Write `register-units/<axis>-band.json` (the named-band array, schema below) to `studio/prelim-search/<slug>/<date>/register-units/<axis>-band.json`, **before you return — returning without it is a failure** (the deterministic driver gates on this file: if it is missing after your turn it fails the stage and retries it under a fresh session key; a band that never lands as a file is lost work). Then **file your audit note by calling `record_unit_note`** — you do not write it, and the dispatch hands you no path for it: the driver renders it from your call. **The counts are not yours to type.** Queries enumerated, incomplete blocks and records carried forward are taken from the band you just wrote, so the note and the band cannot disagree; a note filed before the band exists is refused by name, because an account of a sweep that has not happened is not a short note but a wrong one. What you send is the half the band cannot say: `null_result` if this axis genuinely found nothing (refused against a band that carries records), and `note` — one short observation an auditor would want, in a lawyer's words. **The raw character-noise pile stays in this session** — what crosses the firewall is the **complete named band + crowd descriptors** (the `<axis>-band.json` array), NOT the raw rows. Do **not** apply a relevance gate, do **not** aggregate owners, do **not** decide sufficiency — those are judgment's job (Layer B).
55
+ 7. **Write the band artifact, then return.** Write `register-units/<axis>-band.json` (the named-band array, schema below) to `studio/clearance-search/<slug>/<date>/register-units/<axis>-band.json`, **before you return — returning without it is a failure** (the deterministic driver gates on this file: if it is missing after your turn it fails the stage and retries it under a fresh session key; a band that never lands as a file is lost work). Then **file your audit note by calling `record_unit_note`** — you do not write it, and the dispatch hands you no path for it: the driver renders it from your call. **The counts are not yours to type.** Queries enumerated, incomplete blocks and records carried forward are taken from the band you just wrote, so the note and the band cannot disagree; a note filed before the band exists is refused by name, because an account of a sweep that has not happened is not a short note but a wrong one. What you send is the half the band cannot say: `null_result` if this axis genuinely found nothing (refused against a band that carries records), and `note` — one short observation an auditor would want, in a lawyer's words. **The raw character-noise pile stays in this session** — what crosses the firewall is the **complete named band + crowd descriptors** (the `<axis>-band.json` array), NOT the raw rows. Do **not** apply a relevance gate, do **not** aggregate owners, do **not** decide sufficiency — those are judgment's job (Layer B).
56
56
 
57
57
  ## What else your grant carries, and why you do not call it
58
58