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
|
@@ -26,7 +26,7 @@ flowchart LR
|
|
|
26
26
|
G["GROUNDED<br/>records behind every fact"] --> C["CHALLENGED<br/>skeptic + blind pass +<br/>independent reviewer"]
|
|
27
27
|
C --> K["COMPLETED<br/>coverage honesty,<br/>clamps, no dangling caveats"]
|
|
28
28
|
K --> F["IN FRONT<br/>lawyer vets the<br/>defended draft"]
|
|
29
|
-
F -.-> I["INTERROGABLE<br/>read-only audit API,<br/>per-run
|
|
29
|
+
F -.-> I["INTERROGABLE<br/>read-only audit API,<br/>per-run report-link tokens"]
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
## 1 — Grounded: record fidelity (`registry-fidelity.mjs`, `findings-model.mjs`)
|
|
@@ -162,15 +162,15 @@ one. Calls are metered per run (billing-grade ledger), never hard-capped.
|
|
|
162
162
|
## 4 — The pre-delivery lint (`predelivery-lint.mjs`)
|
|
163
163
|
|
|
164
164
|
Pure code over the assembled deliverable surfaces before anything outward-facing. On a live run
|
|
165
|
-
those are the report and the composed email: there is no second
|
|
166
|
-
lint's
|
|
165
|
+
those are the report and the composed email: there is no second artifact for outside readers, and
|
|
166
|
+
the lint's arms for the retired `clientSummary` are kept only so the archived corpus still replays.
|
|
167
167
|
|
|
168
168
|
Thirty-three check families (`runLint` fans out to that many `*Checks` groups; the coarser `family`
|
|
169
169
|
label stamped on each emitted check collapses them to 14): template integrity, orphan-reference
|
|
170
170
|
precision, machine-work reachability ("Only you can close these" must contain only things genuinely
|
|
171
|
-
|
|
171
|
+
left to the company), counting consistency across surfaces and against the findings set, the registry
|
|
172
172
|
family (§1), finding-provenance cross-contamination, correction consistency (a review-withdrawn
|
|
173
|
-
finding can never resurrect on any surface), client-tier and overall-tier joins, verdict/actions
|
|
173
|
+
finding can never resurrect on any surface), the `client-tier-match` and overall-tier joins, verdict/actions
|
|
174
174
|
coherence, intake-ask completion, WIPO designation language, self-comparison.
|
|
175
175
|
|
|
176
176
|
Repair economics are engineered: failing checks on a drafting surface get one bounded warm redo
|
|
@@ -186,8 +186,8 @@ pass over inherited artifacts is visible as such.
|
|
|
186
186
|
| Severity | Trigger |
|
|
187
187
|
|---|---|
|
|
188
188
|
| **Fails the run** | Zero readable coverage-ledger rows (the coverage-honesty floor cannot run, so no verdict can ship); core findings artifact unparseable after corrective retries; the fatal stages/gates in [03](03-run-lifecycle.md). Two things a reader expects here are **not**: an unresolved screen-gate repairs or discloses and never blocks (a per-mark coverage row + the CONDITIONAL clamp, disclosed in `_driver/screen-gate-unresolved.json` — owner decision 2026-07-22, never a dead run over a provider 404), and the client gate blocks nothing (next row) |
|
|
189
|
-
| **Recorded by the client gate, blocks nothing** (the gate's preflight was removed with the readiness state it chose — `pipeline.mjs`) | `evaluateClientGate` still runs its machine checks inside `publishReport` — registry arithmetic, record fidelity, correction consistency, unparseable/quarantined findings, stale corrections, failed escalations (`publish/index.mjs`, fail-closed: an evaluation error also closes). Its result lands on the audit workbook, `meta.json` and the machine-qc-failed telemetry event. **It decides nothing about who may read**, and there is no
|
|
190
|
-
| **Flags, never blocks** | Everything else — recorded in the `_driver` receipt sinks and surfaced on the audit workbook / quality pages; **the rendered report carries no caveat banner** (the report a lawyer signs is clean; the receipts are the QC surface). Lint flags also never ride `report.md` front-matter (that file is copied verbatim to the
|
|
189
|
+
| **Recorded by the client gate, blocks nothing** (the gate's preflight was removed with the readiness state it chose — `pipeline.mjs`) | `evaluateClientGate` still runs its machine checks inside `publishReport` — registry arithmetic, record fidelity, correction consistency, unparseable/quarantined findings, stale corrections, failed escalations (`publish/index.mjs`, fail-closed: an evaluation error also closes). Its result lands on the audit workbook, `meta.json` and the machine-qc-failed telemetry event. **It decides nothing about who may read**, and there is no separate export to withhold — a defect that changes the LEGAL ANSWER is the verdict clamp's job and rides the report as a CONDITIONAL/BLOCKING verdict, never as a warning about the document |
|
|
190
|
+
| **Flags, never blocks** | Everything else — recorded in the `_driver` receipt sinks and surfaced on the audit workbook / quality pages; **the rendered report carries no caveat banner** (the report a lawyer signs is clean; the receipts are the QC surface). Lint flags also never ride `report.md` front-matter (that file is copied verbatim to the pool outside readers reach; a front-matter flag was a latent leak to them) |
|
|
191
191
|
|
|
192
192
|
## 5 — Observability that refuses to be a gate
|
|
193
193
|
|
|
@@ -221,7 +221,7 @@ verdict, clamp, delivery event), per-attempt telemetry (`_driver/<stage>.jsonl`
|
|
|
221
221
|
class, kill signals, token usage), the fetched records themselves (`_records/`, receipts indexed in
|
|
222
222
|
`_driver/receipts.json`), and the receipt set ([03 §7](03-run-lifecycle.md#7--run-directory-anatomy)
|
|
223
223
|
maps all of it). The provider-usage ledger tallies billable register calls per run (billing-grade:
|
|
224
|
-
counts, retries, errors, cache hits, duplicate-fetch splits), and the token rollup
|
|
224
|
+
counts, retries, errors, cache hits, duplicate-fetch splits), and the token rollup counts every
|
|
225
225
|
attempt including retry waste — tokens only, no currency, by directive.
|
|
226
226
|
|
|
227
227
|
## 7 — The memory that keeps it honest
|
|
@@ -230,12 +230,12 @@ Three layers, from cheapest to most authoritative:
|
|
|
230
230
|
|
|
231
231
|
1. **The $0 replay harness** (`replay-archive.mjs`): re-runs every validator and the lint over the
|
|
232
232
|
archived corpus and diffs against a snapshot; any verdict-string flip fails (exit 2). Nothing in
|
|
233
|
-
`.github/workflows/` runs it, and a hosted runner could not: the corpus is real
|
|
233
|
+
`.github/workflows/` runs it, and a hosted runner could not: the corpus is real clearance data that
|
|
234
234
|
stays on the machine holding it, and the snapshot lives outside the git tree. So the gate is a
|
|
235
235
|
hand-run convention — `--update` on main, diff on the candidate, every flip an intended fix.
|
|
236
236
|
Catches structural/validator regressions; cannot see reasoning drift.
|
|
237
237
|
2. **Gate metrics on holdout runs** (`gate-metrics.mjs`): deferral rendering, skeptic consumption,
|
|
238
|
-
scored-finding grounding,
|
|
238
|
+
scored-finding grounding, `clientTierMatch`, lint first-pass tax — a fix is accepted only if the
|
|
239
239
|
metrics move on runs it never cited.
|
|
240
240
|
3. **The reference library**: lawyer-blessed verdicts on real matters, re-run in a **paid A/B**
|
|
241
241
|
for any grade-moving change, read against the system's measured run-to-run wobble (the
|
|
@@ -261,7 +261,7 @@ write nothing and 7 that do:
|
|
|
261
261
|
`get_provider_usage` (recomputed live from the billing ledger, with drift detection),
|
|
262
262
|
`get_coverage`, `search`, `decision_timeline`, `run_changes` (stable-cursor change feed),
|
|
263
263
|
`diff_artifact` (with diff-ref whitelisting that closes cross-run path escapes), and
|
|
264
|
-
`get_delivery_packet` (the run's send payload; never exposed to
|
|
264
|
+
`get_delivery_packet` (the run's send payload; never exposed to `user` or `account` tokens).
|
|
265
265
|
- **Read, cross-run** — `list_runs`, `search_runs`, `list_profiles`, `list_outbox_events`, plus the
|
|
266
266
|
two free pre-order reads `describe_options` and `plan_run`, which resolve what a search *would* do
|
|
267
267
|
without reserving, spending or queueing anything.
|
|
@@ -269,22 +269,22 @@ write nothing and 7 that do:
|
|
|
269
269
|
`what_if_run` → one sandboxed stage; `what_if_result` → collect a queued one) — **executing** is
|
|
270
270
|
local stdio only, never remote, for any principal. The confirmation token is a deliberate-action
|
|
271
271
|
handshake, not a crypto boundary; the security boundary is ops scope + local-only execution.
|
|
272
|
-
Since the owner's 2026-08-27 ruling
|
|
272
|
+
Since the owner's 2026-08-27 ruling an `account` principal reaches all three, and `what_if_run` on that
|
|
273
273
|
path ENQUEUES into `<runDir>/_experiments/_queue/` rather than shelling — `driver/whatif-worker.mjs`,
|
|
274
|
-
drained by the runner, is what spawns the sandbox. Because the token is unsigned, a
|
|
275
|
-
also name its `runId` so the
|
|
274
|
+
drained by the runner, is what spawns the sandbox. Because the token is unsigned, a call on that path must
|
|
275
|
+
also name its `runId` so the grant check fires, and the enqueue refuses a token naming another run.
|
|
276
276
|
- **5 ops write verbs** (`start_run` — validated atomic enqueue; `stop_run` — real cancel before
|
|
277
277
|
claim, best-effort sentinel after; `feed_context`; and the integrator write-backs `ack_event` and
|
|
278
278
|
`mark_sent`, which refuses to settle a send without a messageId or an explicit attestation) — ops
|
|
279
279
|
scope only, never on the public connector.
|
|
280
280
|
|
|
281
281
|
One run = one self-auditing directory; the read layer adds no state of its own — it projects the
|
|
282
|
-
run dir and the ledgers. The auth model (four principal kinds; run-bound
|
|
282
|
+
run dir and the ledgers. The auth model (four principal kinds; run-bound `user` tokens reaching
|
|
283
283
|
exactly `brief`, `read_artifact` gated to the report, and `list_findings` gated to the curated card
|
|
284
284
|
groups) is documented in [09 — Security and data](09-security-and-data.md).
|
|
285
285
|
|
|
286
|
-
**A signed-in
|
|
287
|
-
what makes a clearance defensible, and the person who has to defend the filing is the
|
|
286
|
+
**A signed-in `account` principal reads the audit chain** (ruling 2026-08-27). The audit trail is
|
|
287
|
+
what makes a clearance defensible, and the person who has to defend the filing is the company's
|
|
288
288
|
lawyer — so `audit`, `narrative`, the record artifacts and a register axis are readable through
|
|
289
289
|
`read_artifact`, the raw `list_findings` path returns the AT#/F#/NR# records, and `get_run`, `trace`
|
|
290
290
|
and `decision_timeline` walk the decision chain. What stays internal is not the chain but the cost
|
|
@@ -68,7 +68,7 @@ These are the things a well-meaning refactor breaks. Each is enforced somewhere;
|
|
|
68
68
|
(+ `stallSec` **strictly less than** the timeout for any stage whose first action can stream
|
|
69
69
|
nothing — a long tool call looks like a stall), `out(paths)` (absolute path via `paths()`),
|
|
70
70
|
`validate`, and the `message(ctx)` with its `reads([...])` (the *live* skill reads —
|
|
71
|
-
`skillReads:` is declarative metadata only; do not "reconcile" them, per-
|
|
71
|
+
`skillReads:` is declarative metadata only; do not "reconcile" them, per-company framework
|
|
72
72
|
selection depends on the difference).
|
|
73
73
|
2. **Write its validator** in `verify.mjs` — lenient enough never to false-fail a valid leaf,
|
|
74
74
|
strict on truncation/emptiness/wrong-stage output. If it needs run context, read the frozen
|
|
@@ -225,8 +225,8 @@ Four realities to respect:
|
|
|
225
225
|
- **The `||=` env guards leak**: a shell exporting a real register credential or
|
|
226
226
|
`CLEAROTRON_PLAN_DISPATCH=on` is *not* overridden by the harness — run the suite in a clean env.
|
|
227
227
|
(CI is safe.)
|
|
228
|
-
- **A skipped guard is not a passed guard.** Several checks enumerate every tracked file (no
|
|
229
|
-
identifier, no operator identity, no citation of a path the public tree will not carry, every env
|
|
228
|
+
- **A skipped guard is not a passed guard.** Several checks enumerate every tracked file (no real
|
|
229
|
+
company's identifier, no operator identity, no citation of a path the public tree will not carry, every env
|
|
230
230
|
var written down) and can only do that off a git checkout; off a source zip they skip by name.
|
|
231
231
|
CI asserts both that no guard printed `[repo-guard] SKIPPED` *and* that at least one printed
|
|
232
232
|
`[repo-guard] ok` — the second half matters, because "no SKIPPED line" also passes on an empty log.
|
|
@@ -14,7 +14,7 @@ them, by inheritance, never by file-copy into configs.**
|
|
|
14
14
|
flowchart TB
|
|
15
15
|
subgraph INET["Internet"]
|
|
16
16
|
U["Staff (browser)"]
|
|
17
|
-
CLI["
|
|
17
|
+
CLI["Company AI agents<br/>(interrogation)"]
|
|
18
18
|
EXT["Model provider · registries ·<br/>research/case-law APIs"]
|
|
19
19
|
end
|
|
20
20
|
subgraph EDGE["Auth proxy + tunnel<br/>(this deployment: Cloudflare)"]
|
|
@@ -67,35 +67,35 @@ are no root units; everything is `systemd --user`.
|
|
|
67
67
|
codebase: trusted local **stdio** (full tool set — trust boundary is the right to exec the
|
|
68
68
|
binary), a **staff HTTP** face (loopback :18790 behind Tunnel + Access), and a **client HTTP**
|
|
69
69
|
face (loopback :18811) that is a *separate process* with a *different Access audience* — "a
|
|
70
|
-
|
|
70
|
+
company's person can never reach internal read-all" is a configuration fact, not a runtime branch (startup
|
|
71
71
|
refuses if the two AUDs are equal). Auth is two-layered and fail-closed:
|
|
72
72
|
- **Outer**: the CF Access JWT is re-verified at origin on every request — RS256 pinned, issuer
|
|
73
73
|
+ audience checked, expiry required, email claim must be a real string (array-claim smuggling
|
|
74
74
|
rejected), domain matched exactly on the final `@` (subdomain look-alikes rejected).
|
|
75
75
|
- **Inner**: HMAC-signed scope tokens (`v1.<payload>.<sig>`, timing-safe compare, fail-closed
|
|
76
76
|
without the secret, default TTL 30 days). Four principal kinds, resolved by `visibleTools()` and
|
|
77
|
-
`authorize()` in `shared/scope.mjs`:
|
|
78
|
-
over staff HTTP — reads + ops verbs; what-if only when local),
|
|
79
|
-
|
|
77
|
+
`authorize()` in `shared/scope.mjs`: **`ops`** (stdio, or ops token
|
|
78
|
+
over staff HTTP — reads + ops verbs; what-if only when local), **`internal`** (verified
|
|
79
|
+
staff at your own domain — all 23 non-write tools, no writes), **`user`** (run-bound token minted into the
|
|
80
80
|
report's "Ask your AI" link — exactly `brief` + `read_artifact` gated to the report (there is
|
|
81
81
|
one report, and the link block is staff-only at serve time) + `list_findings`
|
|
82
82
|
gated to curated groups, pinned to one run; filter args that could reach internal methodology
|
|
83
|
-
are stripped), and
|
|
84
|
-
|
|
85
|
-
`scope: account`, whose
|
|
83
|
+
are stripped), and **`account`** (a signed-in person on the client face — the runs of the
|
|
84
|
+
companies they are granted, reached either by the CF sign-in with no token, or by a per-person API
|
|
85
|
+
key, `scope: account`, whose companies are re-read from the grants file on every request rather than
|
|
86
86
|
baked into it. Wider *reach* than a report link and, since the owner's 2026-08-27 ruling, more
|
|
87
87
|
*depth* too: the audit chain — the audit trail, the reasoning narrative, the record artifacts, a
|
|
88
88
|
register axis, and the `get_run` / `trace` / `decision_timeline` decision walk. Model identity
|
|
89
89
|
and billed counts stay sealed (`get_telemetry`, `get_provider_usage`), as does the reviewers'
|
|
90
90
|
critique of the engine's own output; the chain's prose goes through the report's own
|
|
91
|
-
|
|
91
|
+
scrub passes in `mcp-server/lib/audit-view.mjs`, and the artifact set is its own
|
|
92
92
|
`ACCOUNT_ARTIFACTS` so that widening it never widens the forwardable report link. The same ruling
|
|
93
93
|
opened WHAT-IF, and on this face it queues rather than shells: `what_if_run` writes a job into the
|
|
94
94
|
run's own `_experiments/_queue/` and `driver/whatif-worker.mjs` spawns the sandbox from a service
|
|
95
|
-
process, so no remote face executes the engine. The confirmation token is unsigned, so a
|
|
96
|
-
|
|
95
|
+
process, so no remote face executes the engine. The confirmation token is unsigned, so a call on
|
|
96
|
+
this face must also name its `runId` — the grant check keys on that, and the enqueue refuses a token
|
|
97
97
|
naming a different run).
|
|
98
|
-
Scope resolution is positive: no token and not
|
|
98
|
+
Scope resolution is positive: no token and not
|
|
99
99
|
staff ⇒ 403 — the old silent default-to-internal was a real bug, now regression-pinned.
|
|
100
100
|
The API-key door is a fourth process (loopback :18812) with **no Access in front** — the trade is
|
|
101
101
|
explicit: a mandatory key replaces the browser sign-in, and the mode refuses to start if anything
|
|
@@ -120,12 +120,12 @@ from the repository root; the rest are relative to `driver/`.
|
|
|
120
120
|
|
|
121
121
|
| Destination | What is sent | Code |
|
|
122
122
|
|---|---|---|
|
|
123
|
-
| **The reasoning provider** — `api.anthropic.com` through the Claude CLI, or OpenAI through the Codex CLI | The whole matter: the mark and its variants, the Nice classes, the goods and services wording, the jurisdictions, the requester and forwarding fields of the job file, the
|
|
123
|
+
| **The reasoning provider** — `api.anthropic.com` through the Claude CLI, or OpenAI through the Codex CLI | The whole matter: the mark and its variants, the Nice classes, the goods and services wording, the jurisdictions, the requester and forwarding fields of the job file, the company profile and risk framework the stage reads, the register records already fetched, and every prior stage's artifact | `engine/anthropic-agent.mjs` spawns `claude`; `engine/openai-agent.mjs` spawns `codex`. **The CLI opens the connection — no driver code calls the provider.** Subscription mode deletes `ANTHROPIC_API_KEY` from the child environment (`anthropic-agent.mjs`) |
|
|
124
124
|
| **`api.perplexity.ai/v1/agent`** | The mark and its variants, the goods wording, and the marketplace, dictionary, and meaning probes. The driver writes the grid spec and dictates every cell; the model does not compose the sweep | `providers/perplexity/src/core.js`. On a clearance the `common-law`, `common-law-half`, and `synthesis` stages hold it through `engine/mcp/perplexity-server.mjs` (`engine/mcp/gather-config.mjs`); on a knockout the code-side sweep calls the adapter directly (`pipeline-knockout.mjs`), and with no `PERPLEXITY_API_KEY` that call is never made — the screen skips the sweep and discloses it, so nothing on this row leaves the box |
|
|
125
125
|
|
|
126
126
|
**The one register you configure.** The `register-unit` stages send the mark string, its generated
|
|
127
127
|
variants, the Nice classes, office filters, and record ids for fetches. They do not send the requester,
|
|
128
|
-
the
|
|
128
|
+
the company's name, the goods description, or any profile material.
|
|
129
129
|
|
|
130
130
|
| `CLEAROTRON_DATABASE` | Host | Code |
|
|
131
131
|
|---|---|---|
|
|
@@ -189,32 +189,32 @@ stylesheets above.
|
|
|
189
189
|
non-secret attribution values (session key for usage attribution, agent id) ride the config.
|
|
190
190
|
- **Register credentials are preflighted** at run start and resume — a missing credential fails
|
|
191
191
|
fast before any model spend, never mid-run or at delivery.
|
|
192
|
-
- **Git-side hygiene**: profiles and their audit log are tracked (
|
|
192
|
+
- **Git-side hygiene**: profiles and their audit log are tracked (they identify real companies — see below);
|
|
193
193
|
the replay snapshot deliberately lives *outside* the git tree because it holds mark names; and
|
|
194
|
-
the driver's `.gitignore` blocks run-directory shapes so a stray run dir (
|
|
194
|
+
the driver's `.gitignore` blocks run-directory shapes so a stray run dir (real clearance data) can
|
|
195
195
|
never be swept into a backup commit.
|
|
196
196
|
|
|
197
197
|
## Data classes and where they live
|
|
198
198
|
|
|
199
199
|
| Class | Locations | Notes |
|
|
200
200
|
|---|---|---|
|
|
201
|
-
| **
|
|
201
|
+
| **Clearance data** | queue files + prose sidecars; run dirs; archive tree; publish pool; outbox packets | The crown jewels. Runs are per-agent-workspace; the pool is the only web-reachable copy (Access-gated, group-readable 0640) |
|
|
202
202
|
| **Registry records** | `_records/`, telemetry ledgers | Licensed provider data — contract terms govern retention/transfer at handover |
|
|
203
|
-
| **Doctrine** | `skills/`, framework decks, worked examples | The asset; transfers under the definitive agreement. Worked examples derive from real matters — treat as
|
|
204
|
-
| **
|
|
205
|
-
| **Reference library / calibration corpus** | outside the repo | Built on real
|
|
203
|
+
| **Doctrine** | `skills/`, framework decks, worked examples | The asset; transfers under the definitive agreement. Worked examples derive from real matters — treat them as close to real company data |
|
|
204
|
+
| **Company profiles** | `profiles/*.json`, context packs, `_audit.log` | They identify real companies by design (names, own trading names, competitor lists) — the reason this *pack* names none |
|
|
205
|
+
| **Reference library / calibration corpus** | outside the repo | Built on real clearances — **confidential company material, not freely transferable IP**; transfer needs a consent and sanitization plan agreed with those companies |
|
|
206
206
|
| **Telemetry** | `~/trademark/telemetry/*.jsonl` (a box upgraded across the move keeps the pre-change telemetry directory — resolved by existence, oldest first),`_driver/*.jsonl` | Billing-grade provider usage + attempt telemetry; append-only; no automated retention |
|
|
207
207
|
|
|
208
|
-
**Posture commitments** (engineering-true, restated from the outward materials): no
|
|
209
|
-
trains any model; each
|
|
210
|
-
privileged-and-confidential handling is a per-
|
|
211
|
-
|
|
212
|
-
receives prepared at a single serve-time chokepoint (`driver/portal-report.mjs`) and the
|
|
213
|
-
cut composed from the same driver transforms rather than restating them
|
|
208
|
+
**Posture commitments** (engineering-true, restated from the outward materials): no company's data
|
|
209
|
+
trains any model; each company's context is isolated in its profile bundle and frozen per run;
|
|
210
|
+
privileged-and-confidential handling is a per-company delivery flag; and there is no separate
|
|
211
|
+
export for outside readers to keep in step — one report, with what a non-staff reader
|
|
212
|
+
receives prepared at a single serve-time chokepoint (`driver/portal-report.mjs`) and the client
|
|
213
|
+
face's cut composed from the same driver transforms rather than restating them
|
|
214
214
|
([07 §4](07-quality-and-audit.md#4--the-pre-delivery-lint-predelivery-lintmjs)).
|
|
215
215
|
|
|
216
216
|
**Retention** is currently append-forever everywhere (runs, archive, pool, ledgers). That is a
|
|
217
|
-
deliberate audit-trail choice, but it means data-subject or
|
|
217
|
+
deliberate audit-trail choice, but it means data-subject or company-offboarding requests are manual
|
|
218
218
|
today — flag for the buyer's compliance review.
|
|
219
219
|
|
|
220
220
|
## Supply chain and dependency posture
|
|
@@ -12,7 +12,7 @@ that" question, or when you are changing something and need to know what depends
|
|
|
12
12
|
| [`03-run-lifecycle.md`](03-run-lifecycle.md) | One run from intake to delivered packet — every stage, gate and resume point |
|
|
13
13
|
| [`04-configuration-reference.md`](04-configuration-reference.md) | Every environment variable, what reads it, and what unset means |
|
|
14
14
|
| [`05-config-governance.md`](05-config-governance.md) | The rules configuration obeys: who may add a name, and the drift classes |
|
|
15
|
-
| [`05-customer-profiles.md`](05-customer-profiles.md) | The per-
|
|
15
|
+
| [`05-customer-profiles.md`](05-customer-profiles.md) | The per-company profile: what it carries and how a run resolves one |
|
|
16
16
|
| [`06-operations-runbook.md`](06-operations-runbook.md) | Running a deployment — the units, the triggers, and what to do when one wedges |
|
|
17
17
|
| [`07-quality-and-audit.md`](07-quality-and-audit.md) | How the engine proves what it claims: the ledger, the witness, the refutation gate |
|
|
18
18
|
| [`08-development-guide.md`](08-development-guide.md) | Working in the code — the test tiers, the seams, the conventions |
|
package/docs/branding.md
CHANGED
|
@@ -4,8 +4,8 @@ Operational guidance, not policy. What you may call your deployment is
|
|
|
4
4
|
[TRADEMARKS.md](../TRADEMARKS.md); this page is how you change what the software prints.
|
|
5
5
|
|
|
6
6
|
**Delivering a report that carries somebody else's brand is the failure this page exists to prevent.**
|
|
7
|
-
A clearance report is read by
|
|
8
|
-
yours, you have built the exact problem the software exists to detect.
|
|
7
|
+
A clearance report is read by the people deciding on a name and forwarded to whoever else must agree. If
|
|
8
|
+
it arrives under a name that is not yours, you have built the exact problem the software exists to detect.
|
|
9
9
|
|
|
10
10
|
## What to do instead
|
|
11
11
|
|
|
@@ -19,7 +19,7 @@ install needs no change — but the names below are the ones to write:
|
|
|
19
19
|
| `CLEAROTRON_BRAND_TAGLINE` | *(empty — no strapline is rendered)* | Report and portal chrome |
|
|
20
20
|
| `CLEAROTRON_BRAND_PRODUCT` | `Trademark clearance` | Artifact naming and connector instructions |
|
|
21
21
|
|
|
22
|
-
**The defaults name the product, not
|
|
22
|
+
**The defaults name the product, not an organisation.** A deployment that sets nothing produces neutrally
|
|
23
23
|
branded output. That is deliberate: the alternative is what this page warns against, with one
|
|
24
24
|
organisation's name as the path of least resistance. Setting `CLEAROTRON_BRAND_NAME` to your own
|
|
25
25
|
organisation is still the step to take before you deliver anything to anyone.
|
|
@@ -30,6 +30,11 @@ renders as **absent** — no element, no stray separator — rather than as a bl
|
|
|
30
30
|
They are read once, at import (`shared/brand.mjs`), so they are deployment-static: set them in the
|
|
31
31
|
environment file and restart.
|
|
32
32
|
|
|
33
|
+
`CLEAROTRON_ADMINISTRATOR_CONTACT` is read in the same place and the same way, but it is not a name: it
|
|
34
|
+
is a mail or web address for the person who looks after sign-ins. Preferences tells a signed-in person to
|
|
35
|
+
contact their Clearotron administrator to change their sign-in, and links those words to this contact.
|
|
36
|
+
Unset, the words are plain text.
|
|
37
|
+
|
|
33
38
|
**Three things that seam does not cover**, stated because finding them at deploy time is worse:
|
|
34
39
|
|
|
35
40
|
- **The palette is not env-overridable.** Brand colours are defined in code beside those variables.
|
package/docs/configuration.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Configuration
|
|
2
2
|
|
|
3
|
-
*How to configure risk frameworks, registers and markets for your own
|
|
3
|
+
*How to configure risk frameworks, registers and markets for your own use.*
|
|
4
4
|
|
|
5
|
-
This is the
|
|
6
|
-
knows about each
|
|
5
|
+
This is the guide to the settings an installation makes its own: which register you search, how risk
|
|
6
|
+
gets rated, and what the engine knows about each company. Environment variables and install-time setup are
|
|
7
7
|
[`../INSTALL.md`](../INSTALL.md); the exhaustive variable table is
|
|
8
8
|
[`architecture/04-configuration-reference.md`](architecture/04-configuration-reference.md).
|
|
9
9
|
|
|
@@ -84,7 +84,7 @@ route, and usually the cheaper one.
|
|
|
84
84
|
|
|
85
85
|
## 2. The risk framework
|
|
86
86
|
|
|
87
|
-
**The framework in force rates the
|
|
87
|
+
**The framework in force rates the clearance.** A run rates under the company's own framework if one is
|
|
88
88
|
on file, otherwise the Generic default. There is nothing in between and no blending.
|
|
89
89
|
|
|
90
90
|
A framework is two files that travel together:
|
|
@@ -98,8 +98,8 @@ The Generic default ships at
|
|
|
98
98
|
[`driver/skills/prelim-search/risk-framework.md`](../driver/skills/prelim-search/risk-framework.md)
|
|
99
99
|
with bands Very High · High · Moderate · Manageable.
|
|
100
100
|
|
|
101
|
-
**Replace it with your
|
|
102
|
-
and point a
|
|
101
|
+
**Replace it with your own.** Write your rubric as prose, add a manifest naming your bands,
|
|
102
|
+
and point a company profile at it with `frameworkPath`. Validators, the renderer, the archive index
|
|
103
103
|
and the config UI all read your band vocabulary from the manifest, so your words appear everywhere
|
|
104
104
|
the engine names a risk.
|
|
105
105
|
|
|
@@ -132,7 +132,7 @@ That shape is not decoration. The profile screen extracts what the bands mean fr
|
|
|
132
132
|
bullets, and **it is all or nothing**: one band without a heading, or one heading with no bold-led
|
|
133
133
|
bullet, and the box explaining your bands silently does not render at all — while the title and the
|
|
134
134
|
coloured pills still do, so the page looks finished. Frameworks in this repository have shipped in
|
|
135
|
-
exactly that state, which is why there is now a command that tells you before a
|
|
135
|
+
exactly that state, which is why there is now a command that tells you before a reader does.
|
|
136
136
|
|
|
137
137
|
**2. Write the manifest**, beside the deck and named after it: `your-framework.md` needs
|
|
138
138
|
`your-framework.manifest.json`. The path is derived, never configured, so the two cannot drift apart.
|
|
@@ -160,14 +160,14 @@ than ignored. `schema_version` is `1`. `framework_key` is lowercase letters, dig
|
|
|
160
160
|
names a risk. A band label may contain letters, spaces, slashes and hyphens, and **no digits** — a band
|
|
161
161
|
called "Level 3" invites arithmetic where judgement is wanted. `tone` is one of `severe`, `high`,
|
|
162
162
|
`medium`, `low`, `minimal`, and it chooses a colour, nothing else. `entity_label` is how your deck names
|
|
163
|
-
the
|
|
163
|
+
the company in prose. If your deck is a matrix rather than a ladder, say
|
|
164
164
|
`"structure": { "kind": "matrix" }` — the matrix itself lives in the deck prose, never here.
|
|
165
165
|
|
|
166
166
|
**The manifest carries vocabulary and order only.** No threshold, no mapping table, no decision rule.
|
|
167
167
|
Those belong in the deck, where they are read as reasoning rather than applied as arithmetic.
|
|
168
168
|
|
|
169
|
-
**3. Put both files in your own store** and point a profile at the deck with `frameworkPath`.
|
|
170
|
-
|
|
169
|
+
**3. Put both files in your own store** and point a profile at the deck with `frameworkPath`. A
|
|
170
|
+
company's rubric deliberately does not live inside a checkout of this product.
|
|
171
171
|
|
|
172
172
|
**4. Check it before it is in force**, with the pre-flight. It opens both files exactly as a run would,
|
|
173
173
|
prints what they declare, and where the deck and the manifest disagree it names the band and says what
|
|
@@ -207,7 +207,7 @@ It exits 0 when the two agree and 1 when they do not, so it can gate a deploymen
|
|
|
207
207
|
brandowner add --dry-run` prints the same report for the framework it would set.
|
|
208
208
|
|
|
209
209
|
**It also tells you which file answered.** Resolution looks in your store first and falls back to this
|
|
210
|
-
repository, and the repository ships decks under names
|
|
210
|
+
repository, and the repository ships decks under names you may well have chosen too. A deck that
|
|
211
211
|
went missing from your store is therefore replaced by ours rather than reported absent — same band
|
|
212
212
|
words, different rubric, nothing raised anywhere. When that happens the report says so, above the
|
|
213
213
|
verdict, and the profile screen writes a line to the log.
|
|
@@ -231,10 +231,10 @@ look exactly like right ones.** Have it read by whoever would sign the advice, b
|
|
|
231
231
|
|
|
232
232
|
---
|
|
233
233
|
|
|
234
|
-
## 3.
|
|
234
|
+
## 3. Company profiles
|
|
235
235
|
|
|
236
|
-
One JSON file per
|
|
237
|
-
examples: `generic` (the Generic default) and the demo
|
|
236
|
+
One JSON file per company under [`driver/profiles/`](../driver/profiles/). Two are published as working
|
|
237
|
+
examples: `generic` (the Generic default) and the demo company. Three further synthetic profiles —
|
|
238
238
|
gaming, functional drinks and animal health — exist in the repository for the test suite and are left
|
|
239
239
|
out of the package.
|
|
240
240
|
|
|
@@ -248,8 +248,8 @@ frozen into the run's own sidecar, so editing a profile mid-run cannot change a
|
|
|
248
248
|
|---|---|
|
|
249
249
|
| `name`, `matchDomains[]` | Identity and resolution. Overlapping domains across files is a load-time error. |
|
|
250
250
|
| `platforms[]` | The store domains the common-law sweep covers. The general-web cell is implicit — never list it. |
|
|
251
|
-
| `defaultClasses[]`, `defaultJurisdictions[]` | What
|
|
252
|
-
| `selfExclusionOwners[]` | The
|
|
251
|
+
| `defaultClasses[]`, `defaultJurisdictions[]` | What a clearance assumes when a request names neither. |
|
|
252
|
+
| `selfExclusionOwners[]` | The company's own and affiliate names, so its own rights are not reported as conflicts against it. |
|
|
253
253
|
| `industry` | Sector context that sharpens which adjacencies matter. Context, never a rule that decides. |
|
|
254
254
|
| `riskAppetite` | A prose posture that flavours emphasis and recommended follow-up. |
|
|
255
255
|
| `marketplaceDensity` | `sparse` (default) or `dense` — the per-profile sweep budget. Dense fits long retail listings; gaming stores stay sparse. |
|
|
@@ -287,6 +287,6 @@ in [`PORTAL.md`](PORTAL.md).
|
|
|
287
287
|
| Profile internals and the onboarding runbook | [`architecture/05-customer-profiles.md`](architecture/05-customer-profiles.md) |
|
|
288
288
|
| What each product searches | [`../driver/products.mjs`](../driver/products.mjs) — the declaration the engine reads |
|
|
289
289
|
|
|
290
|
-
**
|
|
290
|
+
**Company profiles and frameworks are not application config.** Keep them in your own private store
|
|
291
291
|
and point the engine at it with `CLEAROTRON_CUSTOMERS_DIR` — the bundled profiles are demo data, and a
|
|
292
|
-
real
|
|
292
|
+
real company's rubric does not belong in a checkout of this repo.
|
package/docs/writing-standard.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Writing standard
|
|
2
2
|
|
|
3
|
-
Every surface a
|
|
3
|
+
Every surface a user reads: report HTML, portal screens, README, docs. Two parts.
|
|
4
4
|
|
|
5
5
|
## Part one: how to write
|
|
6
6
|
|
|
@@ -37,7 +37,7 @@ Say what the search did and what happens next. Never define the product by negat
|
|
|
37
37
|
- Before: "What it is not. A clearance search. We drew no register conclusions and give no filing advice."
|
|
38
38
|
- After: "A name that passes here goes on to clearance."
|
|
39
39
|
|
|
40
|
-
## No engineering word in anything a
|
|
40
|
+
## No engineering word in anything a user reads
|
|
41
41
|
|
|
42
42
|
Error codes, connector names, routing tables and internal identifiers are not the reader's vocabulary.
|
|
43
43
|
State the limit and its consequence.
|
|
@@ -71,7 +71,7 @@ answers questions about any of them. The page carries the finding.
|
|
|
71
71
|
|
|
72
72
|
## A fault is fixed, or shown to the person who can act on it
|
|
73
73
|
|
|
74
|
-
A
|
|
74
|
+
A reader cannot repair a missing coverage record. Narrating the failure to them turns our defect into
|
|
75
75
|
their problem.
|
|
76
76
|
|
|
77
77
|
- Before: "No coverage record was produced for this run. This section normally lists what each search
|
package/driver/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# clearotron-driver
|
|
2
2
|
|
|
3
|
+
## 0.3.2-beta.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 3f4367e: Fixed: A multi-country search no longer refuses to start on a form that is already showing the territories it will search. When you have not chosen territories yourself, the form shows your company's own and the search uses those.
|
|
8
|
+
|
|
9
|
+
Fixed: A new clearance form now opens with one line saying what to do. It no longer shows two warning panels about work you have not started.
|
|
10
|
+
- 3f4367e: Fixed: On a phone, the list of clearances can now be scrolled sideways to read its columns. Before, the risk word was printed on top of the date and names broke in the middle of a word.
|
|
11
|
+
|
|
12
|
+
## 0.3.2-beta.3
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- cc56786: New: an installation can name its administrator contact, a mail or web address, and Preferences links "Clearotron administrator" to it.
|
|
17
|
+
|
|
18
|
+
New: Preferences carries the top bar's blur button, and the blur now stays as you left it in this browser, reloads included.
|
|
19
|
+
|
|
20
|
+
New: Global config is now Installation settings, with one sign-in row, the engine's own web search under Engine, and providers grouped by category.
|
|
21
|
+
|
|
22
|
+
New: a provider needing action says what it needs in a few words and links its setup guide, instead of naming settings and files.
|
|
23
|
+
|
|
24
|
+
New: About lists its facts in one card, and its source link reads as the repository's name, with the build just above.
|
|
25
|
+
|
|
26
|
+
New: the sign-in page leads with one line, "This Clearotron signs in one person: you.", and keeps the reset and sign-on steps under Administrator help.
|
|
27
|
+
- cc56786: New: a report's header labels both of its dates, searched and issued, with Ask AI and Export beside them as two buttons.
|
|
28
|
+
|
|
29
|
+
New: Ask AI on a report offers four questions, and opens Claude with the one you pick typed in, ready for you to send.
|
|
30
|
+
|
|
31
|
+
New: Use your AI is now Connect your AI, and shows whether your assistant is connected, folding the setup steps away once it is.
|
|
32
|
+
|
|
33
|
+
New: after Set it up on a report's Ask AI, Connect your AI offers a button back to that report once your assistant connects.
|
|
34
|
+
|
|
35
|
+
Fixed: Claude's steps no longer tell you to ignore an authentication warning, and copy the address and the key with separate buttons.
|
|
36
|
+
|
|
37
|
+
New: where your installation offers another way to connect, Connect your AI keeps those steps in a closed fold under the sign-in steps.
|
|
38
|
+
|
|
3
39
|
## 0.3.2-beta.2
|
|
4
40
|
|
|
5
41
|
### Patch Changes
|
package/driver/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "clearotron-driver",
|
|
3
3
|
"private": true,
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "0.3.2-beta.
|
|
5
|
+
"version": "0.3.2-beta.4",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
7
7
|
"description": "Deterministic driver for the trademark clearance workflow: orchestration in code (fan-out, fan-in barrier, gating, retries); the model does judgment leaves only, through a reasoning CLI spawned per stage.",
|
|
8
8
|
"engines": {
|
|
@@ -142,7 +142,7 @@ import { orderedQueueFiles, reorderQueue } from "./queue-order.mjs"; // the SA
|
|
|
142
142
|
import { drainingState } from "./worker-heartbeat.mjs"; // / — is anything draining this install
|
|
143
143
|
import { batchMarkName } from "./mark-name.mjs";
|
|
144
144
|
import { DEFAULT_CLIENT_DAILY_RUNS, accountUsage } from "./usage-ledger.mjs";
|
|
145
|
-
import { productIdentity } from "../shared/product-identity.mjs"; // AGPL §13 — one answer, three surfaces
|
|
145
|
+
import { productIdentity, SOURCE_REPO } from "../shared/product-identity.mjs"; // AGPL §13 — one answer, three surfaces
|
|
146
146
|
import { engineCommit } from "./engine-build.mjs"; // — the SAME stamp pool meta records
|
|
147
147
|
// — siblings, on their own line: the guard pins the line above and its subject is the JOIN
|
|
148
148
|
// (this endpoint and pool meta stamp the same function), not the import list. Kept separate so that
|
|
@@ -155,7 +155,7 @@ import { readReport, reportsOf, resolveReportFile, batchSummaryOf } from "./port
|
|
|
155
155
|
import { readArchivedSet, updateArchived } from "./publish/archive-tags.mjs";
|
|
156
156
|
import { readAcks, setAck, withAcks, ACKNOWLEDGEABLE } from "./portal-acks.mjs";
|
|
157
157
|
import { MAX_BRIEF, makeReadBudget } from "./compose-read.mjs";
|
|
158
|
-
import { BRAND, ORGANISATION_NAME, PALETTE, FONT_LINK, FAVICON_LINK, bracketMark, DOOR_ROOT, DOOR_ROOT_DARK, DOOR_THEME_INIT } from "../shared/brand.mjs";
|
|
158
|
+
import { BRAND, ORGANISATION_NAME, ADMINISTRATOR_CONTACT, PALETTE, FONT_LINK, FAVICON_LINK, bracketMark, DOOR_ROOT, DOOR_ROOT_DARK, DOOR_THEME_INIT } from "../shared/brand.mjs";
|
|
159
159
|
import { envFrom, pinEnv } from "../shared/env-aliases.mjs"; // — a refusal names the name in force
|
|
160
160
|
import { accessAudience, audienceLabel } from "../shared/access-audience.mjs"; // — F54; jose-free on purpose
|
|
161
161
|
import { resolveNumericSetting } from "./numeric-setting.mjs"; // — the same table the engine enforces, without the throw a rendering surface must not take
|
|
@@ -1590,6 +1590,9 @@ export function makePortalService({
|
|
|
1590
1590
|
return { status: 200, json: { email: principal.email, ...principalView(principal, grantsHere, accountNames),
|
|
1591
1591
|
accounts: principal.accounts, accountNames, accountFacts,
|
|
1592
1592
|
concurrentRuns: concurrentRunsCap(), brand: ORGANISATION_NAME, engineMode: meEngineMode,
|
|
1593
|
+
// WHERE A PERSON ASKS FOR A CHANGE TO THEIR SIGN-IN, beside the brand and read where it is read:
|
|
1594
|
+
// an href Preferences links "Clearotron administrator" to, or null, and then the words are plain.
|
|
1595
|
+
administratorContact: ADMINISTRATOR_CONTACT,
|
|
1593
1596
|
// WHETHER THE PROGRAM IS ON THIS BOX WHILE THE ENGINE CANNOT SEE IT — true, false, or null
|
|
1594
1597
|
// for "this could not be checked". The screen above renders one of three remedies from it,
|
|
1595
1598
|
// and they are different remedies: install the CLI, restart the service that cannot see it,
|
|
@@ -2494,6 +2497,9 @@ async function connectorDoorKind(url) {
|
|
|
2494
2497
|
// surface serves a loopback address to anybody, and the door's running-or-not stopped being
|
|
2495
2498
|
// a question the moment it auto-started with the product.
|
|
2496
2499
|
publicAddress: url,
|
|
2500
|
+
// THE KEY DOOR'S OWN HOST, when one is deployed. Beside a sign-in door its steps ride along for
|
|
2501
|
+
// the page to fold away; they are never resolved against `url`, which refuses a key.
|
|
2502
|
+
keyAddress: keyUrl,
|
|
2497
2503
|
operator: principal.email ?? null,
|
|
2498
2504
|
// WHAT THE DOOR ANSWERS, read from the door rather than assumed by the row. The steps used to
|
|
2499
2505
|
// be fixed: Claude's said to paste a key and set authentication to None, which is right for a
|
|
@@ -3848,6 +3854,17 @@ const escHtml = (t) => String(t).replace(/[&<>"']/g, (c) => ({ "&": "&", "<"
|
|
|
3848
3854
|
//
|
|
3849
3855
|
// The dark ground moved with that change: the block this page used to carry had guessed #17150f/#ece5d8,
|
|
3850
3856
|
// and brand pack §01 fixes dark at #0f0e0c near-black + #f0e8d8 parchment. The pack wins.
|
|
3857
|
+
// ── THE PLAIN LINE LEADS; THE ADMINISTRATOR'S TWO LINES STEP BACK INTO A FOLD ────────────────────────
|
|
3858
|
+
//
|
|
3859
|
+
// A person arriving here needs the field, the button, and one fact: this install signs in one person.
|
|
3860
|
+
// The reset command and the way to add people are an administrator's business, so they sit in a closed
|
|
3861
|
+
// "Administrator help" fold, word for word as they were, with the same link People gives to putting a
|
|
3862
|
+
// login system in front. A `<details>` needs no script, which this door must render without.
|
|
3863
|
+
//
|
|
3864
|
+
// The reset command can be long — a pinned version, a base directory — so it wraps inside the card at the
|
|
3865
|
+
// card's own width rather than pushing past its edge.
|
|
3866
|
+
export const LOGIN_IN_FRONT_DOC = `${SOURCE_REPO}/blob/main/docs/PORTAL.md#putting-your-own-login-provider-in-front`;
|
|
3867
|
+
|
|
3851
3868
|
export function loginPage({ email, error = null, signedIn = false, discarded = false, resetCommand = null }) {
|
|
3852
3869
|
const reset = resetCommand || `${bareInvocation("passphrase")} --reset`;
|
|
3853
3870
|
const title = signedIn ? "Signed in" : "Sign in";
|
|
@@ -3883,7 +3900,16 @@ ${DOOR_THEME_INIT}
|
|
|
3883
3900
|
border:1px solid var(--err-line); color:var(--err-ink); font-size:14px; }
|
|
3884
3901
|
.hint { margin-top:18px; font-size:13px; }
|
|
3885
3902
|
code { font-family:var(--mono); font-size:12.5px; background:var(--code-bg);
|
|
3886
|
-
padding:1px 5px; border-radius:4px; }
|
|
3903
|
+
padding:1px 5px; border-radius:4px; overflow-wrap:anywhere; }
|
|
3904
|
+
.lead { margin:18px 0 0; padding-top:14px; border-top:1px solid var(--line); font-size:13.5px; color:var(--ink); }
|
|
3905
|
+
.lead b { font-weight:600; }
|
|
3906
|
+
.fold { margin-top:10px; }
|
|
3907
|
+
.fold > summary { display:inline-flex; align-items:center; gap:6px; list-style:none; cursor:pointer;
|
|
3908
|
+
font-size:13px; color:var(--link); }
|
|
3909
|
+
.fold > summary::-webkit-details-marker { display:none; }
|
|
3910
|
+
.fold .chev { flex:none; color:var(--muted); }
|
|
3911
|
+
.fold[open] > summary .chev { transform:rotate(90deg); }
|
|
3912
|
+
.fold .hint { margin:14px 0 0; }
|
|
3887
3913
|
${DOOR_ROOT_DARK}
|
|
3888
3914
|
</style></head><body><div class="card">
|
|
3889
3915
|
${lockup}
|
|
@@ -3900,8 +3926,12 @@ ${error ? `<p class="err">${escHtml(error)}</p>` : ""}
|
|
|
3900
3926
|
<input id="passphrase" name="passphrase" type="password" autocomplete="new-password" autofocus>
|
|
3901
3927
|
<button type="submit">Sign in</button>
|
|
3902
3928
|
</form>
|
|
3929
|
+
<p class="lead"><b>This ${escHtml(BRAND.name)} signs in one person: you.</b></p>
|
|
3930
|
+
<details class="fold"><summary><span>Administrator help</span><svg class="chev" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="m9 18 6-6-6-6"/></svg></summary>
|
|
3903
3931
|
<p class="hint">Lost the passphrase? Run <code>${escHtml(reset)}</code> on the machine
|
|
3904
|
-
running this portal. It mints a new one and prints it once.</p
|
|
3932
|
+
running this portal. It mints a new one and prints it once.</p>
|
|
3933
|
+
<p class="hint">To add people, put it behind a login system such as your company single sign-on. <a href="${escHtml(LOGIN_IN_FRONT_DOC)}" target="_blank" rel="noreferrer">How to set that up</a></p>
|
|
3934
|
+
</details>`}
|
|
3905
3935
|
</div></body></html>`;
|
|
3906
3936
|
}
|
|
3907
3937
|
// THE FIELD DOES NOT INVITE THE BROWSER'S SAVED PASSWORDS. Every local install and demo answers on
|