clearotron 0.3.3 → 0.4.0-beta.1

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.
Files changed (142) hide show
  1. package/.env.example +9 -0
  2. package/INSTALL.md +1 -14
  3. package/bin/brandowner.mjs +5 -5
  4. package/bin/connect.mjs +4 -4
  5. package/bin/onboard.mjs +5 -7
  6. package/bin/start.mjs +20 -5
  7. package/bin/update.mjs +6 -1
  8. package/build-info.json +2 -2
  9. package/docs/architecture/04-configuration-reference.md +2 -6
  10. package/driver/CHANGELOG.md +28 -0
  11. package/driver/ask-ledger.mjs +2 -2
  12. package/driver/band-shape.mjs +8 -8
  13. package/driver/blind-frame-model.mjs +1 -1
  14. package/driver/common-law-receipts.mjs +2 -2
  15. package/driver/commonlaw-carry.mjs +2 -2
  16. package/driver/company-bundle.mjs +11 -18
  17. package/driver/connotation-search.mjs +4 -4
  18. package/driver/contract-e3-backlog.mjs +3 -3
  19. package/driver/declination-call.mjs +1 -1
  20. package/driver/declination-tool.mjs +1 -1
  21. package/driver/dev-portal.mjs +1 -1
  22. package/driver/door-call-verdict.mjs +27 -0
  23. package/driver/driver.config.mjs +17 -11
  24. package/driver/e2e/README.md +1 -1
  25. package/driver/engine/mcp/clarivate-server.mjs +2 -1
  26. package/driver/engine/mcp/corsearch-server.mjs +1 -0
  27. package/driver/engine/mcp/euipo-server.mjs +1 -0
  28. package/driver/engine/mcp/free-tier-server.mjs +1 -1
  29. package/driver/engine/mcp/gather-config.mjs +1 -1
  30. package/driver/engine/mcp/perplexity-server.mjs +1 -1
  31. package/driver/engine/mcp/recording-server.mjs +1 -1
  32. package/driver/engine/mcp/signa-server.mjs +1 -0
  33. package/driver/engine/mcp/supplemental.mjs +1 -1
  34. package/driver/engine/mcp/uspto-local-server.mjs +1 -0
  35. package/driver/enqueue-schema.mjs +2 -2
  36. package/driver/feedback-issues.mjs +1 -1
  37. package/driver/feedback-store.mjs +1 -1
  38. package/driver/findings-model.mjs +3 -3
  39. package/driver/flag-snapshot.mjs +1 -1
  40. package/driver/floor-duty.mjs +2 -2
  41. package/driver/form-neighbourhood.mjs +47 -15
  42. package/driver/frame-diff-model.mjs +3 -3
  43. package/driver/gateway.mjs +5 -5
  44. package/driver/jx-lanes.mjs +1 -1
  45. package/driver/known-conflicts.mjs +18 -0
  46. package/driver/log.mjs +2 -2
  47. package/driver/package.json +1 -1
  48. package/driver/pipeline-knockout.mjs +129 -95
  49. package/driver/pipeline.mjs +69 -32
  50. package/driver/placement-carry.mjs +2 -2
  51. package/driver/placement-form.mjs +1 -1
  52. package/driver/portal-mcp-client.mjs +1 -1
  53. package/driver/portal-request-origin.mjs +79 -0
  54. package/driver/portal-service.mjs +45 -17
  55. package/driver/predelivery-lint.mjs +10 -10
  56. package/driver/profile-page.html +9 -13
  57. package/driver/profile-service.mjs +25 -13
  58. package/driver/profiles.mjs +17 -4
  59. package/driver/progress.mjs +1 -1
  60. package/driver/provider-usage.mjs +24 -1
  61. package/driver/publish/index.mjs +17 -5
  62. package/driver/publish/knockout.mjs +3 -2
  63. package/driver/publish/render-knockout.mjs +1 -1
  64. package/driver/publish/render.mjs +14 -3
  65. package/driver/publish/search-depth.mjs +4 -2
  66. package/driver/recall-reconciliation.mjs +1 -1
  67. package/driver/record-carry.mjs +6 -6
  68. package/driver/recording-agreement.mjs +2 -2
  69. package/driver/reference-score.mjs +27 -27
  70. package/driver/register-count.mjs +56 -1
  71. package/driver/register-digest-record.mjs +1 -1
  72. package/driver/register-plan.mjs +5 -5
  73. package/driver/register-records.mjs +10 -1
  74. package/driver/registry-fidelity.mjs +4 -4
  75. package/driver/repair-composers.mjs +6 -6
  76. package/driver/run-economics.mjs +8 -19
  77. package/driver/screen-gate.mjs +1 -1
  78. package/driver/skills/blind-frame/SKILL.md +2 -2
  79. package/driver/skills/clearance-common-law/SKILL.md +2 -2
  80. package/driver/skills/clearance-common-law/perplexity-prompts.md +4 -4
  81. package/driver/skills/clearance-register/digest.md +1 -1
  82. package/driver/skills/clearance-register/unit.md +1 -1
  83. package/driver/skills/clearance-search/report-prose.md +5 -5
  84. package/driver/skills/clearance-search/synthesis-rules.md +4 -4
  85. package/driver/skills/clearance-variants/SKILL.md +2 -2
  86. package/driver/skills/clearance-variants/transliteration-scripts.md +1 -1
  87. package/driver/skills/frame-diff/SKILL.md +2 -2
  88. package/driver/skills/knockout-assess/SKILL.md +9 -9
  89. package/driver/skills/matter-frame/watchlist-reference.md +1 -1
  90. package/driver/skills/narrative-refutation/SKILL.md +2 -2
  91. package/driver/skills/placement-inquiry/SKILL.md +1 -1
  92. package/driver/stage-context.mjs +4 -4
  93. package/driver/stages.mjs +23 -15
  94. package/driver/suite-census.json +138 -42
  95. package/driver/systemd/clearotron-client-mcp.service +24 -0
  96. package/driver/systemd/clearotron-mcp-face.service +24 -0
  97. package/driver/systemd/clearotron-portal.service +24 -0
  98. package/driver/systemd/clearotron-worker.service +24 -0
  99. package/driver/tokens.mjs +26 -17
  100. package/driver/turnaround-bands.mjs +1 -1
  101. package/driver/unit-inventory.mjs +3 -3
  102. package/driver/variant-manifest-model.mjs +1 -1
  103. package/driver/verify.mjs +2 -2
  104. package/driver/whatif-memo-run.mjs +1 -1
  105. package/mcp-server/CHANGELOG.md +8 -0
  106. package/mcp-server/lib/audit.mjs +9 -2
  107. package/mcp-server/lib/http-handler.mjs +7 -3
  108. package/mcp-server/mint-token.mjs +8 -6
  109. package/mcp-server/package.json +1 -1
  110. package/mcp-server/server.mjs +11 -1
  111. package/package.json +1 -1
  112. package/portal-ui/dist/assets/{index-GBbbyQxc.js → index-D_O_55vK.js} +59 -9
  113. package/portal-ui/dist/index.html +1 -1
  114. package/portal-ui/package.json +1 -1
  115. package/providers/_shared/README.md +1 -1
  116. package/providers/_shared/answer-memory.mjs +199 -0
  117. package/providers/_shared/ledger-path.mjs +1 -1
  118. package/providers/_shared/ledger.mjs +47 -5
  119. package/providers/_shared/script-form.mjs +24 -5
  120. package/providers/_shared/term-shape.mjs +5 -5
  121. package/providers/clarivate/src/capabilities.js +11 -0
  122. package/providers/clarivate/src/core.js +140 -13
  123. package/providers/jx-subclass/lookup.mjs +1 -1
  124. package/providers/oauth-mcp-bridge/CHANGELOG.md +8 -0
  125. package/providers/oauth-mcp-bridge/package.json +1 -1
  126. package/providers/signa/src/capabilities.js +24 -0
  127. package/providers/signa/src/core.js +66 -0
  128. package/scripts/deprecate-below.mjs +114 -2
  129. package/scripts/freeze-example-run.mjs +1 -1
  130. package/scripts/live-surface-check.mjs +11 -2
  131. package/scripts/release-entry-catch-up.mjs +211 -0
  132. package/scripts/release-note-required.mjs +102 -6
  133. package/scripts/release-rehearsal-version.mjs +60 -0
  134. package/scripts/release-sbom.mjs +104 -0
  135. package/scripts/release-visible-check.mjs +7 -5
  136. package/scripts/score.mjs +3 -3
  137. package/shared/brand.mjs +1 -1
  138. package/shared/client-door.mjs +15 -8
  139. package/shared/driver-dir.mjs +20 -9
  140. package/shared/names-in-force.mjs +2 -0
  141. package/shared/scope.mjs +25 -10
  142. package/shared/store-in-repo.mjs +38 -17
