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.
- package/.env.example +58 -26
- package/CONTRIBUTING.md +8 -8
- package/INSTALL.md +148 -81
- package/README.md +3 -3
- package/SECURITY.md +3 -3
- package/bin/brandowner.mjs +3 -3
- package/bin/framework-preflight.mjs +1 -1
- package/bin/onboard.mjs +637 -216
- package/bin/start.mjs +151 -27
- package/bin/update.mjs +58 -11
- package/build-info.json +2 -2
- package/docs/DELIVERY.md +2 -1
- package/docs/INTAKE.md +1 -1
- package/docs/ONBOARDING.md +1 -1
- package/docs/architecture/03-run-lifecycle.md +6 -6
- package/docs/architecture/04-configuration-reference.md +32 -14
- package/docs/architecture/05-config-governance.md +23 -8
- package/docs/architecture/05-customer-profiles.md +2 -2
- package/docs/architecture/06-operations-runbook.md +3 -3
- package/docs/architecture/08-development-guide.md +6 -6
- package/docs/configuration.md +5 -5
- package/docs/decisions/0003-credential-model.md +1 -1
- package/docs/writing-standard.md +4 -0
- package/driver/CHANGELOG.md +124 -0
- package/driver/README.md +3 -3
- package/driver/band-size.mjs +59 -0
- package/driver/binding-layers.mjs +1 -1
- package/driver/citation-census.json +3 -3
- package/driver/{prelim-variants-record.mjs → clearance-variants-record.mjs} +24 -24
- package/driver/common-law-receipts.mjs +2 -2
- package/driver/company-bundle.mjs +3 -3
- package/driver/compose-read.mjs +8 -14
- package/driver/config-inventory.mjs +112 -9
- package/driver/consumption-ledger.mjs +2 -2
- package/driver/contract-arm2-baseline.json +2 -5
- package/driver/contract-dictation-registry.mjs +19 -19
- package/driver/contract-e3-backlog.mjs +43 -43
- package/driver/contract-e3-baseline.json +14 -14
- package/driver/contract-vocabulary.mjs +68 -27
- package/driver/deliver-trigger.sh +16 -16
- package/driver/demo-container.mjs +3 -3
- package/driver/dev-portal.mjs +3 -3
- package/driver/disposition-call.mjs +1 -1
- package/driver/door-gates.mjs +41 -7
- package/driver/doubt-ledger.mjs +2 -2
- package/driver/drainer-identity.mjs +34 -8
- package/driver/driver.config.mjs +367 -104
- package/driver/engine/CONTRACT.md +10 -3
- package/driver/engine/README.md +2 -2
- package/driver/engine/anthropic-agent.mjs +77 -21
- package/driver/engine/auth.mjs +129 -10
- package/driver/engine/jx-turn.mjs +7 -6
- package/driver/engine/mcp/README.md +1 -1
- package/driver/engine/mcp/dispositions-server.mjs +3 -3
- package/driver/engine/mcp/gather-config.mjs +9 -9
- package/driver/engine/mcp/perplexity-server.mjs +2 -2
- package/driver/engine/mcp/recording-server.mjs +18 -5
- package/driver/engine/openai-agent.mjs +4 -2
- package/driver/engine/probe.mjs +110 -23
- package/driver/enqueue-schema.mjs +6 -2
- package/driver/findings-model.mjs +6 -3
- package/driver/flag-snapshot.mjs +34 -8
- package/driver/form-neighbourhood.mjs +54 -7
- package/driver/framework.mjs +4 -4
- package/driver/gateway.mjs +36 -24
- package/driver/jx-lanes.mjs +23 -4
- package/driver/jx-units.mjs +7 -4
- package/driver/jx.mjs +34 -4
- package/driver/knockout-review-record.mjs +56 -4
- package/driver/known-conflicts.mjs +1 -1
- package/driver/matter-frame-record.mjs +90 -1
- package/driver/named-band.mjs +1 -1
- package/driver/ordinary-words.mjs +51 -0
- package/driver/outbox-backoff.mjs +31 -16
- package/driver/package.json +1 -1
- package/driver/partial-payload-baseline.json +2 -2
- package/driver/phase0.mjs +3 -3
- package/driver/pipeline-knockout.mjs +5 -5
- package/driver/pipeline.mjs +396 -81
- package/driver/placement-form.mjs +77 -1
- package/driver/placement-model.mjs +1 -1
- package/driver/portal-config-view.mjs +30 -1
- package/driver/portal-report.mjs +107 -6
- package/driver/portal-service.mjs +80 -14
- package/driver/portal-upstream.mjs +1 -1
- package/driver/predelivery-lint.mjs +12 -2
- package/driver/preserve-merge.mjs +3 -3
- package/driver/product-rows.mjs +2 -2
- package/driver/products.mjs +1 -1
- package/driver/profiles/README.md +3 -3
- package/driver/profiles/demo-brand-owner.json +2 -2
- package/driver/profiles.mjs +55 -17
- package/driver/progress.mjs +18 -8
- package/driver/provider-usage.mjs +8 -8
- package/driver/publish/index.mjs +154 -8
- package/driver/publish/knockout.mjs +39 -5
- package/driver/publish/pool-admin.mjs +1 -1
- package/driver/publish/publish-inputs.mjs +18 -2
- package/driver/publish/render-knockout.mjs +184 -31
- package/driver/publish/render.mjs +323 -93
- package/driver/publish/report-data.mjs +4 -1
- package/driver/publish/report-topbar.mjs +58 -0
- package/driver/publish/search-depth.mjs +133 -4
- package/driver/publish/templates/report.css +78 -4
- package/driver/publish/xlsx.mjs +20 -1
- package/driver/queue-order.mjs +2 -2
- package/driver/recording-agreement.mjs +1 -1
- package/driver/reference-score.mjs +1 -1
- package/driver/register-availability.mjs +2 -2
- package/driver/register-count.mjs +50 -5
- package/driver/register-coverage.mjs +161 -1
- package/driver/register-digest-record.mjs +236 -11
- package/driver/register-grant-vocabulary.mjs +1 -1
- package/driver/register-plan.mjs +189 -2
- package/driver/registry-fidelity.mjs +3 -3
- package/driver/repair-composers.mjs +1 -1
- package/driver/repair-contract.mjs +1 -1
- package/driver/replay-archive.mjs +6 -6
- package/driver/report-overview-record.mjs +2 -2
- package/driver/result-noun-fields.mjs +2 -2
- package/driver/run-economics.mjs +41 -10
- package/driver/run-requirements.mjs +173 -9
- package/driver/runner.mjs +5 -5
- package/driver/scope-facts.mjs +20 -5
- package/driver/scope-ledger.mjs +5 -5
- package/driver/search-policy.mjs +22 -12
- package/driver/skills/README.md +15 -15
- package/driver/skills/blind-frame/SKILL.md +2 -2
- package/driver/skills/case-law-citation/SKILL.md +4 -4
- package/driver/skills/case-law-citation/sources/eurlex.md +1 -1
- package/driver/skills/{prelim-common-law → clearance-common-law}/SKILL.md +22 -22
- package/driver/skills/{prelim-common-law → clearance-common-law}/perplexity-prompts.md +1 -1
- package/driver/skills/{prelim-register → clearance-register}/SKILL.md +10 -10
- package/driver/skills/{prelim-register → clearance-register}/digest.md +2 -2
- package/driver/skills/{prelim-register → clearance-register}/providers/README.md +1 -1
- package/driver/skills/{prelim-register → clearance-register}/providers/clarivate.md +37 -35
- package/driver/skills/{prelim-register → clearance-register}/providers/corsearch.md +20 -11
- package/driver/skills/{prelim-register → clearance-register}/providers/signa.md +5 -5
- package/driver/skills/{prelim-register → clearance-register}/register-recipes.md +3 -3
- package/driver/skills/{prelim-register → clearance-register}/status-rules.md +2 -2
- package/driver/skills/{prelim-register → clearance-register}/stealth-filer-indicators.md +1 -1
- package/driver/skills/{prelim-register → clearance-register}/unit.md +2 -2
- package/driver/skills/{prelim-search → clearance-search}/SKILL.md +31 -31
- package/driver/skills/{prelim-search → clearance-search}/delivery-contract.md +1 -1
- package/driver/skills/{prelim-search → clearance-search}/phase2-execution.md +18 -18
- package/driver/skills/{prelim-search → clearance-search}/synthesis-rules.md +7 -7
- package/driver/skills/{prelim-variants → clearance-variants}/SKILL.md +18 -18
- package/driver/skills/{prelim-variants → clearance-variants}/transliteration-scripts.md +5 -5
- package/driver/skills/frame-diff/SKILL.md +1 -1
- package/driver/skills/knockout-assess/SKILL.md +10 -7
- package/driver/skills/matter-frame/SKILL.md +3 -3
- package/driver/skills/narrative-refutation/SKILL.md +9 -9
- package/driver/skills/placement-inquiry/SKILL.md +5 -5
- package/driver/stage-context.mjs +1 -1
- package/driver/stages-knockout.mjs +4 -4
- package/driver/stages.mjs +65 -61
- package/driver/status-snapshot.mjs +2 -2
- package/driver/suite-census.json +340 -136
- package/driver/surface-exit-verdict.mjs +58 -0
- package/driver/systemd/README.md +9 -6
- package/driver/systemd/clearotron-worker.service +1 -1
- package/driver/terminal-clamp.mjs +109 -1
- package/driver/tokens.mjs +169 -3
- package/driver/unit-environment.mjs +42 -15
- package/driver/unit-inventory.mjs +19 -2
- package/driver/usage-ledger.mjs +1 -1
- package/driver/variant-manifest-model.mjs +4 -4
- package/driver/verify-knockout.mjs +27 -0
- package/driver/verify.mjs +94 -6
- package/driver/whatif-queue.mjs +1 -1
- package/driver/wordlists/en.txt +63906 -0
- package/mcp-server/CHANGELOG.md +8 -0
- package/mcp-server/README.md +1 -1
- package/mcp-server/lib/README.md +1 -1
- package/mcp-server/lib/options.mjs +8 -7
- package/mcp-server/lib/plan.mjs +18 -2
- package/mcp-server/lib/runs.mjs +1 -1
- package/mcp-server/lib/usage.mjs +3 -3
- package/mcp-server/lib/whatif.mjs +1 -1
- package/mcp-server/package.json +1 -1
- package/mcp-server/server.mjs +18 -1
- package/package.json +12 -11
- package/portal-ui/dist/assets/{index-CVOIvdhc.css → index-CtvwLCti.css} +207 -3
- package/portal-ui/dist/assets/{index-5UyqAyNM.js → index-EVaSo5-g.js} +1580 -527
- package/portal-ui/dist/index.html +2 -2
- package/portal-ui/package.json +1 -1
- package/providers/README.md +1 -1
- package/providers/_shared/enumerate.mjs +6 -6
- package/providers/_shared/execute-plan.mjs +3 -3
- package/providers/_shared/ledger.mjs +119 -5
- package/providers/_shared/provider-text.mjs +2 -2
- package/providers/_shared/screen.mjs +2 -2
- package/providers/_shared/script-form.mjs +3 -3
- package/providers/_shared/territory-codes.mjs +23 -3
- package/providers/clarivate/README.md +1 -1
- package/providers/clarivate/src/capabilities.js +12 -12
- package/providers/clarivate/src/core.js +37 -43
- package/providers/corsearch/README.md +1 -1
- package/providers/corsearch/src/capabilities.js +5 -5
- package/providers/corsearch/src/core.js +3 -3
- package/providers/jx/README.md +2 -1
- package/providers/jx/src/turn-envelope.mjs +8 -3
- package/providers/oauth-mcp-bridge/CHANGELOG.md +8 -0
- package/providers/oauth-mcp-bridge/package.json +1 -1
- package/providers/perplexity/src/core.js +1 -1
- package/providers/signa/README.md +1 -1
- package/providers/signa/src/capabilities.js +42 -49
- package/providers/signa/src/core.js +106 -29
- package/providers/uspto-local/README.md +1 -1
- package/providers/uspto-local/src/sync.js +1 -1
- package/scripts/README.md +1 -0
- package/scripts/ask-ai-render-check.mjs +127 -1
- package/scripts/authority-boundary-probe.mjs +8 -6
- package/scripts/backfill-started-at.mjs +2 -2
- package/scripts/census-merge-driver.mjs +33 -2
- package/scripts/citation-anchor-report.mjs +181 -0
- package/scripts/dead-names.mjs +1 -1
- package/scripts/deprecate-below.mjs +66 -8
- package/scripts/drain-preflight.mjs +1 -1
- package/scripts/e2e.mjs +174 -0
- package/scripts/env-audit.mjs +39 -6
- package/scripts/env-classify.mjs +20 -2
- package/scripts/freeze-example-run.mjs +61 -18
- package/scripts/generated-files-are-current.mjs +69 -4
- package/scripts/live-surface-check.mjs +124 -41
- package/scripts/markdown-link-check.mjs +1 -1
- package/scripts/merge-shape-check.mjs +242 -0
- package/scripts/mint-names-in-force.mjs +5 -5
- package/scripts/mint-offered-territories.mjs +72 -0
- package/scripts/mint-public-residue.mjs +2 -2
- package/scripts/mint-reference-strip-backlog.mjs +2 -2
- package/scripts/mint-suite-census.mjs +75 -2
- package/scripts/mint-writing-standard-backlog.mjs +2 -2
- package/scripts/purge-runs.mjs +7 -7
- package/scripts/reconcile-runs.mjs +2 -2
- package/scripts/release-approve-parked.mjs +20 -2
- package/scripts/release-await-cut.mjs +120 -1
- package/scripts/release-note-required.mjs +76 -8
- package/scripts/report-header-render-check.mjs +164 -0
- package/scripts/settings-render-check.mjs +75 -2
- package/scripts/test-full.mjs +96 -3
- package/scripts/test-run.mjs +10 -0
- package/shared/brand.mjs +27 -0
- package/shared/connect-clients.mjs +39 -11
- package/shared/deployment-box.mjs +7 -2
- package/shared/driver-dir.mjs +1 -1
- package/shared/env-aliases.mjs +1 -1
- package/shared/identifier-scan.mjs +65 -9
- package/shared/identifier-sentinels.mjs +22 -0
- package/shared/names-in-force.mjs +4 -2
- package/shared/offered-territories.json +738 -0
- package/shared/pre-rename-spellings.mjs +53 -0
- package/shared/reference-guard-classes.mjs +40 -2
- package/shared/stdio-connect.mjs +39 -4
- package/shared/tree-commit.mjs +48 -0
- /package/driver/skills/{prelim-register → clearance-register}/providers/euipo.md +0 -0
- /package/driver/skills/{prelim-register → clearance-register}/providers/free-tier.md +0 -0
- /package/driver/skills/{prelim-register → clearance-register}/providers/uspto-local.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/field-doctrine-pharma.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/firm-wide-reasoning.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/report-prose.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/risk-framework-demo.manifest.json +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/risk-framework-demo.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/risk-framework-triage.manifest.json +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/risk-framework-triage.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/risk-framework.manifest.json +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/risk-framework.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/template-formatting.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/templates/email/generic.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/templates/search-request-form.html +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/worked-examples-demo.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/worked-examples.md +0 -0
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
// D4 verify.mjs parseCoverageLedgerJson, same shape
|
|
22
22
|
// D5 verify.mjs:1504 fail(`${unaccounted[0].token}:…`) — token minted in a DATA ROW
|
|
23
23
|
// D6 verify.mjs:1567 fail(`${violations[0].token}…`) — validatePlanFeasibility in register-plan.mjs
|
|
24
|
-
// D7 verify.mjs:1558 fail(`${v2[0].token}${detail}…`) — register-plan.mjs:
|
|
25
|
-
// D8 verify.mjs:
|
|
24
|
+
// D7 verify.mjs:1558 fail(`${v2[0].token}${detail}…`) — register-plan.mjs:2183 disclosureTextByAxis
|
|
25
|
+
// D8 verify.mjs:2470 caseLawLedgerFail fail(caseLawLedgerFail(…)) — token built in case-law-ledger.mjs:195 caseLawLedgerFail
|
|
26
26
|
//
|
|
27
27
|
// A partition built on the 60 tokens a regex CAN see would run green while blind to the rest, which is
|
|
28
28
|
// worse than having no E2 at all: it certifies a partition it never checked. So the census is authored
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
// ── PER-STAGE, NEVER GLOBAL ─────────────────────────────────────────────────────────────────────────
|
|
42
42
|
//
|
|
43
43
|
// `too_short` and `missing` come from the shared nonEmpty()/needs() helpers (verify.mjs:123-133) and are
|
|
44
|
-
// legitimately owned by DIFFERENT elements in matter-frame,
|
|
44
|
+
// legitimately owned by DIFFERENT elements in matter-frame, clearance-variants and frame-diff. A global
|
|
45
45
|
// token→element map sees several owners for one token and "fixes" a partition that was never violated.
|
|
46
46
|
// Every row therefore carries `stages`, and the partition is computed per (token, stage) pair.
|
|
47
47
|
|
|
48
48
|
/** The 16 stages of STAGES in stages.mjs. Kept here so a stage added there fails this file's own test. */
|
|
49
49
|
export const ALL_STAGES = [
|
|
50
|
-
"matter-frame", "
|
|
50
|
+
"matter-frame", "clearance-variants", "blind-frame", "common-law", "common-law-half", "register-unit",
|
|
51
51
|
"placement-inquiry", "register-digest", "skeptic", "frame-diff", "synthesis", "case-law",
|
|
52
52
|
"narrative-refutation", "doubt-closure", "report-overview", "report-card",
|
|
53
53
|
];
|
|
@@ -65,12 +65,12 @@ const CL = ["common-law", "common-law-half"];
|
|
|
65
65
|
export const VOCABULARY = [
|
|
66
66
|
// ── the shared helpers: one token, many stages, different owners per stage ─────────────────────────
|
|
67
67
|
{ token: "too_short", stages: ALL_STAGES.filter((s) => !["blind-frame", "doubt-closure", "narrative-refutation"].includes(s)), site: "driver/verify.mjs:133" },
|
|
68
|
-
{ token: "missing", stages: ["matter-frame", "
|
|
68
|
+
{ token: "missing", stages: ["matter-frame", "clearance-variants", "common-law", "common-law-half", "placement-inquiry", "register-digest", "doubt-closure", "report-overview", "report-card"], site: "driver/verify.mjs, in needs()" },
|
|
69
69
|
|
|
70
70
|
// ── common-law / common-law-half ───────────────────────────────────────────────────────────────────
|
|
71
71
|
{ token: "declared_unavailable", stages: CL, site: "driver/verify.mjs" },
|
|
72
72
|
{ token: "grid_spec_unreadable", stages: CL, site: "driver/verify.mjs:257" },
|
|
73
|
-
{ token: "grid_ledger_missing", stages: CL, site: "driver/verify.mjs
|
|
73
|
+
{ token: "grid_ledger_missing", stages: CL, site: "driver/verify.mjs commonLawMeaningSeat" },
|
|
74
74
|
{ token: "grid_ledger_unparseable", stages: CL, site: "driver/verify.mjs:266" },
|
|
75
75
|
{ token: "connotation_query_unrecorded", stages: ["common-law-half"], site: "driver/verify.mjs" },
|
|
76
76
|
{ token: "profile_unparseable", stages: ["common-law"], site: "driver/verify.mjs" },
|
|
@@ -102,6 +102,36 @@ export const VOCABULARY = [
|
|
|
102
102
|
{ token: "finding", stages: ["synthesis"], site: "driver/verify.mjs", family: "driver/findings-model.mjs (token-first throws; `finding_*` and `findings_*`)", dynamic: "D2" },
|
|
103
103
|
|
|
104
104
|
// ── register-digest ────────────────────────────────────────────────────────────────────────────────
|
|
105
|
+
// The per-record accounting family, raised at the EXIT as well as at the call. The call-time refusal
|
|
106
|
+
// is scoped to the batch it judges, which is what lets a dense band be recorded at all; the exit gate
|
|
107
|
+
// is where that is paid for, because once any batch is accepted a document exists and half a band is
|
|
108
|
+
// the same SHAPE as a whole one. All three are armed by the era stamp, so an archived run raises none.
|
|
109
|
+
{ token: "registerdigest_unaccounted_records", stages: ["register-digest"], site: "driver/verify.mjs, and driver/register-digest-record.mjs at the call" },
|
|
110
|
+
{ token: "registerdigest_accounting_unreadable", stages: ["register-digest"], site: "driver/verify.mjs — driver-written, not a model defect" },
|
|
111
|
+
{ token: "registerdigest_model_missing", stages: ["register-digest"], site: "driver/verify.mjs — driver-written, not a model defect" },
|
|
112
|
+
// ── THE TYPED TRANSPORT'S OWN FAMILY (conversion 11) ──────────────────────────────────────────────
|
|
113
|
+
//
|
|
114
|
+
// These are raised by `register-digest-record.mjs` at the ACCEPTANCE BOUNDARY, not by verify.mjs, and
|
|
115
|
+
// they became visible to this census only when verify.mjs began reaching into that module for the
|
|
116
|
+
// digest's exit gate. They existed and were emitted for months before that; nothing was wrong with
|
|
117
|
+
// them, and nothing here changes behaviour. What changes is that the census can now see the family,
|
|
118
|
+
// which is the point of listing the module: a family the tripwire cannot read can grow a member no
|
|
119
|
+
// row covers, and nobody finds out.
|
|
120
|
+
{ token: "registerdigest_uri_missing", stages: ["register-digest"], site: "driver/register-digest-record.mjs — every row joins to a band record by its uri" },
|
|
121
|
+
{ token: "registerdigest_uri_unknown", stages: ["register-digest"], site: "driver/register-digest-record.mjs — a uri this run's band does not carry" },
|
|
122
|
+
{ token: "registerdigest_flag_reason_missing", stages: ["register-digest"], site: "driver/register-digest-record.mjs — the judgment the row exists to carry" },
|
|
123
|
+
{ token: "registerdigest_verify_invalid", stages: ["register-digest"], site: "driver/register-digest-record.mjs — one bare token of yes/no" },
|
|
124
|
+
{ token: "registerdigest_drop_reason_missing", stages: ["register-digest"], site: "driver/register-digest-record.mjs — a drop with no stated reason is a silent recall loss" },
|
|
125
|
+
{ token: "registerdigest_drop_ground_invalid", stages: ["register-digest"], site: "driver/register-digest-record.mjs — the closed ground token" },
|
|
126
|
+
{ token: "registerdigest_drop_ground_contradicted", stages: ["register-digest"], site: "driver/register-digest-record.mjs — the ground contradicts this run's own screen verdict" },
|
|
127
|
+
{ token: "registerdigest_instructed_incomplete", stages: ["register-digest"], site: "driver/register-digest-record.mjs — every instructed check carries ask AND answer" },
|
|
128
|
+
{ token: "registerdigest_adjudication_invalid", stages: ["register-digest"], site: "driver/register-digest-record.mjs — one bare token of ADOPTED/OVERRODE" },
|
|
129
|
+
{ token: "registerdigest_adjudication_incomplete", stages: ["register-digest"], site: "driver/register-digest-record.mjs — an override quotes the reason it contradicts" },
|
|
130
|
+
{ token: "registerdigest_nothing_judged", stages: ["register-digest"], site: "driver/register-digest-record.mjs — a digest that ends no record has not read the band" },
|
|
131
|
+
// The batching members, added with the batched accounting itself.
|
|
132
|
+
{ token: "registerdigest_batch_unknown", stages: ["register-digest"], site: "driver/register-digest-record.mjs — a batch number this run's split does not hold" },
|
|
133
|
+
{ token: "registerdigest_double_counted", stages: ["register-digest"], site: "driver/register-digest-record.mjs — a record ended under one batch cannot be ended under another" },
|
|
134
|
+
{ token: "registerdigest_model_write_failed", stages: ["register-digest"], site: "driver/register-digest-record.mjs — driver-written: the accumulator was lost mid-batch" },
|
|
105
135
|
{ token: "coverage_form_damaged", stages: ["register-digest"], site: "driver/verify.mjs" },
|
|
106
136
|
{ token: "coverage_form_engine_vocabulary", stages: ["register-digest"], site: "driver/verify.mjs" },
|
|
107
137
|
{ token: "coverage_form_axis_invalid", stages: ["register-digest"], site: "driver/verify.mjs" },
|
|
@@ -109,10 +139,10 @@ export const VOCABULARY = [
|
|
|
109
139
|
{ token: "coverage_form_missing", stages: ["register-digest"], site: "driver/verify.mjs" },
|
|
110
140
|
{ token: "coverage_form_empty", stages: ["register-digest"], site: "driver/verify.mjs" },
|
|
111
141
|
{ token: "coverage_status_offenum", stages: ["register-digest"], site: "driver/verify.mjs:2050" },
|
|
112
|
-
{ token: "coverage_deferred_unaccounted", stages: ["register-digest"], site: "driver/verify.mjs
|
|
113
|
-
{ token: "coverage_clean_unexecuted", stages: ["register-digest"], site: "driver/verify.mjs, the matterContext validator", family: "driver/register-plan.mjs:
|
|
114
|
-
{ token: "coverage_clean_skipped", stages: ["register-digest"], site: "driver/verify.mjs, the matterContext validator", family: "driver/register-plan.mjs:
|
|
115
|
-
{ token: "coverage_clean_unverified_incomplete", stages: ["register-digest"], site: "driver/verify.mjs, the matterContext validator", family: "driver/register-plan.mjs:
|
|
142
|
+
{ token: "coverage_deferred_unaccounted", stages: ["register-digest"], site: "driver/verify.mjs coverageFormFail", family: "driver/register-plan.mjs:1860 PROVIDER_HARD_ERROR_PREFIX — token on a data row", dynamic: "D5" },
|
|
143
|
+
{ token: "coverage_clean_unexecuted", stages: ["register-digest"], site: "driver/verify.mjs, the matterContext validator", family: "driver/register-plan.mjs:1594 validatePlanFeasibility", dynamic: "D6" },
|
|
144
|
+
{ token: "coverage_clean_skipped", stages: ["register-digest"], site: "driver/verify.mjs, the matterContext validator", family: "driver/register-plan.mjs:1955 searchedJurisdictionsFromPlan", dynamic: "D6" },
|
|
145
|
+
{ token: "coverage_clean_unverified_incomplete", stages: ["register-digest"], site: "driver/verify.mjs, the matterContext validator", family: "driver/register-plan.mjs:2183 disclosureTextByAxis", dynamic: "D7" },
|
|
116
146
|
{ token: "coverage_clean_tainted", stages: ["register-digest"], site: "driver/verify.mjs" },
|
|
117
147
|
{ token: "coverage_ledger_", stages: ["register-digest"], site: "driver/verify.mjs", family: "driver/coverage-ledger.mjs (parseCoverageLedgerJson token-first throws)", dynamic: "D4" },
|
|
118
148
|
{ token: "coverage_key_unknown", stages: ["register-digest"], site: "driver/verify.mjs", family: "driver/coverage-ledger.mjs", dynamic: "D4" },
|
|
@@ -121,18 +151,18 @@ export const VOCABULARY = [
|
|
|
121
151
|
{ token: "coverage_classes_invalid", stages: ["register-digest"], site: "driver/verify.mjs", family: "driver/coverage-ledger.mjs", dynamic: "D4" },
|
|
122
152
|
{ token: "plan_execution_unreadable", stages: ["register-digest", "narrative-refutation"], site: "driver/verify.mjs:1496, 1712" },
|
|
123
153
|
|
|
124
|
-
// ── matter-frame /
|
|
125
|
-
{ token: "stagecontracts_invalid", stages: ["matter-frame", "
|
|
154
|
+
// ── matter-frame / clearance-variants / blind-frame / frame-diff ──────────────────────────────────────
|
|
155
|
+
{ token: "stagecontracts_invalid", stages: ["matter-frame", "clearance-variants", "placement-inquiry", "case-law"], site: "driver/verify.mjs:1539 coverageEntryList, 1170, 1366, 1677" },
|
|
126
156
|
{ token: "meaning_angles_missing", stages: ["matter-frame"], site: "driver/verify.mjs" },
|
|
127
157
|
{ token: "frame_scope_missing", stages: ["matter-frame"], site: "driver/verify.mjs:1119" },
|
|
128
|
-
{ token: "variantmodel_romanization_missing", stages: ["
|
|
129
|
-
{ token: "variantmodel_family_incomplete", stages: ["
|
|
130
|
-
{ token: "variantmodel_term_markup", stages: ["
|
|
131
|
-
{ token: "variantmodel_missing", stages: ["
|
|
158
|
+
{ token: "variantmodel_romanization_missing", stages: ["clearance-variants"], site: "driver/verify.mjs" },
|
|
159
|
+
{ token: "variantmodel_family_incomplete", stages: ["clearance-variants"], site: "driver/verify.mjs" },
|
|
160
|
+
{ token: "variantmodel_term_markup", stages: ["clearance-variants"], site: "driver/verify.mjs" },
|
|
161
|
+
{ token: "variantmodel_missing", stages: ["clearance-variants"], site: "driver/verify.mjs:1171 checkFindingsSibling, 1230 checkJson" },
|
|
132
162
|
// Recovered during E2 authoring, absent from the draft census: variant-manifest.json is strict-parsed
|
|
133
163
|
// through checkSiblingJson (verify.mjs:1241) → checkJson (:742), so the WHOLE variantmodel_* family
|
|
134
|
-
// reaches
|
|
135
|
-
// CONVERSION 3 widened this family's SOURCE without widening its prefix. `
|
|
164
|
+
// reaches clearance-variants, not just the four literal tokens above.
|
|
165
|
+
// CONVERSION 3 widened this family's SOURCE without widening its prefix. `acceptClearanceVariants` raises
|
|
136
166
|
// `variantmodel_scope_layer_invalid`, `_scope_status_invalid`, `_scope_item_missing` and `_scope_pipe`
|
|
137
167
|
// at the ACCEPTANCE BOUNDARY — the call is refused in the turn where restating is free, and no manifest
|
|
138
168
|
// reaches disk. They share the prefix deliberately: a seat reading one refused call should not have to
|
|
@@ -142,7 +172,7 @@ export const VOCABULARY = [
|
|
|
142
172
|
// `fail(` / `throw new Error(` / `=>` string literals, and every record module returns
|
|
143
173
|
// `{ok: false, reason}` instead — measured, all four extract ZERO tokens. So this row is authored, not
|
|
144
174
|
// extracted, and nothing re-derives it if the module grows a member. Filed as.
|
|
145
|
-
{ token: "variantmodel_", stages: ["
|
|
175
|
+
{ token: "variantmodel_", stages: ["clearance-variants"], site: "driver/verify.mjs:1171 checkFindingsSibling → 742 (JSON family); driver/clearance-variants-record.mjs acceptClearanceVariants (scope-ledger transport family)", family: "driver/variant-manifest-model.mjs (token-first throws) + driver/clearance-variants-record.mjs", dynamic: "D3" },
|
|
146
176
|
{ token: "blindframe_", stages: ["blind-frame"], site: "driver/verify.mjs blindFrame → checkJson", family: "driver/blind-frame-model.mjs", dynamic: "D3" },
|
|
147
177
|
// — THE SKEPTIC TRANSPORT FAMILY, WHICH HAD NO ROW AT ALL. Nine tokens minted by acceptSkeptic
|
|
148
178
|
// and not one of them was covered here: the conversion that moved them to the acceptance boundary moved
|
|
@@ -179,6 +209,9 @@ export const VOCABULARY = [
|
|
|
179
209
|
|
|
180
210
|
// ── placement-inquiry ──────────────────────────────────────────────────────────────────────────────
|
|
181
211
|
{ token: "placementmodel_missing", stages: ["placement-inquiry"], site: "driver/verify.mjs:1352, 1379" },
|
|
212
|
+
{ token: "placement_unjudged", stages: ["placement-inquiry"], site: "driver/verify.mjs placementAccountVerdict" },
|
|
213
|
+
{ token: "placement_register_unrendered", stages: ["placement-inquiry"], site: "driver/verify.mjs placementAccountVerdict" },
|
|
214
|
+
{ token: "placement_form_unreadable", stages: ["placement-inquiry"], site: "driver/verify.mjs placementAccountVerdict" },
|
|
182
215
|
{ token: "placement", stages: ["placement-inquiry"], site: "driver/verify.mjs:1352 → 742", family: "driver/placement-model.mjs (`placement_*` and `placements_*`)", dynamic: "D3" },
|
|
183
216
|
|
|
184
217
|
// ── case-law / narrative-refutation ────────────────────────────────────────────────────────────────
|
|
@@ -231,7 +264,7 @@ export function normalizeFailToken(raw) {
|
|
|
231
264
|
export const ARM1_EXEMPTIONS = [
|
|
232
265
|
{
|
|
233
266
|
token: "stagecontracts_invalid",
|
|
234
|
-
stages: ["matter-frame", "
|
|
267
|
+
stages: ["matter-frame", "clearance-variants", "placement-inquiry", "case-law"],
|
|
235
268
|
reason: "The artifact is DRIVER-written (pipeline.mjs recordStageContract → _driver/stage-contracts.json). A corrupt one is a code or filesystem fault, and verify.mjs:1095 says so in its own comment. Pinning it on a model element would be the exact inversion #850 forbids — a mechanical failure wearing a model's name.",
|
|
236
269
|
},
|
|
237
270
|
// `tool_timeout` was on this list and has been REMOVED: register-unit's tool-written "execute the
|
|
@@ -357,12 +390,12 @@ export const TRIPWIRE_OUT_OF_SCOPE = [
|
|
|
357
390
|
token: "no_citations",
|
|
358
391
|
symbol: { file: "driver/case-law-ledger.mjs", names: ["findCaseLawLedgerViolations", "CASE_LAW_ADVISORY_REASONS", "isCaseLawBlocking"] },
|
|
359
392
|
site: "driver/case-law-ledger.mjs:179 (minted), :65 CASE_LAW_ADVISORY_REASONS, :67 isCaseLawBlocking",
|
|
360
|
-
reason: "ADVISORY, and filtered before the token is built.
|
|
393
|
+
reason: "ADVISORY, and filtered before the token is built. caseLawLedgerFail() in case-law-ledger.mjs keeps only blocking violations (:196), and `no_citations` is the one member of CASE_LAW_ADVISORY_REASONS — so it cannot appear even in the `caselaw_ledger` census payload, let alone as a token head. It is the honest no-on-point-precedent result the report is allowed to state; failing a run for it would manufacture citations.",
|
|
361
394
|
},
|
|
362
395
|
{
|
|
363
396
|
token: "accepted_not_folded",
|
|
364
397
|
symbol: { file: "driver/disposition-call.mjs", names: ["CALL_DROPS"] },
|
|
365
|
-
site: "driver/disposition-tool.mjs:378
|
|
398
|
+
site: "driver/disposition-tool.mjs:378 recordDispositions — where the token is minted, driver/disposition-call.mjs:192 CALL_DROPS",
|
|
366
399
|
reason: "A DRIVER-FAULT journal code, and the fault is ours. It records that the tool accepted a row the accumulator then did not carry; it is written to the call verdict ledger and reaches a seat only inside a sentence that orders the seat NOT to act (`your answer was valid and this is ours to fix`). A stage refusal built on it would be the driver failing a seat for the driver's own defect, so no stage can emit it by construction rather than by omission.",
|
|
367
400
|
},
|
|
368
401
|
{
|
|
@@ -430,7 +463,7 @@ export const INNER_CODES = Object.freeze([
|
|
|
430
463
|
{ code: "call_partial", mints: ["driver/connotation-search.mjs:2055"], rollsUpTo: ["connotation_call_partial"],
|
|
431
464
|
why: "As call_never_made — same table, same projection. This is the pair #1211 cites as its worked example: the composite is covered, the bare form reaches no stage." },
|
|
432
465
|
{ code: "quote_unbound", mints: ["driver/connotation-search.mjs:2186"], rollsUpTo: ["connotation_quote_unbound"],
|
|
433
|
-
why: "The ruled-but-unbound row. Projected at verify.mjs:
|
|
466
|
+
why: "The ruled-but-unbound row. Projected at verify.mjs:1450 unbound, and reported only once nothing is unruled." },
|
|
434
467
|
{ code: "token_absent", mints: ["driver/connotation-search.mjs:2213"], rollsUpTo: ["connotation_token_absent"],
|
|
435
468
|
why: "#592 split this out of no_ruling. Row-level only — repairs.mjs:352 says so in as many words: `never a top-level token`." },
|
|
436
469
|
{ code: "cite_absent", mints: ["driver/connotation-search.mjs:2222"], rollsUpTo: ["connotation_cite_absent"],
|
|
@@ -441,13 +474,13 @@ export const INNER_CODES = Object.freeze([
|
|
|
441
474
|
// data rather than deriving it. Every derivation anyone would write is `connotation_` + the code, and
|
|
442
475
|
// for this row that produces `connotation_no_recorded_queries`, which nothing mints and nothing covers.
|
|
443
476
|
// verify.mjs:912-913 states the ruling: a sweep that did not RUN is a canonical-only decision with its
|
|
444
|
-
// own token and its own remedy, so the projector
|
|
477
|
+
// own token and its own remedy, so the projector beside verify.mjs's CORRECTIONS_SECTION_RE deliberately does not handle it.
|
|
445
478
|
{ code: "no_recorded_queries", mints: ["driver/connotation-search.mjs:2070"], rollsUpTo: ["connotation_search_missing"],
|
|
446
|
-
why: "RENAMED, not namespaced: verify.mjs emits `connotation_search_missing`. It is excluded from CONNOTATION_FORM_REASONS at connotation-search.mjs
|
|
479
|
+
why: "RENAMED, not namespaced: verify.mjs emits `connotation_search_missing`. It is excluded from CONNOTATION_FORM_REASONS at connotation-search.mjs for exactly this reason." },
|
|
447
480
|
|
|
448
481
|
// ── case-law-ledger.mjs — ONE token, the codes as census payload ─────────────────────────────────
|
|
449
482
|
//
|
|
450
|
-
//
|
|
483
|
+
// caseLawLedgerFail() in case-law-ledger.mjs (:195) returns `caselaw_ledger:<census>;<detail>`, and
|
|
451
484
|
// `normalizeFailToken` cuts at the first colon — so the token is `caselaw_ledger` and every code below
|
|
452
485
|
// lives in the payload. The `caselaw_ledger` row already carries `family:
|
|
453
486
|
// "driver/case-law-ledger.mjs:204 (census reasons)"`, which is this ruling written down before the
|
|
@@ -521,11 +554,19 @@ export const COVERED_SOURCES = [
|
|
|
521
554
|
// its token-first throw through unchanged, so their families are already covered where they are raised.
|
|
522
555
|
// They are listed anyway, because the cost of listing a module that mints nothing is zero and the cost
|
|
523
556
|
// of the alternative — noticing, one day, that a module started minting — is the whole of this issue.
|
|
524
|
-
"
|
|
557
|
+
"clearance-variants-record.mjs", "skeptic-record.mjs", "frame-diff-record.mjs", "blind-frame-record.mjs",
|
|
525
558
|
// Conversion 4 — and this one MINTS, unlike the two delegating modules above it.
|
|
526
559
|
"report-overview-record.mjs",
|
|
527
560
|
// Conversion 5 — the fan-out transport; it mints its own family including the bound-index refusals.
|
|
528
561
|
"report-card-record.mjs",
|
|
562
|
+
// Conversion 11 — verify.mjs now reaches `digestAccountingGap`, the digest's exit gate, so the
|
|
563
|
+
// tripwire must read this module's token literals too. Without it the accounting family could grow a
|
|
564
|
+
// member that no vocabulary row covers and nothing would notice, which is this list's whole subject.
|
|
565
|
+
"register-digest-record.mjs",
|
|
566
|
+
// verify.mjs reaches `placementRenderAccount`, the placement pass's own account of what it recorded, and
|
|
567
|
+
// that module names the parser tokens it sorts rows by. It mints none of its own: every token it carries
|
|
568
|
+
// is placement-model.mjs's, passed through, so the `placement` family row already covers them.
|
|
569
|
+
"placement-form.mjs",
|
|
529
570
|
];
|
|
530
571
|
|
|
531
572
|
/**
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
set -u
|
|
23
23
|
|
|
24
24
|
# this fallback chain MIRRORS driver.config.mjs (`outboxDir` = CLEAROTRON_OUTBOX_DIR, else
|
|
25
|
-
# <workspaceRoot>/
|
|
25
|
+
# <workspaceRoot>/clearance-outbox; `workspaceRoot` = CLEAROTRON_WORK_DIR, else $HOME/trademark/workspace).
|
|
26
26
|
# It is a second derivation of the same answer in a language that cannot import the first, so it moves
|
|
27
27
|
# whenever that one does. If they disagree, the driver writes markers where this script never looks and
|
|
28
28
|
# delivery stops with nothing in any log — the shape prelim-outbox.path already has.
|
|
29
|
-
OUTBOX="${CLEAROTRON_OUTBOX_DIR:-${CLEAROTRON_WORK_DIR:-${OPENCLAW_HOME:-$HOME}/trademark/workspace}/
|
|
29
|
+
OUTBOX="${CLEAROTRON_OUTBOX_DIR:-${CLEAROTRON_WORK_DIR:-${OPENCLAW_HOME:-$HOME}/trademark/workspace}/clearance-outbox}"
|
|
30
30
|
OPENCLAW="$(command -v openclaw || echo "${OPENCLAW_HOME:-$HOME}/.npm-global/bin/openclaw")"
|
|
31
31
|
HELPER="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/outbox-backoff.mjs"
|
|
32
32
|
DRAIN_WAIT="${CLEAROTRON_OUTBOX_DRAIN_WAIT:-180}"
|
|
@@ -58,7 +58,7 @@ MSG="The trademark engine's outbox has pending events. Run the clearotron-delive
|
|
|
58
58
|
# below still runs, so a refusal cannot hot-loop the level-triggered .path unit.
|
|
59
59
|
WALL="$(command -v timeout || command -v gtimeout || true)"
|
|
60
60
|
if [ -z "$WALL" ]; then
|
|
61
|
-
echo "
|
|
61
|
+
echo "clearance-outbox: REFUSING TO WAKE — neither timeout(1) nor gtimeout(1) is on PATH, and every" >&2
|
|
62
62
|
echo " courier wake runs under it as an enforced wall (a wake that cannot be killed wedged this" >&2
|
|
63
63
|
echo " lane for 19h on 2026-07-04). NO event has been touched — they are all still pending and" >&2
|
|
64
64
|
echo " will deliver as soon as this is fixed. Install GNU coreutils on this host (Debian/Ubuntu:" >&2
|
|
@@ -70,7 +70,7 @@ fi
|
|
|
70
70
|
|
|
71
71
|
# C5 — deterministic rescan FIRST (cheap: readdir + status.json of unsettled runs only). On a timer fire
|
|
72
72
|
# this is what creates the work; on a marker fire it is a free consistency pass. Failure-tolerant.
|
|
73
|
-
node "$HELPER" rescan || echo "
|
|
73
|
+
node "$HELPER" rescan || echo "clearance-outbox: rescan failed (non-fatal — existing markers still processed)"
|
|
74
74
|
|
|
75
75
|
[ -d "$OUTBOX" ] || exit 0
|
|
76
76
|
shopt -s nullglob
|
|
@@ -89,7 +89,7 @@ for m in "${markers[@]}"; do
|
|
|
89
89
|
if printf '%s' "$a" | grep -qE '^[A-Za-z0-9_-]+$'; then
|
|
90
90
|
by_agent["$a"]+="$m"$'\n'
|
|
91
91
|
else
|
|
92
|
-
echo "
|
|
92
|
+
echo "clearance-outbox: quarantining marker with no routable agent: $m (payload kept)"
|
|
93
93
|
if mkdir -p "$OUTBOX/quarantine"; then mv -f "$m" "$OUTBOX/quarantine/" || true; fi
|
|
94
94
|
fi
|
|
95
95
|
done
|
|
@@ -107,24 +107,24 @@ for agent in "${!by_agent[@]}"; do
|
|
|
107
107
|
# paces the .path re-trigger. Helper failure answers "due" (never lose a delivery).
|
|
108
108
|
gate="$(node "$HELPER" check "$agent" || echo due)"
|
|
109
109
|
if [ "${gate%% *}" = "wait" ]; then
|
|
110
|
-
echo "
|
|
110
|
+
echo "clearance-outbox: $agent in backoff (${gate#wait } s left) — events retained, not waking"
|
|
111
111
|
track_wait "${gate#wait }"
|
|
112
112
|
continue
|
|
113
113
|
fi
|
|
114
114
|
|
|
115
|
-
echo "
|
|
115
|
+
echo "clearance-outbox: waking $agent to run clearotron-deliver"
|
|
116
116
|
# timeout(1) is the enforced wall: the 2026-07-04 incident proved the CLI's own --timeout does not
|
|
117
117
|
# guarantee process EXIT (the agent turn finished; the process idled 19h and wedged the lane).
|
|
118
118
|
# SIGTERM at 840s (inside the unit's TimeoutStartSec budget so the failure is OURS and logged),
|
|
119
119
|
# SIGKILL 30s later. The turn runs server-side to completion either way; since this trigger deletes
|
|
120
120
|
# nothing, a killed wake just leaves the events for the re-fire.
|
|
121
121
|
#
|
|
122
|
-
# FRESH session per wake (was a fixed --session-key
|
|
122
|
+
# FRESH session per wake (was a fixed --session-key clearance-outbox): reusing ONE session meant every
|
|
123
123
|
# re-fire piled onto an ever-growing transcript the model reprocessed each time — that unbounded
|
|
124
124
|
# growth, not the wake count alone, is what turned a stuck marker into $200+/day (2026-07-24/25). A
|
|
125
125
|
# unique key bounds each wake to the skill + this one outbox read. The circuit-breaker in
|
|
126
126
|
# outbox-backoff.mjs (not session history) now owns cross-wake loop detection.
|
|
127
|
-
wake_session="
|
|
127
|
+
wake_session="clearance-outbox-$(date -u +%Y%m%dT%H%M%SZ)-$$-${RANDOM}"
|
|
128
128
|
model_args=()
|
|
129
129
|
[ -n "$WAKE_MODEL" ] && model_args=(--model "$WAKE_MODEL")
|
|
130
130
|
out="$("$WALL" --kill-after=30 840 "$OPENCLAW" agent --agent "$agent" --session-key "$wake_session" "${model_args[@]}" --message "$MSG" --json --timeout 300)"
|
|
@@ -142,21 +142,21 @@ for agent in "${!by_agent[@]}"; do
|
|
|
142
142
|
# is the load-bearing cost stop — it ends the re-fire loop for a marker mark_sent/ack_event can never
|
|
143
143
|
# settle (the 2026-07 runaway class), whatever the cause. Operator notification is integrator-owned:
|
|
144
144
|
# surface stuck deliveries from the audit record / MCP read surface, not from the requester outbox.
|
|
145
|
-
echo "
|
|
145
|
+
echo "clearance-outbox: 🚨 stuck marker(s) for $agent set aside after repeated no-progress wakes — see $OUTBOX/quarantine/STUCK-ALERTS.jsonl"
|
|
146
146
|
track_wait "${verdict#* }"
|
|
147
147
|
;;
|
|
148
148
|
stuck)
|
|
149
149
|
# OK wake that consumed nothing — not a failure, but not progress either. Paced down toward the
|
|
150
150
|
# quarantine threshold instead of hot-refiring every ~3.5min.
|
|
151
|
-
echo "
|
|
151
|
+
echo "clearance-outbox: no delivery progress for $agent — marker retained, paced ${verdict#* }s (circuit-breaker counting toward quarantine)"
|
|
152
152
|
track_wait "${verdict#* }"
|
|
153
153
|
;;
|
|
154
154
|
giveup)
|
|
155
|
-
echo "
|
|
155
|
+
echo "clearance-outbox: wake for $agent failed rc=$rc — fast retries exhausted; sidecar cooldown + rescan timer own this delivery (events retained)"
|
|
156
156
|
track_wait "${verdict#* }"
|
|
157
157
|
;;
|
|
158
158
|
*)
|
|
159
|
-
echo "
|
|
159
|
+
echo "clearance-outbox: wake for $agent failed rc=$rc — events retained, backoff ${verdict#* }s"
|
|
160
160
|
track_wait "${verdict#* }"
|
|
161
161
|
;;
|
|
162
162
|
esac
|
|
@@ -185,8 +185,8 @@ if [ "$woke_ok" = 1 ]; then
|
|
|
185
185
|
sleep 5; waited=$((waited + 5))
|
|
186
186
|
remaining=("$OUTBOX"/*.pending)
|
|
187
187
|
done
|
|
188
|
-
[ ${#remaining[@]} -gt 0 ] || { echo "
|
|
189
|
-
echo "
|
|
188
|
+
[ ${#remaining[@]} -gt 0 ] || { echo "clearance-outbox: drained"; exit 0; }
|
|
189
|
+
echo "clearance-outbox: ${#remaining[@]} event(s) still pending after ${DRAIN_WAIT}s"
|
|
190
190
|
fi
|
|
191
191
|
|
|
192
192
|
# TIGHT-LOOP GUARD (load-bearing): prelim-outbox.path is PathExistsGlob on *.pending — level-triggered,
|
|
@@ -201,7 +201,7 @@ if [ -n "$min_wait" ]; then
|
|
|
201
201
|
[ "$w" -gt "$cap" ] && w="$cap"
|
|
202
202
|
[ "$w" -gt "$budget" ] && w="$budget"
|
|
203
203
|
if [ "$w" -gt 0 ]; then
|
|
204
|
-
echo "
|
|
204
|
+
echo "clearance-outbox: events retained — sleeping ${w}s so the .path re-fire matches the backoff"
|
|
205
205
|
sleep "$w"
|
|
206
206
|
fi
|
|
207
207
|
fi
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
27
27
|
import { tmpdir } from "node:os";
|
|
28
|
-
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
28
|
+
import { basename, dirname, join, resolve, sep } from "node:path"; import { studioDirFor } from "../shared/pre-rename-spellings.mjs";
|
|
29
29
|
|
|
30
30
|
/** The entry file each lane's publisher reads as its source, in the order a child is probed for one. */
|
|
31
31
|
export const ENTRY_FILES = Object.freeze(["report.md", "knockout-findings.json"]);
|
|
@@ -155,7 +155,7 @@ export function publishContainer(root, { repoRoot, tmp = tmpdir() } = {}) {
|
|
|
155
155
|
* The demo published its samples as reports and made no run directory, so the connector its own connect
|
|
156
156
|
* line wires listed nothing: an assistant, one of the demo's three faces, had nothing to explore. Each
|
|
157
157
|
* sample's finished `run/` is copied to the layout the connector walks, under the DEMO'S OWN workspace:
|
|
158
|
-
* `<workspace>/workspace-<agent>/studio/
|
|
158
|
+
* `<workspace>/workspace-<agent>/studio/clearance-search/<slug>/<date>-<codename>/`. Nothing is written
|
|
159
159
|
* anywhere else, so a real install started afterwards sees none of it (the demo is its own install).
|
|
160
160
|
*
|
|
161
161
|
* Copied, never linked: a connector reading a run may write beside it, and `demo/` is tracked. A run
|
|
@@ -176,7 +176,7 @@ export function seedDemoRuns({ workspace, examplesDir, portalOrigin = null }) {
|
|
|
176
176
|
let s;
|
|
177
177
|
try { s = JSON.parse(readFileSync(join(run, "status.json"), "utf8")); } catch { continue; }
|
|
178
178
|
if (!s?.slug || !s?.codename || !s?.date) continue;
|
|
179
|
-
const dir = join(workspace, `workspace-${s.agent || "clawdi"}
|
|
179
|
+
const dir = join(studioDirFor(join(workspace, `workspace-${s.agent || "clawdi"}`)), s.slug, `${s.date}-${s.codename}`);
|
|
180
180
|
if (existsSync(join(dir, "status.json"))) already.push(s.runId);
|
|
181
181
|
else {
|
|
182
182
|
// ONE SAMPLE'S UNREADABLE FILE COSTS THAT SAMPLE ONLY, and is named, never a throw out of the loop.
|
package/driver/dev-portal.mjs
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
import { envFileRead } from "../shared/env-local.mjs"; // side effect: apply this install's .env when THIS file is the CLI entry (never on library import)
|
|
33
33
|
import { createServer, request as httpRequest } from "node:http";
|
|
34
34
|
import { readFileSync, existsSync, statSync, readdirSync, writeFileSync, renameSync, mkdirSync } from "node:fs";
|
|
35
|
-
import { join, resolve, extname, dirname } from "node:path";
|
|
35
|
+
import { join, resolve, extname, dirname } from "node:path"; import { studioDirFor } from "../shared/pre-rename-spellings.mjs";
|
|
36
36
|
import { fileURLToPath } from "node:url";
|
|
37
37
|
import { config } from "./driver.config.mjs";
|
|
38
38
|
import { BRAND } from "../shared/brand.mjs";
|
|
@@ -135,7 +135,7 @@ function readJsonBody(req, maxBytes = 256 * 1024) {
|
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
// Run statuses: every workspace's studio/
|
|
138
|
+
// Run statuses: every workspace's studio/clearance-search/<slug>/<run>/status.json — live runs PLUS the
|
|
139
139
|
// archive (a delivered run moves there on delivery; without it the cockpit shows a run "disappearing"
|
|
140
140
|
// at the exact moment it succeeds — found by the first dev smoke run). Read fresh per request.
|
|
141
141
|
function scanRuns(workspaceRoot) {
|
|
@@ -153,7 +153,7 @@ function scanRuns(workspaceRoot) {
|
|
|
153
153
|
try { names = readdirSync(workspaceRoot); } catch { return out; }
|
|
154
154
|
for (const name of names) {
|
|
155
155
|
if (config.agentIdFromWorkspaceName(name) == null) continue;
|
|
156
|
-
const studio = join(workspaceRoot, name
|
|
156
|
+
const studio = studioDirFor(join(workspaceRoot, name));
|
|
157
157
|
let slugs = [];
|
|
158
158
|
try { slugs = readdirSync(studio); } catch { continue; }
|
|
159
159
|
for (const slug of slugs) {
|
|
@@ -653,7 +653,7 @@ export function validateDispositionCall(rows, recorded, { told = null } = {}) {
|
|
|
653
653
|
// ruling the whole time; what it could not do was copy a fragment that binds. So the missing exit was
|
|
654
654
|
// never from the judgment.
|
|
655
655
|
//
|
|
656
|
-
// AND THE JUDGMENT ALREADY HAS ONE.
|
|
656
|
+
// AND THE JUDGMENT ALREADY HAS ONE. clearance-common-law/SKILL.md dictates it: a row that is on-topic but
|
|
657
657
|
// cannot responsibly be called benign or loaded is ruled `loaded` with the note saying what could not
|
|
658
658
|
// be established, "which is where an unresolved reputational question belongs". Adding a second way
|
|
659
659
|
// to decline a ruling would compete with that, and an easier road past a hard row is the one outcome
|
package/driver/door-gates.mjs
CHANGED
|
@@ -41,7 +41,9 @@
|
|
|
41
41
|
import { resolveEffectiveProfile, recipeProseGuard, platformEntryErrors } from "./profiles.mjs";
|
|
42
42
|
import { wantsPortalRoute, PORTAL_ROUTE_UNAVAILABLE } from "./enqueue-schema.mjs";
|
|
43
43
|
import { gateResolvedPolicy, loadRecipes } from "./search-policy.mjs";
|
|
44
|
-
import {
|
|
44
|
+
import { resolveTerritories } from "./effective-scope.mjs";
|
|
45
|
+
import { uncoveredTerritories, registerReachRefusal } from "./register-coverage.mjs";
|
|
46
|
+
import { readFlagSnapshot, registerTerritoriesFor, registerLabelFor } from "./flag-snapshot.mjs";
|
|
45
47
|
import { config } from "./driver.config.mjs";
|
|
46
48
|
import { resolveRequest } from "./resolve-request.mjs";
|
|
47
49
|
import { checkResolvedProduct } from "./scope-rules.mjs";
|
|
@@ -56,10 +58,14 @@ import { checkResolvedProduct } from "./scope-rules.mjs";
|
|
|
56
58
|
* `readable` says whether the profile store answered at all — the input `checkClearanceScopeRules`
|
|
57
59
|
* needs to tell "this account has no default territories" apart from "we could not read the account".
|
|
58
60
|
*/
|
|
59
|
-
/** The wired register
|
|
60
|
-
* read the snapshot must still open
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
/** The wired register as a door needs it: what it covers, and what to CALL it in a sentence a client
|
|
62
|
+
* reads. One read, both answers. Never throws — a door that cannot read the snapshot must still open,
|
|
63
|
+
* and `territories: undefined` is the fail-open answer every layer below already speaks. */
|
|
64
|
+
function snapshotRegister() {
|
|
65
|
+
try {
|
|
66
|
+
const snap = readFlagSnapshot(config.poolRootOrNull);
|
|
67
|
+
return { territories: registerTerritoriesFor(snap), label: registerLabelFor(snap) };
|
|
68
|
+
} catch { return { territories: undefined, label: null }; }
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
export function resolveForDoor(job) {
|
|
@@ -92,8 +98,12 @@ export function resolveForDoor(job) {
|
|
|
92
98
|
* products.mjs and search-policy.mjs, for every door.
|
|
93
99
|
*/
|
|
94
100
|
export function gateResolvedRequest({ job = null, profile = null, resolved = null, readable = true } = {},
|
|
95
|
-
{ availability = true, registerTerritories = undefined } = {}) {
|
|
101
|
+
{ availability = true, registerTerritories = undefined, registerLabel = undefined } = {}) {
|
|
96
102
|
const out = { errors: [], warnings: [], byCheck: {} };
|
|
103
|
+
// Read at most once per gate call, and not at all when both arms were given their answer — a test
|
|
104
|
+
// driving a Signa-shaped deployment must not need a snapshot on disk to do it.
|
|
105
|
+
let snapshot;
|
|
106
|
+
const register = () => (snapshot ??= snapshotRegister());
|
|
97
107
|
// A resolution that could not be taken is not a refusal — see the fail-open note in the header.
|
|
98
108
|
if (!resolved) return out;
|
|
99
109
|
// A CLARIFY IS RELAYED VERBATIM. It is already an actionable sentence naming the selector that could
|
|
@@ -114,10 +124,34 @@ export function gateResolvedRequest({ job = null, profile = null, resolved = nul
|
|
|
114
124
|
//
|
|
115
125
|
// `undefined` is the fail-open answer at every layer below, so an unreadable or absent snapshot
|
|
116
126
|
// leaves this arm silent and the runner's wall still decides — the door rule stated in the header.
|
|
117
|
-
const terr = registerTerritories !== undefined ? registerTerritories :
|
|
127
|
+
const terr = registerTerritories !== undefined ? registerTerritories : register().territories;
|
|
118
128
|
const gateMsg = gateResolvedPolicy(resolved, { registerTerritories: terr });
|
|
119
129
|
if (gateMsg) { out.errors.push(gateMsg); return out; }
|
|
120
130
|
}
|
|
131
|
+
// ── A TERRITORY THIS REQUEST NAMES THAT THE WIRED REGISTER CANNOT SEARCH ──────────────────────────
|
|
132
|
+
//
|
|
133
|
+
// OUTSIDE the availability block, and that placement is the whole correctness of this arm. The portal
|
|
134
|
+
// and plan_run pass `availability:false` because they word an unavailable PRODUCT in their own words
|
|
135
|
+
// (the header's staff-prose split) — so an arm written inside that block cannot fire at the two doors
|
|
136
|
+
// a client actually orders through, and it would fail to fire SILENTLY, green, on the case the ruling
|
|
137
|
+
// of 2026-09-17 is about. This refusal carries no switch name and no internal key, so unlike the
|
|
138
|
+
// availability twin it is the same sentence on every surface and needs no client-facing rewording.
|
|
139
|
+
//
|
|
140
|
+
// THE TERRITORIES ARE RESOLVED HERE, NOT THREADED IN. `resolveTerritories` is the same ladder
|
|
141
|
+
// effective-scope.mjs runs for the scope a door prints beside this refusal, so the two cannot
|
|
142
|
+
// disagree. Asking each of the six doors to pass its own scope would let one forget the argument and
|
|
143
|
+
// fail open in silence — the exact shape `register-coverage-doors.test.mjs` exists to catch one layer
|
|
144
|
+
// up. One call, in the one gate they all share, covers every door by construction.
|
|
145
|
+
//
|
|
146
|
+
// Fail-open on a throw, the door's rule: an unreadable profile store must not stop somebody searching.
|
|
147
|
+
{
|
|
148
|
+
let named = [];
|
|
149
|
+
try { named = resolveTerritories(job ?? {}, profile, resolved?.recipeScope ?? null).jurisdictions ?? []; } catch { named = []; }
|
|
150
|
+
const terr = registerTerritories !== undefined ? registerTerritories : register().territories;
|
|
151
|
+
const label = registerLabel !== undefined ? registerLabel : register().label;
|
|
152
|
+
const refusal = registerReachRefusal(uncoveredTerritories(named, terr), label);
|
|
153
|
+
if (refusal) { out.errors.push(refusal); return out; }
|
|
154
|
+
}
|
|
121
155
|
const gates = checkResolvedProduct({ job, profile, resolved, profileReadable: profile !== null && readable });
|
|
122
156
|
out.errors.push(...gates.errors);
|
|
123
157
|
out.warnings.push(...gates.warnings);
|
package/driver/doubt-ledger.mjs
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// by design (the audit is the defensibility record of everything considered). copper-gantry shipped three
|
|
7
7
|
// fragments about ONE mark side by side: an asserted "closest analogue, active nationwide product" block,
|
|
8
8
|
// a direct-search "does NOT appear on the owner's official sites" block, and a prose "requires
|
|
9
|
-
//
|
|
9
|
+
// clearance-register layer cross-check" note that NOTHING parses. The resolutions usually EXIST — in
|
|
10
10
|
// findings.json dispositions/actions, in the coverage ledger, in register-findings answer/watchlist
|
|
11
11
|
// lines — the missing piece was the JOIN back to the fragment that raised the doubt. This module is
|
|
12
12
|
// that join, and nothing more.
|
|
@@ -179,7 +179,7 @@ function twoTokenMatch(sig, candidateText) {
|
|
|
179
179
|
// ── minting: gather cross-check hand-offs ─────────────────────────────────────────────────────────
|
|
180
180
|
// The gather stages are DICTATED (stages.mjs) to record any check they could not perform, on its own
|
|
181
181
|
// line, in EXACTLY this shape. The prefix is exact and the parse is deterministic ON PURPOSE: legacy
|
|
182
|
-
// artifacts (and free prose like "requires
|
|
182
|
+
// artifacts (and free prose like "requires clearance-register layer cross-check" buried in a paragraph —
|
|
183
183
|
// the copper-gantry note nothing parsed) mint NOTHING. Carrying prose doubts is the dictation's job at
|
|
184
184
|
// the source, not a fuzzy parser's job here. A leading list bullet is tolerated (models bullet
|
|
185
185
|
// everything); anything else about the shape is strict, including the em-dash between what and why.
|
|
@@ -105,14 +105,40 @@ export function drainerVerdict({ stamp, headCommit, isAlive, processes, ppidOf =
|
|
|
105
105
|
const nameThem = (ps) => ps.map((p) => `pid ${p.pid}`).join(", ");
|
|
106
106
|
|
|
107
107
|
if (!stamp) {
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
108
|
+
// THREE SITUATIONS LIVED IN ONE FAIL, AND ONE OF THEM IS NOT A FINDING.
|
|
109
|
+
//
|
|
110
|
+
// All three begin the same way — no stamp, so what the executing process holds was never
|
|
111
|
+
// established. What separates them is the PROCESS TABLE, and the old message ran the answers
|
|
112
|
+
// together: it asserted "nothing is executing runs on this box", a finding, and closed with "This is
|
|
113
|
+
// a failure to look, never a pass", which is the opposite claim. A reader could act on either.
|
|
114
|
+
//
|
|
115
|
+
// The module's ruling about postures says what each exit's posture IS. It does not license reporting
|
|
116
|
+
// two different facts through one verdict, and a deployment check is exactly where that is
|
|
117
|
+
// expensive: redeploying fixes an idle box and does nothing at all for an unreadable process table.
|
|
118
|
+
//
|
|
119
|
+
// — NOTHING WAS ESTABLISHED IN EITHER DIRECTION. No stamp and no process table: this arm did not
|
|
120
|
+
// find an idle box, it failed to look at one. Skipped and marked, never passed — the caller counts
|
|
121
|
+
// it toward a different exit code, and the box could be perfectly healthy or completely wedged.
|
|
122
|
+
if (seen === null) {
|
|
123
|
+
return { state: "skip", blocked: true,
|
|
124
|
+
message: `no drainer identity stamp at ${STAMP_BASENAME} AND the process table could not be read: what the `
|
|
125
|
+
+ "process that executes runs holds was not established, and neither was whether one is running at all. "
|
|
126
|
+
+ `This is a failure to look — redeploying would change nothing, because nothing was compared.${postureNote}` };
|
|
127
|
+
}
|
|
128
|
+
// — THE INCIDENT'S OWN SHAPE. Drainer-shaped processes are running and none of them stamped
|
|
129
|
+
// anything, so what build they hold is unknown. This is the state the orphaned drainer was in and
|
|
130
|
+
// the reason this arm exists; it is a finding and stays one.
|
|
131
|
+
if (seen.length) {
|
|
132
|
+
return { state: "fail", message: `no drainer identity stamp at ${STAMP_BASENAME} while ${seen.length} `
|
|
133
|
+
+ `drainer-shaped process(es) ARE running (${nameThem(seen)}) — unstamped, so what build they hold is `
|
|
134
|
+
+ `unknown. The process table was read; this is what it said.${postureNote}` };
|
|
135
|
+
}
|
|
136
|
+
// — A FINDING, and the plainest one here. The process table WAS read and holds no drainer, so
|
|
137
|
+
// nothing is executing runs on this box. Saying "failure to look" about a table that answered was
|
|
138
|
+
// the contradiction at the centre of this.
|
|
139
|
+
return { state: "fail", message: `no drainer identity stamp at ${STAMP_BASENAME} and no drainer-shaped process `
|
|
140
|
+
+ "is running, so nothing is executing runs on this box. The process table was read, and this is what "
|
|
141
|
+
+ `it said.${postureNote}` };
|
|
116
142
|
}
|
|
117
143
|
|
|
118
144
|
const pid = Number(stamp.pid) || 0;
|