@sema-agent/settings-schema 10.1.0 → 11.0.0

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 (235) hide show
  1. package/CHANGELOG.md +419 -0
  2. package/README.md +141 -65
  3. package/bin/settings-schema.mjs +13 -6
  4. package/conformance/VERSION +1 -1
  5. package/conformance/baseline.json +3 -1
  6. package/conformance/cases/c01-entry-salvage-then-typo/expected.json +3 -1
  7. package/conformance/cases/c02-hosts-clamp-stacked/expected.json +12 -5
  8. package/conformance/cases/c02-hosts-clamp-stacked/meta.json +1 -1
  9. package/conformance/cases/c03-literal-dotted-top-key/expected.json +22 -2
  10. package/conformance/cases/c04-all-bad-collection-not-salvaged/expected.json +3 -1
  11. package/conformance/cases/c06-legacy-governance-lift/expected.json +11 -101
  12. package/conformance/cases/c06-legacy-governance-lift/meta.json +1 -1
  13. package/conformance/cases/c07-hooks-is-not-a-config-domain/expected.json +3 -1
  14. package/conformance/cases/c08-limits-unknown-carried-64/expected.json +203 -2
  15. package/conformance/cases/c09-limits-unknown-carried-65/expected.json +204 -2
  16. package/conformance/cases/c10-record-key-secret-redacted-twice/expected.json +3 -1
  17. package/conformance/cases/c11-unicode-unknown-keys/expected.json +20 -2
  18. package/conformance/cases/c12-prototype-name-top-keys/expected.json +3 -1
  19. package/conformance/cases/c13-models-field-null/expected.json +3 -1
  20. package/conformance/cases/c14-models-field-empty-array/expected.json +6 -1
  21. package/conformance/cases/c15-models-field-number/expected.json +3 -1
  22. package/conformance/cases/c16-deep-nesting-205/expected.json +14 -2
  23. package/conformance/cases/c17-empty-domain-file/expected.json +3 -1
  24. package/conformance/cases/c18-wire-envelope-not-an-object/expected.json +3 -1
  25. package/conformance/cases/c19-wire-envelope-no-version/expected.json +3 -1
  26. package/conformance/cases/c20-governance-absent-lifts/expected.json +11 -86
  27. package/conformance/cases/c20-governance-absent-lifts/meta.json +1 -1
  28. package/conformance/cases/c21-governance-empty-object-wins/expected.json +6 -5
  29. package/conformance/cases/c21-governance-empty-object-wins/input.json +1 -4
  30. package/conformance/cases/c21-governance-empty-object-wins/meta.json +1 -1
  31. package/conformance/cases/c23-mixed-validity-models/expected.json +3 -1
  32. package/conformance/cases/c24-valid-entries-with-unknown-keys/expected.json +22 -2
  33. package/conformance/cases/c25-published-roundtrip-zero-warnings/expected.json +6 -1
  34. package/conformance/cases/c26-hosts-array-1024/expected.json +3 -1
  35. package/conformance/cases/c27-hosts-array-1025/expected.json +6 -7175
  36. package/conformance/cases/c27-hosts-array-1025/meta.json +1 -1
  37. package/conformance/cases/c28-large-document-over-1mb/expected.json +14 -2
  38. package/conformance/cases/c29-salvage-then-domain-refine-fails/expected.json +3 -1
  39. package/conformance/cases/c30-version-triple-a-first/expected.json +6 -1
  40. package/conformance/cases/c31-version-triple-b-changed/expected.json +6 -1
  41. package/conformance/cases/c32-version-triple-a-restored/expected.json +6 -1
  42. package/conformance/cases/c33-limits-nested-carried-key/expected.json +18 -2
  43. package/conformance/cases/c34-skills-content-vs-manifest/expected.json +19 -3
  44. package/conformance/cases/c35-portable-domain-file-is-null/expected.json +3 -1
  45. package/conformance/cases/c36-skills-entry-without-content/expected.json +6 -2
  46. package/conformance/cases/c37-skills-field-null/expected.json +6 -2
  47. package/conformance/cases/c38-remote-exec-is-a-non-domain-file/expected.json +3 -1
  48. package/conformance/cases/c39-hidden-file-in-config-d/expected.json +3 -1
  49. package/conformance/cases/c40-s712-identity-only-what-reads-out/expected.json +11 -4
  50. package/conformance/cases/c41-s792-encoded-pem-identity/expected.json +9 -3
  51. package/conformance/cases/c42-s792-unknown-key-secret-redacted/expected.json +39 -2
  52. package/conformance/cases/c43-s792-form-and-deep-encoded-pem/expected.json +4 -1
  53. package/conformance/cases/c44-s792-utf8-escape-glued-token/expected.json +3 -1
  54. package/conformance/cases/c45-s792-identity-bounds-and-decode-depth/expected.json +19 -10
  55. package/conformance/cases/c45-s792-identity-bounds-and-decode-depth/meta.json +1 -1
  56. package/conformance/cases/{c46-s811-host-name-url-userinfo-characterization → c46-s811-host-name-url-userinfo-withheld}/expected.json +12 -5
  57. package/conformance/cases/c46-s811-host-name-url-userinfo-withheld/meta.json +9 -0
  58. package/conformance/cases/{c47-s811-roles-key-url-userinfo-characterization → c47-s811-roles-key-url-userinfo-withheld}/expected.json +23 -3
  59. package/conformance/cases/{c47-s811-roles-key-url-userinfo-characterization → c47-s811-roles-key-url-userinfo-withheld}/input.json +6 -0
  60. package/conformance/cases/c47-s811-roles-key-url-userinfo-withheld/meta.json +10 -0
  61. package/conformance/cases/c48-s935-model-headers-transported/expected.json +6 -1
  62. package/conformance/cases/c49-s935-model-headers-secret-entry-dropped/expected.json +3 -1
  63. package/conformance/cases/c50-s784-lane-host-legal/expected.json +3 -1
  64. package/conformance/cases/c51-s784-lane-e2b-legal/expected.json +3 -1
  65. package/conformance/cases/c52-s784-lane-k8s-legal/expected.json +3 -1
  66. package/conformance/cases/c53-s784-lane-ssh-legal/expected.json +3 -1
  67. package/conformance/cases/c54-s784-lane-adb-legal/expected.json +3 -1
  68. package/conformance/cases/c55-s784-lane-local-docker-legal/expected.json +3 -1
  69. package/conformance/cases/c56-s784-lane-device-legal/expected.json +3 -1
  70. package/conformance/cases/c57-s784-g1-enabled-no-lane/expected.json +3 -1
  71. package/conformance/cases/c58-s784-g2-multitenant-host/expected.json +3 -1
  72. package/conformance/cases/c59-s784-g3-k8s-missing-image/expected.json +3 -1
  73. package/conformance/cases/c60-s784-g3-e2b-missing-key/expected.json +3 -1
  74. package/conformance/cases/c61-s784-g3-other-lane-key/expected.json +3 -1
  75. package/conformance/cases/c62-s784-g7a-session-tidb/expected.json +3 -1
  76. package/conformance/cases/c63-s784-host-two-replicas/expected.json +3 -1
  77. package/conformance/cases/c64-s784-multitenant-local-store/expected.json +3 -1
  78. package/conformance/cases/c65-s784-pg-without-db/expected.json +3 -1
  79. package/conformance/cases/c66-s784-memory-backend-mismatch/expected.json +3 -1
  80. package/conformance/cases/c67-s784-retired-field-loud/expected.json +3 -1
  81. package/conformance/cases/c67-s784-retired-field-loud/meta.json +1 -1
  82. package/conformance/cases/c68-s784-device-local-store/expected.json +3 -1
  83. package/conformance/cases/c69-deep-encoded-token-past-every-reading/expected.json +3 -1
  84. package/conformance/cases/c70-rewritten-token-in-front-of-encoded-pem-header/expected.json +3 -1
  85. package/conformance/cases/c71-one-scanner-write-reads-display-forms/expected.json +119 -0
  86. package/conformance/cases/c71-one-scanner-write-reads-display-forms/input.json +24 -0
  87. package/conformance/cases/c71-one-scanner-write-reads-display-forms/meta.json +10 -0
  88. package/conformance/cases/c72-dangling-reference-write-seat-refuses/expected.json +111 -0
  89. package/conformance/cases/c72-dangling-reference-write-seat-refuses/input.json +26 -0
  90. package/conformance/cases/c72-dangling-reference-write-seat-refuses/meta.json +6 -0
  91. package/conformance/cases/cc01-mcp-toolfaces-non-object/expected.json +3 -1
  92. package/conformance/cases/cc02-mcp-source-key-is-transported/expected.json +3 -1
  93. package/conformance/cases/cc03-model-compat-unknown-subkey/expected.json +6 -1
  94. package/conformance/cases/cli01-model-name-nfc-vs-nfd/expected.json +11 -1
  95. package/conformance/cases/cli02-control-and-zero-width-chars/expected.json +11 -1
  96. package/conformance/cases/cli03-credential-pasted-into-unknown-key/expected.json +16 -2
  97. package/conformance/cases/cli04-env-value-with-newline/expected.json +3 -1
  98. package/conformance/cases/cli05-long-and-prefix-colliding-names/expected.json +6 -1
  99. package/conformance/cases/t01-absent-domain-key-not-null/expected.json +3 -1
  100. package/conformance/cases/t03-prototype-name-key-not-swallowed/expected.json +29 -2
  101. package/conformance/cases/t04-secret-literal-never-in-warning-value/expected.json +3 -1
  102. package/conformance/cases/z01-every-domain-empty-object/expected.json +8 -4
  103. package/conformance/cases/z01-every-domain-empty-object/input.json +0 -1
  104. package/conformance/cases/z01-every-domain-empty-object/meta.json +1 -1
  105. package/conformance/cases/z02-every-domain-unknown-key/expected.json +163 -23
  106. package/conformance/cases/z02-every-domain-unknown-key/input.json +0 -3
  107. package/conformance/cases/z02-every-domain-unknown-key/meta.json +1 -1
  108. package/dist/api/auth-bridge.d.ts +51 -181
  109. package/dist/api/auth-bridge.js +58 -33
  110. package/dist/api/auth.d.ts +37 -146
  111. package/dist/api/auth.js +16 -26
  112. package/dist/api/feedback.d.ts +87 -0
  113. package/dist/api/feedback.js +66 -0
  114. package/dist/api/pull-token.d.ts +32 -0
  115. package/dist/api/pull-token.js +88 -0
  116. package/dist/api/scopes.d.ts +82 -174
  117. package/dist/api/scopes.js +23 -18
  118. package/dist/bundle.d.ts +15 -7
  119. package/dist/bundle.js +28 -27
  120. package/dist/cli.d.ts +3 -1
  121. package/dist/cli.js +132 -81
  122. package/dist/config-d-file.d.ts +14 -0
  123. package/dist/config-d-file.js +67 -0
  124. package/dist/config-fns.d.ts +87 -186
  125. package/dist/config-fns.js +207 -262
  126. package/dist/conformance/contract-adapter.d.ts +9 -2
  127. package/dist/conformance/contract-adapter.js +15 -7
  128. package/dist/conformance/corpus.d.ts +3 -0
  129. package/dist/conformance/corpus.js +5 -0
  130. package/dist/conformance/derive.d.ts +3 -0
  131. package/dist/conformance/index.d.ts +2 -2
  132. package/dist/conformance/index.js +2 -2
  133. package/dist/conformance/run.js +67 -22
  134. package/dist/conformance/types.d.ts +31 -15
  135. package/dist/conformance/types.js +5 -0
  136. package/dist/conformance/warnings.d.ts +1 -1
  137. package/dist/conformance/warnings.js +1 -4
  138. package/dist/cross-domain.d.ts +66 -22
  139. package/dist/cross-domain.js +164 -93
  140. package/dist/cross-session.d.ts +29 -11
  141. package/dist/default-model.d.ts +43 -0
  142. package/dist/default-model.js +34 -0
  143. package/dist/execution-lane-index.d.ts +4 -8
  144. package/dist/execution-lane-index.js +4 -8
  145. package/dist/execution-lanes.d.ts +31 -8
  146. package/dist/execution-lanes.js +23 -5
  147. package/dist/file-edit.js +5 -2
  148. package/dist/file-store.d.ts +7 -6
  149. package/dist/file-store.js +37 -50
  150. package/dist/fleet.d.ts +364 -762
  151. package/dist/fleet.js +277 -224
  152. package/dist/hooks.d.ts +1151 -4737
  153. package/dist/hooks.js +59 -15
  154. package/dist/index.d.ts +10 -4
  155. package/dist/index.js +13 -7
  156. package/dist/integer.d.ts +11 -0
  157. package/dist/integer.js +11 -0
  158. package/dist/issue-path.d.ts +10 -0
  159. package/dist/issue-path.js +10 -0
  160. package/dist/loopback.d.ts +26 -0
  161. package/dist/loopback.js +54 -0
  162. package/dist/migration-receipt.d.ts +42 -0
  163. package/dist/migration-receipt.js +12 -0
  164. package/dist/one-time-migrations.d.ts +56 -0
  165. package/dist/one-time-migrations.js +819 -0
  166. package/dist/prompts-digest.d.ts +1 -1
  167. package/dist/prompts-digest.js +3 -2
  168. package/dist/reader.d.ts +2 -2
  169. package/dist/remote-exec.d.ts +45 -187
  170. package/dist/remote-exec.js +13 -7
  171. package/dist/resolve-roster.d.ts +18 -3
  172. package/dist/resolve-roster.js +28 -25
  173. package/dist/retired-envs.d.ts +24 -0
  174. package/dist/retired-envs.js +114 -0
  175. package/dist/retired-form.d.ts +31 -0
  176. package/dist/retired-form.js +28 -0
  177. package/dist/safety-merge-spec.d.ts +131 -191
  178. package/dist/safety-merge-spec.js +18 -14
  179. package/dist/scheduler-lifetime.d.ts +5 -0
  180. package/dist/scheduler-lifetime.js +7 -0
  181. package/dist/scheduler-store-migration.d.ts +14 -0
  182. package/dist/scheduler-store-migration.js +14 -0
  183. package/dist/scheduler-store-node.d.ts +24 -9
  184. package/dist/scheduler-store-node.js +25 -15
  185. package/dist/scheduler-store.d.ts +47 -14
  186. package/dist/scheduler-store.js +32 -61
  187. package/dist/secret-refs.d.ts +3 -3
  188. package/dist/secret-refs.js +1 -1
  189. package/dist/secret-scan.d.ts +14 -24
  190. package/dist/secret-scan.js +45 -23
  191. package/dist/sha256-core.d.ts +16 -0
  192. package/dist/sha256-core.js +138 -0
  193. package/dist/sha256.d.ts +6 -1
  194. package/dist/sha256.js +8 -98
  195. package/dist/skills-manifest.js +1 -1
  196. package/dist/types.d.ts +1501 -13536
  197. package/dist/types.js +494 -438
  198. package/dist/url-shape.d.ts +34 -0
  199. package/dist/url-shape.js +61 -0
  200. package/dist/web-admin-credential.d.ts +96 -0
  201. package/dist/{center-credential.js → web-admin-credential.js} +46 -43
  202. package/dist/web-admin-env.d.ts +33 -0
  203. package/dist/web-admin-env.js +33 -0
  204. package/dist/worker-row-verdict.d.ts +16 -0
  205. package/dist/worker-row-verdict.js +31 -0
  206. package/dist/workers-rows.d.ts +34 -0
  207. package/dist/workers-rows.js +42 -0
  208. package/dist/zod-unwrap.d.ts +11 -0
  209. package/dist/zod-unwrap.js +25 -0
  210. package/package.json +17 -9
  211. package/conformance/cases/c46-s811-host-name-url-userinfo-characterization/meta.json +0 -6
  212. package/conformance/cases/c47-s811-roles-key-url-userinfo-characterization/meta.json +0 -6
  213. package/conformance/migrate-workers/m01-g5-k8s-env-lifted/expected.json +0 -49
  214. package/conformance/migrate-workers/m01-g5-k8s-env-lifted/input.json +0 -26
  215. package/conformance/migrate-workers/m01-g5-k8s-env-lifted/meta.json +0 -4
  216. package/conformance/migrate-workers/m02-g5-idempotent/expected.json +0 -38
  217. package/conformance/migrate-workers/m02-g5-idempotent/input.json +0 -33
  218. package/conformance/migrate-workers/m02-g5-idempotent/meta.json +0 -5
  219. package/conformance/migrate-workers/m03-g5-refused-no-lane/expected.json +0 -71
  220. package/conformance/migrate-workers/m03-g5-refused-no-lane/input.json +0 -42
  221. package/conformance/migrate-workers/m03-g5-refused-no-lane/meta.json +0 -4
  222. package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/expected.json +0 -52
  223. package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/input.json +0 -30
  224. package/conformance/migrate-workers/m04-g7b-session-tidb-lifted/meta.json +0 -4
  225. package/conformance/migrate-workers/m05-row-verdict-reserved-env/expected.json +0 -82
  226. package/conformance/migrate-workers/m05-row-verdict-reserved-env/input.json +0 -68
  227. package/conformance/migrate-workers/m05-row-verdict-reserved-env/meta.json +0 -4
  228. package/dist/center-credential.d.ts +0 -116
  229. package/dist/issue-text.d.ts +0 -10
  230. package/dist/issue-text.js +0 -8
  231. package/dist/migrate-workers.d.ts +0 -71
  232. package/dist/migrate-workers.js +0 -351
  233. package/dist/migrate.d.ts +0 -255
  234. package/dist/migrate.js +0 -542
  235. /package/conformance/cases/{c46-s811-host-name-url-userinfo-characterization → c46-s811-host-name-url-userinfo-withheld}/input.json +0 -0
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "contributor": "contract",
3
- "claim": "十七个域各给一份**合法空文档** `{}` ⇒ 零告警、每域落 schema 默认。覆盖律的第一份:每个域至少被两条 case 摸过。它同时钉住「设了空」这一形在三腿上的读数,以及 local-root 腿对五个非便携域各报一条 unread-config-file。",
3
+ "claim": "十六个域各给一份**合法空文档** `{}` ⇒ 零告警、每域落 schema 默认。覆盖律的第一份:每个域至少被两条 case 摸过。它同时钉住「设了空」这一形在三腿上的读数,以及 local-root 腿对五个非便携域各报一条 unread-config-file。",
4
4
  "firstRedOn": []