@@ -101,7 +101,7 @@
101
101
  },
102
102
  "a-capability-gap-is-not-reopened.pipeline.test.mjs": {
103
103
  "tests": 1,
104
- "asserts": 6,
104
+ "asserts": 8,
105
105
  "skips": 0,
106
106
  "todos": 0
107
107
  },
@@ -130,8 +130,8 @@
130
130
  "todos": 0
131
131
  },
132
132
  "a-change-a-reader-can-see-arrives-with-something-to-read.test.mjs": {
133
- "tests": 23,
134
- "asserts": 55,
133
+ "tests": 32,
134
+ "asserts": 82,
135
135
  "skips": 1,
136
136
  "todos": 0
137
137
  },
@@ -142,8 +142,8 @@
142
142
  "todos": 0
143
143
  },
144
144
  "a-check-that-could-not-look-does-not-report-a-drift.test.mjs": {
145
- "tests": 10,
146
- "asserts": 26,
145
+ "tests": 13,
146
+ "asserts": 37,
147
147
  "skips": 0,
148
148
  "todos": 0
149
149
  },
@@ -159,6 +159,12 @@
159
159
  "skips": 0,
160
160
  "todos": 0
161
161
  },
162
+ "a-clarivate-run-asks-each-question-and-fetches-each-record-once.test.mjs": {
163
+ "tests": 10,
164
+ "asserts": 28,
165
+ "skips": 0,
166
+ "todos": 0
167
+ },
162
168
  "a-class-the-client-reaches-is-added-and-costs-one-question.test.mjs": {
163
169
  "tests": 5,
164
170
  "asserts": 17,
@@ -220,8 +226,14 @@
220
226
  "todos": 0
221
227
  },
