clearotron 0.3.2-beta.11 → 0.3.2-beta.13
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 +1 -1
- package/CONTRIBUTING.md +6 -5
- package/INSTALL.md +3 -4
- package/README.md +2 -1
- package/bin/clearotron.mjs +14 -0
- package/bin/connect.mjs +68 -3
- package/bin/example.mjs +12 -1
- package/bin/key.mjs +6 -1
- package/bin/onboard.mjs +23 -3
- package/bin/passphrase.mjs +4 -2
- package/bin/start.mjs +18 -6
- package/build-info.json +2 -2
- package/docs/CLIENT-MCP.md +6 -6
- package/docs/DELIVERY.md +3 -3
- package/docs/ONBOARDING.md +1 -1
- package/docs/PORTAL.md +3 -3
- package/docs/RELEASES.md +1 -1
- package/docs/SECURITY.md +1 -1
- package/docs/architecture/04-configuration-reference.md +4 -4
- package/docs/architecture/05-config-governance.md +10 -10
- package/docs/architecture/06-operations-runbook.md +3 -3
- package/docs/architecture/07-quality-and-audit.md +1 -1
- package/docs/architecture/08-development-guide.md +2 -2
- package/docs/architecture/09-security-and-data.md +1 -1
- package/docs/decisions/0002-no-dark-functionality.md +1 -1
- package/docs/decisions/0006-what-the-public-repository-carries.md +3 -3
- package/driver/CHANGELOG.md +29 -0
- package/driver/ask-ledger.mjs +1 -1
- package/driver/band-shape.mjs +1 -1
- package/driver/bundled-demos.mjs +2 -2
- package/driver/card-budget.mjs +2 -2
- package/driver/case-law-ledger.mjs +2 -2
- package/driver/connotation-search.mjs +5 -5
- package/driver/contract-e3-backlog.mjs +13 -13
- package/driver/contract-vocabulary.mjs +5 -5
- package/driver/coverage-form.mjs +2 -2
- package/driver/demo-container.mjs +26 -2
- package/driver/disposition-tool.mjs +2 -2
- package/driver/engine/CONTRACT.md +3 -3
- package/driver/engine/mcp/gather-config.mjs +1 -1
- package/driver/engine/mcp/recording-server.mjs +1 -1
- package/driver/engine/mcp/supplemental.mjs +22 -5
- package/driver/engine/openai-agent.mjs +2 -2
- package/driver/findings-model.mjs +21 -6
- package/driver/gateway.mjs +1 -1
- package/driver/knockout-next-step.mjs +72 -0
- package/driver/named-band.mjs +1 -1
- package/driver/package.json +1 -1
- package/driver/pipeline-knockout.mjs +27 -1
- package/driver/pipeline.mjs +4 -4
- package/driver/placement-union.mjs +1 -1
- package/driver/portal-mcp-client.mjs +1 -1
- package/driver/portal-report.mjs +25 -3
- package/driver/portal-service.mjs +25 -13
- package/driver/predelivery-lint.mjs +9 -4
- package/driver/progress.mjs +37 -1
- package/driver/publish/render-knockout.mjs +14 -9
- package/driver/publish/render.mjs +6 -6
- package/driver/record-discard.mjs +1 -1
- package/driver/register-availability.mjs +1 -1
- package/driver/register-count.mjs +1 -1
- package/driver/register-digest-record.mjs +1 -1
- package/driver/register-plan.mjs +81 -11
- package/driver/report-card-record.mjs +2 -2
- package/driver/result-noun-fields.mjs +3 -1
- package/driver/roster-verdict.mjs +2 -2
- package/driver/search-policy.mjs +1 -1
- package/driver/skeptic-record.mjs +1 -1
- package/driver/stages-knockout.mjs +1 -1
- package/driver/stages.mjs +1 -1
- package/driver/suite-census.json +72 -24
- package/driver/systemd/README.md +1 -1
- package/driver/unit-inventory.mjs +2 -2
- package/driver/verify-knockout.mjs +0 -27
- package/driver/verify.mjs +1 -1
- package/mcp-server/CHANGELOG.md +8 -0
- package/mcp-server/CONNECT.md +8 -8
- package/mcp-server/lib/runs.mjs +1 -1
- package/mcp-server/package.json +1 -1
- package/mcp-server/serve.mjs +27 -0
- package/package.json +1 -1
- package/portal-ui/dist/assets/{index-CtvwLCti.css → index-7Lq-dXDV.css} +12 -9
- package/portal-ui/dist/assets/{index-DXSRxPV_.js → index-w8GFZftk.js} +110 -69
- package/portal-ui/dist/index.html +2 -2
- package/portal-ui/package.json +1 -1
- package/providers/free-tier/src/capabilities.js +2 -2
- package/providers/jx/src/core.js +3 -3
- package/providers/jx/src/turn-envelope.mjs +1 -1
- package/providers/oauth-mcp-bridge/CHANGELOG.md +8 -0
- package/providers/oauth-mcp-bridge/package.json +1 -1
- package/providers/perplexity/README.md +1 -1
- package/providers/signa/src/capabilities.js +2 -2
- package/providers/signa/src/core.js +2 -2
- package/providers/uspto-local/src/core.js +1 -1
- package/providers/uspto-local/src/sync.js +1 -1
- package/scripts/README.md +2 -6
- package/scripts/ask-ai-render-check.mjs +26 -1
- package/scripts/citation-anchor-report.mjs +1 -1
- package/scripts/citation-line-check.mjs +3 -3
- package/scripts/dead-names.mjs +17 -16
- package/scripts/e2e.mjs +1 -1
- package/scripts/env-audit.mjs +7 -1
- package/scripts/env-classify.mjs +1 -1
- package/scripts/pack-publishable.mjs +1 -1
- package/scripts/release-artifact-seal.mjs +2 -2
- package/scripts/repo-writes.mjs +42 -0
- package/scripts/report-sections-render-check.mjs +245 -0
- package/scripts/report-theme-render-check.mjs +31 -3
- package/scripts/settings-render-check.mjs +15 -8
- package/scripts/strip-tracker-citations.mjs +4 -4
- package/scripts/test-run.mjs +108 -6
- package/shared/browser-temp-root.mjs +10 -3
- package/shared/client-door.mjs +38 -6
- package/shared/connect-clients.mjs +2 -0
- package/shared/identifier-scan.mjs +2 -2
- package/shared/invocation.mjs +1 -1
- package/shared/parent-watch.mjs +33 -0
- package/shared/reference-guard-classes.mjs +5 -3
- package/shared/running-start.mjs +14 -3
- package/shared/scope.mjs +22 -3
- package/shared/stdio-connect.mjs +39 -18
- package/shared/writing-standard-classes.mjs +2 -3
package/driver/suite-census.json
CHANGED
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
},
|
|
66
66
|
"a-browser-run-gets-its-own-temp-root.test.mjs": {
|
|
67
67
|
"tests": 12,
|
|
68
|
-
"asserts":
|
|
68
|
+
"asserts": 31,
|
|
69
69
|
"skips": 0,
|
|
70
70
|
"todos": 0
|
|
71
71
|
},
|
|
@@ -195,9 +195,15 @@
|
|
|
195
195
|
"skips": 0,
|
|
196
196
|
"todos": 0
|
|
197
197
|
},
|
|
198
|
+
"a-conditional-with-nothing-stated-prints-no-conditional-line.test.mjs": {
|
|
199
|
+
"tests": 2,
|
|
200
|
+
"asserts": 6,
|
|
201
|
+
"skips": 0,
|
|
202
|
+
"todos": 0
|
|
203
|
+
},
|
|
198
204
|
"a-connect-line-says-where-it-runs.test.mjs": {
|
|
199
205
|
"tests": 11,
|
|
200
|
-
"asserts":
|
|
206
|
+
"asserts": 56,
|
|
201
207
|
"skips": 0,
|
|
202
208
|
"todos": 0
|
|
203
209
|
},
|
|
@@ -255,6 +261,12 @@
|
|
|
255
261
|
"skips": 0,
|
|
256
262
|
"todos": 0
|
|
257
263
|
},
|
|
264
|
+
"a-demo-leaves-no-temp-copies.test.mjs": {
|
|
265
|
+
"tests": 2,
|
|
266
|
+
"asserts": 6,
|
|
267
|
+
"skips": 0,
|
|
268
|
+
"todos": 0
|
|
269
|
+
},
|
|
258
270
|
"a-demo-report-declares-itself.test.mjs": {
|
|
259
271
|
"tests": 5,
|
|
260
272
|
"asserts": 15,
|
|
@@ -279,6 +291,12 @@
|
|
|
279
291
|
"skips": 0,
|
|
280
292
|
"todos": 0
|
|
281
293
|
},
|
|
294
|
+
"a-demo-stops-when-whatever-started-it-is-gone.test.mjs": {
|
|
295
|
+
"tests": 3,
|
|
296
|
+
"asserts": 11,
|
|
297
|
+
"skips": 0,
|
|
298
|
+
"todos": 0
|
|
299
|
+
},
|
|
282
300
|
"a-depth-check-that-read-nothing-is-on-the-investigate-list.test.mjs": {
|
|
283
301
|
"tests": 3,
|
|
284
302
|
"asserts": 8,
|
|
@@ -555,6 +573,12 @@
|
|
|
555
573
|
"skips": 1,
|
|
556
574
|
"todos": 0
|
|
557
575
|
},
|
|
576
|
+
"a-next-step-the-model-writes-comes-off-at-publish.test.mjs": {
|
|
577
|
+
"tests": 12,
|
|
578
|
+
"asserts": 28,
|
|
579
|
+
"skips": 0,
|
|
580
|
+
"todos": 0
|
|
581
|
+
},
|
|
558
582
|
"a-note-the-release-refuses-is-refused-on-its-own-pull-request.test.mjs": {
|
|
559
583
|
"tests": 2,
|
|
560
584
|
"asserts": 3,
|
|
@@ -837,6 +861,12 @@
|
|
|
837
861
|
"skips": 0,
|
|
838
862
|
"todos": 0
|
|
839
863
|
},
|
|
864
|
+
"a-running-demo-connects-by-its-folder.test.mjs": {
|
|
865
|
+
"tests": 4,
|
|
866
|
+
"asserts": 18,
|
|
867
|
+
"skips": 0,
|
|
868
|
+
"todos": 0
|
|
869
|
+
},
|
|
840
870
|
"a-save-that-cannot-commit-says-so.test.mjs": {
|
|
841
871
|
"tests": 4,
|
|
842
872
|
"asserts": 19,
|
|
@@ -1510,8 +1540,8 @@
|
|
|
1510
1540
|
"todos": 0
|
|
1511
1541
|
},
|
|
1512
1542
|
"client-door.test.mjs": {
|
|
1513
|
-
"tests":
|
|
1514
|
-
"asserts":
|
|
1543
|
+
"tests": 39,
|
|
1544
|
+
"asserts": 168,
|
|
1515
1545
|
"skips": 1,
|
|
1516
1546
|
"todos": 0
|
|
1517
1547
|
},
|
|
@@ -1827,6 +1857,12 @@
|
|
|
1827
1857
|
"skips": 0,
|
|
1828
1858
|
"todos": 0
|
|
1829
1859
|
},
|
|
1860
|
+
"dead-names.test.mjs": {
|
|
1861
|
+
"tests": 5,
|
|
1862
|
+
"asserts": 8,
|
|
1863
|
+
"skips": 2,
|
|
1864
|
+
"todos": 0
|
|
1865
|
+
},
|
|
1830
1866
|
"declared-park-excuses-proof-not-judgment.test.mjs": {
|
|
1831
1867
|
"tests": 9,
|
|
1832
1868
|
"asserts": 34,
|
|
@@ -2062,8 +2098,8 @@
|
|
|
2062
2098
|
"todos": 0
|
|
2063
2099
|
},
|
|
2064
2100
|
"doctor-refuses-what-cannot-run.test.mjs": {
|
|
2065
|
-
"tests":
|
|
2066
|
-
"asserts":
|
|
2101
|
+
"tests": 9,
|
|
2102
|
+
"asserts": 22,
|
|
2067
2103
|
"skips": 0,
|
|
2068
2104
|
"todos": 0
|
|
2069
2105
|
},
|
|
@@ -2513,7 +2549,7 @@
|
|
|
2513
2549
|
},
|
|
2514
2550
|
"findings-model.test.mjs": {
|
|
2515
2551
|
"tests": 68,
|
|
2516
|
-
"asserts":
|
|
2552
|
+
"asserts": 258,
|
|
2517
2553
|
"skips": 0,
|
|
2518
2554
|
"todos": 0
|
|
2519
2555
|
},
|
|
@@ -2812,8 +2848,8 @@
|
|
|
2812
2848
|
"todos": 0
|
|
2813
2849
|
},
|
|
2814
2850
|
"knockout-structured-read.test.mjs": {
|
|
2815
|
-
"tests":
|
|
2816
|
-
"asserts":
|
|
2851
|
+
"tests": 12,
|
|
2852
|
+
"asserts": 57,
|
|
2817
2853
|
"skips": 0,
|
|
2818
2854
|
"todos": 0
|
|
2819
2855
|
},
|
|
@@ -3004,8 +3040,8 @@
|
|
|
3004
3040
|
"todos": 0
|
|
3005
3041
|
},
|
|
3006
3042
|
"no-test-writes-inside-the-checkout.test.mjs": {
|
|
3007
|
-
"tests":
|
|
3008
|
-
"asserts":
|
|
3043
|
+
"tests": 21,
|
|
3044
|
+
"asserts": 58,
|
|
3009
3045
|
"skips": 0,
|
|
3010
3046
|
"todos": 0
|
|
3011
3047
|
},
|
|
@@ -3305,7 +3341,7 @@
|
|
|
3305
3341
|
},
|
|
3306
3342
|
"portal-local-login.test.mjs": {
|
|
3307
3343
|
"tests": 28,
|
|
3308
|
-
"asserts":
|
|
3344
|
+
"asserts": 113,
|
|
3309
3345
|
"skips": 0,
|
|
3310
3346
|
"todos": 0
|
|
3311
3347
|
},
|
|
@@ -3340,8 +3376,8 @@
|
|
|
3340
3376
|
"todos": 0
|
|
3341
3377
|
},
|
|
3342
3378
|
"portal-service.test.mjs": {
|
|
3343
|
-
"tests":
|
|
3344
|
-
"asserts":
|
|
3379
|
+
"tests": 131,
|
|
3380
|
+
"asserts": 712,
|
|
3345
3381
|
"skips": 1,
|
|
3346
3382
|
"todos": 0
|
|
3347
3383
|
},
|
|
@@ -3862,8 +3898,8 @@
|
|
|
3862
3898
|
"todos": 0
|
|
3863
3899
|
},
|
|
3864
3900
|
"render.test.mjs": {
|
|
3865
|
-
"tests":
|
|
3866
|
-
"asserts":
|
|
3901
|
+
"tests": 162,
|
|
3902
|
+
"asserts": 675,
|
|
3867
3903
|
"skips": 0,
|
|
3868
3904
|
"todos": 0
|
|
3869
3905
|
},
|
|
@@ -4486,8 +4522,8 @@
|
|
|
4486
4522
|
"todos": 0
|
|
4487
4523
|
},
|
|
4488
4524
|
"status-and-stop-see-a-foreground-start.test.mjs": {
|
|
4489
|
-
"tests":
|
|
4490
|
-
"asserts":
|
|
4525
|
+
"tests": 7,
|
|
4526
|
+
"asserts": 30,
|
|
4491
4527
|
"skips": 0,
|
|
4492
4528
|
"todos": 0
|
|
4493
4529
|
},
|
|
@@ -4959,6 +4995,12 @@
|
|
|
4959
4995
|
"skips": 0,
|
|
4960
4996
|
"todos": 0
|
|
4961
4997
|
},
|
|
4998
|
+
"the-house-element-stays-out-of-what-folds-in-later.test.mjs": {
|
|
4999
|
+
"tests": 6,
|
|
5000
|
+
"asserts": 22,
|
|
5001
|
+
"skips": 0,
|
|
5002
|
+
"todos": 0
|
|
5003
|
+
},
|
|
4962
5004
|
"the-identifier-sweep-fires-on-its-sentinels.test.mjs": {
|
|
4963
5005
|
"tests": 10,
|
|
4964
5006
|
"asserts": 36,
|
|
@@ -5327,7 +5369,7 @@
|
|
|
5327
5369
|
},
|
|
5328
5370
|
"the-sign-in-door-folds-its-administrator-help.test.mjs": {
|
|
5329
5371
|
"tests": 5,
|
|
5330
|
-
"asserts":
|
|
5372
|
+
"asserts": 23,
|
|
5331
5373
|
"skips": 0,
|
|
5332
5374
|
"todos": 0
|
|
5333
5375
|
},
|
|
@@ -5343,9 +5385,15 @@
|
|
|
5343
5385
|
"skips": 0,
|
|
5344
5386
|
"todos": 0
|
|
5345
5387
|
},
|
|
5388
|
+
"the-status-says-which-step-the-run-is-in-now.test.mjs": {
|
|
5389
|
+
"tests": 3,
|
|
5390
|
+
"asserts": 8,
|
|
5391
|
+
"skips": 0,
|
|
5392
|
+
"todos": 0
|
|
5393
|
+
},
|
|
5346
5394
|
"the-summary-carries-structure.test.mjs": {
|
|
5347
|
-
"tests":
|
|
5348
|
-
"asserts":
|
|
5395
|
+
"tests": 14,
|
|
5396
|
+
"asserts": 37,
|
|
5349
5397
|
"skips": 0,
|
|
5350
5398
|
"todos": 0
|
|
5351
5399
|
},
|
|
@@ -6034,7 +6082,7 @@
|
|
|
6034
6082
|
},
|
|
6035
6083
|
"root-mcp-json-connects.test.mjs": {
|
|
6036
6084
|
"tests": 3,
|
|
6037
|
-
"asserts":
|
|
6085
|
+
"asserts": 14,
|
|
6038
6086
|
"skips": 0,
|
|
6039
6087
|
"todos": 0
|
|
6040
6088
|
},
|
|
@@ -6446,8 +6494,8 @@
|
|
|
6446
6494
|
"todos": 0
|
|
6447
6495
|
},
|
|
6448
6496
|
"reportSections.test.ts": {
|
|
6449
|
-
"tests":
|
|
6450
|
-
"asserts":
|
|
6497
|
+
"tests": 13,
|
|
6498
|
+
"asserts": 41,
|
|
6451
6499
|
"skips": 0,
|
|
6452
6500
|
"todos": 0
|
|
6453
6501
|
},
|
package/driver/systemd/README.md
CHANGED
|
@@ -33,7 +33,7 @@ missing one and writes nothing, because a unit with one placeholder left starts
|
|
|
33
33
|
worse than one that does not start. Which units need it is **derived from the files**, not from a list —
|
|
34
34
|
and `driver/unit-inventory.mjs` declares them, with a test asserting the two agree in both directions.
|
|
35
35
|
|
|
36
|
-
These are for a **server, not a laptop**. On a workstation there is nothing to install: `
|
|
36
|
+
These are for a **server, not a laptop**. On a workstation there is nothing to install: `clearotron start` supervises the
|
|
37
37
|
same loop for you, and`node driver/runner.mjs --watch` is what to run by hand if you started with
|
|
38
38
|
`--no-worker` (`INSTALL.md` §5) — one foreground process that polls for queued jobs and for parked runs whose
|
|
39
39
|
window has elapsed.
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
// docs/architecture/05-config-governance.md, tier 2). Getting that wrong replaces working auth with
|
|
46
46
|
// placeholders that look configured, and it is not work to do beside a running round.
|
|
47
47
|
//
|
|
48
|
-
// So the untracked units are declared as untracked, WITH THE REASON, which is exactly what
|
|
49
|
-
//
|
|
48
|
+
// So the untracked units are declared as untracked, WITH THE REASON, which is exactly what the
|
|
49
|
+
// requirement asks for: "either has a tracked file it is compared against, or is named here with the
|
|
50
50
|
// reason it does not".
|
|
51
51
|
//
|
|
52
52
|
// ── THE CORRECTION THIS FILE NEEDED ITSELF ───────────────────────────────────────────────────────
|
|
@@ -29,25 +29,6 @@ const nameKey = (s) => norm(s).toLowerCase().replace(/\s+/g, " ");
|
|
|
29
29
|
|
|
30
30
|
// ── Tone guards (the skill's rules, mechanical subset) ───────────────────────────────────────────────
|
|
31
31
|
export const BANNED_TONE_RE = /\b(extremely difficult|most dangerous|massive|enormous)\b/i;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* A RECOMMENDATION IS A SHAPE, AND THIS SCREEN MAY NOT WRITE ONE (owner, 2026-09-18).
|
|
35
|
-
*
|
|
36
|
-
* The screen states findings and a rating; what to do with the name is the reading lawyer's. Two
|
|
37
|
-
* instructions that asked for a conclusion were cut first, and a re-run then wrote one anyway, under a
|
|
38
|
-
* heading of its own: "Practical next step — <NAME> is not knocked out at this screening depth. Advance
|
|
39
|
-
* it to clearance…". Cutting an instruction stops the engine asking; only a refusal stops the offer.
|
|
40
|
-
*
|
|
41
|
-
* TWO SHAPES, because both reached a reader: a block the writer heads itself, and a closing line that
|
|
42
|
-
* moves the name on. WHAT THIS CANNOT SEE: the same conclusion as ordinary prose — "the remaining work
|
|
43
|
-
* here is a full search" — and no pattern can. It is a floor under the doctrine, never a substitute.
|
|
44
|
-
*
|
|
45
|
-
* The false positives were measured rather than assumed: the degraded note this lane REQUIRES reads
|
|
46
|
-
* "Manual verification recommended" and matches neither, and a register record "proceeding to
|
|
47
|
-
* registration" matches neither — only proceeding *to clearance* does.
|
|
48
|
-
*/
|
|
49
|
-
export const RECOMMENDATION_RE = /^[ \t]*(?:[*_]{0,2}|#{1,6}\s*)(?:practical\s+|immediate\s+|suggested\s+)?(?:next steps?|what to do\b|what happens next|recommendations?|our recommendation)/im;
|
|
50
|
-
export const ADVANCE_RE = /\b(?:advance|move|take|send)\s+(?:it|this|the name|[A-Z][A-Z0-9'’-]{2,})\s+(?:on\s+)?(?:to|into|through)\s+(?:a\s+)?(?:full\s+)?clearance\b|\bproceeds?\s+to\s+(?:a\s+)?(?:full\s+)?clearance\b|\bshould\s+(?:proceed|advance|be advanced|move)\b|\bwe\s+recommend\b/i;
|
|
51
32
|
export const QUANT_CLAIM_RE = /(\b\d[\d,.]*\s*(?:M|million|billion|k|thousand)?\s*(?:streams|downloads|copies sold|units sold)\b)|(\$\s?\d[\d,.]*\s*(?:M|million|billion|k)?\s*(?:in\s+)?(?:annual\s+)?(?:revenue|sales))/i;
|
|
52
33
|
|
|
53
34
|
// ── URL normalization for the receipts gate ──────────────────────────────────────────────────────────
|
|
@@ -505,14 +486,6 @@ export const validators = {
|
|
|
505
486
|
const claim = [prose, c.chunkSummary].filter(Boolean).join("\n").match(REGISTER_CLAIM_RE);
|
|
506
487
|
if (claim)
|
|
507
488
|
return { ok: false, reason: `knockout_register_claim:${m.name}: "${claim[0].trim()}" — this turn cannot see the register lane and must not describe it. The report states register coverage in code, from the run's own count sidecar; a summary that says the registers were not run, above a table of counts that were, is the contradiction this rule closes. Delete the clause` };
|
|
508
|
-
// THE PER-NAME READ IS SWEPT TOO, and until now it was not: the checks below read the finding
|
|
509
|
-
// fields, while `assessment` was validated for length and structure alone — which is exactly the
|
|
510
|
-
// field the conclusion arrived in. Refused HERE so the stage re-asks with the line quoted, rather
|
|
511
|
-
// than a reader meeting it.
|
|
512
|
-
const read = [m.assessment, prose].filter(Boolean).join("\n");
|
|
513
|
-
const recommended = read.match(RECOMMENDATION_RE) ?? read.match(ADVANCE_RE);
|
|
514
|
-
if (recommended)
|
|
515
|
-
return { ok: false, reason: `mark "${m.name}": "${recommended[0].trim()}" — this screen states findings and a rating; what to do with the name, and whether it advances, is the reading lawyer's. Delete the sentence: the report's own closing caveat already says what the screen is` };
|
|
516
489
|
const banned = prose.match(BANNED_TONE_RE);
|
|
517
490
|
if (banned) return { ok: false, reason: `mark "${m.name}": banned tone "${banned[0]}" — measured tone only (the band colour carries urgency)` };
|
|
518
491
|
const quant = prose.match(QUANT_CLAIM_RE);
|
package/driver/verify.mjs
CHANGED
|
@@ -1375,7 +1375,7 @@ function connotationViolations(content, queryCount, opts = {}, dispositionsPath
|
|
|
1375
1375
|
// patch — two families emitting a bare `form_damaged` would be indistinguishable there and the repair
|
|
1376
1376
|
// would rewrite the wrong form.
|
|
1377
1377
|
//
|
|
1378
|
-
// THE SHAPE IS BUILT AROUND THREE CONSUMERS, each of which fails SILENTLY on a mismatch
|
|
1378
|
+
// THE SHAPE IS BUILT AROUND THREE CONSUMERS, each of which fails SILENTLY on a mismatch:
|
|
1379
1379
|
// - The CAUSE CENSUS IS FRONT-LOADED, `no_ruling=<n>`, before any named list: repairs.mjs CENSUS_RE
|
|
1380
1380
|
// sums exactly that, pipeline.mjs shows the failing model `tok.slice(0, 160)`, and a census that fell
|
|
1381
1381
|
// off the end of a slice would read as a missing quantity — i.e. as converged.
|
package/mcp-server/CHANGELOG.md
CHANGED
package/mcp-server/CONNECT.md
CHANGED
|
@@ -5,7 +5,7 @@ MCP-capable app. Two ways in, and they are not variants of each other:
|
|
|
5
5
|
|
|
6
6
|
| | **Local** | **Hosted** |
|
|
7
7
|
|---|---|---|
|
|
8
|
-
| What it is | your app spawns `
|
|
8
|
+
| What it is | your app spawns `serve.mjs` from your own clone | you were given a URL by whoever operates the engine |
|
|
9
9
|
| Who it is for | anyone who cloned this repository | a customer or colleague reading someone else's runs |
|
|
10
10
|
| Setup | copy-paste below, no account, no credential | paste the URL, sign in |
|
|
11
11
|
| Reach | everything, including the write verbs | read-only, scoped to your own matters |
|
|
@@ -46,7 +46,7 @@ One command. Substitute your clone's path and your workspace root:
|
|
|
46
46
|
```sh
|
|
47
47
|
claude mcp add trademark-artifacts --scope user \
|
|
48
48
|
-e CLEAROTRON_WORK_DIR=/path/to/your/workspace \
|
|
49
|
-
-- node /path/to/clearotron/mcp-server/
|
|
49
|
+
-- node /path/to/clearotron/mcp-server/serve.mjs
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
Check it: `claude mcp list` prints `trademark-artifacts: … - √ Connected`.
|
|
@@ -64,7 +64,7 @@ PowerShell 5.1, write the separator as `"--"`: that shell drops a bare `--`. Rem
|
|
|
64
64
|
"mcpServers": {
|
|
65
65
|
"trademark-artifacts": {
|
|
66
66
|
"command": "node",
|
|
67
|
-
"args": ["/path/to/clearotron/mcp-server/
|
|
67
|
+
"args": ["/path/to/clearotron/mcp-server/serve.mjs"],
|
|
68
68
|
"env": { "CLEAROTRON_WORK_DIR": "/path/to/your/workspace" }
|
|
69
69
|
}
|
|
70
70
|
}
|
|
@@ -82,7 +82,7 @@ Codex reads `~/.codex/config.toml`:
|
|
|
82
82
|
```toml
|
|
83
83
|
[mcp_servers.trademark-artifacts]
|
|
84
84
|
command = "node"
|
|
85
|
-
args = ["/path/to/clearotron/mcp-server/
|
|
85
|
+
args = ["/path/to/clearotron/mcp-server/serve.mjs"]
|
|
86
86
|
env = { CLEAROTRON_WORK_DIR = "/path/to/your/workspace" }
|
|
87
87
|
```
|
|
88
88
|
|
|
@@ -94,13 +94,13 @@ is a value written to a file.
|
|
|
94
94
|
|
|
95
95
|
## Any other MCP host
|
|
96
96
|
|
|
97
|
-
The contract is the same three things every time: run `node mcp-server/
|
|
97
|
+
The contract is the same three things every time: run `node mcp-server/serve.mjs`, over stdio, with
|
|
98
98
|
`CLEAROTRON_WORK_DIR` in its environment.
|
|
99
99
|
|
|
100
100
|
```json
|
|
101
101
|
{
|
|
102
102
|
"command": "node",
|
|
103
|
-
"args": ["/path/to/clearotron/mcp-server/
|
|
103
|
+
"args": ["/path/to/clearotron/mcp-server/serve.mjs"],
|
|
104
104
|
"env": { "CLEAROTRON_WORK_DIR": "…", "CLEAROTRON_REPORTS_DIR": "…" }
|
|
105
105
|
}
|
|
106
106
|
```
|
|
@@ -125,7 +125,7 @@ read them. Spawn the server as that user:
|
|
|
125
125
|
```json
|
|
126
126
|
{
|
|
127
127
|
"command": "sudo",
|
|
128
|
-
"args": ["-u", "<operator>", "node", "/path/to/clearotron/mcp-server/
|
|
128
|
+
"args": ["-u", "<operator>", "node", "/path/to/clearotron/mcp-server/serve.mjs"]
|
|
129
129
|
}
|
|
130
130
|
```
|
|
131
131
|
|
|
@@ -133,7 +133,7 @@ That needs a one-time NOPASSWD rule, or the stdio handshake hangs on a password
|
|
|
133
133
|
|
|
134
134
|
```
|
|
135
135
|
# /etc/sudoers.d/trademark-artifacts-mcp (chmod 0440)
|
|
136
|
-
<caller> ALL=(<operator>) NOPASSWD: /usr/bin/node /path/to/clearotron/mcp-server/
|
|
136
|
+
<caller> ALL=(<operator>) NOPASSWD: /usr/bin/node /path/to/clearotron/mcp-server/serve.mjs
|
|
137
137
|
```
|
|
138
138
|
|
|
139
139
|
## What to ask it
|
package/mcp-server/lib/runs.mjs
CHANGED
|
@@ -40,7 +40,7 @@ export function unreadableRunsReason({ workSet, workRoot, workExists, poolSet })
|
|
|
40
40
|
if (workSet || workExists || poolSet) return null;
|
|
41
41
|
return `no searches can be read here: CLEAROTRON_WORK_DIR is unset and ${workRoot} does not exist, `
|
|
42
42
|
+ "and CLEAROTRON_REPORTS_DIR is unset. Set them to the install's directories — `npx clearotron doctor` "
|
|
43
|
-
+ "prints where an install keeps them.";
|
|
43
|
+
+ "prints where an install keeps them, and mcp-server/CONNECT.md says how to connect this server.";
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// Every workspace-<agent>/studio/clearance-search root under the live workspace root.
|
package/mcp-server/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trademark-artifacts-mcp",
|
|
3
|
-
"version": "0.3.2-beta.
|
|
3
|
+
"version": "0.3.2-beta.13",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
5
|
"private": true,
|
|
6
6
|
"description": "MCP server to interrogate clearotron trademark-clearance runs — list/read artifacts, trace the full decision flow, telemetry/cost, coverage, single-run search, and a gated single-step what-if. Imports the clearotron-driver read-only; touches no driver/template/deploy files.",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
|
+
// Copyright 2026 Cordillera Sàrl. Additional terms under section 7 of the AGPL-3.0 apply — see ADDITIONAL-TERMS.md
|
|
4
|
+
//
|
|
5
|
+
// serve.mjs — the MCP server over stdio, with the Node check in front of it. The connect lines name
|
|
6
|
+
// this file.
|
|
7
|
+
//
|
|
8
|
+
// server.mjs cannot check the Node it runs on. An ES module's imports are all loaded before any of its
|
|
9
|
+
// code runs, so on a Node below the floor the server fails while loading, with an error that names a
|
|
10
|
+
// module and says nothing about the version. Measured on Node 18.20.8: "SyntaxError: The requested
|
|
11
|
+
// module 'node:util' does not provide an export named 'parseEnv'". On a Windows laptop running the
|
|
12
|
+
// connect line through WSL, the distribution's own Node 18 met "SyntaxError: Unexpected token 'with'"
|
|
13
|
+
// (2026-09-19). This file imports only what an old Node can load, refuses in one plain line, and only
|
|
14
|
+
// then loads the server.
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
import { nodeFloorVerdict, nodeFloorRefusal } from "../shared/node-floor.mjs"; // one floor, read from package.json
|
|
17
|
+
|
|
18
|
+
const floor = nodeFloorVerdict();
|
|
19
|
+
if (!floor.ok) {
|
|
20
|
+
console.error(`clearotron: ${nodeFloorRefusal(floor)}`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// THE SERVER STARTS AS THE ENTRY IT WOULD HAVE BEEN. It starts its stdio transport, and reads the
|
|
25
|
+
// install's settings, only when it is the process's entry file, so the entry is handed over first.
|
|
26
|
+
process.argv[1] = fileURLToPath(new URL("./server.mjs", import.meta.url));
|
|
27
|
+
await import("./server.mjs");
|
package/package.json
CHANGED
|
@@ -254,19 +254,19 @@ html.anon-on [data-anon='mark']:not(.anon-clear) {
|
|
|
254
254
|
border-bottom: 1px solid var(--border-hairline);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
/* THE HEADER'S
|
|
257
|
+
/* THE HEADER'S LOWER ROWS: which read you are in, then where you are inside it.
|
|
258
258
|
The Reads strip used to sit BELOW this box and the report's own section breadcrumb inside the frame,
|
|
259
259
|
so neither stayed on screen — the frame is sized to its content, which leaves a `position:sticky` bar
|
|
260
260
|
in there pinned to nothing. Both are rows of the pinned header now (owner, 2026-09-18).
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
.
|
|
264
|
-
|
|
261
|
+
THE SECTIONS HAVE A ROW OF THEIR OWN, UNDER THE READS (owner, 2026-09-19). Side by side, sixteen reads
|
|
262
|
+
wrapped into two ragged columns while the strip floated beside them at mid-height. The reads wrap; the
|
|
263
|
+
sections scroll sideways rather than wrapping, so the strip stays one line however narrow the screen. */
|
|
264
|
+
.report-nav { display: flex; flex-direction: column; align-items: stretch; gap: 8px; margin-top: 9px; }
|
|
265
|
+
.report-sections {
|
|
266
|
+
display: flex; align-items: center; gap: 2px;
|
|
265
267
|
overflow-x: auto; scrollbar-width: none;
|
|
266
268
|
}
|
|
267
|
-
.report-
|
|
268
|
-
.report-nav-sep { flex: none; width: 1px; align-self: stretch; background: var(--border-hairline); }
|
|
269
|
-
.report-sections { display: flex; align-items: center; gap: 2px; }
|
|
269
|
+
.report-sections::-webkit-scrollbar { display: none; }
|
|
270
270
|
.report-section {
|
|
271
271
|
flex: none; display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
|
|
272
272
|
font: inherit; font-size: 12.5px; font-weight: 600; letter-spacing: .01em;
|
|
@@ -277,8 +277,11 @@ html.anon-on [data-anon='mark']:not(.anon-clear) {
|
|
|
277
277
|
.report-section-dot {
|
|
278
278
|
width: 8px; height: 8px; border-radius: 50%; border: 1.5px solid currentColor; box-sizing: border-box;
|
|
279
279
|
}
|
|
280
|
+
/* PROGRESS: every section reached has a filled dot, the rest stay hollow; the one in view also sits on
|
|
281
|
+
the sunken pill, so it can be told from the ones behind it. */
|
|
282
|
+
.report-section[data-reached='true'] { color: var(--text-strong); }
|
|
283
|
+
.report-section[data-reached='true'] .report-section-dot { background: var(--accent); border-color: var(--accent); }
|
|
280
284
|
.report-section[aria-current='true'] { color: var(--text-strong); background: var(--surface-sunken); }
|
|
281
|
-
.report-section[aria-current='true'] .report-section-dot { border-color: var(--accent); border-width: 3px; }
|
|
282
285
|
|
|
283
286
|
/* The breadcrumb above it: one step back as a quiet button, then where the reader is. Compound selectors
|
|
284
287
|
throughout this block, because the button and row rules they adjust are declared later in the file. */
|