5
5
  }
@@ -28,6 +28,9 @@
28
28
  "servers": []
29
29
  },
30
30
  "models": {
31
+ "atMention": {
32
+ "mode": "all"
33
+ },
31
34
  "models": [],
32
35
  "roles": {},
33
36
  "tierGroups": []
@@ -44,7 +47,6 @@
44
47
  "rosters": {
45
48
  "rosters": []
46
49
  },
47
- "runtime": {},
48
50
  "scenarios": {
49
51
  "scenarios": []
50
52
  },
@@ -59,24 +61,6 @@
59
61
  }
60
62
  },
61
63
  "warnings": [
62
- {
63
- "domain": "governance",
64
- "keys": [
65
- [
66
- "zzzUnknown"
67
- ]
68
- ],
69
- "kind": "unknown-keys-dropped"
70
- },
71
- {
72
- "domain": "runtime",
73
- "keys": [
74
- [
75
- "zzzUnknown"
76
- ]
77
- ],
78
- "kind": "unknown-keys-dropped"
79
- },
80
64
  {
81
65
  "domain": "models",
82
66
  "keys": [
@@ -167,6 +151,15 @@
167
151
  ],
168
152
  "kind": "unknown-keys-dropped"
169
153
  },
154
+ {
155
+ "domain": "governance",
156
+ "keys": [
157
+ [
158
+ "zzzUnknown"
159
+ ]
160
+ ],
161
+ "kind": "unknown-keys-dropped"
162
+ },
170
163
  {
171
164
  "domain": "entitlement",
172
165
  "keys": [
@@ -247,6 +240,9 @@
247
240
  "servers": []
248
241
  },
249
242
  "models": {
243
+ "atMention": {
244
+ "mode": "all"
245
+ },
250
246
  "models": [],
251
247
  "roles": {},
252
248
  "tierGroups": []
@@ -263,7 +259,6 @@
263
259
  "rosters": {
264
260
  "rosters": []
265
261
  },
266
- "runtime": {},
267
262
  "scenarios": {
268
263
  "scenarios": []
269
264
  },
@@ -277,18 +272,163 @@
277
272
  "workers": []
278
273
  }
279
274
  },
280
- "warnings": [],
275
+ "warnings": [
276
+ {
277
+ "domain": "models",
278
+ "keys": [
279
+ [
280
+ "zzzUnknown"
281
+ ]
282
+ ],
283
+ "kind": "unknown-keys-dropped"
284
+ },
285
+ {
286
+ "domain": "rosters",
287
+ "keys": [
288
+ [
289
+ "zzzUnknown"
290
+ ]
291
+ ],
292
+ "kind": "unknown-keys-dropped"
293
+ },
294
+ {
295
+ "domain": "skills",
296
+ "keys": [
297
+ [
298
+ "zzzUnknown"
299
+ ]
300
+ ],
301
+ "kind": "unknown-keys-dropped"
302
+ },
303
+ {
304
+ "domain": "mcp",
305
+ "keys": [
306
+ [
307
+ "zzzUnknown"
308
+ ]
309
+ ],
310
+ "kind": "unknown-keys-dropped"
311
+ },
312
+ {
313
+ "domain": "plugins",
314
+ "keys": [
315
+ [
316
+ "zzzUnknown"
317
+ ]
318
+ ],
319
+ "kind": "unknown-keys-dropped"
320
+ },
321
+ {
322
+ "domain": "scenarios",
323
+ "keys": [
324
+ [
325
+ "zzzUnknown"
326
+ ]
327
+ ],
328
+ "kind": "unknown-keys-dropped"
329
+ },
330
+ {
331
+ "domain": "systems",
332
+ "keys": [
333
+ [
334
+ "zzzUnknown"
335
+ ]
336
+ ],
337
+ "kind": "unknown-keys-dropped"
338
+ },
339
+ {
340
+ "domain": "collab",
341
+ "keys": [
342
+ [
343
+ "zzzUnknown"
344
+ ]
345
+ ],
346
+ "kind": "unknown-keys-dropped"
347
+ },
348
+ {
349
+ "domain": "workers",
350
+ "keys": [
351
+ [
352
+ "zzzUnknown"
353
+ ]
354
+ ],
355
+ "kind": "unknown-keys-dropped"
356
+ },
357
+ {
358
+ "domain": "hosts",
359
+ "keys": [
360
+ [
361
+ "zzzUnknown"
362
+ ]
363
+ ],
364
+ "kind": "unknown-keys-dropped"
365
+ },
366
+ {
367
+ "domain": "governance",
368
+ "keys": [
369
+ [
370
+ "zzzUnknown"
371
+ ]
372
+ ],
373
+ "kind": "unknown-keys-dropped"
374
+ },
375
+ {
376
+ "domain": "entitlement",
377
+ "keys": [
378
+ [
379
+ "zzzUnknown"
380
+ ]
381
+ ],
382
+ "kind": "unknown-keys-dropped"
383
+ },
384
+ {
385
+ "domain": "execution",
386
+ "keys": [
387
+ [
388
+ "zzzUnknown"
389
+ ]
390
+ ],
391
+ "kind": "unknown-keys-dropped"
392
+ },
393
+ {
394
+ "domain": "projects",
395
+ "keys": [
396
+ [
397
+ "zzzUnknown"
398
+ ]
399
+ ],
400
+ "kind": "unknown-keys-dropped"
401
+ },
402
+ {
403
+ "domain": "prompts",
404
+ "keys": [
405
+ [
406
+ "zzzUnknown"
407
+ ]
408
+ ],
409
+ "kind": "unknown-keys-dropped"
410
+ },
411
+ {
412
+ "domain": "limits",
413
+ "keys": [
414
+ [
415
+ "zzzUnknown"
416
+ ]
417
+ ],
418
+ "kind": "unknown-keys-carried"
419
+ }
420
+ ],
281
421
  "metadata": {
282
422
  "version": 7,
283
423
  "updatedAt": "2026-09-16T00:00:00.000Z"
284
424
  },
285
- "why": "受理:十七个域各带一个未知键 —— 十六个被 schema 剥掉(读腿报 unknown-keys-dropped)、limits 承运(unknown-keys-carried);严写同样剥 / 承运、不铸告警,受理形等于读腿十七格。"
425
+ "why": "受理:十六个域各带一个未知键 —— 十五个被 schema 剥掉(读腿报 unknown-keys-dropped)、limits 承运(unknown-keys-carried);严写同样剥 / 承运、不铸告警,受理形等于读腿十六格。"
286
426
  },