222
228
  "a-company-created-in-the-browser-is-a-whole-company.test.mjs": {
223
- "tests": 11,
224
- "asserts": 61,
229
+ "tests": 14,
230
+ "asserts": 75,
231
+ "skips": 0,
232
+ "todos": 0
233
+ },
234
+ "a-company-with-no-marketplaces-is-described-as-searched.test.mjs": {
235
+ "tests": 2,
236
+ "asserts": 4,
225
237
  "skips": 0,
226
238
  "todos": 0
227
239
  },
@@ -459,6 +471,12 @@
459
471
  "skips": 0,
460
472
  "todos": 0
461
473
  },
474
+ "a-follow-up-re-runs-only-what-is-missing.test.mjs": {
475
+ "tests": 4,
476
+ "asserts": 9,
477
+ "skips": 0,
478
+ "todos": 0
479
+ },
462
480
  "a-full-country-card-keeps-what-the-multi-country-card-shows.test.mjs": {
463
481
  "tests": 2,
464
482
  "asserts": 12,
@@ -561,6 +579,12 @@
561
579
  "skips": 0,
562
580
  "todos": 0
563
581
  },
582
+ "a-knockout-whose-counts-all-fail-pays-for-no-owner-lookup.test.mjs": {
583
+ "tests": 3,
584
+ "asserts": 12,
585
+ "skips": 0,
586
+ "todos": 0
587
+ },
564
588
  "a-link-in-the-workbook-is-not-banned-vocabulary.test.mjs": {
565
589
  "tests": 2,
566
590
  "asserts": 5,
@@ -621,6 +645,12 @@
621
645
  "skips": 0,
622
646
  "todos": 0
623
647
  },
648
+ "a-mixed-alphabet-look-alike-is-not-sent-where-the-register-drops-its-letters.test.mjs": {
649
+ "tests": 10,
650
+ "asserts": 45,
651
+ "skips": 0,
652
+ "todos": 0
653
+ },
624
654
  "a-model-of-the-current-generation-is-named-in-every-spelling.test.mjs": {
625
655
  "tests": 4,
626
656
  "asserts": 13,
@@ -659,10 +689,16 @@
659
689
  },
660
690
  "a-new-install-signs-in-with-its-own-passphrase.test.mjs": {
661
691
  "tests": 10,
662
- "asserts": 57,
692
+ "asserts": 58,
663
693
  "skips": 1,
664
694
  "todos": 0
665
695
  },
696
+ "a-new-run-folder-is-closed-to-other-accounts.test.mjs": {
697
+ "tests": 5,
698
+ "asserts": 9,
699
+ "skips": 5,
700
+ "todos": 0
701
+ },
666
702
  "a-next-step-the-model-writes-comes-off-at-publish.test.mjs": {
667
703
  "tests": 12,
668
704
  "asserts": 28,
@@ -789,6 +825,12 @@
789
825
  "skips": 0,
790
826
  "todos": 0
791
827
  },
828
+ "a-range-deprecation-takes-exactly-the-named-versions.test.mjs": {
829
+ "tests": 7,
830
+ "asserts": 17,
831
+ "skips": 0,
832
+ "todos": 0
833
+ },
792
834
  "a-read-the-engine-could-not-answer-names-the-check.test.mjs": {
793
835
  "tests": 4,
794
836
  "asserts": 14,
@@ -915,6 +957,18 @@
915
957
  "skips": 0,
916
958
  "todos": 0
917
959
  },
960
+ "a-rehearsal-dry-runs-the-version-a-cut-would-publish.test.mjs": {
961
+ "tests": 10,
962
+ "asserts": 41,
963
+ "skips": 0,
964
+ "todos": 0
965
+ },
966
+ "a-release-carries-its-parts-list.test.mjs": {
967
+ "tests": 5,
968
+ "asserts": 27,
969
+ "skips": 0,
970
+ "todos": 0
971
+ },
918
972
  "a-release-is-announced-only-once-a-stranger-can-install-it.test.mjs": {
919
973
  "tests": 8,
920
974
  "asserts": 19,
@@ -957,6 +1011,12 @@
957
1011
  "skips": 0,
958
1012
  "todos": 0
959
1013
  },
1014
+ "a-run-asks-signa-each-question-once.test.mjs": {
1015
+ "tests": 18,
1016
+ "asserts": 83,
1017
+ "skips": 0,
1018
+ "todos": 0
1019
+ },
960
1020
  "a-run-records-the-tier-it-asked-for.test.mjs": {
961
1021
  "tests": 5,
962
1022
  "asserts": 18,
@@ -1077,6 +1137,12 @@
1077
1137
  "skips": 0,
1078
1138
  "todos": 0
1079
1139
  },
1140
+ "a-state-change-from-another-site-is-refused.test.mjs": {
1141
+ "tests": 15,
1142
+ "asserts": 70,
1143
+ "skips": 0,
1144
+ "todos": 0
1145
+ },
1080
1146
  "a-stop-is-read-once-more-before-anything-is-published.test.mjs": {
1081
1147
  "tests": 4,
1082
1148
  "asserts": 12,
@@ -1197,6 +1263,12 @@
1197
1263
  "skips": 2,
1198
1264
  "todos": 0
1199
1265
  },
