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.
- package/.env.example +34 -3
- package/CONTRIBUTING.md +8 -8
- package/INSTALL.md +6 -6
- package/SECURITY.md +3 -3
- package/bin/brandowner.mjs +3 -3
- package/bin/framework-preflight.mjs +1 -1
- package/bin/start.mjs +18 -4
- 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 +6 -3
- package/docs/architecture/05-config-governance.md +6 -1
- 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 +48 -0
- package/driver/README.md +3 -3
- 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/consumption-ledger.mjs +2 -2
- package/driver/contract-arm2-baseline.json +2 -3
- package/driver/contract-dictation-registry.mjs +19 -19
- package/driver/contract-e3-backlog.mjs +19 -19
- package/driver/contract-e3-baseline.json +14 -14
- package/driver/contract-vocabulary.mjs +24 -17
- 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/doubt-ledger.mjs +2 -2
- package/driver/drainer-identity.mjs +34 -8
- package/driver/driver.config.mjs +95 -45
- 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 +5 -5
- package/driver/enqueue-schema.mjs +6 -2
- package/driver/findings-model.mjs +5 -2
- package/driver/flag-snapshot.mjs +6 -3
- package/driver/form-neighbourhood.mjs +54 -7
- package/driver/framework.mjs +4 -4
- package/driver/gateway.mjs +12 -6
- package/driver/jx-lanes.mjs +2 -2
- package/driver/jx-units.mjs +1 -1
- package/driver/jx.mjs +30 -2
- package/driver/knockout-review-record.mjs +56 -4
- package/driver/known-conflicts.mjs +1 -1
- package/driver/named-band.mjs +1 -33
- 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 +206 -68
- package/driver/placement-form.mjs +77 -1
- package/driver/placement-model.mjs +1 -1
- package/driver/portal-report.mjs +92 -5
- package/driver/portal-service.mjs +34 -8
- package/driver/portal-upstream.mjs +1 -1
- 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 +110 -5
- package/driver/publish/knockout.mjs +29 -4
- package/driver/publish/pool-admin.mjs +1 -1
- package/driver/publish/publish-inputs.mjs +18 -2
- package/driver/publish/render-knockout.mjs +115 -24
- package/driver/publish/render.mjs +153 -34
- package/driver/publish/search-depth.mjs +133 -4
- package/driver/publish/templates/report.css +60 -3
- package/driver/publish/xlsx.mjs +8 -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-count.mjs +50 -5
- package/driver/register-coverage.mjs +67 -0
- package/driver/register-grant-vocabulary.mjs +1 -1
- package/driver/register-plan.mjs +19 -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/run-requirements.mjs +3 -3
- package/driver/runner.mjs +2 -2
- 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 +53 -53
- package/driver/status-snapshot.mjs +2 -2
- package/driver/suite-census.json +218 -92
- package/driver/surface-exit-verdict.mjs +58 -0
- package/driver/systemd/README.md +2 -2
- package/driver/systemd/clearotron-worker.service +1 -1
- package/driver/terminal-clamp.mjs +2 -0
- 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 +67 -6
- package/driver/whatif-queue.mjs +1 -1
- package/driver/wordlists/en.txt +63906 -0
- package/mcp-server/CHANGELOG.md +4 -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 +3 -0
- package/package.json +12 -11
- package/portal-ui/dist/assets/{index-CVOIvdhc.css → index-CtvwLCti.css} +207 -3
- package/portal-ui/dist/assets/{index-6jzO9HiX.js → index-EVaSo5-g.js} +1459 -482
- 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/oauth-mcp-bridge/CHANGELOG.md +4 -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/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 +4 -4
- 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 +27 -0
- package/scripts/env-classify.mjs +20 -2
- package/scripts/freeze-example-run.mjs +20 -10
- 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/shared/brand.mjs +27 -0
- package/shared/connect-clients.mjs +39 -11
- 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 +3 -1
- 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
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright 2026 Cordillera Sarl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md
|
|
3
|
+
//
|
|
4
|
+
// WHICH ANSWER THE DEPLOYMENT CHECK GIVES, as a number a caller can act on.
|
|
5
|
+
//
|
|
6
|
+
// Extracted from scripts/live-surface-check.mjs for the reason roster-verdict.mjs and
|
|
7
|
+
// unit-state-verdict.mjs were: that file is a program, and importing it to reach one decision runs its
|
|
8
|
+
// preflight and exits. A decision nobody can drive without a deployment to point at is a decision nobody
|
|
9
|
+
// drives.
|
|
10
|
+
//
|
|
11
|
+
// ── THE DEFECT THIS SETTLES ──────────────────────────────────────────────────────────────────────────
|
|
12
|
+
//
|
|
13
|
+
// The check reported "I could not look" and "this has drifted" through the same FAIL. Two arms said in
|
|
14
|
+
// their own message "This is a failure to look, never a pass" and then returned the verdict a genuine
|
|
15
|
+
// drift returns, so a reader could not tell them apart without reading to the end of the message.
|
|
16
|
+
//
|
|
17
|
+
// They want different things done. A drift is fixed by redeploying. A could-not-look is fixed by pointing
|
|
18
|
+
// the check at something it can read, and until somebody does, nothing is known about that surface in
|
|
19
|
+
// either direction — redeploying would change nothing, because nothing was compared.
|
|
20
|
+
//
|
|
21
|
+
// The cost of leaving it is the familiar one: a FAIL that turns out to be "could not look" teaches
|
|
22
|
+
// whoever runs the check to read FAIL as noise, and the run where it means drift is the one nobody acts
|
|
23
|
+
// on. A deployment check is exactly where that is expensive.
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The exit code for a finished run.
|
|
27
|
+
*
|
|
28
|
+
* 0 every surface was read and none disagreed
|
|
29
|
+
* 1 a surface DRIFTED — redeploy; the report names which
|
|
30
|
+
* 3 nothing drifted, and a surface COULD NOT BE READ
|
|
31
|
+
*
|
|
32
|
+
* 2 belongs to the preflight refusals, which fire before any surface is examined: the instance did not
|
|
33
|
+
* say where its pool or its doors are, so the run has nothing to report rather than something to report
|
|
34
|
+
* badly.
|
|
35
|
+
*
|
|
36
|
+
* A DRIFT OUTRANKS A COULD-NOT-LOOK when both are present. The drift is actionable now and the unreadable
|
|
37
|
+
* surface is a second errand; both are on the report, and only the code is ordered.
|
|
38
|
+
*
|
|
39
|
+
* ORDINARY SKIPS MUST NOT REACH HERE, which is why the caller passes a separate count rather than every
|
|
40
|
+
* skip. Several surfaces are deliberately not probed — a client door behind an access proxy, a door this
|
|
41
|
+
* instance does not name — and those are the resting state of a healthy box. A code that moved on them
|
|
42
|
+
* would fire on every good run and be ignored inside a week, which is this same defect one level up.
|
|
43
|
+
*
|
|
44
|
+
* @param {{failed?: number, couldNotLook?: number}} counts
|
|
45
|
+
*/
|
|
46
|
+
export function exitFor({ failed = 0, couldNotLook = 0 } = {}) {
|
|
47
|
+
if (failed) return 1;
|
|
48
|
+
if (couldNotLook) return 3;
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** What each code means, for a caller printing it or a reader wondering. Keyed by the code itself. */
|
|
53
|
+
export const EXIT_MEANING = Object.freeze({
|
|
54
|
+
0: "every surface was read and none disagreed",
|
|
55
|
+
1: "a surface drifted — redeploy; the report names which",
|
|
56
|
+
2: "the instance did not say where its pool or its doors are, so nothing was examined",
|
|
57
|
+
3: "nothing drifted, and a surface could not be read — nothing is known about it either way",
|
|
58
|
+
});
|
package/driver/systemd/README.md
CHANGED
|
@@ -137,7 +137,7 @@ on a **literal glob** -- a `.path` unit cannot read an environment variable, so
|
|
|
137
137
|
your configuration:
|
|
138
138
|
|
|
139
139
|
```
|
|
140
|
-
PathExistsGlob=%h/.openclaw/workspace-clawdi/studio/
|
|
140
|
+
PathExistsGlob=%h/.openclaw/workspace-clawdi/studio/clearance-search/queue/*.json
|
|
141
141
|
```
|
|
142
142
|
|
|
143
143
|
**That prefix is one deployment's layout, not yours.** Enable this unit without editing that line to
|
|
@@ -194,7 +194,7 @@ degrades and the degradation should be findable.
|
|
|
194
194
|
|
|
195
195
|
| Part | Needs | What happens without it |
|
|
196
196
|
|---|---|---|
|
|
197
|
-
| **Outbox delivery trigger** — `driver/deliver-trigger.sh`, driven by the `
|
|
197
|
+
| **Outbox delivery trigger** — `driver/deliver-trigger.sh`, driven by the `clearance-outbox` systemd `.path`/`.service`/`.timer` units | systemd; bash >= 4 for `declare -A`; `timeout(1)` (GNU coreutils, or `gtimeout` from Homebrew) as the enforced wall on every courier wake | The script refuses at startup and names the missing piece. It will not wake a courier it cannot put a wall around — an unkillable wake wedged a lane for 19h once. No event is touched: everything stays pending and delivers as soon as the host is fixed. |
|
|
198
198
|
| **PID-reuse claim defence** — the queue runner telling a live claimer from a recycled pid | A birth stamp for a process:`/proc/<pid>/stat` on Linux, `ps -o lstart` on macOS and anywhere else POSIX. Absent only where neither answers — WSL1, some sandboxes | Degrades **fail-safe**, and the runner says so once at startup. Claims record a bare pid, so a claim whose liveness cannot be proved counts as alive: no run is ever double-claimed and no lawyer double-delivered to. What is lost is the escape hatch — a `.processing` marker held by a recycled pid waits for the max-claim-age ceiling instead of being freed on the next tick. |
|
|
199
199
|
|
|
200
200
|
CI runs the suite on macOS as well as Linux, and an assertion covering a capability the box lacks skips
|
|
@@ -49,7 +49,7 @@ Environment=PATH=%h/.local/bin:%h/.npm-global/bin:/usr/local/bin:/usr/bin:/bin
|
|
|
49
49
|
Environment=CLEAROTRON_NO_ENV_FILE=1
|
|
50
50
|
ExecStart=/usr/bin/node ${CLEAROTRON_CHECKOUT_DIR}/driver/runner.mjs --watch
|
|
51
51
|
# ── REFRESH THE CAPABILITY PAGE'S CAPTURE AT EVERY START ─────────────────────────────────────────────
|
|
52
|
-
# The capability page renders `pool/_state/
|
|
52
|
+
# The capability page renders `pool/_state/clearance-flag-snapshot.json`, and until this line its only
|
|
53
53
|
# writers were a RUN and the `clearotron start` launcher. A hosted box runs neither: these units are the
|
|
54
54
|
# entrypoint, and a deployment being CONFIGURED runs nothing by definition. So the page reported the old
|
|
55
55
|
# configuration as current fact for exactly as long as somebody was working on the configuration, which
|
|
@@ -110,6 +110,7 @@ export function unrenderableConditions({ reasons, clauses } = {}) {
|
|
|
110
110
|
const rs = Array.isArray(reasons) ? reasons : [];
|
|
111
111
|
const cs = Array.isArray(clauses) ? clauses : [];
|
|
112
112
|
return rs.filter((r, i) => {
|
|
113
|
+
if (cs[i] === null) return false; // run record only BY RULING, not a clause that failed to compose
|
|
113
114
|
if (typeof cs[i] === "string" && cs[i].trim()) return false;
|
|
114
115
|
const text = String(r ?? "").trim();
|
|
115
116
|
if (!text) return false;
|
|
@@ -246,6 +247,7 @@ export function clientConditions({ reasons, clauses } = {}) {
|
|
|
246
247
|
const rs = Array.isArray(reasons) ? reasons : [];
|
|
247
248
|
const cs = Array.isArray(clauses) ? clauses : [];
|
|
248
249
|
return rs.map((r, i) => {
|
|
250
|
+
if (cs[i] === null) return ""; // a stored null is a condition ruled for the run record alone
|
|
249
251
|
const clause = typeof cs[i] === "string" ? cs[i].trim() : "";
|
|
250
252
|
if (clause) return clause;
|
|
251
253
|
const text = String(r ?? "").trim();
|
package/driver/usage-ledger.mjs
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// portal-service re-exports both names, so every existing caller is untouched.
|
|
12
12
|
//
|
|
13
13
|
// THIS FILE OWNS THE LEDGER PATH. It used to reconstruct a workspace-relative one —
|
|
14
|
-
// `<workspaceRoot>/workspace-*/studio/
|
|
14
|
+
// `<workspaceRoot>/workspace-*/studio/clearance-search/.matter-ledger.jsonl` — under a comment claiming it
|
|
15
15
|
// was what runner.mjs computed. The comment was right and the code was not: once the product moved the
|
|
16
16
|
// queue to a standalone directory, that path resolved to nothing, and because a missing ledger is a low
|
|
17
17
|
// count rather than an error, every account read as ZERO on every request. Two copies of one calculation
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
2
|
// Copyright 2026 Cordillera Sàrl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md
|
|
3
|
-
// variant-manifest-model.mjs — strict parser for the
|
|
3
|
+
// variant-manifest-model.mjs — strict parser for the clearance-variants stage's machine output
|
|
4
4
|
// (variant-manifest.json, the structured SIBLING of variant-manifest.md).
|
|
5
5
|
//
|
|
6
6
|
// WS2 (F2 — reproducible search): the model reasons ONCE about what to search (elements,
|
|
@@ -34,7 +34,7 @@ export const ELEMENT_KINDS = ["distinctive", "common", "saturated-common"];
|
|
|
34
34
|
// transliteration-numeric axis); composite = the element inside a larger mark.
|
|
35
35
|
//
|
|
36
36
|
// — THE DOCTRINE'S FOUR UNIVERSAL TAGS ARE WRITABLE. The variants doctrine
|
|
37
|
-
// (
|
|
37
|
+
// (clearance-variants SKILL.md, "Universal categories") tells the seat to tag rows `exact-phrase`,
|
|
38
38
|
// `exact-element`, `plural-root` and `formative-family`, and this enum refused every one — a manifest
|
|
39
39
|
// that obeyed the doctrine literally failed the stage, so seats substituted (`other` on one run,
|
|
40
40
|
// `composite` in the fixture corpus) and the family lane's contains-not-exact mandate had nothing to
|
|
@@ -171,7 +171,7 @@ export function parseVariantManifestModel(raw) {
|
|
|
171
171
|
// compromise: it is the granularity at which BOTH sides are typed, and the only one where the join
|
|
172
172
|
// cannot go quietly wrong.
|
|
173
173
|
//
|
|
174
|
-
// WHY IT IS DESIGNATED HERE AND JUDGED ELSEWHERE.
|
|
174
|
+
// WHY IT IS DESIGNATED HERE AND JUDGED ELSEWHERE. clearance-variants designates; clearance-register writes the
|
|
175
175
|
// coverage row that either honours it or does not. Different stage, earlier turn, before any outcome is
|
|
176
176
|
// known — which is the whole mechanism. A floor field on the coverage row itself would let the seat that
|
|
177
177
|
// missed the work also decide the work was never obliged: the self-grading loophole rebuilt inside its
|
|
@@ -266,7 +266,7 @@ export function variantRomanizationGaps(model) {
|
|
|
266
266
|
* deferred row both stop the nil search, and neither one tells the stage that AUTHORED the string.
|
|
267
267
|
* A `**`-wrapped variant silently becomes a deferred row and the manifest still says the family was
|
|
268
268
|
* covered — the search shrinks and nothing asks for it back. This arm hands the reason to the
|
|
269
|
-
* corrective ladder in-turn, so
|
|
269
|
+
* corrective ladder in-turn, so clearance-variants restates the term while the run is still cheap: the
|
|
270
270
|
* half of the issue's first acceptance criterion the plan-side screen cannot reach.
|
|
271
271
|
*
|
|
272
272
|
* MARKUP ARM ONLY, deliberately. The prose/long-form arm is legitimately shielded for a slogan mark
|
|
@@ -29,6 +29,25 @@ const nameKey = (s) => norm(s).toLowerCase().replace(/\s+/g, " ");
|
|
|
29
29
|
|
|
30
30
|
// ── Tone guards (the skill's rules, mechanical subset) ───────────────────────────────────────────────
|
|
31
31
|
export const BANNED_TONE_RE = /\b(extremely difficult|most dangerous|massive|enormous)\b/i;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A RECOMMENDATION IS A SHAPE, AND THIS SCREEN MAY NOT WRITE ONE (owner, 2026-09-18).
|
|
35
|
+
*
|
|
36
|
+
* The screen states findings and a rating; what to do with the name is the reading lawyer's. Two
|
|
37
|
+
* instructions that asked for a conclusion were cut first, and a re-run then wrote one anyway, under a
|
|
38
|
+
* heading of its own: "Practical next step — <NAME> is not knocked out at this screening depth. Advance
|
|
39
|
+
* it to clearance…". Cutting an instruction stops the engine asking; only a refusal stops the offer.
|
|
40
|
+
*
|
|
41
|
+
* TWO SHAPES, because both reached a reader: a block the writer heads itself, and a closing line that
|
|
42
|
+
* moves the name on. WHAT THIS CANNOT SEE: the same conclusion as ordinary prose — "the remaining work
|
|
43
|
+
* here is a full search" — and no pattern can. It is a floor under the doctrine, never a substitute.
|
|
44
|
+
*
|
|
45
|
+
* The false positives were measured rather than assumed: the degraded note this lane REQUIRES reads
|
|
46
|
+
* "Manual verification recommended" and matches neither, and a register record "proceeding to
|
|
47
|
+
* registration" matches neither — only proceeding *to clearance* does.
|
|
48
|
+
*/
|
|
49
|
+
export const RECOMMENDATION_RE = /^[ \t]*(?:[*_]{0,2}|#{1,6}\s*)(?:practical\s+|immediate\s+|suggested\s+)?(?:next steps?|what to do\b|what happens next|recommendations?|our recommendation)/im;
|
|
50
|
+
export const ADVANCE_RE = /\b(?:advance|move|take|send)\s+(?:it|this|the name|[A-Z][A-Z0-9'’-]{2,})\s+(?:on\s+)?(?:to|into|through)\s+(?:a\s+)?(?:full\s+)?clearance\b|\bproceeds?\s+to\s+(?:a\s+)?(?:full\s+)?clearance\b|\bshould\s+(?:proceed|advance|be advanced|move)\b|\bwe\s+recommend\b/i;
|
|
32
51
|
export const QUANT_CLAIM_RE = /(\b\d[\d,.]*\s*(?:M|million|billion|k|thousand)?\s*(?:streams|downloads|copies sold|units sold)\b)|(\$\s?\d[\d,.]*\s*(?:M|million|billion|k)?\s*(?:in\s+)?(?:annual\s+)?(?:revenue|sales))/i;
|
|
33
52
|
|
|
34
53
|
// ── URL normalization for the receipts gate ──────────────────────────────────────────────────────────
|
|
@@ -486,6 +505,14 @@ export const validators = {
|
|
|
486
505
|
const claim = [prose, c.chunkSummary].filter(Boolean).join("\n").match(REGISTER_CLAIM_RE);
|
|
487
506
|
if (claim)
|
|
488
507
|
return { ok: false, reason: `knockout_register_claim:${m.name}: "${claim[0].trim()}" — this turn cannot see the register lane and must not describe it. The report states register coverage in code, from the run's own count sidecar; a summary that says the registers were not run, above a table of counts that were, is the contradiction this rule closes. Delete the clause` };
|
|
508
|
+
// THE PER-NAME READ IS SWEPT TOO, and until now it was not: the checks below read the finding
|
|
509
|
+
// fields, while `assessment` was validated for length and structure alone — which is exactly the
|
|
510
|
+
// field the conclusion arrived in. Refused HERE so the stage re-asks with the line quoted, rather
|
|
511
|
+
// than a reader meeting it.
|
|
512
|
+
const read = [m.assessment, prose].filter(Boolean).join("\n");
|
|
513
|
+
const recommended = read.match(RECOMMENDATION_RE) ?? read.match(ADVANCE_RE);
|
|
514
|
+
if (recommended)
|
|
515
|
+
return { ok: false, reason: `mark "${m.name}": "${recommended[0].trim()}" — this screen states findings and a rating; what to do with the name, and whether it advances, is the reading lawyer's. Delete the sentence: the report's own closing caveat already says what the screen is` };
|
|
489
516
|
const banned = prose.match(BANNED_TONE_RE);
|
|
490
517
|
if (banned) return { ok: false, reason: `mark "${m.name}": banned tone "${banned[0]}" — measured tone only (the band colour carries urgency)` };
|
|
491
518
|
const quant = prose.match(QUANT_CLAIM_RE);
|
package/driver/verify.mjs
CHANGED
|
@@ -35,7 +35,7 @@ import { coverageFormStamp, readCoverageForm } from "./coverage-form-io.mjs";
|
|
|
35
35
|
import { readUnacknowledgedTaintAxes } from "./register-taint.mjs";
|
|
36
36
|
import { registerPlanCallKilled } from "./tool-calls.mjs"; // — did the dictated call return?
|
|
37
37
|
import { parseFindingsJson, parseFindingsJsonLenient, CLIENT_TIER_BY_COMPOSITE, isUnconditionalProceed, joinFindingToBlock, parseBlockOrd } from "./findings-model.mjs";
|
|
38
|
-
import { parsePlacementsJson } from "./placement-model.mjs";
|
|
38
|
+
import { parsePlacementsJson } from "./placement-model.mjs"; import { placementFormSidecarName, parsePlacementForm, placementRenderAccount } from "./placement-form.mjs";
|
|
39
39
|
import { parseCaseLawLedger, findCaseLawLedgerViolations, caseLawLedgerFail } from "./case-law-ledger.mjs";
|
|
40
40
|
import { parseFrameworkManifest, aboveLowestBand, normalizeBand } from "./framework.mjs";
|
|
41
41
|
import { parseNamedBand, findCollapsedBands } from "./named-band.mjs";
|
|
@@ -1759,7 +1759,7 @@ export const validators = {
|
|
|
1759
1759
|
// HERE, where a miss re-prompts the stage that authors it.
|
|
1760
1760
|
//
|
|
1761
1761
|
// The floor's gate is the driver-written stage-contract marker (_driver/stage-contracts.json,
|
|
1762
|
-
// "
|
|
1762
|
+
// "clearance-variants".romanization — written by pipeline.mjs recordStageContract at DISPATCH), i.e.
|
|
1763
1763
|
// evidence the artifact was MINTED under the romanisation-carriage prompt. It must never be the
|
|
1764
1764
|
// instructed-scope sentinel: that sentinel is written at INTAKE and present on EVERY current-era
|
|
1765
1765
|
// run — archived and parked ones included — so gating the new requirement on it (the first cut of
|
|
@@ -1788,7 +1788,7 @@ export const validators = {
|
|
|
1788
1788
|
let contract = null;
|
|
1789
1789
|
const marker = driverDir(dir, "stage-contracts.json");
|
|
1790
1790
|
if (existsSync(marker)) {
|
|
1791
|
-
try { contract = JSON.parse(readFileSync(marker, "utf8"))
|
|
1791
|
+
try { contract = variantsStageContract(JSON.parse(readFileSync(marker, "utf8"))); } // either name: see variantsStageContract
|
|
1792
1792
|
catch { return fail("stagecontracts_invalid"); }
|
|
1793
1793
|
}
|
|
1794
1794
|
if (!contract?.romanization && !contract?.completeness && !contract?.term_shape) return sib;
|
|
@@ -2005,8 +2005,8 @@ export const validators = {
|
|
|
2005
2005
|
const base = all(nonEmpty(c), needsSection(c, "placement-tiers", [/tier|placement|sheet|level/i], "placement tiers"));
|
|
2006
2006
|
if (!base.ok) return base;
|
|
2007
2007
|
const dir = dirname(String(p ?? ""));
|
|
2008
|
-
|
|
2009
|
-
|
|
2008
|
+
const sib = existsSync(join(dir, "placements.json")) ? checkSiblingJson(p, "placements.json", parsePlacementsJson, "placement-model", "placementmodel_missing") : null;
|
|
2009
|
+
if (sib) return sib.ok && placementAccountArmed(dir) ? placementAccountVerdict(dir) : sib; // placementAccount: see the block at the end of this file
|
|
2010
2010
|
let structured = false;
|
|
2011
2011
|
let formEra = false;
|
|
2012
2012
|
const marker = driverDir(dir, "stage-contracts.json");
|
|
@@ -2032,7 +2032,7 @@ export const validators = {
|
|
|
2032
2032
|
// What replaces the floor is stronger, not weaker: the tiers live in a driver-held accumulator that a
|
|
2033
2033
|
// kill cannot reach, and the rendered file is parse-then-land through this same strict parser before
|
|
2034
2034
|
// it is allowed on disk. Archived runs carry no `placementForm` key and keep the old floor exactly.
|
|
2035
|
-
if (formEra) return base;
|
|
2035
|
+
if (formEra) return placementAccountArmed(dir) ? placementAccountVerdict(dir) : base;
|
|
2036
2036
|
return structured ? fail("placementmodel_missing") : base;
|
|
2037
2037
|
},
|
|
2038
2038
|
// The opus digest legitimately splits the section ("## On-field findings" / "## Off-field findings"), so the
|
|
@@ -2618,3 +2618,64 @@ function checkClientSummaryJoin(p, c) {
|
|
|
2618
2618
|
return ok("client-summary-join");
|
|
2619
2619
|
}
|
|
2620
2620
|
const short = (v) => String(v ?? "").replace(/\s+/g, " ").trim().slice(0, 40);
|
|
2621
|
+
|
|
2622
|
+
// ── A PLACEMENT PASS THAT DID NOT RECORD ITS ANSWERS HAS NOT SUCCEEDED ──────────────────────────────────
|
|
2623
|
+
//
|
|
2624
|
+
// THE DEFECT, measured 2026-09-18. A pass tiered 141 in-class identical and near-identical register records;
|
|
2625
|
+
// every tier and reason sat in the driver's form; not one reached placements.json, because every register
|
|
2626
|
+
// row was refused on an owner the fold never carried. The render dropped them as it is written to — an
|
|
2627
|
+
// unsettled row is OMITTED rather than emitted half-formed — and this validator, which only parsed the file
|
|
2628
|
+
// that was left, passed six common-law rows as a completed pass. The client received a report silent on
|
|
2629
|
+
// the register over eighty-one identical live registrations.
|
|
2630
|
+
//
|
|
2631
|
+
// TWO REFUSALS, and the line between them was measured rather than chosen. Replayed over every archived
|
|
2632
|
+
// form-era run (25): three carry the discard-all and would refuse; twenty-two healthy runs would not. A
|
|
2633
|
+
// stricter "any outstanding row refuses" was measured too and it refuses five of those twenty-two — each
|
|
2634
|
+
// over a handful of single records at offices that publish no owner, a real and ordinary register fact
|
|
2635
|
+
// that no corrective turn can supply. Those are counted in the run record, not refused.
|
|
2636
|
+
//
|
|
2637
|
+
// placement_unjudged=N a row the SEAT owes is not finished — the corrective turn can finish it.
|
|
2638
|
+
// placement_register_unrendered register candidates were selected and NONE renders — a lost register.
|
|
2639
|
+
//
|
|
2640
|
+
// ARMED ON ITS OWN STAMP KEY (`placementAccount: 1`), written at dispatch like every other key in the
|
|
2641
|
+
// marker, so an archived run replays to exactly the verdict it was minted under. A marker that will not
|
|
2642
|
+
// parse leaves this arm OFF here rather than failing: both call sites already had an answer for that case
|
|
2643
|
+
// before this arm existed, and this must not change it.
|
|
2644
|
+
function placementAccountArmed(dir) {
|
|
2645
|
+
try {
|
|
2646
|
+
return JSON.parse(readFileSync(driverDir(dir, "stage-contracts.json"), "utf8"))?.["placement-inquiry"]?.placementAccount === 1;
|
|
2647
|
+
} catch { return false; }
|
|
2648
|
+
}
|
|
2649
|
+
function placementAccountVerdict(dir) {
|
|
2650
|
+
const sidecar = driverDir(dir, placementFormSidecarName());
|
|
2651
|
+
let raw = null;
|
|
2652
|
+
try { raw = readFileSync(sidecar, "utf8"); } catch { raw = null; }
|
|
2653
|
+
// The form is written BEFORE the seat is dispatched and re-unioned before every judgement, so under this
|
|
2654
|
+
// stamp its absence is the recording apparatus failing — the class this arm exists for — never "no rows".
|
|
2655
|
+
if (raw === null) return fail("placement_form_unreadable (the driver's placement form is absent — nothing this pass placed can be accounted for)");
|
|
2656
|
+
const { rows, error } = parsePlacementForm(raw);
|
|
2657
|
+
if (rows === null) return fail(`placement_form_unreadable (the driver's placement form ${error})`);
|
|
2658
|
+
const a = placementRenderAccount(rows);
|
|
2659
|
+
if (a.unjudged.length) {
|
|
2660
|
+
const named = a.unjudged.slice(0, 8).map((u) => `${u.row_id ?? u.select ?? "?"} (${u.cause})`).join(", ");
|
|
2661
|
+
return fail(`placement_unjudged=${a.unjudged.length}: ${named}${a.unjudged.length > 8 ? ", …" : ""} — each of these rows is `
|
|
2662
|
+
+ "in placement-form.json and its own judgement will not render: a selected row owes a `tier` from the closed set and a `reason` "
|
|
2663
|
+
+ "stating the ground; a row you wrote in full owes mark, owner and jurisdiction too. Finish these rows in the form; "
|
|
2664
|
+
+ "every other row stands.");
|
|
2665
|
+
}
|
|
2666
|
+
if (a.register_selected > 0 && a.register_rendered === 0) {
|
|
2667
|
+
const causes = Object.entries(a.register_facts).map(([t, n]) => `${t} ×${n}`).join(", ") || "no cause recorded";
|
|
2668
|
+
return fail(`placement_register_unrendered=${a.register_selected}: every register candidate this pass selected and tiered `
|
|
2669
|
+
+ `is refused on a fact the driver copies from the register's own records (${causes}) — not one reaches placements.json. `
|
|
2670
|
+
+ "This is not a judgement the seat can repair: those fields are machine-copied and anything typed into them is ignored.");
|
|
2671
|
+
}
|
|
2672
|
+
return ok();
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
// THE VARIANTS STAGE WAS RENAMED, AND A RUN'S MARKER IS KEYED BY STAGE NAME. A run dispatched on an earlier
|
|
2676
|
+
// build stamped its manifest floors under `prelim-variants`; read under the new name alone, a resumed run
|
|
2677
|
+
// finds no stamp and skips the romanisation, completeness and term-shape floors it was minted under. The new
|
|
2678
|
+
// key wins where both exist, because the stage writes it on every fresh dispatch. PURE.
|
|
2679
|
+
export function variantsStageContract(marker) {
|
|
2680
|
+
return marker?.["clearance-variants"] ?? marker?.["prelim-variants"] ?? null;
|
|
2681
|
+
}
|
package/driver/whatif-queue.mjs
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
//
|
|
11
11
|
// ── WHY IT IS NOT IN THE CLEARANCE QUEUE ─────────────────────────────────────────────────────────────
|
|
12
12
|
//
|
|
13
|
-
// studio/
|
|
13
|
+
// studio/clearance-search/queue holds CLEARANCE jobs, and the runner treats every file in it as one: it
|
|
14
14
|
// runs validateJob's whole field allowlist, resolves a product and a scope through resolveRequest,
|
|
15
15
|
// checks the matter ledger for duplicates, counts the daily allowance, and takes a slot from the global
|
|
16
16
|
// run-lock pool. A what-if is none of those things — it re-runs ONE stage of a run that already exists,
|