clearotron 0.3.2-beta.7 → 0.3.2-beta.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +58 -26
- package/CONTRIBUTING.md +8 -8
- package/INSTALL.md +148 -81
- package/README.md +3 -3
- package/SECURITY.md +3 -3
- package/bin/brandowner.mjs +3 -3
- package/bin/framework-preflight.mjs +1 -1
- package/bin/onboard.mjs +637 -216
- package/bin/start.mjs +151 -27
- package/bin/update.mjs +58 -11
- package/build-info.json +2 -2
- package/docs/DELIVERY.md +2 -1
- package/docs/INTAKE.md +1 -1
- package/docs/ONBOARDING.md +1 -1
- package/docs/architecture/03-run-lifecycle.md +6 -6
- package/docs/architecture/04-configuration-reference.md +32 -14
- package/docs/architecture/05-config-governance.md +23 -8
- package/docs/architecture/05-customer-profiles.md +2 -2
- package/docs/architecture/06-operations-runbook.md +3 -3
- package/docs/architecture/08-development-guide.md +6 -6
- package/docs/configuration.md +5 -5
- package/docs/decisions/0003-credential-model.md +1 -1
- package/docs/writing-standard.md +4 -0
- package/driver/CHANGELOG.md +124 -0
- package/driver/README.md +3 -3
- package/driver/band-size.mjs +59 -0
- package/driver/binding-layers.mjs +1 -1
- package/driver/citation-census.json +3 -3
- package/driver/{prelim-variants-record.mjs → clearance-variants-record.mjs} +24 -24
- package/driver/common-law-receipts.mjs +2 -2
- package/driver/company-bundle.mjs +3 -3
- package/driver/compose-read.mjs +8 -14
- package/driver/config-inventory.mjs +112 -9
- package/driver/consumption-ledger.mjs +2 -2
- package/driver/contract-arm2-baseline.json +2 -5
- package/driver/contract-dictation-registry.mjs +19 -19
- package/driver/contract-e3-backlog.mjs +43 -43
- package/driver/contract-e3-baseline.json +14 -14
- package/driver/contract-vocabulary.mjs +68 -27
- package/driver/deliver-trigger.sh +16 -16
- package/driver/demo-container.mjs +3 -3
- package/driver/dev-portal.mjs +3 -3
- package/driver/disposition-call.mjs +1 -1
- package/driver/door-gates.mjs +41 -7
- package/driver/doubt-ledger.mjs +2 -2
- package/driver/drainer-identity.mjs +34 -8
- package/driver/driver.config.mjs +367 -104
- package/driver/engine/CONTRACT.md +10 -3
- package/driver/engine/README.md +2 -2
- package/driver/engine/anthropic-agent.mjs +77 -21
- package/driver/engine/auth.mjs +129 -10
- package/driver/engine/jx-turn.mjs +7 -6
- package/driver/engine/mcp/README.md +1 -1
- package/driver/engine/mcp/dispositions-server.mjs +3 -3
- package/driver/engine/mcp/gather-config.mjs +9 -9
- package/driver/engine/mcp/perplexity-server.mjs +2 -2
- package/driver/engine/mcp/recording-server.mjs +18 -5
- package/driver/engine/openai-agent.mjs +4 -2
- package/driver/engine/probe.mjs +110 -23
- package/driver/enqueue-schema.mjs +6 -2
- package/driver/findings-model.mjs +6 -3
- package/driver/flag-snapshot.mjs +34 -8
- package/driver/form-neighbourhood.mjs +54 -7
- package/driver/framework.mjs +4 -4
- package/driver/gateway.mjs +36 -24
- package/driver/jx-lanes.mjs +23 -4
- package/driver/jx-units.mjs +7 -4
- package/driver/jx.mjs +34 -4
- package/driver/knockout-review-record.mjs +56 -4
- package/driver/known-conflicts.mjs +1 -1
- package/driver/matter-frame-record.mjs +90 -1
- package/driver/named-band.mjs +1 -1
- package/driver/ordinary-words.mjs +51 -0
- package/driver/outbox-backoff.mjs +31 -16
- package/driver/package.json +1 -1
- package/driver/partial-payload-baseline.json +2 -2
- package/driver/phase0.mjs +3 -3
- package/driver/pipeline-knockout.mjs +5 -5
- package/driver/pipeline.mjs +396 -81
- package/driver/placement-form.mjs +77 -1
- package/driver/placement-model.mjs +1 -1
- package/driver/portal-config-view.mjs +30 -1
- package/driver/portal-report.mjs +107 -6
- package/driver/portal-service.mjs +80 -14
- package/driver/portal-upstream.mjs +1 -1
- package/driver/predelivery-lint.mjs +12 -2
- package/driver/preserve-merge.mjs +3 -3
- package/driver/product-rows.mjs +2 -2
- package/driver/products.mjs +1 -1
- package/driver/profiles/README.md +3 -3
- package/driver/profiles/demo-brand-owner.json +2 -2
- package/driver/profiles.mjs +55 -17
- package/driver/progress.mjs +18 -8
- package/driver/provider-usage.mjs +8 -8
- package/driver/publish/index.mjs +154 -8
- package/driver/publish/knockout.mjs +39 -5
- package/driver/publish/pool-admin.mjs +1 -1
- package/driver/publish/publish-inputs.mjs +18 -2
- package/driver/publish/render-knockout.mjs +184 -31
- package/driver/publish/render.mjs +323 -93
- package/driver/publish/report-data.mjs +4 -1
- package/driver/publish/report-topbar.mjs +58 -0
- package/driver/publish/search-depth.mjs +133 -4
- package/driver/publish/templates/report.css +78 -4
- package/driver/publish/xlsx.mjs +20 -1
- package/driver/queue-order.mjs +2 -2
- package/driver/recording-agreement.mjs +1 -1
- package/driver/reference-score.mjs +1 -1
- package/driver/register-availability.mjs +2 -2
- package/driver/register-count.mjs +50 -5
- package/driver/register-coverage.mjs +161 -1
- package/driver/register-digest-record.mjs +236 -11
- package/driver/register-grant-vocabulary.mjs +1 -1
- package/driver/register-plan.mjs +189 -2
- package/driver/registry-fidelity.mjs +3 -3
- package/driver/repair-composers.mjs +1 -1
- package/driver/repair-contract.mjs +1 -1
- package/driver/replay-archive.mjs +6 -6
- package/driver/report-overview-record.mjs +2 -2
- package/driver/result-noun-fields.mjs +2 -2
- package/driver/run-economics.mjs +41 -10
- package/driver/run-requirements.mjs +173 -9
- package/driver/runner.mjs +5 -5
- package/driver/scope-facts.mjs +20 -5
- package/driver/scope-ledger.mjs +5 -5
- package/driver/search-policy.mjs +22 -12
- package/driver/skills/README.md +15 -15
- package/driver/skills/blind-frame/SKILL.md +2 -2
- package/driver/skills/case-law-citation/SKILL.md +4 -4
- package/driver/skills/case-law-citation/sources/eurlex.md +1 -1
- package/driver/skills/{prelim-common-law → clearance-common-law}/SKILL.md +22 -22
- package/driver/skills/{prelim-common-law → clearance-common-law}/perplexity-prompts.md +1 -1
- package/driver/skills/{prelim-register → clearance-register}/SKILL.md +10 -10
- package/driver/skills/{prelim-register → clearance-register}/digest.md +2 -2
- package/driver/skills/{prelim-register → clearance-register}/providers/README.md +1 -1
- package/driver/skills/{prelim-register → clearance-register}/providers/clarivate.md +37 -35
- package/driver/skills/{prelim-register → clearance-register}/providers/corsearch.md +20 -11
- package/driver/skills/{prelim-register → clearance-register}/providers/signa.md +5 -5
- package/driver/skills/{prelim-register → clearance-register}/register-recipes.md +3 -3
- package/driver/skills/{prelim-register → clearance-register}/status-rules.md +2 -2
- package/driver/skills/{prelim-register → clearance-register}/stealth-filer-indicators.md +1 -1
- package/driver/skills/{prelim-register → clearance-register}/unit.md +2 -2
- package/driver/skills/{prelim-search → clearance-search}/SKILL.md +31 -31
- package/driver/skills/{prelim-search → clearance-search}/delivery-contract.md +1 -1
- package/driver/skills/{prelim-search → clearance-search}/phase2-execution.md +18 -18
- package/driver/skills/{prelim-search → clearance-search}/synthesis-rules.md +7 -7
- package/driver/skills/{prelim-variants → clearance-variants}/SKILL.md +18 -18
- package/driver/skills/{prelim-variants → clearance-variants}/transliteration-scripts.md +5 -5
- package/driver/skills/frame-diff/SKILL.md +1 -1
- package/driver/skills/knockout-assess/SKILL.md +10 -7
- package/driver/skills/matter-frame/SKILL.md +3 -3
- package/driver/skills/narrative-refutation/SKILL.md +9 -9
- package/driver/skills/placement-inquiry/SKILL.md +5 -5
- package/driver/stage-context.mjs +1 -1
- package/driver/stages-knockout.mjs +4 -4
- package/driver/stages.mjs +65 -61
- package/driver/status-snapshot.mjs +2 -2
- package/driver/suite-census.json +340 -136
- package/driver/surface-exit-verdict.mjs +58 -0
- package/driver/systemd/README.md +9 -6
- package/driver/systemd/clearotron-worker.service +1 -1
- package/driver/terminal-clamp.mjs +109 -1
- package/driver/tokens.mjs +169 -3
- package/driver/unit-environment.mjs +42 -15
- package/driver/unit-inventory.mjs +19 -2
- package/driver/usage-ledger.mjs +1 -1
- package/driver/variant-manifest-model.mjs +4 -4
- package/driver/verify-knockout.mjs +27 -0
- package/driver/verify.mjs +94 -6
- package/driver/whatif-queue.mjs +1 -1
- package/driver/wordlists/en.txt +63906 -0
- package/mcp-server/CHANGELOG.md +8 -0
- package/mcp-server/README.md +1 -1
- package/mcp-server/lib/README.md +1 -1
- package/mcp-server/lib/options.mjs +8 -7
- package/mcp-server/lib/plan.mjs +18 -2
- package/mcp-server/lib/runs.mjs +1 -1
- package/mcp-server/lib/usage.mjs +3 -3
- package/mcp-server/lib/whatif.mjs +1 -1
- package/mcp-server/package.json +1 -1
- package/mcp-server/server.mjs +18 -1
- package/package.json +12 -11
- package/portal-ui/dist/assets/{index-CVOIvdhc.css → index-CtvwLCti.css} +207 -3
- package/portal-ui/dist/assets/{index-5UyqAyNM.js → index-EVaSo5-g.js} +1580 -527
- package/portal-ui/dist/index.html +2 -2
- package/portal-ui/package.json +1 -1
- package/providers/README.md +1 -1
- package/providers/_shared/enumerate.mjs +6 -6
- package/providers/_shared/execute-plan.mjs +3 -3
- package/providers/_shared/ledger.mjs +119 -5
- package/providers/_shared/provider-text.mjs +2 -2
- package/providers/_shared/screen.mjs +2 -2
- package/providers/_shared/script-form.mjs +3 -3
- package/providers/_shared/territory-codes.mjs +23 -3
- package/providers/clarivate/README.md +1 -1
- package/providers/clarivate/src/capabilities.js +12 -12
- package/providers/clarivate/src/core.js +37 -43
- package/providers/corsearch/README.md +1 -1
- package/providers/corsearch/src/capabilities.js +5 -5
- package/providers/corsearch/src/core.js +3 -3
- package/providers/jx/README.md +2 -1
- package/providers/jx/src/turn-envelope.mjs +8 -3
- package/providers/oauth-mcp-bridge/CHANGELOG.md +8 -0
- package/providers/oauth-mcp-bridge/package.json +1 -1
- package/providers/perplexity/src/core.js +1 -1
- package/providers/signa/README.md +1 -1
- package/providers/signa/src/capabilities.js +42 -49
- package/providers/signa/src/core.js +106 -29
- package/providers/uspto-local/README.md +1 -1
- package/providers/uspto-local/src/sync.js +1 -1
- package/scripts/README.md +1 -0
- package/scripts/ask-ai-render-check.mjs +127 -1
- package/scripts/authority-boundary-probe.mjs +8 -6
- package/scripts/backfill-started-at.mjs +2 -2
- package/scripts/census-merge-driver.mjs +33 -2
- package/scripts/citation-anchor-report.mjs +181 -0
- package/scripts/dead-names.mjs +1 -1
- package/scripts/deprecate-below.mjs +66 -8
- package/scripts/drain-preflight.mjs +1 -1
- package/scripts/e2e.mjs +174 -0
- package/scripts/env-audit.mjs +39 -6
- package/scripts/env-classify.mjs +20 -2
- package/scripts/freeze-example-run.mjs +61 -18
- package/scripts/generated-files-are-current.mjs +69 -4
- package/scripts/live-surface-check.mjs +124 -41
- package/scripts/markdown-link-check.mjs +1 -1
- package/scripts/merge-shape-check.mjs +242 -0
- package/scripts/mint-names-in-force.mjs +5 -5
- package/scripts/mint-offered-territories.mjs +72 -0
- package/scripts/mint-public-residue.mjs +2 -2
- package/scripts/mint-reference-strip-backlog.mjs +2 -2
- package/scripts/mint-suite-census.mjs +75 -2
- package/scripts/mint-writing-standard-backlog.mjs +2 -2
- package/scripts/purge-runs.mjs +7 -7
- package/scripts/reconcile-runs.mjs +2 -2
- package/scripts/release-approve-parked.mjs +20 -2
- package/scripts/release-await-cut.mjs +120 -1
- package/scripts/release-note-required.mjs +76 -8
- package/scripts/report-header-render-check.mjs +164 -0
- package/scripts/settings-render-check.mjs +75 -2
- package/scripts/test-full.mjs +96 -3
- package/scripts/test-run.mjs +10 -0
- package/shared/brand.mjs +27 -0
- package/shared/connect-clients.mjs +39 -11
- package/shared/deployment-box.mjs +7 -2
- package/shared/driver-dir.mjs +1 -1
- package/shared/env-aliases.mjs +1 -1
- package/shared/identifier-scan.mjs +65 -9
- package/shared/identifier-sentinels.mjs +22 -0
- package/shared/names-in-force.mjs +4 -2
- package/shared/offered-territories.json +738 -0
- package/shared/pre-rename-spellings.mjs +53 -0
- package/shared/reference-guard-classes.mjs +40 -2
- package/shared/stdio-connect.mjs +39 -4
- package/shared/tree-commit.mjs +48 -0
- /package/driver/skills/{prelim-register → clearance-register}/providers/euipo.md +0 -0
- /package/driver/skills/{prelim-register → clearance-register}/providers/free-tier.md +0 -0
- /package/driver/skills/{prelim-register → clearance-register}/providers/uspto-local.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/field-doctrine-pharma.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/firm-wide-reasoning.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/report-prose.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/risk-framework-demo.manifest.json +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/risk-framework-demo.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/risk-framework-triage.manifest.json +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/risk-framework-triage.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/risk-framework.manifest.json +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/risk-framework.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/template-formatting.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/templates/email/generic.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/templates/search-request-form.html +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/worked-examples-demo.md +0 -0
- /package/driver/skills/{prelim-search → clearance-search}/worked-examples.md +0 -0
package/bin/start.mjs
CHANGED
|
@@ -84,8 +84,10 @@ import { writeSecretFile } from "../shared/secret-file.mjs"; // one atomic wri
|
|
|
84
84
|
// below: to COMPOSE the units' environment and to GUARD it before this command reports success. The
|
|
85
85
|
// tables are handed in rather than imported by it, because the register table lives in a CLI entry and
|
|
86
86
|
// the driver must not point at `bin/`.
|
|
87
|
-
import { runRequiredNames, missingRequirements } from "../driver/run-requirements.mjs";
|
|
88
|
-
import {
|
|
87
|
+
import { runRequiredNames, missingRequirements, CLOUD_ROUTES } from "../driver/run-requirements.mjs";
|
|
88
|
+
import { CLOUD_SWITCH, cloudsSwitchedOn } from "../driver/engine/auth.mjs"; // a switch compared the way the program reads it: on or off
|
|
89
|
+
import { ENGINE_BINARIES, DEFAULT_ENGINE_ID as RUN_DEFAULT_ENGINE, resolveEngineProgram } from "../driver/driver.config.mjs";
|
|
90
|
+
import { unitEnvironment, unitValue } from "../driver/unit-environment.mjs"; // the PATH the worker unit will run with, read the way doctor reads it
|
|
89
91
|
|
|
90
92
|
/**
|
|
91
93
|
* The tables the requirements authority needs — resolved at CALL time, never at module scope.
|
|
@@ -104,13 +106,14 @@ import { ENGINE_BINARIES, DEFAULT_ENGINE_ID as RUN_DEFAULT_ENGINE } from "../dri
|
|
|
104
106
|
* driver/test/a-backgrounded-install-can-actually-run-a-clearance.test.mjs refuses a static import of
|
|
105
107
|
* onboard from this file, so the cycle cannot come back quietly.
|
|
106
108
|
*/
|
|
107
|
-
async function runTables() {
|
|
109
|
+
export async function runTables() {
|
|
108
110
|
const { PROVIDERS } = await import("./onboard.mjs");
|
|
109
|
-
return { registers: PROVIDERS, engines: ENGINE_BINARIES, defaultEngine: RUN_DEFAULT_ENGINE };
|
|
111
|
+
return { registers: PROVIDERS, engines: ENGINE_BINARIES, defaultEngine: RUN_DEFAULT_ENGINE, resolveEngine: resolveEngineProgram };
|
|
110
112
|
}
|
|
111
113
|
import { spawn, spawnSync, execFileSync } from "node:child_process";
|
|
112
114
|
import { storeInRepo, storeOutsideRepoMessage, storeCommitRefusal } from "../shared/store-in-repo.mjs"; //
|
|
113
115
|
import { stdioConnectOffer } from "../shared/stdio-connect.mjs";
|
|
116
|
+
import { wslTarget } from "../shared/wsl.mjs"; // — and which distribution a row should start the server in
|
|
114
117
|
import { ensureDemoProgram } from "../shared/permanent-install.mjs"; // — a demo from npx keeps its own copy
|
|
115
118
|
import { mergeEnvFile } from "../shared/env-file-merge.mjs";
|
|
116
119
|
import { mcpOriginFor } from "../shared/lane-address.mjs"; // — one author for the origin
|
|
@@ -188,6 +191,89 @@ export function homeEnvUpdate(homeText, union) {
|
|
|
188
191
|
return mergeEnvFile(homeText, union, { refresh: LAUNCHER_MINTED });
|
|
189
192
|
}
|
|
190
193
|
|
|
194
|
+
/**
|
|
195
|
+
* The services' settings file as this start will leave it, and the run's settings in it that differ from
|
|
196
|
+
* the configuration this command holds. PURE, and the one reading `--background` uses for both its guard
|
|
197
|
+
* and its write, so a test drives start's own answer rather than a copy of it.
|
|
198
|
+
*
|
|
199
|
+
* THE GUARD CHECKED A MERGE THE FILE DOES NOT PERFORM. It read `{ ...file, ...union }`, where this
|
|
200
|
+
* command's value wins, while the add-only merge keeps the file's line, an empty one included. So a file
|
|
201
|
+
* holding `CLAUDE_CODE_USE_FOUNDRY=` passed the guard on this command's `=1`, kept its empty line, and
|
|
202
|
+
* every search was refused at the order wall. `reads` is the merged text, parsed: what the units read.
|
|
203
|
+
*
|
|
204
|
+
* AND WHAT THE FILE KEEPS IS SAID, never replaced. The merge adds only what the file lacks, and that is
|
|
205
|
+
* deliberate: the file is the running product's configuration, an operator edits it to change what the
|
|
206
|
+
* services do, and a start that rewrote it from this command's configuration would undo that edit. What
|
|
207
|
+
* was wrong was the silence. A machine moved from one cloud to another, or holding a rotated key, started
|
|
208
|
+
* again and reported the file complete while the services kept the old account.
|
|
209
|
+
* `differ` names the run settings on which the two disagree, so start can say which. Names only, never a
|
|
210
|
+
* value.
|
|
211
|
+
*
|
|
212
|
+
* WHICH DISAGREEMENTS, BY THE KIND OF SETTING, and never by which side holds the value. A healthy install
|
|
213
|
+
* can keep its register key, its engine's path and its research key in the units' file alone, because
|
|
214
|
+
* that file is where start tells an operator to change what the services use; this command's shell then
|
|
215
|
+
* holds none of them, and naming them on every start would warn about a working install. So a setting
|
|
216
|
+
* counts only when this command holds a value the file contradicts: a rotated key, or a line kept empty.
|
|
217
|
+
* The billing word and the settings that pick a cloud are the exception, and count in either direction,
|
|
218
|
+
* because the file holding one this command does not is exactly the machine billing an account nobody
|
|
219
|
+
* chose any more. They are compared as the program reads them: an unset billing word is the subscription,
|
|
220
|
+
* and a switch is on or off, so `1` beside `true` is not a difference.
|
|
221
|
+
*
|
|
222
|
+
* BUT ONLY WHERE THIS COMMAND HOLDS AN OPINION. A configuration that sets no billing word says nothing
|
|
223
|
+
* about how the services pay: an api-key, Codex api-key or cloud install whose billing lives in the units'
|
|
224
|
+
* file alone, where start's own remedy offers to put it, was warned about its billing word and its switch
|
|
225
|
+
* on every start. So with no billing word here, neither the word nor the cloud settings are compared. Under
|
|
226
|
+
* `cloud` with no cloud named here, which cloud is not compared either. And under `subscription` or
|
|
227
|
+
* `api-key` a cloud setting this command holds counts as unset, because the run door refuses a switch
|
|
228
|
+
* beside either word and start never carries one: naming it sent the operator to put into the file a
|
|
229
|
+
* switch every search would then be refused over. A cloud the FILE holds under those words still counts.
|
|
230
|
+
*/
|
|
231
|
+
export function unitsFileAfterStart(homeText, union, { config = {}, tables = {} } = {}) {
|
|
232
|
+
const merged = homeEnvUpdate(homeText, union);
|
|
233
|
+
const reads = parseEnvFile(merged.text);
|
|
234
|
+
const ours = (k) => String(union[k] ?? config[k] ?? "").trim();
|
|
235
|
+
const theirs = (k) => String(reads[k] ?? "").trim();
|
|
236
|
+
const words = new Set(Object.values(tables.engines ?? {}).map((e) => e?.authEnv).filter(Boolean));
|
|
237
|
+
const switches = Object.values(CLOUD_SWITCH);
|
|
238
|
+
const as = (k, v) => words.has(k) ? (v.toLowerCase() || "subscription")
|
|
239
|
+
: switches.includes(k) ? cloudsSwitchedOn({ [k]: v }).length > 0 : v;
|
|
240
|
+
const ourWord = ([...words].map(ours).find(Boolean) ?? "").toLowerCase();
|
|
241
|
+
const ourRoutes = Object.fromEntries(CLOUD_ROUTES.map((k) => [k, ours(k)]));
|
|
242
|
+
const ourCloud = cloudsSwitchedOn(ourRoutes).length > 0 || ourRoutes.ANTHROPIC_BASE_URL !== "";
|
|
243
|
+
const route = (k) => CLOUD_ROUTES.includes(k);
|
|
244
|
+
const opinion = (k) => ourWord !== "" && (!route(k) || ourWord !== "cloud" || ourCloud);
|
|
245
|
+
const oursAs = (k) => as(k, route(k) && ourWord !== "cloud" ? "" : ours(k));
|
|
246
|
+
const eitherWay = (k) => words.has(k) || route(k);
|
|
247
|
+
const names = new Set([...runRequiredNames(config, tables), ...runRequiredNames(reads, tables), ...CLOUD_ROUTES]);
|
|
248
|
+
const differ = [...names].filter((k) => !LAUNCHER_MINTED.includes(k)
|
|
249
|
+
&& (eitherWay(k) ? opinion(k) && oursAs(k) !== as(k, theirs(k)) : ours(k) !== "" && ours(k) !== theirs(k)));
|
|
250
|
+
return { merged, reads, differ };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* What start says about `differ`, the settings on which the units' file and this command's configuration
|
|
255
|
+
* disagree. PURE, so the words are driven rather than read from source. Names only, never a value.
|
|
256
|
+
*
|
|
257
|
+
* BOTH PLACES, because the add-only merge makes one of them a trap. This said to edit the units' file and
|
|
258
|
+
* restart. An operator who moved the services from one cloud to another that way, with this command's
|
|
259
|
+
* configuration still naming the first, had the first cloud's switch added back on the next start, since
|
|
260
|
+
* the file no longer held its line: two clouds on, and every search refused. Deleting that line, as the
|
|
261
|
+
* notice said, only repeated it. So it names the file the units read and the configuration start adds from,
|
|
262
|
+
* `cliEnv` (envFileRead(), or null when this command read no file and its shell is the configuration).
|
|
263
|
+
*/
|
|
264
|
+
export function keptSettingsNotice(differ, { homeEnv, cliEnv = null } = {}) {
|
|
265
|
+
if (!differ?.length) return [];
|
|
266
|
+
const one = differ.length === 1;
|
|
267
|
+
return [
|
|
268
|
+
` ⚠ ${homeEnv} and this command's configuration differ on ${one ? "this setting" : "these settings"}, and the units use what the file says:`,
|
|
269
|
+
` ${differ.join(", ")}`,
|
|
270
|
+
` This command only adds a setting the file has no line for; it never replaces one. To change what the units`,
|
|
271
|
+
` use, change ${one ? "it" : "them"} in both places, then restart them:`,
|
|
272
|
+
` ${homeEnv}\n the file the units read`,
|
|
273
|
+
` ${cliEnv ?? "this command's environment"}\n what this command adds from: a line the file above lacks is added back from here on the next start`,
|
|
274
|
+
];
|
|
275
|
+
}
|
|
276
|
+
|
|
191
277
|
/**
|
|
192
278
|
* What a `--background` run has ALREADY DONE when systemd refuses to enable a unit.
|
|
193
279
|
*
|
|
@@ -1709,22 +1795,19 @@ if (isMain) {
|
|
|
1709
1795
|
// said everything was fine, and a lawyer's search that died at its first stage with a stack trace,
|
|
1710
1796
|
// delivering "nothing was delivered. Clearotron has been notified" on a box that notified nobody.
|
|
1711
1797
|
//
|
|
1712
|
-
// CHECKED AGAINST
|
|
1713
|
-
// `mergeEnvFile` is add-only and an
|
|
1798
|
+
// CHECKED AGAINST WHAT THE FILE WILL SAY: the file's own lines, with `union` added where the file has
|
|
1799
|
+
// no line, because `mergeEnvFile` is add-only and an existing line wins, an empty one included. That
|
|
1800
|
+
// is `unitsFileAfterStart`, the same reading the write below uses. Checking `process.env` here would
|
|
1714
1801
|
// measure this shell rather than the units, and pass on exactly the box that fails.
|
|
1802
|
+
let homeText = "";
|
|
1803
|
+
try { homeText = readFileSync(HOME_ENV, "utf8"); } catch (e) { if (e.code !== "ENOENT") fatal(`${HOME_ENV} exists but could not be read (${e.code}).`); }
|
|
1804
|
+
const unitsFile = unitsFileAfterStart(homeText, union, { config: process.env, tables: RUN_TABLES });
|
|
1715
1805
|
//
|
|
1716
1806
|
// BLOCKING REFUSES; NARROWING IS SAID OUT LOUD AND STARTS ANYWAY. A research key this box does not
|
|
1717
1807
|
// hold means the three clearance searches refuse at preflight and a Knockout search still runs and
|
|
1718
1808
|
// discloses what it skipped — so refusing to start over it would take a box that can serve a real
|
|
1719
1809
|
// product and make it serve none. The operator is told which products this install can fill.
|
|
1720
1810
|
{
|
|
1721
|
-
const already = {};
|
|
1722
|
-
try {
|
|
1723
|
-
for (const line of readFileSync(HOME_ENV, "utf8").split("\n")) {
|
|
1724
|
-
const m = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=(.*)$/.exec(line);
|
|
1725
|
-
if (m) already[m[1]] = m[2];
|
|
1726
|
-
}
|
|
1727
|
-
} catch { /* no file yet — the union is the whole of it */ }
|
|
1728
1811
|
// ONE COMPOSER for "where do I set these", used by the start-time refusal and by the order-time
|
|
1729
1812
|
// announcement below it. Two copies of this sentence is how one of them comes to name a file the
|
|
1730
1813
|
// reader cannot use.
|
|
@@ -1739,7 +1822,29 @@ if (isMain) {
|
|
|
1739
1822
|
: `Set them in ${homeEnv} — the file the units read. This command read no environment file of `
|
|
1740
1823
|
+ `its own, so that is the address. \`${invoke("install")}\` writes them for you IN A TERMINAL.`;
|
|
1741
1824
|
};
|
|
1742
|
-
const willRead = { ...
|
|
1825
|
+
const willRead = { ...unitsFile.reads };
|
|
1826
|
+
// ── AND THE PATH THE WORKER WILL SEARCH FOR THE ENGINE'S PROGRAM ─────────────────────────────
|
|
1827
|
+
//
|
|
1828
|
+
// The check asks the engine resolver, and a resolver handed no PATH finds only a path setting or
|
|
1829
|
+
// the copy setup installed. So a `claude` on the units' PATH was announced as "every run is
|
|
1830
|
+
// refused", and the run found it and ran. The PATH is the worker unit's own, read from the file
|
|
1831
|
+
// placed below: the worker runs the clearance, and every shipped unit sets
|
|
1832
|
+
// `Environment=PATH=%h/…`, which the unit reader expands to this home. Never this shell's PATH,
|
|
1833
|
+
// which the units do not inherit.
|
|
1834
|
+
//
|
|
1835
|
+
// THE SETTINGS FILE IS READ WITH IT, because on systemd a PATH in that file wins over the unit's own
|
|
1836
|
+
// `Environment=PATH=` line, wherever the two lines sit (systemd.exec(5)), and the unit reader
|
|
1837
|
+
// applies that rule. Nothing Clearotron writes puts a PATH there, but a hand-edited file can, and
|
|
1838
|
+
// then the worker searches that PATH and not the unit's. A file that is not there yet reads as
|
|
1839
|
+
// empty: this command is about to write it, and the unit's PATH is then the one in force.
|
|
1840
|
+
{
|
|
1841
|
+
let text = null;
|
|
1842
|
+
try { text = readFileSync(join(REPO, "driver", "systemd", "clearotron-worker.service"), "utf8"); } catch { /* the install loop below names a missing unit */ }
|
|
1843
|
+
const settingsFile = (p) => { if (p !== HOME_ENV) return ""; try { return readFileSync(p, "utf8"); } catch { return ""; } };
|
|
1844
|
+
const workerPath = unitValue(unitEnvironment({ units: [{ name: "clearotron-worker.service", text }],
|
|
1845
|
+
readEnvFile: settingsFile, home: homedir() }), "PATH").value;
|
|
1846
|
+
if (workerPath) willRead.PATH = workerPath;
|
|
1847
|
+
}
|
|
1743
1848
|
const miss = missingRequirements(willRead, RUN_TABLES);
|
|
1744
1849
|
// ── — WHICH HALF OF `blocking` MAY REFUSE A START ─────────────────────────
|
|
1745
1850
|
//
|
|
@@ -1769,9 +1874,9 @@ if (isMain) {
|
|
|
1769
1874
|
//
|
|
1770
1875
|
// BOTH FILES, and that is the difference from the port refusals, which say `~/.env` "is NOT read
|
|
1771
1876
|
// here". They are right: nothing in that file reaches a port decision. Here both are true. The
|
|
1772
|
-
// block above reads HOME_ENV into `
|
|
1773
|
-
// satisfies this check on the next run; and the CLI's own file reaches it too,
|
|
1774
|
-
// `runRequiredNames(process.env, …)` loop that copies its values into `union`. Driven rather than
|
|
1877
|
+
// block above reads HOME_ENV into `willRead`, with its lines winning as they do in the file, so a
|
|
1878
|
+
// value set there satisfies this check on the next run; and the CLI's own file reaches it too,
|
|
1879
|
+
// through the `runRequiredNames(process.env, …)` loop that copies its values into `union`. Driven rather than
|
|
1775
1880
|
// read: three blocking names cleared from the CLI's file alone, and the refusal came back naming
|
|
1776
1881
|
// a fourth that the first three had newly required.
|
|
1777
1882
|
//
|
|
@@ -1817,26 +1922,32 @@ if (isMain) {
|
|
|
1817
1922
|
// it"), not about which gate happened to print it, and the arms in
|
|
1818
1923
|
// `a-refusal-names-the-file-when-the-command-it-offers-cannot-be-run.test.mjs` measure it here now.
|
|
1819
1924
|
//
|
|
1820
|
-
// BOTH FILES, because both genuinely reach the check: `~/.env` is
|
|
1821
|
-
// and this command's own file reaches it through the carry loop
|
|
1822
|
-
// never a path composed here — null means this process read no file of its own (a systemd start,
|
|
1925
|
+
// BOTH FILES, because both genuinely reach the check: `~/.env` is read into `willRead` above,
|
|
1926
|
+
// and this command's own file reaches it through the carry loop where `~/.env` has no line.
|
|
1927
|
+
// `envFileRead()` for the second, never a path composed here — null means this process read no file of its own (a systemd start,
|
|
1823
1928
|
// or CLEAROTRON_NO_ENV_FILE=1) and then HOME_ENV is the only honest address there is.
|
|
1824
1929
|
say(` Nothing has been installed that cannot run, and nothing has been spent.`);
|
|
1825
1930
|
say(` ${orderRemedy(HOME_ENV)}`);
|
|
1826
1931
|
}
|
|
1827
1932
|
for (const r of miss.narrowing)
|
|
1828
1933
|
say(` ⚠ ${r.name} is not set — ${r.why}`);
|
|
1934
|
+
// ── WHAT THE FILE KEEPS, SAID BY NAME ──────────────────────────────────────────────────────────
|
|
1935
|
+
//
|
|
1936
|
+
// The merge never replaces a line (see `unitsFileAfterStart`), so a setting changed in this
|
|
1937
|
+
// command's configuration after the first start does not reach the units. A machine moved from one
|
|
1938
|
+
// cloud to another went on billing the first, and a rotated key stayed at its first value, while this
|
|
1939
|
+
// command reported the file complete. Said here, by name and never by value, naming both places the
|
|
1940
|
+
// setting lives (see `keptSettingsNotice` for why one is not enough).
|
|
1941
|
+
for (const line of keptSettingsNotice(unitsFile.differ, { homeEnv: HOME_ENV, cliEnv: envFileRead() })) say(line);
|
|
1829
1942
|
}
|
|
1830
1943
|
|
|
1831
|
-
let homeText = "";
|
|
1832
|
-
try { homeText = readFileSync(HOME_ENV, "utf8"); } catch (e) { if (e.code !== "ENOENT") fatal(`${HOME_ENV} exists but could not be read (${e.code}).`); }
|
|
1833
1944
|
// THE TRIGGER KEY IS MINTED HERE, SO IT IS REWRITTEN HERE. Everything else in this union is
|
|
1834
1945
|
// collected — the operator's credentials, their paths — and add-only is what stops a launcher from
|
|
1835
1946
|
// losing them. The trigger key is the opposite: this process mints it, thirty days at a time, and a
|
|
1836
1947
|
// value written once and never again runs down to expiry on a server nobody has touched. When it
|
|
1837
1948
|
// lapses every Start stops, and the failure arrives as an upstream refusal that reads like an engine
|
|
1838
1949
|
// fault rather than an expired key card.
|
|
1839
|
-
const merged =
|
|
1950
|
+
const { merged } = unitsFile;
|
|
1840
1951
|
if (merged.added.length || merged.refreshed.length) {
|
|
1841
1952
|
writeSecretFile(HOME_ENV, merged.text);
|
|
1842
1953
|
const parts = [];
|
|
@@ -2412,11 +2523,24 @@ if (isMain) {
|
|
|
2412
2523
|
// THE WORKSPACE AND POOL THE SERVICES WERE HANDED, not this process's environment: a demo reads no env
|
|
2413
2524
|
// file, so its own line named no workspace and the connector fell back to the real install's.
|
|
2414
2525
|
// A demo run from npx names its own copy of the program, which a cache clean does not remove.
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2526
|
+
// AND WHICH SIDE OF A WSL INSTALL THE READER IS ON, because this is where he read the line from. An
|
|
2527
|
+
// install inside WSL can be reached from Windows and from inside the distribution, by two different
|
|
2528
|
+
// commands; printing one of them unheaded is how a reader pastes the wrong one. The target is read
|
|
2529
|
+
// here and passed, because this module is pure by design and reads no environment of its own.
|
|
2530
|
+
const connect = stdioConnectOffer({ workDir: paths.workspace, reportsDir: paths.pool, wsl: wslTarget(), ...(demoProgramRoot ? { installRoot: demoProgramRoot } : {}) });
|
|
2531
|
+
// "one line" IS DELETED RATHER THAN MADE CONDITIONAL. Under WSL two lines are printed, one per side,
|
|
2532
|
+
// and the count was never the point of the sentence — what it promises is no address and no sign-in,
|
|
2533
|
+
// which is true on both sides and on every other install.
|
|
2534
|
+
say(" Connect your assistant to this install — no address and no sign-in:");
|
|
2419
2535
|
say("");
|
|
2536
|
+
// THE HEADINGS COME WITH THE PAIR, from the composer. Nothing is written here: the page prints these
|
|
2537
|
+
// same two words above these same two commands, and a second author is how the two surfaces drift.
|
|
2538
|
+
if (connect.variants) {
|
|
2539
|
+
for (const v of connect.variants) { say(` ${v.heading}`); say(` ${v.text}`); say(""); }
|
|
2540
|
+
} else {
|
|
2541
|
+
say(` ${connect.command}`);
|
|
2542
|
+
say("");
|
|
2543
|
+
}
|
|
2420
2544
|
say(` Check it: ${connect.verify}`);
|
|
2421
2545
|
say("");
|
|
2422
2546
|
// ── WHERE TO TYPE THE THINGS JUST PRINTED ( — F31) ───────────────────────
|
package/bin/update.mjs
CHANGED
|
@@ -51,7 +51,7 @@ import { existsSync } from "node:fs";
|
|
|
51
51
|
import { join, dirname, resolve } from "node:path";
|
|
52
52
|
import { fileURLToPath } from "node:url";
|
|
53
53
|
|
|
54
|
-
import { config } from "../driver/driver.config.mjs";
|
|
54
|
+
import { config, ENGINE_BINARIES, enginesFolder, engineInstallArgs } from "../driver/driver.config.mjs";
|
|
55
55
|
import { isInsideCheckout } from "../shared/inside-checkout.mjs"; // — one copy of the rule
|
|
56
56
|
import { overlayReport, renderOverlayReport, treeFiles } from "../shared/doctrine-overlay.mjs";
|
|
57
57
|
import { liveRunHolds } from "../driver/deploy-live-run-guard.mjs"; // — one live-run test, shared with deploy-preflight
|
|
@@ -180,6 +180,34 @@ export function isGitCheckout(repo = REPO, exists = existsSync) {
|
|
|
180
180
|
return exists(join(repo, ".git"));
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
/**
|
|
184
|
+
* The engine programs setup installed for this user, which `clearotron update` refreshes: every engine
|
|
185
|
+
* whose package is in the engines folder. Setup installs only the one the reader chose, so this is usually
|
|
186
|
+
* one, and none where the machine's own copy was found first or the reader declined the install.
|
|
187
|
+
*/
|
|
188
|
+
export function enginesToRefresh({ dir = enginesFolder(), exists = existsSync } = {}) {
|
|
189
|
+
return Object.values(ENGINE_BINARIES)
|
|
190
|
+
.filter((e) => e.package && exists(join(dir, "node_modules", ...e.package.split("/"), "package.json")));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Run setup's install again for each of them, in the same folder. The same command, because re-running an
|
|
195
|
+
* install with a `>=` range moves the program to the newest its vendor publishes (driver.config.mjs, above
|
|
196
|
+
* engineInstallArgs). Returns 0, or the first failing exit code.
|
|
197
|
+
*/
|
|
198
|
+
function refreshEngines(engines, dir = enginesFolder()) {
|
|
199
|
+
if (!engines.length) return 0;
|
|
200
|
+
say(`\n Refreshing the engine program Clearotron installed in ${dir}.`);
|
|
201
|
+
for (const e of engines) {
|
|
202
|
+
const rc = runInCheckout("npm", engineInstallArgs(e, dir));
|
|
203
|
+
if (rc !== 0) {
|
|
204
|
+
console.error(`\n npm could not refresh ${e.package}. \`clearotron doctor\` says which copy a run would use now.`);
|
|
205
|
+
return rc;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return 0;
|
|
209
|
+
}
|
|
210
|
+
|
|
183
211
|
function runInCheckout(cmd, args) {
|
|
184
212
|
say(`\n $ ${cmd} ${args.join(" ")}`);
|
|
185
213
|
const r = spawnSync(cmd, args, { cwd: REPO, stdio: "inherit" });
|
|
@@ -301,22 +329,38 @@ export async function update(argv = process.argv.slice(2)) {
|
|
|
301
329
|
}
|
|
302
330
|
|
|
303
331
|
if (packaged) {
|
|
332
|
+
// ONE NPM RUN, WITH THE LAUNCHER PUT BACK AFTER IT, and both branches below install through it, so
|
|
333
|
+
// neither can run npm and forget the second half. npm puts its own link back at
|
|
334
|
+
// `<prefix>/bin/clearotron` on every install, over the launcher the install wrote, and that link runs
|
|
335
|
+
// whichever `node` is first on PATH. Put the launcher back, but only over npm's link or our own:
|
|
336
|
+
// anything else there was not ours before this update either.
|
|
337
|
+
const reinstall = () => {
|
|
338
|
+
const rc = runInCheckout("npm", packaged.npmArgs);
|
|
339
|
+
if (rc !== 0) return rc;
|
|
340
|
+
const kind = inspectShim(shimPath()).kind;
|
|
341
|
+
if (kind === "npm-link" || kind === "ours" || kind === "ours-other-install") {
|
|
342
|
+
const shim = installShim();
|
|
343
|
+
if (!shim.ok) console.error(`\n The update worked, but the launcher at ${shim.path ?? "~/.local/bin/clearotron"} could not be written back: ${shim.detail}.`);
|
|
344
|
+
}
|
|
345
|
+
return 0;
|
|
346
|
+
};
|
|
304
347
|
if (packaged.current) {
|
|
305
|
-
say(`\n This install is ${packaged.installed}, and nothing newer is published (${packaged.tag}: ${packaged.version})
|
|
348
|
+
say(`\n This install is ${packaged.installed}, and nothing newer is published (${packaged.tag}: ${packaged.version}).`);
|
|
349
|
+
// CURRENT STILL REFRESHES THE ENGINE PROGRAM setup installed: it moves on its vendor's schedule, not
|
|
350
|
+
// this package's. A machine's own copy on PATH updates itself and is used first.
|
|
351
|
+
const engines = enginesToRefresh();
|
|
352
|
+
if (!engines.length) { say(" Nothing was touched.\n"); return 0; }
|
|
353
|
+
const rc = refreshEngines(engines);
|
|
354
|
+
if (rc !== 0) return rc;
|
|
355
|
+
say("\n Clearotron itself was already current; restart the services so they use the refreshed program.\n");
|
|
306
356
|
return 0;
|
|
307
357
|
}
|
|
308
358
|
if (packaged.unread) say(`\n npm did not say which versions are published, so this follows the ${packaged.tag} channel.`);
|
|
309
359
|
say(`\n Updating this install at ${packaged.prefix} from ${packaged.installed ?? "an unreadable version"} to clearotron@${packaged.spec}.`);
|
|
310
|
-
const rc =
|
|
360
|
+
const rc = reinstall();
|
|
311
361
|
if (rc !== 0) return rc;
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
// over npm's link or our own: anything else there was not ours before this update either.
|
|
315
|
-
const kind = inspectShim(shimPath()).kind;
|
|
316
|
-
if (kind === "npm-link" || kind === "ours" || kind === "ours-other-install") {
|
|
317
|
-
const shim = installShim();
|
|
318
|
-
if (!shim.ok) console.error(`\n The update worked, but the launcher at ${shim.path ?? "~/.local/bin/clearotron"} could not be written back: ${shim.detail}.`);
|
|
319
|
-
}
|
|
362
|
+
const refreshed = refreshEngines(enginesToRefresh());
|
|
363
|
+
if (refreshed !== 0) return refreshed;
|
|
320
364
|
say("\n Updated. An assistant starts the new version the next time it launches Clearotron; restart the services for the portal.\n");
|
|
321
365
|
return 0;
|
|
322
366
|
}
|
|
@@ -393,6 +437,9 @@ export async function update(argv = process.argv.slice(2)) {
|
|
|
393
437
|
console.error(` the custom instructions could not be read — ${e.message}`);
|
|
394
438
|
}
|
|
395
439
|
|
|
440
|
+
const refreshed = refreshEngines(enginesToRefresh());
|
|
441
|
+
if (refreshed !== 0) return refreshed;
|
|
442
|
+
|
|
396
443
|
say("\n Up to date.\n");
|
|
397
444
|
return 0;
|
|
398
445
|
}
|
package/build-info.json
CHANGED
package/docs/DELIVERY.md
CHANGED
|
@@ -18,7 +18,8 @@ ignores the value.
|
|
|
18
18
|
|
|
19
19
|
## The outbox
|
|
20
20
|
|
|
21
|
-
`config.outboxDir` = `CLEAROTRON_OUTBOX_DIR` (default `<CLEAROTRON_WORK_DIR>/
|
|
21
|
+
`config.outboxDir` = `CLEAROTRON_OUTBOX_DIR` (default `<CLEAROTRON_WORK_DIR>/clearance-outbox`; the
|
|
22
|
+
earlier `clearance-outbox` is still read, so markers written before the rename still drain).
|
|
22
23
|
All packets are written atomically (`.tmp` + rename) — a watcher never sees a half-written
|
|
23
24
|
file. Every packet carries a `ts` ISO timestamp. Watch the dir for `*.pending` (systemd
|
|
24
25
|
`.path`, inotify, or poll); a periodic scan of run `status.json` files is the recommended
|
package/docs/INTAKE.md
CHANGED
|
@@ -23,7 +23,7 @@ Resolution (the runner drains **all** of these; `config.queueDirs`):
|
|
|
23
23
|
| Source | Path | Use |
|
|
24
24
|
|---|---|---|
|
|
25
25
|
| `CLEAROTRON_QUEUE_DIR` env | one explicit dir | **headless deployments** (the product default; no agent workspaces needed). Jobs here run as `config.defaultAgent`. |
|
|
26
|
-
| workspace scan | `<CLEAROTRON_WORK_DIR>/workspace-<agent>/studio/
|
|
26
|
+
| workspace scan | `<CLEAROTRON_WORK_DIR>/workspace-<agent>/studio/clearance-search/queue` | legacy/agent-adjacent deployments; the agent identity is derived from the queue location |
|
|
27
27
|
|
|
28
28
|
The enqueue CLI resolves its target the same way: `--queue-dir` flag → `CLEAROTRON_QUEUE_DIR` →
|
|
29
29
|
the default agent's workspace queue.
|
package/docs/ONBOARDING.md
CHANGED
|
@@ -32,7 +32,7 @@ malformed one is refused before anything is written.
|
|
|
32
32
|
| `--name` | the legal name. Required. |
|
|
33
33
|
| `--domains` | comma-separated email domains that resolve to this company |
|
|
34
34
|
| `--platforms` | marketplaces their searches cover. Omitted, the default's platforms apply and are named in the output. |
|
|
35
|
-
| `--framework` | their risk framework, as `skills/
|
|
35
|
+
| `--framework` | their risk framework, as `skills/clearance-search/<file>.md`. Omitted, the default applies and is named in the output. |
|
|
36
36
|
| `--industry` | free text, shown on their profile |
|
|
37
37
|
| `--context` | a file whose contents become this company's context pack |
|
|
38
38
|
| `--dry-run` | say exactly what would be written, and write nothing |
|
|
@@ -27,7 +27,7 @@ Two doctrines govern everything below:
|
|
|
27
27
|
sequenceDiagram
|
|
28
28
|
autonumber
|
|
29
29
|
participant A as Forwarding agent<br/>(integrator platform)
|
|
30
|
-
participant Q as Per-agent queue dir<br/>(studio/
|
|
30
|
+
participant Q as Per-agent queue dir<br/>(studio/clearance-search/queue)
|
|
31
31
|
participant S as systemd<br/>(.path + 90s .timer)
|
|
32
32
|
participant R as runner.mjs
|
|
33
33
|
participant P as pipeline.mjs
|
|
@@ -89,7 +89,7 @@ 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
|
|
92
|
-
keeps a matter ledger (`studio/
|
|
92
|
+
keeps a matter ledger (`studio/clearance-search/.matter-ledger.jsonl`) and parks as `.duplicate` any
|
|
93
93
|
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
|
|
@@ -108,7 +108,7 @@ winner (`runner.mjs`). A `.pid` sidecar records `<pid>:<starttime>` (starttime t
|
|
|
108
108
|
**Run identity is minted before any spend.** The codename (`adjective-noun`) is minted at dispatch
|
|
109
109
|
and written atomically to `<id>.processing.meta` *before* the pipeline starts (`runner.mjs`).
|
|
110
110
|
A crash anywhere after that resumes the *same* run directory instead of re-spending a fresh run.
|
|
111
|
-
Run dirs are `<workspace>/studio/
|
|
111
|
+
Run dirs are `<workspace>/studio/clearance-search/<slug>/<date>-<codename>`, slug =
|
|
112
112
|
`tmp<n>-<kebab-mark>` (or `noref<6-hex>-<mark>` when no reference was given; `phase0.mjs`).
|
|
113
113
|
|
|
114
114
|
**Orphan reclaim** (`runner.mjs`) runs once per drain. A `.processing` whose claimer is
|
|
@@ -177,7 +177,7 @@ seeding. Frozen sidecars are never silently re-derived; a corrupt one crashes lo
|
|
|
177
177
|
```mermaid
|
|
178
178
|
flowchart TD
|
|
179
179
|
subgraph HEAD["Phase 1-2 head (fatal)"]
|
|
180
|
-
MF[matter-frame] --> PV[
|
|
180
|
+
MF[matter-frame] --> PV[clearance-variants]
|
|
181
181
|
PV --> DER["code derivations:<br/>scope ledger · form neighbourhood ·<br/>register plan freeze · recall probes"]
|
|
182
182
|
end
|
|
183
183
|
DER --> GRID["grid spec dictated by code<br/>(terms × platforms × connotation; A1 split)"]
|
|
@@ -217,7 +217,7 @@ flowchart TD
|
|
|
217
217
|
|
|
218
218
|
Reading order for the phases, with what code decides at each:
|
|
219
219
|
|
|
220
|
-
1. **Head stages** — `matter-frame` then `
|
|
220
|
+
1. **Head stages** — `matter-frame` then `clearance-variants`, both fatal. Code then derives the
|
|
221
221
|
scope ledger, the *form neighbourhood* (the model picks the distinctive token; the machine
|
|
222
222
|
generates the complete mechanical variant floor), freezes the register plan
|
|
223
223
|
(`_driver/register-plan.json`, frozen for the life of *this run* — a resume never re-plans, and a
|
|
@@ -445,7 +445,7 @@ node pipeline.mjs --resume <codename> --experiment <stage> [--label <t>]
|
|
|
445
445
|
- **`--from`** forces stages at or after the named ordinal even if their outputs validate; earlier
|
|
446
446
|
stages still skip. A `--from synthesis` fork deliberately does *not* lock the digest.
|
|
447
447
|
- **`--experiment`** runs one stage in a shadow dir (`_experiments/<ts>-<tag>/`) on copies of its
|
|
448
|
-
inputs, under a `
|
|
448
|
+
inputs, under a `clearance-exp-…` session key that is excluded from the run's provider-usage
|
|
449
449
|
attribution. The canonical run is untouched.
|
|
450
450
|
- **Orphan self-resume**: a manually resumed run that parks has no queue sidecars; the runner scans
|
|
451
451
|
run dirs for due, payload-complete `.postponed` sentinels not owned by any queue and resumes them
|