1266
+ "a-version-npm-is-still-validating-gets-its-entry-once-served.test.mjs": {
1267
+ "tests": 20,
1268
+ "asserts": 72,
1269
+ "skips": 0,
1270
+ "todos": 0
1271
+ },
1200
1272
  "a-visible-line-is-written-for-the-client.test.mjs": {
1201
1273
  "tests": 11,
1202
1274
  "asserts": 24,
@@ -1323,6 +1395,12 @@
1323
1395
  "skips": 0,
1324
1396
  "todos": 0
1325
1397
  },
1398
+ "an-audit-lists-only-its-own-companys-recall-checks.test.mjs": {
1399
+ "tests": 4,
1400
+ "asserts": 11,
1401
+ "skips": 0,
1402
+ "todos": 0
1403
+ },
1326
1404
  "an-empty-config-store-overrides-nothing.test.mjs": {
1327
1405
  "tests": 5,
1328
1406
  "asserts": 29,
@@ -1708,8 +1786,8 @@
1708
1786
  "todos": 0
1709
1787
  },
1710
1788
  "client-door.test.mjs": {
1711
- "tests": 39,
1712
- "asserts": 168,
1789
+ "tests": 40,
1790
+ "asserts": 173,
1713
1791
  "skips": 1,
1714
1792
  "todos": 0
1715
1793
  },
@@ -1725,6 +1803,12 @@
1725
1803
  "skips": 0,
1726
1804
  "todos": 0
1727
1805
  },
1806
+ "closing-the-terminal-stops-what-start-started.test.mjs": {
1807
+ "tests": 2,
1808
+ "asserts": 6,
1809
+ "skips": 1,
1810
+ "todos": 0
1811
+ },
1728
1812
  "cn-scope-honesty.test.mjs": {
1729
1813
  "tests": 22,
1730
1814
  "asserts": 96,
@@ -2759,7 +2843,7 @@
2759
2843
  },
2760
2844
  "flag-snapshot.test.mjs": {
2761
2845
  "tests": 24,
2762
- "asserts": 82,
2846
+ "asserts": 81,
2763
2847
  "skips": 0,
2764
2848
  "todos": 0
2765
2849
  },
@@ -3395,7 +3479,7 @@
3395
3479
  },
3396
3480
  "park-tells-the-truth.test.mjs": {
3397
3481
  "tests": 8,
3398
- "asserts": 20,
3482
+ "asserts": 19,
3399
3483
  "skips": 0,
3400
3484
  "todos": 0
3401
3485
  },
@@ -3430,8 +3514,8 @@
3430
3514
  "todos": 0
3431
3515
  },
3432
3516
  "pipeline.mock.registergap.test.mjs": {
3433
- "tests": 6,
3434
- "asserts": 34,
3517
+ "tests": 7,
3518
+ "asserts": 43,
3435
3519
  "skips": 0,
3436
3520
  "todos": 0
3437
3521
  },
@@ -3442,8 +3526,8 @@
3442
3526
  "todos": 0
3443
3527
  },
3444
3528
  "pipeline.mock.test.mjs": {
3445
- "tests": 99,
3446
- "asserts": 827,
3529
+ "tests": 103,
3530
+ "asserts": 853,
3447
3531
  "skips": 0,
3448
3532
  "todos": 0
3449
3533
  },
@@ -3580,8 +3664,8 @@
3580
3664
  "todos": 0
3581
3665
  },
3582
3666
  "portal-service.test.mjs": {
3583
- "tests": 131,
3584
- "asserts": 712,
3667
+ "tests": 132,
3668
+ "asserts": 715,
3585
3669
  "skips": 1,
3586
3670
  "todos": 0
3587
3671
  },
@@ -3688,8 +3772,8 @@
3688
3772
  "todos": 0
3689
3773
  },
3690
3774
  "profiles.test.mjs": {
3691
- "tests": 48,
3692
- "asserts": 263,
3775
+ "tests": 49,
3776
+ "asserts": 272,
3693
3777
  "skips": 0,
3694
3778
  "todos": 0
3695
3779
  },
@@ -3959,7 +4043,7 @@
3959
4043
  },
3960
4044
  "register-capabilities.test.mjs": {
3961
4045
  "tests": 34,
3962
- "asserts": 268,
4046
+ "asserts": 272,
3963
4047
  "skips": 0,
3964
4048
  "todos": 0
3965
4049
  },
@@ -4078,8 +4162,8 @@
4078
4162
  "todos": 0
4079
4163
  },
4080
4164
  "release-pipeline.test.mjs": {
4081
- "tests": 121,
4082
- "asserts": 456,
4165
+ "tests": 123,
4166
+ "asserts": 467,
4083
4167
  "skips": 0,
4084
4168
  "todos": 0
4085
4169
  },
@@ -4102,8 +4186,8 @@
4102
4186
  "todos": 0
4103
4187
  },
4104
4188
  "render.test.mjs": {
4105
- "tests": 162,
4106
- "asserts": 675,
4189
+ "tests": 163,
4190
+ "asserts": 681,
4107
4191
  "skips": 0,
4108
4192
  "todos": 0
4109
4193
  },
@@ -4276,8 +4360,8 @@
4276
4360
  "todos": 0
4277
4361
  },