287
427
  "wire": {
288
428
  "derive": true
289
429
  },
290
430
  "localRoot": {
291
431
  "derive": true,
292
- "localVersion": 2336752390152956
432
+ "localVersion": 567413778934550
293
433
  }
294
434
  }
@@ -34,9 +34,6 @@
34
34
  "hosts": {
35
35
  "zzzUnknown": 1
36
36
  },
37
- "runtime": {
38
- "zzzUnknown": 1
39
- },
40
37
  "governance": {
41
38
  "zzzUnknown": 1
42
39
  },
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "contributor": "contract",
3
- "claim": "十七个域各给一份带同名未知键的文档 ⇒ 十六个闭世界域报 unknown-keys-dropped、limits(open-world)报 unknown-keys-carried。覆盖律的第二份,同时把「剥」与「承运」两条告警在同一份文档上分开钉死 —— 两者混为一谈的消费方会把承运的键当成丢了的键去补。",
3
+ "claim": "十六个域各给一份带同名未知键的文档 ⇒ 十五个闭世界域报 unknown-keys-dropped、limits(open-world)报 unknown-keys-carried。覆盖律的第二份,同时把「剥」与「承运」两条告警在同一份文档上分开钉死 —— 两者混为一谈的消费方会把承运的键当成丢了的键去补。",
4
4
  "firstRedOn": []
