clearotron 0.3.2-beta.2 → 0.3.2-beta.4
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 +10 -0
- package/INSTALL.md +2 -0
- package/README.md +15 -10
- package/bin/onboard.mjs +4 -4
- package/build-info.json +2 -2
- package/docs/CLIENT-MCP.md +54 -54
- package/docs/DELIVERY.md +16 -15
- package/docs/E2E.md +8 -8
- package/docs/GLOSSARY.md +2 -2
- package/docs/INTAKE.md +11 -11
- package/docs/ONBOARDING.md +17 -16
- package/docs/PORTAL.md +18 -16
- package/docs/README.md +10 -10
- package/docs/SECURITY.md +20 -20
- package/docs/architecture/01-product-overview.md +17 -16
- package/docs/architecture/02-architecture.md +6 -6
- package/docs/architecture/03-run-lifecycle.md +7 -7
- package/docs/architecture/04-configuration-reference.md +14 -13
- package/docs/architecture/05-config-governance.md +30 -29
- package/docs/architecture/05-customer-profiles.md +35 -35
- package/docs/architecture/06-operations-runbook.md +20 -20
- package/docs/architecture/07-quality-and-audit.md +17 -17
- package/docs/architecture/08-development-guide.md +3 -3
- package/docs/architecture/09-security-and-data.md +27 -27
- package/docs/architecture/README.md +1 -1
- package/docs/branding.md +8 -3
- package/docs/configuration.md +18 -18
- package/docs/writing-standard.md +3 -3
- package/driver/CHANGELOG.md +36 -0
- package/driver/package.json +1 -1
- package/driver/portal-service.mjs +34 -4
- package/driver/suite-census.json +114 -48
- package/mcp-server/CHANGELOG.md +8 -0
- package/mcp-server/package.json +1 -1
- package/mcp-server/packs/client/CONNECT.md +6 -6
- package/package.json +1 -1
- package/portal-ui/dist/assets/{index-BsbasHjM.js → index-5UyqAyNM.js} +3384 -2973
- package/portal-ui/dist/assets/{index-DNQpLYZF.css → index-CVOIvdhc.css} +992 -205
- package/portal-ui/dist/index.html +2 -2
- package/portal-ui/package.json +1 -1
- package/providers/_shared/script-form.mjs +2 -2
- package/providers/clarivate/src/core.js +18 -27
- package/providers/oauth-mcp-bridge/CHANGELOG.md +8 -0
- package/providers/oauth-mcp-bridge/package.json +1 -1
- package/providers/signa/src/core.js +3 -3
- package/scripts/ask-ai-render-check.mjs +287 -105
- package/scripts/env-classify.mjs +6 -0
- package/scripts/release-note-required.mjs +16 -2
- package/scripts/settings-render-check.mjs +575 -0
- package/shared/brand.mjs +29 -0
- package/shared/connect-clients.mjs +99 -47
- package/shared/names-in-force.mjs +1 -0
- package/shared/stdio-connect.mjs +16 -2
- package/shared/writing-standard-classes.mjs +34 -3
package/docs/ONBOARDING.md
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
|
|
2
2
|
<!-- Copyright 2026 Cordillera Sàrl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md -->
|
|
3
3
|
|
|
4
|
-
# Onboarding a
|
|
4
|
+
# Onboarding a company
|
|
5
5
|
|
|
6
6
|
One page, one command.
|
|
7
7
|
|
|
8
|
-
A
|
|
9
|
-
bundle in the
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
A company is a business whose names this installation clears — your own, or one you clear names for.
|
|
9
|
+
Onboarding one means creating its bundle in the company store and choosing the risk framework its
|
|
10
|
+
clearances are rated under. The command still says `brandowner`, the word it used before the product
|
|
11
|
+
settled on company. Before this page existed the command shipped and no document mentioned it, so an
|
|
12
|
+
operator following the docs hand-edited JSON in a directory holding real companies' material.
|
|
12
13
|
|
|
13
14
|
## Before you start
|
|
14
15
|
|
|
15
|
-
You need the
|
|
16
|
+
You need the company store. `CLEAROTRON_CUSTOMERS_DIR` names it, and the command refuses by name if it
|
|
16
17
|
is unset or unreadable rather than writing somewhere else. It is the private config repository described
|
|
17
18
|
in `docs/architecture/05-config-governance.md` — not part of this repository, and not created by the
|
|
18
19
|
installer.
|
|
@@ -29,11 +30,11 @@ malformed one is refused before anything is written.
|
|
|
29
30
|
| option | |
|
|
30
31
|
|---|---|
|
|
31
32
|
| `--name` | the legal name. Required. |
|
|
32
|
-
| `--domains` | comma-separated email domains that resolve to this
|
|
33
|
+
| `--domains` | comma-separated email domains that resolve to this company |
|
|
33
34
|
| `--platforms` | marketplaces their searches cover. Omitted, the default's platforms apply and are named in the output. |
|
|
34
35
|
| `--framework` | their risk framework, as `skills/prelim-search/<file>.md`. Omitted, the default applies and is named in the output. |
|
|
35
36
|
| `--industry` | free text, shown on their profile |
|
|
36
|
-
| `--context` | a file whose contents become this
|
|
37
|
+
| `--context` | a file whose contents become this company's context pack |
|
|
37
38
|
| `--dry-run` | say exactly what would be written, and write nothing |
|
|
38
39
|
|
|
39
40
|
**Run it with `--dry-run` first.** It prints the same decisions and the same refusals against the same
|
|
@@ -48,9 +49,9 @@ prints which one it used.
|
|
|
48
49
|
**Absent and broken are different events, deliberately.**
|
|
49
50
|
|
|
50
51
|
- **You gave no `--framework`.** The default applies, and the output names it. Onboarding proceeds —
|
|
51
|
-
a
|
|
52
|
+
a company without a framework of its own yet is not a reason to refuse it.
|
|
52
53
|
- **You gave one and it cannot be read.** The command refuses and writes nothing. Falling back here
|
|
53
|
-
would rate a
|
|
54
|
+
would rate a company's clearances under a framework nobody chose, while the operator believed they had
|
|
54
55
|
set theirs — silently, which is the part that makes it worth an exit code.
|
|
55
56
|
|
|
56
57
|
Read the line that names the framework. It is the whole receipt for a decision you cannot see in the
|
|
@@ -71,12 +72,12 @@ plainly shows. Reconcile it before onboarding anything else.
|
|
|
71
72
|
|
|
72
73
|
## After it succeeds
|
|
73
74
|
|
|
74
|
-
The
|
|
75
|
-
framework's title and bands. Order a first clearance for
|
|
76
|
-
portal, or through the MCP door described in `docs/CLIENT-MCP.md`.
|
|
75
|
+
The company's profile is readable by the portal and by the engine, and its profile page in the portal
|
|
76
|
+
shows the framework's title and bands. Order a first clearance for it the way you order any other —
|
|
77
|
+
through the portal, or through the MCP door described in `docs/CLIENT-MCP.md`.
|
|
77
78
|
|
|
78
79
|
## What this page does not cover
|
|
79
80
|
|
|
80
|
-
Editing an existing
|
|
81
|
-
profile service's, not this command's — a
|
|
82
|
-
refusal is deliberate and is documented with the service rather than here.
|
|
81
|
+
Editing an existing company, and the validation the portal's own profile form applies. Both are the
|
|
82
|
+
profile service's, not this command's — a save from the portal may not introduce a framework selection,
|
|
83
|
+
and that refusal is deliberate and is documented with the service rather than here.
|
package/docs/PORTAL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The portal
|
|
2
2
|
|
|
3
|
-
*One address and one login,
|
|
3
|
+
*One address and one login, whoever is signing in.*
|
|
4
4
|
|
|
5
5
|
**Two ways to prove who you are, and one place that decides what you see.** Hosted,
|
|
6
6
|
`PORTAL_AUTH_MODE=auth-proxy` means any login system in front that authenticates in the browser and
|
|
@@ -53,9 +53,9 @@ burned it.
|
|
|
53
53
|
sign-in form, not a screen in `portal-ui`. The names are reserved on every deployment, so behind CF
|
|
54
54
|
Access they 404 rather than rendering the app shell. A signed-out browser is redirected here; a
|
|
55
55
|
signed-out API caller gets the same 401 the edge produces for a missing JWT.
|
|
56
|
-
- `GET /portal/api/searches?account=` — registry levels + the
|
|
56
|
+
- `GET /portal/api/searches?account=` — registry levels + the company's saved recipes.
|
|
57
57
|
- `POST /portal/api/run/plan` — the **confirmation gate**: validation, the registry-derived
|
|
58
|
-
stage label (never a
|
|
58
|
+
stage label (never a company's recipe label), mark count, turnaround hint, the standing caveat, and
|
|
59
59
|
a 10-minute HMAC `confirmationToken` bound to the fields of the server-stamped job that fix scope,
|
|
60
60
|
cost and identity (`jobHashOf`: marks, markName, classes, goods, product/recipeKey), the confirming
|
|
61
61
|
identity, and a ONE-SHOT jti. Jurisdictions are deliberately OUTSIDE the hash, so the plan step can
|
|
@@ -63,7 +63,7 @@ burned it.
|
|
|
63
63
|
spends here.
|
|
64
64
|
- `POST /portal/api/run` — re-runs the plan gates, verifies the token (a mutated request, another
|
|
65
65
|
sign-in's token, or a replay all 409) then triggers via **real MCP JSON-RPC over the ops face's
|
|
66
|
-
`/mcp`** (`driver/portal-mcp-client.mjs`: initialize → tools/call with the
|
|
66
|
+
`/mcp`** (`driver/portal-mcp-client.mjs`: initialize → tools/call with the company-scoped
|
|
67
67
|
`PORTAL_OPS_TOKEN`; wire shape test-pinned against the face's own handler) — the portal's blast
|
|
68
68
|
radius is that token's grant, enqueue-only, and scoped tokens must name `profileKey` explicitly.
|
|
69
69
|
Job identity (profileKey, forwarder, forwarderEmail) is SERVER-stamped from the verified principal;
|
|
@@ -73,20 +73,21 @@ burned it.
|
|
|
73
73
|
and copied into `meta.json` by the clearance publisher.
|
|
74
74
|
- `GET /portal/api/runs?account=` — delivered pool rows (released reports linked; held runs listed
|
|
75
75
|
unlinked) + live workspace rows.
|
|
76
|
-
- `GET /portal/report/<runId>/` — the
|
|
77
|
-
|
|
76
|
+
- `GET /portal/report/<runId>/` — the report as the people it belongs to see it, ownership-checked;
|
|
77
|
+
foreign/held/missing = 404.
|
|
78
|
+
- `GET /portal/admin/*` — staff-only (everyone else gets 404).
|
|
78
79
|
|
|
79
|
-
Every plan/trigger is audited to `PORTAL_AUDIT` (JSONL, verified email +
|
|
80
|
+
Every plan/trigger is audited to `PORTAL_AUDIT` (JSONL, verified email + company + selector).
|
|
80
81
|
|
|
81
|
-
## Per-
|
|
82
|
+
## Per-company admission caps (`runCaps`)
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
Company-profile key (visible, git-tracked — never a hidden env var). The closed key set is
|
|
84
85
|
`{maxQueued?, dailyRuns?, monthlyRuns?}`, at least one required when the block is present
|
|
85
86
|
(`driver/profiles.mjs`) — for example
|
|
86
87
|
`"runCaps": { "maxQueued": 3, "monthlyRuns": 40 }` — enforced at the runner's `claimAndPrep`
|
|
87
88
|
chokepoint for EVERY door (email, CLI, MCP, portal). Over-cap **clarifies** (requester notified,
|
|
88
89
|
re-sendable), never drops. Monthly counting rides the matter ledger (now stamped with `profileKey` +
|
|
89
|
-
`enqueuedBy`); queued counting scans the queue manifests' tags.
|
|
90
|
+
`enqueuedBy`); queued counting scans the queue manifests' tags. Company-only (a project cannot
|
|
90
91
|
widen caps). `runCaps` is one of the `CODE_OWNED_FIELDS` (`driver/profile-service.mjs`): the profile
|
|
91
92
|
editor has no form field for it and preserves whatever is on file across a save, so it is edited in
|
|
92
93
|
the profile JSON and never lost by a form that does not mention it.
|
|
@@ -136,7 +137,7 @@ clear. Put a TLS-terminating proxy in front if it has to be reachable.
|
|
|
136
137
|
|
|
137
138
|
Grants fixture: `{"tenants":{"demo":{"accounts":["foxglade"],"users":{"cli@celta.example":["foxglade"]}}}}`.
|
|
138
139
|
|
|
139
|
-
The trigger lane needs the MCP HTTP face and
|
|
140
|
+
The trigger lane needs the MCP HTTP face and a company-scoped ops token; without both, the run step
|
|
140
141
|
reports the trigger lane unwired and the plan step still works. **The face no longer has to be run in
|
|
141
142
|
its dev bypass to provide that**:`TRADEMARK_MCP_AUTH_MODE=token` runs it with a mandatory scoped
|
|
142
143
|
access key and no auth proxy — loopback only, and refused outright alongside
|
|
@@ -174,7 +175,7 @@ the model.
|
|
|
174
175
|
**The procedure:**
|
|
175
176
|
|
|
176
177
|
1. Put the proxy in front of the portal's port and make it require sign-in. The portal must not be
|
|
177
|
-
reachable except through it — an origin
|
|
178
|
+
reachable except through it — an origin anyone can reach directly is an origin with no door.
|
|
178
179
|
2. Set `PORTAL_AUTH_MODE=auth-proxy` and the four values above in `.env`.
|
|
179
180
|
3. `npx clearotron doctor` — the **Portal door** section reports which door is configured and which of
|
|
180
181
|
the four values are present, by name. It never prints their values.
|
|
@@ -200,13 +201,14 @@ no proxy in front is the one shape to avoid: `doctor` reports the fronted door w
|
|
|
200
201
|
absent, and the portal refuses to start without an issuer. If you want the passphrase door, say
|
|
201
202
|
`PORTAL_AUTH_MODE=local`.
|
|
202
203
|
|
|
203
|
-
## How a run gets its
|
|
204
|
+
## How a run gets its company
|
|
204
205
|
|
|
205
206
|
`runAccountKey` (`mcp-server/lib/runs.mjs`) reads the run's own frozen profile sidecar
|
|
206
207
|
(`_driver/profile.json`) and takes `profileKey`, falling back to `key`. That key is what grants
|
|
207
|
-
scoping filters on, so a run whose sidecar carries neither is untagged and
|
|
208
|
+
scoping filters on, so a run whose sidecar carries neither is untagged, and only a person with access to
|
|
209
|
+
everything sees it.
|
|
208
210
|
|
|
209
|
-
The write side is gated the same way.
|
|
210
|
-
grant — `stop_run` checks the
|
|
211
|
+
The write side is gated the same way. A company-scoped token can only dequeue jobs inside its
|
|
212
|
+
grant — `stop_run` checks the company on the queue form as well as on a live run — and every
|
|
211
213
|
`start_run` stamps the verified token `sub` into the job as `enqueuedBy`, ignoring any value the
|
|
212
214
|
body supplied.
|
package/docs/README.md
CHANGED
|
@@ -25,7 +25,7 @@ the vendor flags approximate is UNKNOWN, never a number.
|
|
|
25
25
|
|
|
26
26
|
| Doc | What it answers |
|
|
27
27
|
|---|---|
|
|
28
|
-
| [`configuration.md`](configuration.md) | Registers, risk frameworks,
|
|
28
|
+
| [`configuration.md`](configuration.md) | Registers, risk frameworks, company profiles — the settings that make an installation its own |
|
|
29
29
|
| [`architecture/04-configuration-reference.md`](architecture/04-configuration-reference.md) | Every environment variable, with ownership tiers |
|
|
30
30
|
| [`architecture/05-customer-profiles.md`](architecture/05-customer-profiles.md) | Profile internals and the onboarding runbook |
|
|
31
31
|
|
|
@@ -36,7 +36,7 @@ the vendor flags approximate is UNKNOWN, never a number.
|
|
|
36
36
|
| [`INTAKE.md`](INTAKE.md) | How a job reaches the runner — the headless queue contract |
|
|
37
37
|
| [`DELIVERY.md`](DELIVERY.md) | What the engine emits when a run finishes, and who sends it |
|
|
38
38
|
| [`PORTAL.md`](PORTAL.md) | The portal: what it serves, and who sees what |
|
|
39
|
-
| [`CLIENT-MCP.md`](CLIENT-MCP.md) | Publishing a connector
|
|
39
|
+
| [`CLIENT-MCP.md`](CLIENT-MCP.md) | Publishing a connector that each company's people sign in to, and how their access is scoped. To connect *your own* app to *your own* runs, use [`../mcp-server/CONNECT.md`](../mcp-server/CONNECT.md) instead |
|
|
40
40
|
| [`E2E.md`](E2E.md) | Proving a deployment works end to end |
|
|
41
41
|
| [`GLOSSARY.md`](GLOSSARY.md) | The words this codebase uses in a particular way — one line each, for a contributor meeting them for the first time |
|
|
42
42
|
| [`SECURITY.md`](SECURITY.md) | The security envelope — what protects what, and where it is enforced in code. To report a vulnerability, use [`../SECURITY.md`](../SECURITY.md) |
|
|
@@ -47,13 +47,13 @@ tokens is [`architecture/06-operations-runbook.md`](architecture/06-operations-r
|
|
|
47
47
|
what you set at install time, including the four variables that keep two instances on one machine
|
|
48
48
|
apart, is [`../INSTALL.md`](../INSTALL.md) §8.
|
|
49
49
|
[`../examples/grants.example.json`](../examples/grants.example.json) is a runnable guest list over the
|
|
50
|
-
demo
|
|
50
|
+
demo companies.
|
|
51
51
|
|
|
52
52
|
## Architecture
|
|
53
53
|
|
|
54
54
|
[`architecture/`](architecture/) is the reference pack: product overview, run lifecycle, the
|
|
55
55
|
configuration reference, the
|
|
56
|
-
[config-governance inventory](architecture/05-config-governance.md),
|
|
56
|
+
[config-governance inventory](architecture/05-config-governance.md), company profiles, quality and
|
|
57
57
|
audit, security and data, and the
|
|
58
58
|
[development guide](architecture/08-development-guide.md) — which is where to look before adding a
|
|
59
59
|
stage, an engine adapter, or a register provider.
|
|
@@ -64,8 +64,8 @@ mechanically; it is a convention held by review.
|
|
|
64
64
|
|
|
65
65
|
## What this repo contains, and what it does not
|
|
66
66
|
|
|
67
|
-
**No
|
|
68
|
-
A guard sweeps every tracked file for
|
|
67
|
+
**No data from a real clearance.** No names of the companies it cleared for, no marks under clearance, no
|
|
68
|
+
matter numbers, no run identifiers. A guard sweeps every tracked file for a real company's identity,
|
|
69
69
|
and a second sweeps for operator identity and for any
|
|
70
70
|
citation of a path withheld at the public cut — that second one reads a list of withheld paths
|
|
71
71
|
carrying a reason per entry, and fails a citation of one that is not declared. Both are tests in the contributor
|
|
@@ -77,10 +77,10 @@ The other half is structural: it fails on any undeclared identity inside a matte
|
|
|
77
77
|
which is the half that catches something new. Without the private table the guard runs on synthetic
|
|
78
78
|
sentinels: the machinery is exercised and there is nothing real to find.
|
|
79
79
|
|
|
80
|
-
**Demo
|
|
81
|
-
demo
|
|
82
|
-
animal health — which exercise the per-
|
|
83
|
-
Real
|
|
80
|
+
**Demo companies are synthetic.** The published package carries a Generic default (`generic`) and one
|
|
81
|
+
demo company. The repository holds three further invented companies — gaming, functional drinks and
|
|
82
|
+
animal health — which exercise the per-company machinery and the test suite and are never published.
|
|
83
|
+
Real company bundles load at runtime from a private store (`CLEAROTRON_CUSTOMERS_DIR`) and are never
|
|
84
84
|
committed here.
|
|
85
85
|
|
|
86
86
|
**Real third-party names are deliberate.** Registers, marketplaces, regulators, research providers and
|
package/docs/SECURITY.md
CHANGED
|
@@ -10,9 +10,9 @@ here corresponds to shipped behavior; when hardening changes, change this file i
|
|
|
10
10
|
| Surface | Trust | Guard |
|
|
11
11
|
|---|---|---|
|
|
12
12
|
| stdio MCP (`mcp-server/server.mjs`) | local/full ("ops") | OS user boundary — run it AS the operator account; it is the only surface on which `what_if_run` EXECUTES (`visibleTools` keeps what-if out of the HTTP listing for ops, but the CallTool chokepoint gates on `authorize()` alone, which admits it for any ops token not `--verbs`-scoped) |
|
|
13
|
-
| Client MCP (`mcp-server/http-server-client.mjs`) | signed-in
|
|
13
|
+
| Client MCP (`mcp-server/http-server-client.mjs`) | a company's signed-in person / their access key | `what_if_run` from an `account` principal ENQUEUES rather than executes (ruling 2026-08-27) — it never imports the engine, and `driver/whatif-worker.mjs` spawns the sandbox from an OS service process. A confirmation token is unsigned, so the call must ALSO name its `runId`: the grant check keys on it, and `whatIfEnqueue` refuses a token naming a different run. The `model` argument is refused on this face. |
|
|
14
14
|
| HTTP MCP (`mcp-server/http-server.mjs`) | authenticated remote | auth-BEFORE-data; fail-closed construction; inner scoped tokens |
|
|
15
|
-
| Report "Ask your AI" links | external report recipients | run-bound `user` tokens minted at publish;
|
|
15
|
+
| Report "Ask your AI" links | external report recipients | run-bound `user` tokens minted at publish; the plain-language report tools (`clientSafe`) only |
|
|
16
16
|
| Dev portal (`driver/dev-portal.mjs`) | dev only | loopback-only (throws on any other host); never production serving |
|
|
17
17
|
|
|
18
18
|
## Authentication (the outer gate — both faces)
|
|
@@ -77,17 +77,17 @@ with access to everything.
|
|
|
77
77
|
|
|
78
78
|
## Authorization (the inner gate — both faces; `shared/scope.mjs`, enforced at ONE chokepoint)
|
|
79
79
|
|
|
80
|
-
- Four principal kinds:
|
|
81
|
-
exactly ONE run — report recipients),
|
|
82
|
-
identity is granted: the
|
|
80
|
+
- Four principal kinds: **`ops`** (write verbs; automation/operator), **`user`** (read-only, pinned to
|
|
81
|
+
exactly ONE run — report recipients), **`account`** (a signed-in person across the companies their
|
|
82
|
+
identity is granted: the plain-language report tools, the evidence layer — `list_evidence` / `list_searches` /
|
|
83
83
|
`get_search_coverage` — the AUDIT CHAIN (ruling 2026-08-27: `read_artifact` over the chain
|
|
84
84
|
artifacts named in `ACCOUNT_ARTIFACTS`, `list_findings` on the raw `kind` path, `get_finding`,
|
|
85
85
|
`get_run`, `trace`, `decision_timeline`), WHAT-IF as a queued sandbox job (`what_if_plan`,
|
|
86
86
|
`what_if_run`, `what_if_result`), and the run lifecycle on their own runs, and nothing else. All of it accountSafe and deliberately NOT clientSafe, because a report link is forwardable
|
|
87
|
-
and an account is an enrolled identity),
|
|
88
|
-
- **What an account still cannot read, and why each one**: `get_telemetry` / `get_provider_usage`
|
|
89
|
-
(model identity and billed counts — the
|
|
90
|
-
either, so sealing them costs the
|
|
87
|
+
and an `account` principal is an enrolled identity), **`internal`** (authenticated staff, read-all, no writes).
|
|
88
|
+
- **What an `account` principal still cannot read, and why each one**: `get_telemetry` / `get_provider_usage`
|
|
89
|
+
(model identity and billed counts — the operator's cost structure, and the only two tools that carry
|
|
90
|
+
either, so sealing them costs the reader nothing of the chain); the `skepticFlags` /
|
|
91
91
|
`seniorEyeReview` artifacts (the reviewers' judgment of the engine's OWN output — the verdict they
|
|
92
92
|
produced travels, the critique does not); `status.json` / `run.jsonl` (JSON that the markdown
|
|
93
93
|
scrub would pass through untouched, carrying the run codename, the agent id, absolute paths and
|
|
@@ -102,15 +102,15 @@ with access to everything.
|
|
|
102
102
|
omitted runId pinned), reach any write/spend tool, or read internal artifacts — `read_artifact`
|
|
103
103
|
is name-gated to the report alone (`USER_ARTIFACTS`), and `list_findings` to the curated
|
|
104
104
|
report-card groups, so the raw audit trail stays sealed. **The 2026-08-27 audit-chain ruling did
|
|
105
|
-
not move this line.** `USER_ARTIFACTS` gated `read_artifact` for both
|
|
105
|
+
not move this line.** `USER_ARTIFACTS` gated `read_artifact` for both non-staff kinds, so the `account`
|
|
106
106
|
layer was given its own `ACCOUNT_ARTIFACTS` rather than the shared set being widened: a user token
|
|
107
|
-
rides inside a delivered PDF and can be forwarded to anyone, and the ruling was about
|
|
108
|
-
|
|
107
|
+
rides inside a delivered PDF and can be forwarded to anyone, and the ruling was about people the
|
|
108
|
+
operator enrolled. Both sets are gated at the read_artifact tool AND at the Resources surface
|
|
109
109
|
(`resources/list` / `resources/read`), kind for kind — two doors to the same bytes, one rule.
|
|
110
110
|
- **Ops tokens are least-privilege**: an optional `verbs[]` allowlist restricts write tools per
|
|
111
111
|
principal (an intake connector physically cannot `stop_run`). `what_if_*` is filtered out of the
|
|
112
112
|
HTTP tool LISTING for every OPS scope (`visibleTools`, keyed on `local` — the `local` test governs
|
|
113
|
-
the ops branch only, and
|
|
113
|
+
the ops branch only, and an `account` principal returns above it). That is hygiene, not a wall:
|
|
114
114
|
`authorize()` never sees `local` and treats what-if as an ordinary ops write verb, so an ops token
|
|
115
115
|
minted without `--verbs` can still call it over HTTP — which is why every HTTP ops token should be
|
|
116
116
|
minted verb-scoped.
|
|
@@ -124,7 +124,7 @@ what the mechanism guarantees.*
|
|
|
124
124
|
principal in every audit line; the `jti` printed at mint time is the revocation handle). Two
|
|
125
125
|
automatic minters sit beside it on the same `mintToken`: the clearance publisher mints the report
|
|
126
126
|
link's run-bound `user` token at publish, and `npx clearotron start` mints the portal's verb-scoped,
|
|
127
|
-
|
|
127
|
+
company-capped ops token in memory at every start. Neither prints, and neither is written down.
|
|
128
128
|
- **Revocation**: denylist file checked on every verification; missing file = nothing revoked (the
|
|
129
129
|
denylist can never take all auth down). **Rotation**: two-secret window, flag-day-free.
|
|
130
130
|
- **Rate limits**: per-identity bucket on every request plus a separate lower per-principal bucket
|
|
@@ -138,9 +138,9 @@ principal) and before dispatch; it is best-effort and never blocks a request.
|
|
|
138
138
|
|
|
139
139
|
## Data plane
|
|
140
140
|
|
|
141
|
-
- **No
|
|
142
|
-
an external store (`CLEAROTRON_CUSTOMERS_DIR`/`CLEAROTRON_INSTRUCTIONS_DIR`); the repo ships synthetic demo
|
|
143
|
-
|
|
141
|
+
- **No real company's data in this repository — structural, not procedural.** Real company bundles live
|
|
142
|
+
in an external store (`CLEAROTRON_CUSTOMERS_DIR`/`CLEAROTRON_INSTRUCTIONS_DIR`); the repo ships synthetic demo
|
|
143
|
+
companies only. Run data lives in operator-owned directories outside git (`CLEAROTRON_REPORTS_DIR`,
|
|
144
144
|
workspace root, outbox), backed up by the operator, never committed.
|
|
145
145
|
- Secrets enter only via environment (`.env` on the host); the repo carries `.env*.example` files
|
|
146
146
|
with placeholders. CI runs a secret scan (gitleaks) on every push.
|
|
@@ -166,12 +166,12 @@ no messages and holds no channel credentials.
|
|
|
166
166
|
|
|
167
167
|
## Prompt-injection posture
|
|
168
168
|
|
|
169
|
-
-
|
|
170
|
-
scrubbers pass them through, and
|
|
169
|
+
- Tool outputs a company's assistant receives carry context-phrased guidance (not imperatives) so MCP
|
|
170
|
+
metadata scrubbers pass them through, and that assistant's pack tells it to relay the report's own
|
|
171
171
|
wording and never to invent a finding, level, jurisdiction or source
|
|
172
172
|
(`skills/clearotron-client/SKILL.md`). What no pack yet says is that report content is DATA rather
|
|
173
173
|
than instructions: nothing in the prompt payload answers an instruction embedded in a report, so on
|
|
174
|
-
|
|
174
|
+
that side the output note is the whole of this control today.
|
|
175
175
|
- The courier contract is **verbatim relay** — an integrator agent following the ops pack never
|
|
176
176
|
executes instructions found inside packets, it transports them.
|
|
177
177
|
|
|
@@ -11,7 +11,8 @@ never as the orchestrator.
|
|
|
11
11
|
## What it does
|
|
12
12
|
|
|
13
13
|
**Who this is for.** Anyone who needs to know whether a name is free to use and is willing to run the
|
|
14
|
-
search themselves: a
|
|
14
|
+
search themselves: a company clearing its own names, a lawyer clearing them for the companies they act
|
|
15
|
+
for, or an individual clearing their own mark. You need three
|
|
15
16
|
self-serve accounts: a reasoning CLI, a register, and web research.
|
|
16
17
|
|
|
17
18
|
**What you get.** Four searches at different depths. A knockout screens up to eight names in minutes.
|
|
@@ -40,7 +41,7 @@ Every completed matter is a self-contained run directory plus a published delive
|
|
|
40
41
|
|
|
41
42
|
| Artifact | What it is | Consumer |
|
|
42
43
|
|---|---|---|
|
|
43
|
-
| **Clearance report** (HTML) | The deliverable: verdict, four reads, rated findings, coverage statement, actions.
|
|
44
|
+
| **Clearance report** (HTML) | The deliverable: verdict, four reads, rated findings, coverage statement, actions. Formatted for the company via the profile layer. | The company, via the vetting lawyer |
|
|
44
45
|
| **Audit workbook** (Excel) | Every finding — including deliberately excluded noise — with its written reasoning and source record. Built by pure code from the findings spine. | The vetting lawyer; diligence |
|
|
45
46
|
| **Receipts** | Pre-delivery lint, coverage ledger (prose + machine JSON), reasoning-integrity receipt, provider-usage ledger, token rollup. | Operators; auditors |
|
|
46
47
|
| **Decision trace** | Append-only event stream of every stage, retry, gate action, escalation, and delivery step (`_driver/run.jsonl`). | Operators; auditors |
|
|
@@ -59,11 +60,11 @@ flowchart LR
|
|
|
59
60
|
C --> D["Challenge<br/>the draft"]
|
|
60
61
|
D --> E["Deliver the<br/>decision"]
|
|
61
62
|
|
|
62
|
-
A -.- a2["Email in; matter,
|
|
63
|
+
A -.- a2["Email in; matter, company,<br/>scope, deadline resolved"]
|
|
63
64
|
B -.- b2["Registers + live marketplace,<br/>worldwide; depth follows risk"]
|
|
64
65
|
C -.- c2["Legal / commercial / risk / impact —<br/>separated to the last page"]
|
|
65
66
|
D -.- d2["Independent review +<br/>blind re-derivation"]
|
|
66
|
-
E -.- e2["
|
|
67
|
+
E -.- e2["The company's framework and format;<br/>lawyer vets, then it moves"]
|
|
67
68
|
|
|
68
69
|
classDef phase fill:#1a3a5c,stroke:#4a90d9,color:#fff
|
|
69
70
|
classDef note fill:none,stroke:none,color:#888,font-size:12px
|
|
@@ -79,17 +80,17 @@ The full stage-by-stage mechanics — fan-out, barriers, gates, escalation and r
|
|
|
79
80
|
Risk is never one blended number. Every matter carries four separated reads, kept apart from the
|
|
80
81
|
first reasoning stage to the final page of the report:
|
|
81
82
|
|
|
82
|
-
- **Legal read** — would a claim succeed?
|
|
83
|
-
legal read for every
|
|
83
|
+
- **Legal read** — would a claim succeed? Company-independent: the same conflict gets the same
|
|
84
|
+
legal read for every company.
|
|
84
85
|
- **Commercial read** — would this opponent actually fight, and what kind of fight: a classic
|
|
85
86
|
infringement battle, a negotiation, a paper conflict with a dormant registration, or nuisance?
|
|
86
87
|
- **Risk read** — how likely the conflict becomes a real problem, all told.
|
|
87
|
-
- **Impact read** — what a fight would mean for *this*
|
|
88
|
-
where the
|
|
88
|
+
- **Impact read** — what a fight would mean for *this* company, industry, and launch. The one read
|
|
89
|
+
where the company's world properly enters the analysis.
|
|
89
90
|
|
|
90
91
|
The separation is engineered, not stylistic: the profile layer can shape emphasis, vocabulary, and
|
|
91
92
|
format, but configuration that attempts to move a legal rating is rejected by the system itself
|
|
92
|
-
(the anti-threshold guard — see [05 —
|
|
93
|
+
(the anti-threshold guard — see [05 — Company profiles](05-customer-profiles.md)).
|
|
93
94
|
|
|
94
95
|
## The disciplines that make it a product
|
|
95
96
|
|
|
@@ -99,7 +100,7 @@ mechanism in the code, not a policy statement — the pointers go to the chapter
|
|
|
99
100
|
| Discipline | Mechanism | Documented in |
|
|
100
101
|
|---|---|---|
|
|
101
102
|
| Judgment encoded, not rules | Doctrine as prose methodology (skills) reasoned by the judgment tier; hard ceilings in a locked rating framework | [08](08-development-guide.md), [05](05-customer-profiles.md) |
|
|
102
|
-
|
|
|
103
|
+
| Companies drive the deliverable, never the analysis | Profile layer with closed key enum + anti-threshold guards + stage-level firewall; framework manifests carry vocabulary only, never rules (CI-linted) | [05](05-customer-profiles.md) |
|
|
103
104
|
| Four reads, never one number | Findings model carries the reads separately; report templates render them separately | [07](07-quality-and-audit.md) |
|
|
104
105
|
| It knows what to leave out | Below-threshold exclusions keep their written reasoning in the audit workbook | [07](07-quality-and-audit.md) |
|
|
105
106
|
| Crowding must be earned | A crowded-field mitigation requires the counted, filtered field on the record | [07](07-quality-and-audit.md) |
|
|
@@ -111,7 +112,7 @@ mechanism in the code, not a policy statement — the pointers go to the chapter
|
|
|
111
112
|
Beneath all nine sit two engineering properties: **judgment on rails** (the deterministic pipeline,
|
|
112
113
|
[02](02-architecture.md)) and **a memory that keeps it honest** (the reference library and replay
|
|
113
114
|
harness every change to the system's thinking is re-tested against — a discipline someone runs by hand,
|
|
114
|
-
not a mechanism: the replay corpus is real
|
|
115
|
+
not a mechanism: the replay corpus is real clearance data on the machine that holds it, invoked from the
|
|
115
116
|
command line, the reference library is a paid A/B, and neither is in `npm test` or in CI,
|
|
116
117
|
[07 §7](07-quality-and-audit.md#7--the-memory-that-keeps-it-honest)).
|
|
117
118
|
|
|
@@ -120,9 +121,9 @@ command line, the reference library is a paid A/B, and neither is in `npm test`
|
|
|
120
121
|
- The driver runs as systemd `--user` units of one service account (no root units), entirely
|
|
121
122
|
outside any agent sandbox. Where an integrator agent platform is deployed beside it (the
|
|
122
123
|
reference integration), those agents have `exec` denied and can only write queue files.
|
|
123
|
-
- Per-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
- Per-company behaviour is configuration, never a fork: every deployment runs the same engine and
|
|
125
|
+
companies differ only in their profile bundles ([05](05-customer-profiles.md)). No real company is
|
|
126
|
+
named here.
|
|
126
127
|
- Wall-clock per matter is on the order of several hours — an operational measurement, not a specification:
|
|
127
128
|
deliberate sequencing and provider pacing, with model compute a fraction of it. Stage timeout
|
|
128
129
|
budgets in [04](04-configuration-reference.md) bound the components.
|
|
@@ -154,8 +155,8 @@ Terms used throughout this pack and the code. The code's names win over prose de
|
|
|
154
155
|
| **Sentinel** | An on-disk marker file that makes an action idempotent (e.g. `.published`, `.sent`). |
|
|
155
156
|
| **Sidecar** | A small metadata file next to a primary artifact (e.g. claimer pid next to a claimed job). |
|
|
156
157
|
| **Slug / codename** | Run-directory naming: deterministic slug plus a generated `adjective-noun` codename. |
|
|
157
|
-
| **Profile bundle** | A
|
|
158
|
-
| **Context pack** |
|
|
158
|
+
| **Profile bundle** | A company's git-owned configuration: structural config, context pack, delivery style, framework. |
|
|
159
|
+
| **Context pack** | What the engine knows about the company, fed to reasoning as context — sharpens judgment, never overrides it. |
|
|
159
160
|
| **Doctrine** | The encoded legal method: the skills prose, rating framework, and worked examples. |
|
|
160
161
|
| **Reference library** | Lawyer-blessed verdicts on real matters; every change to the thinking is re-tested against it. |
|
|
161
162
|
| **Replay harness** | The $0 pure-file re-run over archived runs; catches structural regressions, not reasoning drift. |
|
|
@@ -25,14 +25,14 @@ these.
|
|
|
25
25
|
and it is architectural, not a tuning knob.
|
|
26
26
|
4. **Fail loud, fail closed, repair first.** Every failure has a class in a closed taxonomy with
|
|
27
27
|
distinct handling; bounded repairs (warm patches, code re-dispatch, quarantines) run before any
|
|
28
|
-
retry burns a fresh session; gates that protect the
|
|
28
|
+
retry burns a fresh session; gates that protect the reader (client gate, coverage terminals)
|
|
29
29
|
fail closed; and a run that dies tells the operator on the same guaranteed lane as delivery.
|
|
30
30
|
5. **The quality floor never falls back.** Only transient-infrastructure failures may retry or
|
|
31
31
|
fall over; a content or coverage defect never gets handed to a weaker model or waved through.
|
|
32
32
|
6. **Configuration is layered and frozen per run.** Environment variables tune mechanics; profile
|
|
33
|
-
bundles carry per-
|
|
33
|
+
bundles carry per-company knowledge; both are resolved once at run start and frozen into the
|
|
34
34
|
run dir. A run's behaviour is fully explained by its own directory.
|
|
35
|
-
7. **Tokens, not dollars.** The driver
|
|
35
|
+
7. **Tokens, not dollars.** The driver counts model usage in tokens only. Cost arithmetic is the
|
|
36
36
|
provider's business; the driver's job is attribution.
|
|
37
37
|
|
|
38
38
|
## The two substrates
|
|
@@ -56,7 +56,7 @@ flowchart TB
|
|
|
56
56
|
GWM["gateway.mjs — runStage()<br/>retry ladder · file-truth gate · fail taxonomy"]
|
|
57
57
|
ENG["engine seam (CLEAROTRON_AI)<br/>anthropic-agent (default) | openai-agent"]
|
|
58
58
|
SKL["skills/ — stage methodology (doctrine)"]
|
|
59
|
-
PROF["profiles/ — per-
|
|
59
|
+
PROF["profiles/ — per-company bundles"]
|
|
60
60
|
PUB["publish/ — report · audit workbook · pool"]
|
|
61
61
|
RUN --> PIPE --> GWM --> ENG
|
|
62
62
|
STG --> GWM
|
|
@@ -276,7 +276,7 @@ All paths relative to [`driver/`](../../driver/). The load-bearing seven are mar
|
|
|
276
276
|
| `phase0.mjs` | Pure run identity: slug, codename, dates, run/archive dirs. |
|
|
277
277
|
| `enqueue-schema.mjs` | Job-file shape, `validateJob` classification (reject/clarify/run). |
|
|
278
278
|
| `slot-lock.mjs` | Cross-process counting locks (run slots, turn/ping lanes). |
|
|
279
|
-
| `profiles.mjs` · `profiles/` · `framework.mjs` | Per-
|
|
279
|
+
| `profiles.mjs` · `profiles/` · `framework.mjs` | Per-company layer: bundle resolution, freeze, rating framework. [05](05-customer-profiles.md). |
|
|
280
280
|
| `coverage-ledger.mjs` | Coverage-ledger contract: strict JSON mirror, prose parser, axes decisions. |
|
|
281
281
|
| `findings-model.mjs` | The findings spine: structure, validation, consolidation. |
|
|
282
282
|
| `registry-fidelity.mjs` | Record grounding: citation closure, identifier auto-correction from records. |
|
|
@@ -306,5 +306,5 @@ For a buyer: these are the exact surfaces to re-point, and nothing else.
|
|
|
306
306
|
| **Out** | Published report (templated HTML) + Excel audit workbook + receipts in the pool | [07](07-quality-and-audit.md) |
|
|
307
307
|
| **Out** | Delivery packet (`_driver/delivery.json`: composed email HTML, chat text, URL, verdict) + outbox wake marker | [03 §4](03-run-lifecycle.md) |
|
|
308
308
|
| **Out** | Failure packet on the same lane (`_driver/failure.json`) | [03 §5](03-run-lifecycle.md) |
|
|
309
|
-
| **Sideways** | Artifacts MCP read layer (runs, findings, traces, briefs; scoped
|
|
309
|
+
| **Sideways** | Artifacts MCP read layer (runs, findings, traces, briefs; scoped `user` and `account` tokens) — effectively the product API | [07](07-quality-and-audit.md), [09](09-security-and-data.md) |
|
|
310
310
|
| **Providers** | Model engine seam (`engine/CONTRACT.md`) · register-provider seam (`activeProvider()`) | above; [08](08-development-guide.md) |
|
|
@@ -85,7 +85,7 @@ intake AI, and classifies rather than just rejecting:
|
|
|
85
85
|
| `run` | Good to go | warnings may note proceed-with-default choices |
|
|
86
86
|
|
|
87
87
|
Warnings never block: a missing TMP reference produces a `noref` slug instead of a silent reject;
|
|
88
|
-
an unknown
|
|
88
|
+
an unknown company proceeds on the generic profile with a late-bind watch (§4).
|
|
89
89
|
|
|
90
90
|
**Matter-level dedup** (`runner.mjs`). Queue-file dedup is per *message*; a "please
|
|
91
91
|
proceed" reply in an already-handled thread arrives under a new message-id. The driver therefore
|
|
@@ -94,7 +94,7 @@ job within the window (a fixed 24 hours) that matches a prior entry by
|
|
|
94
94
|
exact signature (`forwarder|mark|classes|customer|ref`, plus a `|level:<product>` dimension on any
|
|
95
95
|
non-baseline product) or by same conversation-thread with agreeing mark *and* agreeing product. The
|
|
96
96
|
product dimension is why a knockout→clearance escalation of one matter — same forwarder, mark,
|
|
97
|
-
classes,
|
|
97
|
+
classes, company and ref — is never parked as a duplicate; that escalation is the offering's
|
|
98
98
|
headline flow. Three distinct marks forwarded in one thread all run; a forced re-run is
|
|
99
99
|
`dupOverride: true` in the job. Failed runs drop their ledger entry so a genuine re-send is never
|
|
100
100
|
blocked.
|
|
@@ -284,7 +284,7 @@ Reading order for the phases, with what code decides at each:
|
|
|
284
284
|
**verdict sidecar** (`_driver/verdict.json`) then becomes the single verdict authority for
|
|
285
285
|
everything downstream; failing to write it is fatal.
|
|
286
286
|
14. **Delivery phase** — report overview (fatal), per-finding report cards (fan-out, individually
|
|
287
|
-
non-fatal, assembled by code with a code-built "Only you can close these" section),
|
|
287
|
+
non-fatal, assembled by code with a code-built "Only you can close these" section), the
|
|
288
288
|
audit workbook from the findings spine (code, count-guarded, non-fatal), then the pre-delivery
|
|
289
289
|
lint block: registry-record closure (every cited register URI owes a fetched record — absentees
|
|
290
290
|
are code-fetched), lint checks, registry identifier auto-correction *from the record*, one warm
|
|
@@ -302,10 +302,10 @@ coverage terminal, the core-artifact gate, and the client gate. *Note-and-contin
|
|
|
302
302
|
and enrichment (blind-frame, frame-diff/reopen, skeptic, case-law, per-card renders, audit build,
|
|
303
303
|
closure passes, receipts, rollups, notify). An outage in a checker never destroys completed gather work.
|
|
304
304
|
|
|
305
|
-
**One report, no
|
|
306
|
-
that writes one: a live run produces one report, and what a non-staff reader receives is prepared at
|
|
305
|
+
**One report, no second version.** There is no separate summary artifact for outside readers and no
|
|
306
|
+
stage that writes one: a live run produces one report, and what a non-staff reader receives is prepared at
|
|
307
307
|
serve time from it. The lint checks and validators that used to cover a second surface are kept so
|
|
308
|
-
archived runs still replay unchanged, but a live run passes them nothing. The report a
|
|
308
|
+
archived runs still replay unchanged, but a live run passes them nothing. The report a company's people read
|
|
309
309
|
is guarded by the code-built verdict-bound row, the pre-delivery lint, and the client gate.
|
|
310
310
|
|
|
311
311
|
## 4 — Delivery handoff
|
|
@@ -322,7 +322,7 @@ any notify, and both halves are idempotent.
|
|
|
322
322
|
50-minute rescan is the backstop. A lost wake can delay a send; it can never lose or double-send
|
|
323
323
|
one — the deliverer re-derives everything from the packet and the sentinels.
|
|
324
324
|
|
|
325
|
-
**Late-bind** deserves a note: a job forwarded for an unknown
|
|
325
|
+
**Late-bind** deserves a note: a job forwarded for an unknown company runs on the generic profile
|
|
326
326
|
with four code checkpoints (`pre-matter-frame`, `pre-digest`, `pre-synthesis`, `pre-delivery`)
|
|
327
327
|
polling for a `customer-bind.json` dropped by the operator; each checkpoint applies the strongest
|
|
328
328
|
still-safe action its phase allows (`lateBindAction`: fold the job, ride the digest message,
|