4278
4362
  "run-economics.test.mjs": {
4279
- "tests": 25,
4280
- "asserts": 158,
4363
+ "tests": 26,
4364
+ "asserts": 161,
4281
4365
  "skips": 0,
4282
4366
  "todos": 0
4283
4367
  },
@@ -4379,7 +4463,7 @@
4379
4463
  },
4380
4464
  "runner.knockout-e2e.test.mjs": {
4381
4465
  "tests": 3,
4382
- "asserts": 115,
4466
+ "asserts": 118,
4383
4467
  "skips": 0,
4384
4468
  "todos": 0
4385
4469
  },
@@ -5380,8 +5464,8 @@
5380
5464
  "todos": 0
5381
5465
  },
5382
5466
  "the-people-page-can-change-and-remove-a-person.test.mjs": {
5383
- "tests": 16,
5384
- "asserts": 80,
5467
+ "tests": 17,
5468
+ "asserts": 85,
5385
5469
  "skips": 0,
5386
5470
  "todos": 0
5387
5471
  },
@@ -5483,7 +5567,7 @@
5483
5567
  },
5484
5568
  "the-record-half-of-an-add-must-reach-git.test.mjs": {
5485
5569
  "tests": 11,
5486
- "asserts": 39,
5570
+ "asserts": 40,
5487
5571
  "skips": 0,
5488
5572
  "todos": 0
5489
5573
  },
@@ -5609,7 +5693,7 @@
5609
5693
  },
5610
5694
  "the-seats-attestation-decides-the-use-source.test.mjs": {
5611
5695
  "tests": 5,
5612
- "asserts": 9,
5696
+ "asserts": 10,
5613
5697
  "skips": 0,
5614
5698
  "todos": 0
5615
5699
  },
@@ -5631,6 +5715,12 @@
5631
5715
  "skips": 0,
5632
5716
  "todos": 0
5633
5717
  },
5718
+ "the-shipped-services-may-not-gain-privileges.test.mjs": {
5719
+ "tests": 4,
5720
+ "asserts": 7,
5721
+ "skips": 0,
5722
+ "todos": 0
5723
+ },
5634
5724
  "the-short-surfaces-quote-the-report.test.mjs": {
5635
5725
  "tests": 3,
5636
5726
  "asserts": 9,
@@ -5927,7 +6017,7 @@
5927
6017
  },
5928
6018
  "update-writes-only-inside-the-checkout.test.mjs": {
5929
6019
  "tests": 8,
5930
- "asserts": 29,
6020
+ "asserts": 30,
5931
6021
  "skips": 0,
5932
6022
  "todos": 0
5933
6023
  },
@@ -6134,6 +6224,12 @@
6134
6224
  "skips": 0,
6135
6225
  "todos": 0
6136
6226
  },
6227
+ "a-tool-the-listing-hides-cannot-be-called-by-name.test.mjs": {
6228
+ "tests": 4,
6229
+ "asserts": 10,
6230
+ "skips": 0,
6231
+ "todos": 0
6232
+ },
6137
6233
  "account-audit-chain.test.mjs": {
6138
6234
  "tests": 10,
6139
6235
  "asserts": 48,
@@ -6267,8 +6363,8 @@
6267
6363
  "todos": 0
6268
6364
  },
6269
6365
  "http-handler.test.mjs": {
6270
- "tests": 20,
6271
- "asserts": 47,
6366
+ "tests": 23,
6367
+ "asserts": 58,
6272
6368
  "skips": 0,
6273
6369
  "todos": 0
6274
6370
  },
@@ -6316,7 +6412,7 @@
6316
6412
  },
6317
6413
  "ops-token.test.mjs": {
6318
6414
  "tests": 8,
6319
- "asserts": 39,
6415
+ "asserts": 41,
6320
6416
  "skips": 0,
6321
6417
  "todos": 0
6322
6418
  },
@@ -6345,8 +6441,8 @@
6345
6441
  "todos": 0
6346
6442
  },
6347
6443
  "portal-trigger-wire.test.mjs": {
6348
- "tests": 1,
6349
- "asserts": 7,
6444
+ "tests": 2,
6445
+ "asserts": 11,
6350
6446
  "skips": 0,
6351
6447
  "todos": 0
6352
6448
  },
@@ -6375,8 +6471,8 @@
6375
6471
  "todos": 0
6376
6472
  },
6377
6473
  "scope.test.mjs": {
6378
- "tests": 27,
6379
- "asserts": 114,
6474
+ "tests": 30,
6475
+ "asserts": 121,
6380
6476
  "skips": 0,
6381
6477
  "todos": 0
6382
6478
  },
@@ -6734,8 +6830,8 @@
6734
6830
  "todos": 0
6735
6831
  },
6736
6832
  "profileFields.test.ts": {
6737
- "tests": 54,
6738
- "asserts": 173,
6833
+ "tests": 55,
6834
+ "asserts": 178,
6739
6835
  "skips": 0,
6740
6836
  "todos": 0
6741
6837
  },
@@ -65,6 +65,30 @@ Environment=CLEAROTRON_NO_ENV_FILE=1
65
65
  # itself REFUSES to bind a non-loopback address in token-only mode, with the reason printed. A unit file
66
66
  # is the wrong place to enforce it, because it enforces it only until somebody edits the unit.