5
5
  }
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * `api/auth-bridge` — the 鉴权桥 contract: how a WORKER (the worker service / any data-plane service) verifies a
3
- * registry-minted USER access JWT and maps it into its existing `x-agent-principal` identity system.
4
- * (REGISTRY-REBUILD-DESIGN §5, M3 — registry half = JWKS already shipped; service half = ONE verifier
3
+ * web-admin-minted USER access JWT and maps it into its existing `x-agent-principal` identity system.
4
+ * (REGISTRY-REBUILD-DESIGN §5, M3 — web-admin half = JWKS already shipped; service half = ONE verifier
5
5
  * middleware implementing the rules below. This file is the schema + normative spec the service copies.)
6
6
  *
7
- * TRUST MODEL (single trust root, zero new worker config): the worker already trusts the registry for its
8
- * effective config; it extends the SAME trust to the registry's JWKS. A bearer token that is a well-formed
7
+ * TRUST MODEL (single trust root, zero new worker config): the worker already trusts web-admin for its
8
+ * effective config; it extends the SAME trust to web-admin's JWKS. A bearer token that is a well-formed
9
9
  * JWT and verifies against that JWKS with the checks below IS the user — `sub` feeds x-agent-principal
10
10
  * directly (owner semantics / costQuota / entitlement are already principal-keyed). Existing
11
11
  * SERVICE_AUTH_TOKENS / wpt_ bearer branches are untouched; this is an ADDITIONAL branch tried when the
@@ -19,25 +19,26 @@
19
19
  * token whose header alg is absent. Pin the list in the JWT library call — never read alg from the
20
20
  * token to decide how to verify.
21
21
  *
22
- * R2 KEY SOURCE. Verification keys come from the registry JWKS endpoint `GET {registryBaseUrl}` +
23
- * REGISTRY_JWKS_PATH ("/api/auth/sso/jwks"; response shape = `Jwks` below, public members only:
22
+ * R2 KEY SOURCE. Verification keys come from the web-admin JWKS endpoint `GET {webAdminBaseUrl}` +
23
+ * WEB_ADMIN_JWKS_PATH ("/api/auth/sso/jwks"; response shape = `Jwks` below, public members only:
24
24
  * kty/n/e/kid/use/alg). Match the token header `kid` against cached keys.
25
25
  *
26
26
  * R3 KID-MISS FORCED REFRESH + THROTTLE. kid found in cache → use the cached key (no fetch on the hot
27
27
  * path). kid NOT in cache → force ONE JWKS refetch, then retry the match (this is the key-ROTATION
28
- * window: a freshly rotated registry would otherwise reject every new token until the cache expired).
28
+ * window: a freshly rotated web-admin would otherwise reject every new token until the cache expired).
29
29
  * Forced refreshes are throttled to at most one per `jwksRefreshMinIntervalSec` (default 60s) —
30
30
  * otherwise an attacker spraying random-kid tokens turns the verifier into a JWKS-fetch DoS cannon.
31
31
  * Within the throttle window an unknown kid fails as `invalid_signature` WITHOUT fetching.
32
32
  * (Decision function: `shouldForceJwksRefresh`.)
33
33
  *
34
- * R4 ISSUER PIN. `iss` MUST equal the CONFIGURED issuer exactly (VerifierConfig.issuer = the registry's
34
+ * R4 ISSUER PIN. `iss` MUST equal the CONFIGURED issuer exactly (VerifierConfig.issuer = web-admin's
35
35
  * SSO_ISSUER, trailing slash stripped on both sides). A missing or different iss → `unknown_issuer`.
36
36
  * Never derive the expected issuer from the token or from request headers.
37
37
  *
38
38
  * R5 TIME WINDOW WITH SKEW. `exp` is REQUIRED: reject when nowSec > exp + clockSkewSec. `nbf`, when
39
- * present: reject when nowSec < nbf - clockSkewSec. clockSkewSec default 60 (DEFAULT_CLOCK_SKEW_SEC).
40
- * Both failures classify as `expired`. (Decision function: `classifyTimeClaims`.)
39
+ * present: reject when nowSec < nbf - clockSkewSec. `iat`, when present: reject when nowSec < iat - clockSkewSec
40
+ * (issued in the future). clockSkewSec default 60 (DEFAULT_CLOCK_SKEW_SEC), one tolerance for all three.
41
+ * These failures classify as `expired`. (Decision function: `classifyTimeClaims`.)
41
42
  *
42
43
  * R6 PRINCIPAL. `sub` MUST be a non-empty string — it becomes `VerifiedIdentity.principal` and feeds the
43
44
  * existing x-agent-principal pipeline verbatim. Empty/missing sub → `malformed`.
@@ -48,14 +49,17 @@
48
49
  *
49
50
  * R8 OFFLINE GRACE / FAIL-CLOSED. JWKS fetch fails (network/5xx/malformed body): keys already cached
50
51
  * remain USABLE for up to `offlineGraceSec` (default 24h, DEFAULT_OFFLINE_GRACE_SEC) measured from the
51
- * last SUCCESSFUL fetch — a registry blip must not take the whole data plane down. Past the grace, or
52
+ * last SUCCESSFUL fetch — a web-admin blip must not take the whole data plane down. Past the grace, or
52
53
  * with no cache at all, verification fails CLOSED as `jwks_unavailable` (never fail-open, never skip
53
54
  * signature checks). (Decision function: `jwksWithinOfflineGrace`.)
54
55
  *
55
56
  * R9 OUTPUT. Success → `VerifiedIdentity { principal: sub, role: token.role, grantId: token.jti,
56
- * scope: token.scope }` (`scope` = the multi-tenant active scope claim, `api/scopes`; absent = "global").
57
- * `role` is the registry RBAC role claim (string, informational for the worker's own authz mapping);
58
- * `grantId` is the jti when the registry stamps one (absent today — optional forever). Failure → one
57
+ * scope: token.scope, iat: token.iat }` (`scope` = the multi-tenant active scope claim, `api/scopes`; read it with
58
+ * `readTokenScope` — an absent claim is refused, not read as "global"; `iat` = issued-at, integer seconds, carried
59
+ * verbatim — a reader that learns a principal was deleted at T cuts off its tokens issued before T; absent claim ⇒ no
60
+ * `iat` key; present but not a non-negative integer ⇒ the token is `malformed`).
61
+ * `role` is web-admin RBAC role claim (string, informational for the worker's own authz mapping);
62
+ * `grantId` is the jti when web-admin stamps one (absent today — optional forever). Failure → one
59
63
  * of AUTH_BRIDGE_ERROR_CODES; the HTTP surface answers 401 with a GENERIC message (no error detail
60
64
  * disclosure to the caller; the code goes to logs/metrics only).
61
65
  *
@@ -67,8 +71,8 @@
67
71
  * library; THESE shapes pin down its configuration), browser-safe.
68
72
  */
69
73
  import { z } from "zod";
70
- /** The registry JWKS endpoint, relative to the registry origin (shipped; public by design, RFC 7517 §5). */
71
- export declare const REGISTRY_JWKS_PATH = "/api/auth/sso/jwks";
74
+ /** The web-admin JWKS endpoint, relative to the web-admin origin (shipped; public by design, RFC 7517 §5). */
75
+ export declare const WEB_ADMIN_JWKS_PATH = "/api/auth/sso/jwks";
72
76
  /** R1 — the ONLY acceptable JWS algorithms. */
73
77
  export declare const AUTH_BRIDGE_ALGS: readonly ["RS256"];
74
78
  export type AuthBridgeAlg = (typeof AUTH_BRIDGE_ALGS)[number];
@@ -78,172 +82,51 @@ export declare const DEFAULT_CLOCK_SKEW_SEC = 60;
78
82
  export declare const DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC = 60;
79
83
  /** R8 — default seconds a cached JWKS stays usable after fetches start failing (24h), then fail-closed. */
80
84
  export declare const DEFAULT_OFFLINE_GRACE_SEC: number;
81
- /** One RSA public JWK as the registry publishes it (public members ONLY — a `d`/`p`/`q` here is a registry
85
+ /** R6 — the longest principal the data plane accepts: the engine's principal gate refuses a longer one (400), because every
86
+ * scope / owner column a principal lands in verbatim is that wide — an over-long principal would truncate at the insert and
87
+ * split one identity into two. Anyone validating or minting a principal (a token `sub`, a membership row, an outbound
88
+ * principal header) checks against THIS value. */
89
+ export declare const PRINCIPAL_MAX_LENGTH = 190;
90
+ /** One RSA public JWK as web-admin publishes it (public members ONLY — a `d`/`p`/`q` here is a web-admin
82
91
  * bug, but the verifier MUST still never use/echo private members). */
83
- export declare const RegistryJwk: z.ZodObject<{
92
+ export declare const WebAdminJwk: z.ZodObject<{
84
93
  kty: z.ZodLiteral<"RSA">;
85
- /** modulus, base64url */
86
94
  n: z.ZodString;
87
- /** exponent, base64url */
88
95
  e: z.ZodString;
89
- /** RFC 7638 thumbprint of the public JWK — the rotation-stable key id tokens carry in their header. */
90
96
  kid: z.ZodString;
91
97
  use: z.ZodOptional<z.ZodLiteral<"sig">>;
92
- alg: z.ZodOptional<z.ZodEnum<["RS256"]>>;
93
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
94
- kty: z.ZodLiteral<"RSA">;
95
- /** modulus, base64url */
96
- n: z.ZodString;
97
- /** exponent, base64url */
98
- e: z.ZodString;
99
- /** RFC 7638 thumbprint of the public JWK — the rotation-stable key id tokens carry in their header. */
100
- kid: z.ZodString;
101
- use: z.ZodOptional<z.ZodLiteral<"sig">>;
102
- alg: z.ZodOptional<z.ZodEnum<["RS256"]>>;
103
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
104
- kty: z.ZodLiteral<"RSA">;
105
- /** modulus, base64url */
106
- n: z.ZodString;
107
- /** exponent, base64url */
108
- e: z.ZodString;
109
- /** RFC 7638 thumbprint of the public JWK — the rotation-stable key id tokens carry in their header. */
110
- kid: z.ZodString;
111
- use: z.ZodOptional<z.ZodLiteral<"sig">>;
112
- alg: z.ZodOptional<z.ZodEnum<["RS256"]>>;
113
- }, z.ZodTypeAny, "passthrough">>;
114
- export type RegistryJwk = z.infer<typeof RegistryJwk>;
115
- /** The JWKS document. `{keys: []}` is VALID (registry with SSO disabled) — every token then fails as
116
- * `invalid_signature` (there is a registry, it just mints nothing). */
117
- export declare const RegistryJwks: z.ZodObject<{
118
- keys: z.ZodArray<z.ZodObject<{
119
- kty: z.ZodLiteral<"RSA">;
120
- /** modulus, base64url */
121
- n: z.ZodString;
122
- /** exponent, base64url */
123
- e: z.ZodString;
124
- /** RFC 7638 thumbprint of the public JWK — the rotation-stable key id tokens carry in their header. */
125
- kid: z.ZodString;
126
- use: z.ZodOptional<z.ZodLiteral<"sig">>;
127
- alg: z.ZodOptional<z.ZodEnum<["RS256"]>>;
128
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
129
- kty: z.ZodLiteral<"RSA">;
130
- /** modulus, base64url */
131
- n: z.ZodString;
132
- /** exponent, base64url */
133
- e: z.ZodString;
134
- /** RFC 7638 thumbprint of the public JWK — the rotation-stable key id tokens carry in their header. */
135
- kid: z.ZodString;
136
- use: z.ZodOptional<z.ZodLiteral<"sig">>;
137
- alg: z.ZodOptional<z.ZodEnum<["RS256"]>>;
138
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
139
- kty: z.ZodLiteral<"RSA">;
140
- /** modulus, base64url */
141
- n: z.ZodString;
142
- /** exponent, base64url */
143
- e: z.ZodString;
144
- /** RFC 7638 thumbprint of the public JWK — the rotation-stable key id tokens carry in their header. */
145
- kid: z.ZodString;
146
- use: z.ZodOptional<z.ZodLiteral<"sig">>;
147
- alg: z.ZodOptional<z.ZodEnum<["RS256"]>>;
148
- }, z.ZodTypeAny, "passthrough">>, "many">;
149
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
98
+ alg: z.ZodOptional<z.ZodEnum<{
99
+ RS256: "RS256";
100
+ }>>;
101
+ }, z.core.$loose>;
102
+ export type WebAdminJwk = z.infer<typeof WebAdminJwk>;
103
+ /** The JWKS document. `{keys: []}` is VALID (web-admin with SSO disabled) — every token then fails as
104
+ * `invalid_signature` (there is a web-admin, it just mints nothing). */
105
+ export declare const WebAdminJwks: z.ZodObject<{
150
106
  keys: z.ZodArray<z.ZodObject<{
151
107
  kty: z.ZodLiteral<"RSA">;
152
- /** modulus, base64url */
153
- n: z.ZodString;
154
- /** exponent, base64url */
155
- e: z.ZodString;
156
- /** RFC 7638 thumbprint of the public JWK — the rotation-stable key id tokens carry in their header. */
157
- kid: z.ZodString;
158
- use: z.ZodOptional<z.ZodLiteral<"sig">>;
159
- alg: z.ZodOptional<z.ZodEnum<["RS256"]>>;
160
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
161
- kty: z.ZodLiteral<"RSA">;
162
- /** modulus, base64url */
163
- n: z.ZodString;
164
- /** exponent, base64url */
165
- e: z.ZodString;
166
- /** RFC 7638 thumbprint of the public JWK — the rotation-stable key id tokens carry in their header. */
167
- kid: z.ZodString;
168
- use: z.ZodOptional<z.ZodLiteral<"sig">>;
169
- alg: z.ZodOptional<z.ZodEnum<["RS256"]>>;
170
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
171
- kty: z.ZodLiteral<"RSA">;
172
- /** modulus, base64url */
173
- n: z.ZodString;
174
- /** exponent, base64url */
175
- e: z.ZodString;
176
- /** RFC 7638 thumbprint of the public JWK — the rotation-stable key id tokens carry in their header. */
177
- kid: z.ZodString;
178
- use: z.ZodOptional<z.ZodLiteral<"sig">>;
179
- alg: z.ZodOptional<z.ZodEnum<["RS256"]>>;
180
- }, z.ZodTypeAny, "passthrough">>, "many">;
181
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
182
- keys: z.ZodArray<z.ZodObject<{
183
- kty: z.ZodLiteral<"RSA">;
184
- /** modulus, base64url */
185
- n: z.ZodString;
186
- /** exponent, base64url */
187
- e: z.ZodString;
188
- /** RFC 7638 thumbprint of the public JWK — the rotation-stable key id tokens carry in their header. */
189
- kid: z.ZodString;
190
- use: z.ZodOptional<z.ZodLiteral<"sig">>;
191
- alg: z.ZodOptional<z.ZodEnum<["RS256"]>>;
192
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
193
- kty: z.ZodLiteral<"RSA">;
194
- /** modulus, base64url */
195
- n: z.ZodString;
196
- /** exponent, base64url */
197
- e: z.ZodString;
198
- /** RFC 7638 thumbprint of the public JWK — the rotation-stable key id tokens carry in their header. */
199
- kid: z.ZodString;
200
- use: z.ZodOptional<z.ZodLiteral<"sig">>;
201
- alg: z.ZodOptional<z.ZodEnum<["RS256"]>>;
202
- }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
203
- kty: z.ZodLiteral<"RSA">;
204
- /** modulus, base64url */
205
108
  n: z.ZodString;
206
- /** exponent, base64url */
207
109
  e: z.ZodString;
208
- /** RFC 7638 thumbprint of the public JWK — the rotation-stable key id tokens carry in their header. */
209
110
  kid: z.ZodString;
210
111
  use: z.ZodOptional<z.ZodLiteral<"sig">>;
211
- alg: z.ZodOptional<z.ZodEnum<["RS256"]>>;
212
- }, z.ZodTypeAny, "passthrough">>, "many">;
213
- }, z.ZodTypeAny, "passthrough">>;
214
- export type RegistryJwks = z.infer<typeof RegistryJwks>;
112
+ alg: z.ZodOptional<z.ZodEnum<{
113
+ RS256: "RS256";
114
+ }>>;
115
+ }, z.core.$loose>>;
116
+ }, z.core.$loose>;
117
+ export type WebAdminJwks = z.infer<typeof WebAdminJwks>;
215
118
  /** Everything the service verifier is allowed to be configured with. In the zero-new-config deployment the
216
- * worker derives `jwksUrl` from the registry base URL it already has (config pull) + REGISTRY_JWKS_PATH,
217
- * and `issuer` from the same registry identity — but both stay explicit here so a split deployment
119
+ * worker derives `jwksUrl` from web-admin base URL it already has (config pull) + WEB_ADMIN_JWKS_PATH,
120
+ * and `issuer` from the same web-admin identity — but both stay explicit here so a split deployment
218
121
  * (issuer behind a proxy ≠ fetch URL) is expressible. */
219
122
  export declare const VerifierConfig: z.ZodObject<{
220
- /** R4 — the EXACT expected `iss` (the registry's SSO_ISSUER). Compare with trailing slash stripped. */
221
123
  issuer: z.ZodString;
222
- /** R2 — absolute JWKS URL. Default: issuer (or the worker's registry base URL) + REGISTRY_JWKS_PATH. */
223
124
  jwksUrl: z.ZodOptional<z.ZodString>;
224
- /** R7 — when set, `aud` must contain this value; unset = aud ignored. */
225
125
  audience: z.ZodOptional<z.ZodString>;
226
- /** R5 — seconds of exp/nbf tolerance. Default DEFAULT_CLOCK_SKEW_SEC (60). */
227
126
  clockSkewSec: z.ZodDefault<z.ZodNumber>;
228
- /** R3 — min seconds between forced kid-miss refetches. Default 60. */
229
127
  jwksRefreshMinIntervalSec: z.ZodDefault<z.ZodNumber>;
230
- /** R8 — seconds a stale cache survives fetch failures before fail-closed. Default 86400 (24h). */
231
128
  offlineGraceSec: z.ZodDefault<z.ZodNumber>;
232
- }, "strip", z.ZodTypeAny, {
233
- issuer: string;
234
- clockSkewSec: number;
235
- jwksRefreshMinIntervalSec: number;
236
- offlineGraceSec: number;
237
- jwksUrl?: string | undefined;
238
- audience?: string | undefined;
239
- }, {
240
- issuer: string;
241
- jwksUrl?: string | undefined;
242
- audience?: string | undefined;
243
- clockSkewSec?: number | undefined;
244
- jwksRefreshMinIntervalSec?: number | undefined;
245
- offlineGraceSec?: number | undefined;
246
- }>;
129
+ }, z.core.$strip>;
247
130
  export type VerifierConfig = z.infer<typeof VerifierConfig>;
248
131
  /** The pre-parse (all-optional-defaults) input shape, for consumers assembling config by hand. */
249
132
  export type VerifierConfigInput = z.input<typeof VerifierConfig>;
@@ -252,28 +135,12 @@ export declare const AUTH_BRIDGE_ERROR_CODES: readonly ["expired", "invalid_sign
252
135
  export type AuthBridgeErrorCode = (typeof AUTH_BRIDGE_ERROR_CODES)[number];
253
136
  /** R9 success output — what the verifier middleware hands the existing principal pipeline. */
254
137
  export declare const VerifiedIdentity: z.ZodObject<{
255
- /** = token `sub`. Feeds x-agent-principal / owner semantics / costQuota / entitlement keying verbatim. */
256
138
  principal: z.ZodString;
257
- /** = token `role` claim (registry RBAC: admin/editor/viewer/…) — informational; the worker maps it to
258
- * its own authz, it does NOT replace worker-side entitlement checks. */
259
139
  role: z.ZodOptional<z.ZodString>;
260
- /** = token `jti` when present (the auth_grants grant id — audit correlation). Absent today; optional forever. */
261
140
  grantId: z.ZodOptional<z.ZodString>;
262
- /** = token `scope` claim when present (the active tenant scope, `api/scopes`) — transparently forwarded
263
- * to the worker's principal pipeline. ABSENT means the pre-scope/default token: semantically "global"
264
- * (use `tokenScopeOf` from api/scopes to normalize). Optional forever — backward compatible. */
265
141
  scope: z.ZodOptional<z.ZodString>;
266
- }, "strip", z.ZodTypeAny, {
267
- principal: string;
268
- scope?: string | undefined;
269
- role?: string | undefined;
270
- grantId?: string | undefined;
271
- }, {
272
- principal: string;
273
- scope?: string | undefined;
274
- role?: string | undefined;
275
- grantId?: string | undefined;
276
- }>;
142
+ iat: z.ZodOptional<z.ZodNumber>;
143
+ }, z.core.$strip>;
277
144
  export type VerifiedIdentity = z.infer<typeof VerifiedIdentity>;
278
145
  /** The verifier's total result — exactly one of ok/error. */
279
146
  export type AuthBridgeResult = {
@@ -308,12 +175,14 @@ export declare function shouldForceJwksRefresh(kid: string, cache: JwksCacheSnap
308
175
  export declare function jwksWithinOfflineGrace(cache: Pick<JwksCacheSnapshot, "lastFetchSuccessMs" | "nowMs">, cfg: Pick<VerifierConfig, "offlineGraceSec">): boolean;
309
176
  /**
310
177
  * R5 — classify the token's time window. `exp` REQUIRED (a JWT without exp is not acceptable here —
311
- * registry tokens always carry one; classify a missing exp as "expired" so it can never live forever).
312
- * All values in SECONDS (JWT NumericDate).
178
+ * web-admin tokens always carry one; classify a missing exp as "expired" so it can never live forever).
179
+ * `nbf` / `iat`, when present, must not lie beyond now + skew (not yet valid / issued in the future).
180
+ * All values in SECONDS (JWT NumericDate); one tolerance (`clockSkewSec`) for all three.
313
181
  */
314
182
  export declare function classifyTimeClaims(claims: {
315
183
  exp?: number;
316
184
  nbf?: number;
185
+ iat?: number;
317
186
  }, nowSec: number, clockSkewSec: number): "ok" | "expired";
318
187
  /**
319
188
  * R6/R7/R9 — map a signature-verified payload to the identity, or reject. Pure: call AFTER the JWT
@@ -325,6 +194,7 @@ export declare function toVerifiedIdentity(payload: {
325
194
  jti?: unknown;
326
195
  aud?: unknown;
327
196
  scope?: unknown;
197
+ iat?: unknown;
328
198
  }, cfg?: Pick<VerifierConfig, "audience">): AuthBridgeResult;
329
199
  /** Cheap pre-filter: does this bearer LOOK like a JWT (three non-empty dot-separated segments)? Use it to
330
200
  * route between the existing static-token branch and this verifier — NOT as any kind of validation. */