67
67
  ExecStart=/usr/bin/node ${CLEAROTRON_CHECKOUT_DIR}/mcp-server/http-server-client.mjs
68
+ # ── WHAT THIS SERVICE MAY NOT DO ─────────────────────────────────────────────────────────────────────
69
+ # Neither this service nor any program the engine starts under it needs to gain privileges, create a
70
+ # set-user-ID or set-group-ID file, switch its execution domain, take real-time scheduling or make a
71
+ # system call of another architecture. These five are what a user unit applies on a machine that refuses
72
+ # unprivileged user namespaces. PrivateTmp, ProtectSystem and ProtectHome are skipped there without a
73
+ # word, so they are not written here, where they would read as protection that is not in force.
74
+ # Measured 2026-09-23 with all five set: the process reads NoNewPrivs 1 and Seccomp 2, a knockout on each
75
+ # engine is delivered, and a report folder created inside a set-group-ID pool still inherits the bit,
76
+ # because the kernel sets it from the parent and RestrictSUIDSGID refuses only a mode that asks for it.
77
+ NoNewPrivileges=yes
78
+ RestrictSUIDSGID=yes
79
+ LockPersonality=yes
80
+ RestrictRealtime=yes
81
+ SystemCallArchitectures=native
82
+ #
83
+ # ── WHAT THIS SERVICE CREATES IS CLOSED TO OTHER ACCOUNTS ─────────────────────────────────────────────
84
+ # Every file and folder this service or the engine creates comes out with no access for accounts outside
85
+ # its group: run records, known-conflicts, outbox packets, archive folders, and whatever a later writer
86
+ # adds, without a mode at each write site. Group write is kept on purpose: a store shared by a group, as
87
+ # a set-group-ID checkout that several accounts pull into, must stay writable by that group, and 0027
88
+ # would make each new folder there closed to the others. Measured 2026-09-23 with 0027: a knockout was
89
+ # delivered and its report served, every new folder 750 and file 640, and a saved search on a shared
90
+ # checkout would have created a folder the group could no longer write into.
91
+ UMask=0007
68
92
  Restart=on-failure
69
93
  RestartSec=10
70
94
 
@@ -23,6 +23,30 @@ EnvironmentFile=%h/.env
23
23
  Environment=PATH=%h/.local/bin:%h/.npm-global/bin:/usr/local/bin:/usr/bin:/bin
24
24
  Environment=CLEAROTRON_NO_ENV_FILE=1
25
25
  ExecStart=/usr/bin/node ${CLEAROTRON_CHECKOUT_DIR}/mcp-server/http-server.mjs
26
+ # ── WHAT THIS SERVICE MAY NOT DO ─────────────────────────────────────────────────────────────────────
27
+ # Neither this service nor any program the engine starts under it needs to gain privileges, create a
28
+ # set-user-ID or set-group-ID file, switch its execution domain, take real-time scheduling or make a
29
+ # system call of another architecture. These five are what a user unit applies on a machine that refuses
30
+ # unprivileged user namespaces. PrivateTmp, ProtectSystem and ProtectHome are skipped there without a
31
+ # word, so they are not written here, where they would read as protection that is not in force.
32
+ # Measured 2026-09-23 with all five set: the process reads NoNewPrivs 1 and Seccomp 2, a knockout on each
33
+ # engine is delivered, and a report folder created inside a set-group-ID pool still inherits the bit,
34
+ # because the kernel sets it from the parent and RestrictSUIDSGID refuses only a mode that asks for it.
35
+ NoNewPrivileges=yes
36
+ RestrictSUIDSGID=yes
37
+ LockPersonality=yes
38
+ RestrictRealtime=yes
39
+ SystemCallArchitectures=native
40
+ #
41
+ # ── WHAT THIS SERVICE CREATES IS CLOSED TO OTHER ACCOUNTS ─────────────────────────────────────────────
42
+ # Every file and folder this service or the engine creates comes out with no access for accounts outside
43
+ # its group: run records, known-conflicts, outbox packets, archive folders, and whatever a later writer
44
+ # adds, without a mode at each write site. Group write is kept on purpose: a store shared by a group, as
45
+ # a set-group-ID checkout that several accounts pull into, must stay writable by that group, and 0027
46
+ # would make each new folder there closed to the others. Measured 2026-09-23 with 0027: a knockout was
47
+ # delivered and its report served, every new folder 750 and file 640, and a saved search on a shared
48
+ # checkout would have created a folder the group could no longer write into.
49
+ UMask=0007
26
50
  Restart=on-failure
27
51
  RestartSec=10
28
52
 
@@ -74,6 +74,30 @@ ExecStart=/usr/bin/node ${CLEAROTRON_CHECKOUT_DIR}/driver/portal-service.mjs
74
74
  # So the worker unit writes it and this one does not. `clearotron-worker.service` carries the
75
75
  # ExecStartPost, and a run refreshes it after every drain — both of those are the engine, which is whose
76
76
  # posture the row claims to report.
77
+ # ── WHAT THIS SERVICE MAY NOT DO ─────────────────────────────────────────────────────────────────────
78
+ # Neither this service nor any program the engine starts under it needs to gain privileges, create a
79
+ # set-user-ID or set-group-ID file, switch its execution domain, take real-time scheduling or make a
80
+ # system call of another architecture. These five are what a user unit applies on a machine that refuses
81
+ # unprivileged user namespaces. PrivateTmp, ProtectSystem and ProtectHome are skipped there without a
82
+ # word, so they are not written here, where they would read as protection that is not in force.
83
+ # Measured 2026-09-23 with all five set: the process reads NoNewPrivs 1 and Seccomp 2, a knockout on each
84
+ # engine is delivered, and a report folder created inside a set-group-ID pool still inherits the bit,
85
+ # because the kernel sets it from the parent and RestrictSUIDSGID refuses only a mode that asks for it.
86
+ NoNewPrivileges=yes
87
+ RestrictSUIDSGID=yes
88
+ LockPersonality=yes
89
+ RestrictRealtime=yes
90
+ SystemCallArchitectures=native
91
+ #
92
+ # ── WHAT THIS SERVICE CREATES IS CLOSED TO OTHER ACCOUNTS ─────────────────────────────────────────────
93
+ # Every file and folder this service or the engine creates comes out with no access for accounts outside
94
+ # its group: run records, known-conflicts, outbox packets, archive folders, and whatever a later writer
95
+ # adds, without a mode at each write site. Group write is kept on purpose: a store shared by a group, as
96
+ # a set-group-ID checkout that several accounts pull into, must stay writable by that group, and 0027
97
+ # would make each new folder there closed to the others. Measured 2026-09-23 with 0027: a knockout was
98
+ # delivered and its report served, every new folder 750 and file 640, and a saved search on a shared
99
+ # checkout would have created a folder the group could no longer write into.
100
+ UMask=0007
77
101
  Restart=on-failure
78
102
  RestartSec=10
79
103
 
@@ -78,6 +78,30 @@ ExecStartPost=-/usr/bin/node ${CLEAROTRON_CHECKOUT_DIR}/driver/flag-snapshot.mjs
78
78
  # main(). Until the deploy path calls the refresh, this ExecStartPost starts working on test and prod when
79
79
  # somebody runs it, not when the code lands. Recorded here because the next person wondering why the
80
80
  # last-run row is stale will read this file first.
81
+ # ── WHAT THIS SERVICE MAY NOT DO ─────────────────────────────────────────────────────────────────────
82
+ # Neither this service nor any program the engine starts under it needs to gain privileges, create a
83
+ # set-user-ID or set-group-ID file, switch its execution domain, take real-time scheduling or make a
84
+ # system call of another architecture. These five are what a user unit applies on a machine that refuses
85
+ # unprivileged user namespaces. PrivateTmp, ProtectSystem and ProtectHome are skipped there without a
86
+ # word, so they are not written here, where they would read as protection that is not in force.
87
+ # Measured 2026-09-23 with all five set: the process reads NoNewPrivs 1 and Seccomp 2, a knockout on each
88
+ # engine is delivered, and a report folder created inside a set-group-ID pool still inherits the bit,
89
+ # because the kernel sets it from the parent and RestrictSUIDSGID refuses only a mode that asks for it.
90
+ NoNewPrivileges=yes
91
+ RestrictSUIDSGID=yes
92
+ LockPersonality=yes
93
+ RestrictRealtime=yes
94
+ SystemCallArchitectures=native
95
+ #
96
+ # ── WHAT THIS SERVICE CREATES IS CLOSED TO OTHER ACCOUNTS ─────────────────────────────────────────────
97
+ # Every file and folder this service or the engine creates comes out with no access for accounts outside
98
+ # its group: run records, known-conflicts, outbox packets, archive folders, and whatever a later writer
99
+ # adds, without a mode at each write site. Group write is kept on purpose: a store shared by a group, as
100
+ # a set-group-ID checkout that several accounts pull into, must stay writable by that group, and 0027
101
+ # would make each new folder there closed to the others. Measured 2026-09-23 with 0027: a knockout was
102
+ # delivered and its report served, every new folder 750 and file 640, and a saved search on a shared
103
+ # checkout would have created a folder the group could no longer write into.
104
+ UMask=0007
81
105
  Restart=on-failure
82
106
  RestartSec=10
83
107
 
package/driver/tokens.mjs CHANGED
@@ -6,13 +6,14 @@
6
6
  // Each stage writes one record PER ATTEMPT to _driver/<stage>.jsonl with {model, usage, ...} (gateway.mjs).
7
7
  // This sums token counts across EVERY attempt (so retry waste is included) directly from `usage` —
8
8
  //
9
- // …and across every DIRECT-API call too. The jx lanes do not go through the gateway (they are
10
- // non-agentic Messages calls) and write their own `_driver/jx-completions.jsonl`; until 2026-07-28 those
11
- // rows named their counts `tokens` and carried no `model`, so the model gate below dropped every one of
12
- // them and a whole lane's spend was counted NOWHERE. They now write {model, usage} like any other row.
13
- // The `byStage` split keys off the filename, so the direct-API share stays recoverable as
9
+ // …and across every native-language call too. The jx lanes do not go through the gateway (each turn runs
10
+ // through the engine's own runTurn, engine/jx-turn.mjs) and write their own `_driver/jx-completions.jsonl`;
11
+ // until 2026-07-28 those rows named their counts `tokens` and carried no `model`, so the model gate below
12
+ // dropped every one of them and a whole lane's spend was counted NOWHERE. They now write {model, usage}
13
+ // like any other row.
14
+ // The `byStage` split keys off the filename, so the native-language share stays recoverable as
14
15
  // `byStage["jx-completions"]` — worth knowing when reading `attempts`, which counts model invocations
15
- // (agent turns AND single API calls), not gateway retries alone.
16
+ // (stage turns AND single native-language turns), not gateway retries alone.
16
17
  // self-contained, so it also works on historical runs (their rows may carry a legacy costUsd; it is
17
18
  // ignored, never re-emitted). The run-level event log (_driver/run.jsonl) is skipped (it holds runLog
18
19
  // events, not stage-attempt usage). Best-effort by contract: an unreadable dir / bad line never throws —
@@ -68,27 +69,35 @@ function emptyAcc() {
68
69
  * turn (`engine.resolveModelId ?? resolveModel`) and stamps the answer on the row as `modelUsed`. So
69
70
  * this reads the stamp rather than re-deriving it — one resolution, at the point that knows.
70
71
  */
71
- function modelKey(rec) {
72
+ export function modelKey(rec) {
72
73
  if (typeof rec.modelUsed === "string" && rec.modelUsed) return rec.modelUsed;
73
74
 
74
75
  // NO STAMP. Two different situations, and guessing the same way for both is what caused the bug.
75
76
  const engine = typeof rec.engine === "string" ? rec.engine : "";
76
77
 
77
- // Rows predating the stamp, and the direct-API jx lanes, are Anthropic — that was the only engine
78
- // when they were written, and the jx lanes name a bare claude id that resolveModel exists to
79
- // normalise. Resolving keeps every historical rollup keyed exactly as it was.
80
- if (!engine || engine === "anthropic-agent") return resolveModel(rec.model);
78
+ // A TURN THAT NAMED NO MODEL, a native-language row recording `modelActual: null` (see isAttemptRow),
79
+ // has no id at all. Its tokens still account, under a key that says the model is missing rather than
80
+ // one built from the absent field. Asked FIRST, so no row keys as `undefined` because the catalog was
81
+ // handed nothing to resolve.
82
+ if (typeof rec.model !== "string") return `${engine || "unknown"}/no-model-reported`;
83
+
84
+ // Rows predating the stamp are Anthropic — that was the only engine when they were written — and
85
+ // resolving keeps every historical rollup keyed exactly as it was.
86
+ //
87
+ // A NATIVE-LANGUAGE ROW IS STAMPED WITH ITS VENDOR, NOT AN ENGINE (jxBillingStamp in jx-lanes.mjs), and
88
+ // its `model` is the id that served the turn. An Anthropic one is normalised through the catalog like
89
+ // any served Claude id, so it keys as `anthropic/claude-haiku-4-5`, apart from a stage's
90
+ // `anthropic/claude-haiku` — the split ruled on and accepted with recording the tier. It used to fall
91
+ // to the branch below and key as `anthropic/unstamped:<id>`, a name for a missing stamp on a row that
92
+ // carries one. An OpenAI one keys as its served id, which is what an openai-agent stage row carries.
93
+ if (!engine || engine === "anthropic-agent" || engine === "anthropic") return resolveModel(rec.model);
94
+ if (engine === "openai") return rec.model;
81
95
 
82
96
  // Any OTHER engine with no stamp. The tier is not a model id and this catalog is not that engine's,
83
97
  // so there is no honest id to key under. Name the gap instead: the tokens still account (dropping
84
98
  // them would break byModel summing to total, and an invisible gap is the failure this file already
85
99
  // fixed once for byEngine), and the key says what is missing rather than asserting an Anthropic
86
100
  // model produced them.
87
- //
88
- // A TURN THAT NAMED NO MODEL, a native-language row recording `modelActual: null` (see isAttemptRow),
89
- // has no id at all. Its tokens still account, under a key that says the model is missing rather than
90
- // one built from the absent field. Such a row always carries its vendor's stamp, so it reaches here.
91
- if (typeof rec.model !== "string") return `${engine || "unknown"}/no-model-reported`;
92
101
  return `${engine}/unstamped:${rec.model}`;
93
102
  }
94
103
 
@@ -154,7 +163,7 @@ export function rollupTokens(runDir) {
154
163
  // (different tokenizers, different accounting). Rolled up per engine, these stay comparable to
155
164
  // themselves over time, which is what a margin question actually needs.
156
165
  //
157
- // A row carrying no stamp — one predating it, or a direct-API lane like jx-completions — buckets as
166
+ // A row carrying no stamp — one written before the stamps existed, jx-completions rows included — buckets as
158
167
  // "unknown" rather than being dropped, so `byEngine` always sums to `total` and the unattributed
159
168
  // share is VISIBLE. Dropping it would make the gap look like it did not exist.
160
169
  //
@@ -62,7 +62,7 @@ export const TURNAROUND_BANDS = Object.freeze({
62
62
  }),
63
63
  clearance: Object.freeze({
64
64
  minutes: 120,
65
- source: "owner benchmark 2026-08-04, corrected 2026-08-08 (#523) after three scenarios were found carrying their own estimates instead",
65
+ source: "owner benchmark 2026-08-04, corrected 2026-08-08 after three scenarios were found carrying their own estimates instead",
66
66
  }),
67
67
  });
68
68