@sema-agent/settings-schema 14.6.0 → 14.8.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 (95) hide show
  1. package/CHANGELOG.md +475 -0
  2. package/README.md +89 -5
  3. package/conformance/VERSION +1 -1
  4. package/conformance/cases/c84-sandbox-git-block-carried-verbatim/expected.json +153 -0
  5. package/conformance/cases/c84-sandbox-git-block-carried-verbatim/input.json +23 -0
  6. package/conformance/cases/c84-sandbox-git-block-carried-verbatim/meta.json +5 -0
  7. package/conformance/cases/c85-sandbox-git-refused-block-still-carried/expected.json +153 -0
  8. package/conformance/cases/c85-sandbox-git-refused-block-still-carried/input.json +23 -0
  9. package/conformance/cases/c85-sandbox-git-refused-block-still-carried/meta.json +5 -0
  10. package/dist/api/auth-bridge.d.ts +16 -2
  11. package/dist/api/auth-bridge.js +59 -24
  12. package/dist/api/credentials.d.ts +281 -0
  13. package/dist/api/credentials.js +149 -0
  14. package/dist/api/scopes.js +5 -1
  15. package/dist/atomic-write.d.ts +15 -0
  16. package/dist/atomic-write.js +109 -5
  17. package/dist/catalog-manages.d.ts +15 -0
  18. package/dist/catalog-manages.js +60 -0
  19. package/dist/center-refs.d.ts +68 -0
  20. package/dist/center-refs.js +70 -0
  21. package/dist/config-d-file.js +33 -15
  22. package/dist/config-dir-migration.js +1 -0
  23. package/dist/config-fns.js +147 -81
  24. package/dist/config-root-documents.d.ts +106 -0
  25. package/dist/config-root-documents.js +93 -0
  26. package/dist/config-root-node.d.ts +117 -0
  27. package/dist/config-root-node.js +260 -0
  28. package/dist/conformance/canonical.js +4 -4
  29. package/dist/conformance/contract-adapter.js +26 -1
  30. package/dist/conformance/corpus.js +4 -4
  31. package/dist/conformance/derive.js +2 -2
  32. package/dist/conformance/run.d.ts +3 -0
  33. package/dist/conformance/run.js +53 -12
  34. package/dist/conformance/temp-roots.d.ts +31 -0
  35. package/dist/conformance/temp-roots.js +184 -0
  36. package/dist/cross-session.d.ts +4 -4
  37. package/dist/declared-capture.d.ts +41 -0
  38. package/dist/declared-capture.js +344 -0
  39. package/dist/default-model.d.ts +1 -1
  40. package/dist/default-model.js +5 -4
  41. package/dist/env-model-table.d.ts +163 -0
  42. package/dist/env-model-table.js +257 -0
  43. package/dist/file-edit.js +11 -15
  44. package/dist/fleet.d.ts +36 -7
  45. package/dist/fleet.js +83 -32
  46. package/dist/hash.d.ts +0 -9
  47. package/dist/hash.js +64 -7
  48. package/dist/hooks-config.js +18 -3
  49. package/dist/http-hook-allowlists.d.ts +22 -9
  50. package/dist/http-hook-allowlists.js +169 -91
  51. package/dist/index.d.ts +7 -0
  52. package/dist/index.js +7 -0
  53. package/dist/mcp-request-entry.d.ts +67 -13
  54. package/dist/mcp-request-entry.js +132 -93
  55. package/dist/mcp-server-name.d.ts +17 -0
  56. package/dist/mcp-server-name.js +19 -0
  57. package/dist/migration-receipt.d.ts +10 -6
  58. package/dist/migration-receipt.js +5 -3
  59. package/dist/node.d.ts +1 -0
  60. package/dist/node.js +2 -0
  61. package/dist/one-time-migrations.d.ts +4 -2
  62. package/dist/one-time-migrations.js +236 -96
  63. package/dist/own-key-read.d.ts +247 -0
  64. package/dist/own-key-read.js +449 -0
  65. package/dist/plain-json-object.d.ts +11 -1
  66. package/dist/plain-json-object.js +37 -1
  67. package/dist/remote-exec.js +9 -1
  68. package/dist/retired-form.d.ts +19 -0
  69. package/dist/retired-form.js +24 -1
  70. package/dist/safety-merge-spec.d.ts +6 -6
  71. package/dist/safety-merge-spec.js +50 -37
  72. package/dist/sandbox-git.d.ts +64 -0
  73. package/dist/sandbox-git.js +89 -0
  74. package/dist/scheduler-store.js +19 -11
  75. package/dist/settings-units.js +14 -12
  76. package/dist/tier-words.d.ts +33 -0
  77. package/dist/tier-words.js +43 -0
  78. package/dist/types.d.ts +12 -2
  79. package/dist/types.js +35 -6
  80. package/dist/url-shape.d.ts +16 -0
  81. package/dist/url-shape.js +18 -0
  82. package/dist/web-admin-credential.js +5 -2
  83. package/dist/web-admin-session-url.js +2 -2
  84. package/dist/worker-row-verdict.d.ts +11 -0
  85. package/dist/worker-row-verdict.js +58 -2
  86. package/dist/workers-rows.js +38 -10
  87. package/dist/zod-unwrap.d.ts +6 -0
  88. package/dist/zod-unwrap.js +14 -7
  89. package/docs/API-SURFACE.md +100 -5
  90. package/docs/CONSUMER-INTEGRATION.md +250 -2
  91. package/llms-full.txt +26 -4
  92. package/llms.txt +11 -4
  93. package/package.json +2 -2
  94. package/dist/definition-copy.d.ts +0 -23
  95. package/dist/definition-copy.js +0 -52
@@ -4,9 +4,9 @@
4
4
  > 每次全量重算并逐名比对 —— 加 / 删 / 改形一个导出而不重生成本档 ⇒ 红。导出面的每次变动因此以本档的 diff 出现在评审里。
5
5
  > 形:`value` = 运行期拿得到的值;`type` = 只在类型层;`value+type` = 同名的值与类型(zod schema 与它推出的类型)。
6
6
 
7
- 子路径 24 条(资产出口 `./package.json` / `./fleet-paths.json` 不是模块,不列),导出名合计 1365 个(同名在多条子路径上各计一次)。
7
+ 子路径 24 条(资产出口 `./package.json` / `./fleet-paths.json` 不是模块,不列),导出名合计 1460 个(同名在多条子路径上各计一次)。
8
8
 
9
- ## `.`(680)
9
+ ## `.`(761)
10
10
 
11
11
  - `ABSOLUTE_HOST_PATH_MAX` — value
12
12
  - `ACCESS_TOKEN_TTL_SECONDS` — value
@@ -33,8 +33,12 @@
33
33
  - `BaseHookInput` — value+type
34
34
  - `BudgetGroup` — value+type
35
35
  - `BudgetGroupMember` — value
36
+ - `CATALOG_REPLACES_ENV_MODELS_CODE` — value
37
+ - `CENTER_REFS_VERDICTS` — value
38
+ - `CENTER_REF_FAULTS` — value
36
39
  - `COMMAND_DECISIONS` — value
37
40
  - `CONFIG_CHANGE_SOURCES` — value
41
+ - `CONFIG_ROOT_DOCUMENTS` — value
38
42
  - `CONTROL_AND_BIDI_CHARS` — value
39
43
  - `CREDENTIAL_PARAM_NAMES` — value
40
44
  - `CROSS_SESSION_INBOUND_UNSET` — value
@@ -44,6 +48,12 @@
44
48
  - `CasWriteResult` — type
45
49
  - `CatalogDefaultModel` — type
46
50
  - `CatalogDefaultSource` — type
51
+ - `CenterRefFault` — type
52
+ - `CenterRefLookup` — type
53
+ - `CenterRefMember` — type
54
+ - `CenterRefMemberVerdict` — type
55
+ - `CenterRefsResolution` — type
56
+ - `CenterRefsVerdict` — type
47
57
  - `CollabConfig` — value+type
48
58
  - `CollabEarlyStop` — value+type
49
59
  - `CollabFinalizerType` — value+type
@@ -56,7 +66,10 @@
56
66
  - `ConfigChangeHookInput` — value
57
67
  - `ConfigPath` — type
58
68
  - `ConfigReader` — type
69
+ - `ConfigRootDocument` — type
70
+ - `CredentialHandleAnswer` — value+type
59
71
  - `CredentialParamName` — type
72
+ - `CredentialResolveRequest` — value+type
60
73
  - `CrossSessionInboundSetting` — value
61
74
  - `CrossSessionInboundSettingValue` — type
62
75
  - `CrossSessionInboundValue` — type
@@ -69,6 +82,7 @@
69
82
  - `DEFAULT_HEARTBEAT_MS` — value
70
83
  - `DEFAULT_HOOK_TIMEOUT_SECONDS` — value
71
84
  - `DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC` — value
85
+ - `DEFAULT_MODEL_KEY` — value
72
86
  - `DEFAULT_OFFLINE_GRACE_SEC` — value
73
87
  - `DEFAULT_ROLE_TIER_LADDER` — value
74
88
  - `DELIVER_DENYLIST` — value
@@ -119,6 +133,9 @@
119
133
  - `DroppedEntryReasonCode` — type
120
134
  - `ENGINE_OWNED_HOOK_EVENTS` — value
121
135
  - `ENGINE_SIGNAL_KEY` — value
136
+ - `ENV_MODELS_DECISIONS` — value
137
+ - `ENV_MODELS_DOCUMENT` — value
138
+ - `ENV_MODEL_TABLE_KEYS` — value
122
139
  - `ENV_NAME` — value
123
140
  - `EXECUTION_LANES` — value
124
141
  - `EXECUTION_LANE_WORDS` — value
@@ -141,8 +158,23 @@
141
158
  - `EntitlementTier` — value+type
142
159
  - `EntryKeptIndex` — type
143
160
  - `EntrySalvageResult` — type
161
+ - `EnvCheapSlot` — type
162
+ - `EnvModelBaseline` — type
163
+ - `EnvModelTableEntry` — type
164
+ - `EnvModelTableKey` — type
165
+ - `EnvModelTableLanding` — type
166
+ - `EnvModelTableReceipt` — type
167
+ - `EnvModelTableRoleRow` — type
168
+ - `EnvModelTableTarget` — type
169
+ - `EnvModelTableWriteInput` — type
170
+ - `EnvModelTableWriteIntent` — type
171
+ - `EnvModelTableWritePlan` — type
172
+ - `EnvModelsDecision` — type
173
+ - `EnvModelsDecisionWord` — type
144
174
  - `EnvRef` — type
145
175
  - `EnvRefUse` — type
176
+ - `EnvRoleBinding` — type
177
+ - `EnvSnapshot` — type
146
178
  - `ExecutionLane` — type
147
179
  - `ExecutionLaneRow` — type
148
180
  - `ExecutionPolicy` — value+type
@@ -151,6 +183,7 @@
151
183
  - `FEEDBACK_DESCRIPTION_MAX_CHARS` — value
152
184
  - `FEEDBACK_TRANSCRIPT_MAX_JSON_CHARS` — value
153
185
  - `FEEDBACK_V1_PATH` — value
186
+ - `FLEET_ADVERTISE_ADDRESS_ENV` — value
154
187
  - `FLEET_GENERATION_ENV` — value
155
188
  - `FLEET_LIVE_PATHS` — value
156
189
  - `FLEET_PATHS` — value
@@ -242,6 +275,7 @@
242
275
  - `MODEL_ENTRY_REFUSAL_CODES` — value
243
276
  - `MODEL_PLANE_REFUSAL_CODES` — value
244
277
  - `MODEL_SWITCH_SOURCES` — value
278
+ - `MarkedMigrationId` — type
245
279
  - `McpConfig` — value+type
246
280
  - `McpContentOrigin` — type
247
281
  - `McpEntryKeyIssue` — type
@@ -261,6 +295,7 @@
261
295
  - `MergeCategorySpec` — value+type
262
296
  - `MergeShape` — value+type
263
297
  - `MessageDisplayHookInput` — value
298
+ - `MigrationMarker` — type
264
299
  - `MinTrust` — value+type
265
300
  - `ModelCost` — value
266
301
  - `ModelEntry` — value+type
@@ -280,7 +315,11 @@
280
315
  - `OAuthErrorCode` — type
281
316
  - `OAuthErrorResponse` — value+type
282
317
  - `PARSE_TRANSPARENT_KEYS` — value
318
+ - `PATH_BASE_URL_FORBIDDEN_PARTS` — value
319
+ - `PLAIN_STRING_RECORD_FAULTS` — value
320
+ - `PLAIN_STRING_RECORD_RESERVED_MEMBER` — value
283
321
  - `PLUGIN_ORIGIN` — value
322
+ - `PRINCIPAL_INC_CLAIM` — value
284
323
  - `PRINCIPAL_MAX_LENGTH` — value
285
324
  - `PRIVATE_KEY_PEM_HEADER` — value
286
325
  - `PROBE_CPU_CORES_MAX` — value
@@ -303,6 +342,8 @@
303
342
  - `PermissionRuleValue` — value+type
304
343
  - `PermissionUpdate` — value+type
305
344
  - `PermissionUpdateDestination` — value+type
345
+ - `PlainStringRecordFault` — type
346
+ - `PlainStringRecordRead` — type
306
347
  - `PluginSource` — value+type
307
348
  - `PluginSpec` — value+type
308
349
  - `PluginsConfig` — value+type
@@ -316,6 +357,7 @@
316
357
  - `PreModelSwitchHookInput` — value+type
317
358
  - `PreToolUseHookInput` — value
318
359
  - `PrincipalCapsWire` — value+type
360
+ - `PrincipalIncarnation` — value+type
319
361
  - `PrincipalOrgMemoryWire` — value+type
320
362
  - `ProjectContextItem` — value+type
321
363
  - `ProjectContextItemKind` — type
@@ -343,6 +385,7 @@
343
385
  - `REF_ISSUE_TARGET_DOMAIN` — value
344
386
  - `REF_REFERRER_DOMAINS` — value
345
387
  - `REMOTE_EXEC_DOCUMENT` — value
388
+ - `REMOTE_MCP_SERVER_NAME_PREFIX` — value
346
389
  - `RESERVED_SCOPE_IDS` — value
347
390
  - `RESERVED_WORKER_ENV` — value
348
391
  - `RETIRED_DOMAINS` — value
@@ -350,6 +393,7 @@
350
393
  - `RETIRED_ENV_REFUSAL_CODE` — value
351
394
  - `RETIRED_LANE_WORDS` — value
352
395
  - `ROLE_RANK` — value
396
+ - `ROOT_DOCUMENT_UNREADABLE_REASONS` — value
353
397
  - `ROSTER_CHEAP_ROLES` — value
354
398
  - `ROSTER_PRIMARY_ROLES` — value
355
399
  - `RUNTIME_CAP_STRICT` — value
@@ -373,10 +417,18 @@
373
417
  - `RetiredEnvWire` — type
374
418
  - `RetiredLaneWord` — type
375
419
  - `RoleTarget` — value+type
420
+ - `RootDocumentUnreadableReason` — type
376
421
  - `RosterEntry` — value+type
377
422
  - `RostersConfig` — value+type
378
423
  - `RoutingVerdict` — type
379
424
  - `SAFETY_MERGE_SPEC` — value
425
+ - `SANDBOX_GIT_MAX_ORIGINS` — value
426
+ - `SANDBOX_GIT_ORIGIN_REASONS` — value
427
+ - `SANDBOX_GIT_ORIGIN_STATES` — value
428
+ - `SANDBOX_GIT_ORIGIN_VERDICTS` — value
429
+ - `SANDBOX_GIT_PERMANENCE` — value
430
+ - `SANDBOX_GIT_REFUSALS` — value
431
+ - `SANDBOX_GIT_REFUSAL_ERRORS` — value
380
432
  - `SCOPES_V1_PATHS` — value
381
433
  - `SCOPE_CLAIM` — value
382
434
  - `SCOPE_ID_REGEX` — value
@@ -401,8 +453,22 @@
401
453
  - `STALE_SESSION_RECORD_MS` — value
402
454
  - `STORE_BACKENDS` — value
403
455
  - `SUBMIT_IDEMPOTENCY_KEY` — value
456
+ - `SUMMARIZE_MODEL_MISSING_CODE` — value
404
457
  - `SafetyMergeCategory` — type
405
458
  - `SafetyMergeMember` — type
459
+ - `SandboxGitConfig` — value+type
460
+ - `SandboxGitConnectUrl` — value+type
461
+ - `SandboxGitCredentialAnswer` — value+type
462
+ - `SandboxGitCredentialRefusal` — value+type
463
+ - `SandboxGitCredentialRequest` — value+type
464
+ - `SandboxGitOrigin` — value+type
465
+ - `SandboxGitOriginAnswer` — value+type
466
+ - `SandboxGitOriginEntry` — value+type
467
+ - `SandboxGitOriginList` — value+type
468
+ - `SandboxGitOriginReason` — type
469
+ - `SandboxGitOriginState` — type
470
+ - `SandboxGitPermanence` — type
471
+ - `SandboxGitRefusalError` — type
406
472
  - `ScenarioAssignments` — value+type
407
473
  - `ScenarioConfig` — value+type
408
474
  - `ScenarioEntry` — value+type
@@ -535,9 +601,11 @@
535
601
  - `aggregateUsage` — value
536
602
  - `applyProjectPatch` — value
537
603
  - `buildEffective` — value
604
+ - `buildEnvModelBaseline` — value
538
605
  - `buildLayerPartsUnreadNotice` — value
539
606
  - `buildRetiredEnvWire` — value
540
607
  - `canSwitchScope` — value
608
+ - `catalogManagesModelPlane` — value
541
609
  - `clampServingLeaseTtlMs` — value
542
610
  - `classifyHooksConfig` — value
543
611
  - `classifyTimeClaims` — value
@@ -547,6 +615,7 @@
547
615
  - `createSiblingResolver` — value
548
616
  - `danglingRefs` — value
549
617
  - `describeBadContentOrigin` — value
618
+ - `describeBadMcpServerName` — value
550
619
  - `describeBadWireName` — value
551
620
  - `describeNotStringArray` — value
552
621
  - `describeNotStringRecord` — value
@@ -555,6 +624,10 @@
555
624
  - `drainVerdict` — value
556
625
  - `effectiveScopeRole` — value
557
626
  - `emptyEffective` — value
627
+ - `enabledEntryCount` — value
628
+ - `envModelTableDeclared` — value
629
+ - `envModelTableWriteRefusal` — value
630
+ - `envModelsDecisionTag` — value
558
631
  - `extraBodyUnsafe` — value
559
632
  - `findSkillContent` — value
560
633
  - `findUrlCredential` — value
@@ -589,9 +662,11 @@
589
662
  - `isRetiredDomainName` — value
590
663
  - `isRole` — value
591
664
  - `isRoutable` — value
665
+ - `isSandboxGitOrigin` — value
592
666
  - `isSchedulerRecord` — value
593
667
  - `isStringArray` — value
594
668
  - `isStringRecord` — value
669
+ - `isUsableMcpServerName` — value
595
670
  - `isUsableWireName` — value
596
671
  - `judgeReadiness` — value
597
672
  - `judgeRoutability` — value
@@ -608,6 +683,7 @@
608
683
  - `memberTighten` — value
609
684
  - `membersOf` — value
610
685
  - `mintScopedToken` — value
686
+ - `mintedCheapId` — value
611
687
  - `narrowAtMention` — value
612
688
  - `nextPollInterval` — value
613
689
  - `normalizeContentHash` — value
@@ -619,7 +695,9 @@
619
695
  - `parseSchedulerStore` — value
620
696
  - `parseWebAdminCredentialFile` — value
621
697
  - `parseWebAdminSessionUrl` — value
698
+ - `pathBaseUrlFlaws` — value
622
699
  - `pickInstance` — value
700
+ - `planEnvModelTableWrite` — value
623
701
  - `projectWarning` — value
624
702
  - `promptArtifactFor` — value
625
703
  - `readCapabilityReading` — value
@@ -629,9 +707,11 @@
629
707
  - `readDrainRequest` — value
630
708
  - `readEffectiveWire` — value
631
709
  - `readEngineSignal` — value
710
+ - `readEnvModelSlots` — value
632
711
  - `readHttpHookAllowlistLayer` — value
633
712
  - `readMcpIdentityHeaders` — value
634
713
  - `readModelRefusals` — value
714
+ - `readPlainStringRecord` — value
635
715
  - `readRequestMcpTransport` — value
636
716
  - `readScopedTokenBinding` — value
637
717
  - `readServingLeaseRequest` — value
@@ -649,6 +729,7 @@
649
729
  - `renderRefIssue` — value
650
730
  - `resolveActiveTiers` — value
651
731
  - `resolveCatalogDefaultModel` — value
732
+ - `resolveCenterRefs` — value
652
733
  - `resolveEffectiveForWorker` — value
653
734
  - `resolveMemberAdmission` — value
654
735
  - `resolveMemberTighten` — value
@@ -1083,7 +1164,7 @@
1083
1164
  - `tightenVerdict` — value
1084
1165
  - `trustRank` — value
1085
1166
 
1086
- ## `./node`(39)
1167
+ ## `./node`(48)
1087
1168
 
1088
1169
  - `ConfigBundle` — type
1089
1170
  - `ConfigDirectoryDocument` — type
@@ -1091,7 +1172,11 @@
1091
1172
  - `ConfigDirectoryMigration` — type
1092
1173
  - `ConfigDirectoryRefusal` — type
1093
1174
  - `ConfigDocumentsMigration` — type
1175
+ - `ConfigRootIo` — type
1094
1176
  - `DomainReadError` — type
1177
+ - `EnvModelsDecisionWrite` — type
1178
+ - `EnvModelsMigration` — type
1179
+ - `EnvModelsMint` — type
1095
1180
  - `FileConfigStore` — value+type
1096
1181
  - `LocalConfig` — type
1097
1182
  - `MigrateConfigDirectoryOptions` — type
@@ -1114,15 +1199,20 @@
1114
1199
  - `loadSchedulerStore` — value
1115
1200
  - `migrateConfigDirectory` — value
1116
1201
  - `migrateConfigDocuments` — value
1202
+ - `migrateEnvModelsDecision` — value
1117
1203
  - `mutateSchedulerStore` — value
1118
1204
  - `nodeConfigDirectoryIo` — value
1205
+ - `nodeConfigRootIo` — value
1119
1206
  - `readBundle` — value
1207
+ - `readEnvModelsDecision` — value
1208
+ - `readMigrationMarker` — value
1120
1209
  - `remoteExecPath` — value
1121
1210
  - `saveSchedulerStore` — value
1122
1211
  - `validateDomain` — value
1123
1212
  - `validateRemoteExec` — value
1124
1213
  - `writeBundle` — value
1125
1214
  - `writeDomainFile` — value
1215
+ - `writeEnvModelsDecision` — value
1126
1216
  - `writeRemoteExec` — value
1127
1217
 
1128
1218
  ## `./one-time-migrations`(18)
@@ -1256,9 +1346,10 @@
1256
1346
  - `interpolateHookEnvVars` — value
1257
1347
  - `stopAttributionText` — value
1258
1348
 
1259
- ## `./fleet`(83)
1349
+ ## `./fleet`(86)
1260
1350
 
1261
1351
  - `AggregatedPrincipalUsage` — type
1352
+ - `CATALOG_REPLACES_ENV_MODELS_CODE` — value
1262
1353
  - `CapabilityReading` — type
1263
1354
  - `DEFAULT_DRAIN_GRACE_MS` — value
1264
1355
  - `DEFAULT_HEARTBEAT_MS` — value
@@ -1280,6 +1371,7 @@
1280
1371
  - `ENGINE_SIGNAL_KEY` — value
1281
1372
  - `EngineDraining` — value+type
1282
1373
  - `EngineSignal` — value+type
1374
+ - `FLEET_ADVERTISE_ADDRESS_ENV` — value
1283
1375
  - `FLEET_GENERATION_ENV` — value
1284
1376
  - `FLEET_LIVE_PATHS` — value
1285
1377
  - `FLEET_PATHS` — value
@@ -1311,6 +1403,7 @@
1311
1403
  - `SERVING_LEASE_VERDICTS` — value
1312
1404
  - `STALE_HEARTBEAT_MULTIPLIER` — value
1313
1405
  - `SUBMIT_IDEMPOTENCY_KEY` — value
1406
+ - `SUMMARIZE_MODEL_MISSING_CODE` — value
1314
1407
  - `ServingLeaseDeniedReason` — value+type
1315
1408
  - `ServingLeaseReading` — type
1316
1409
  - `ServingLeaseRequest` — value+type
@@ -1368,7 +1461,7 @@
1368
1461
  - `nextPollInterval` — value
1369
1462
  - `normalizeUserCode` — value
1370
1463
 
1371
- ## `./api/auth-bridge`(21)
1464
+ ## `./api/auth-bridge`(23)
1372
1465
 
1373
1466
  - `AUTH_BRIDGE_ALGS` — value
1374
1467
  - `AUTH_BRIDGE_ERROR_CODES` — value
@@ -1379,7 +1472,9 @@
1379
1472
  - `DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC` — value
1380
1473
  - `DEFAULT_OFFLINE_GRACE_SEC` — value
1381
1474
  - `JwksCacheSnapshot` — type
1475
+ - `PRINCIPAL_INC_CLAIM` — value
1382
1476
  - `PRINCIPAL_MAX_LENGTH` — value
1477
+ - `PrincipalIncarnation` — value+type
1383
1478
  - `VerifiedIdentity` — value+type
1384
1479
  - `VerifierConfig` — value+type
1385
1480
  - `VerifierConfigInput` — type
@@ -7,6 +7,9 @@
7
7
  > S-570 收车档;3.0.0 之后的下一次真实改动,请同一批把这份文档也带上,别再停摆。**7.0.0**(M-R2 WorkerSpec 结构块)的
8
8
  > 三方迁移句在 §0.2,`remoteExec` 删 `remote-docker` 在 §5。**8.0.0**(一致性门第四条腿 + 表态律 + CLI `--check`)在 §0.3。
9
9
  > **11.0.0** 的持久面(`runtime` 域退役、读侧兼容臂退役、一次性迁移族 `./one-time-migrations`)在 §0.4。
10
+ > **14.7.0** 的沙箱 git 凭据平面(取值口 wire 型、有效配置块 `sandboxGit`、`VerifiedIdentity.principalInc`)在 §12。
11
+ > **14.7.0** 的路径基址判官(`PATH_BASE_URL_FORBIDDEN_PARTS` / `pathBaseUrlFlaws`)与公告地址 env 名(`FLEET_ADVERTISE_ADDRESS_ENV`)在 §13。
12
+ > 中心引用解析口 `resolveCenterRefs` 与记录读器 `readPlainStringRecord`(原因词表 `PLAIN_STRING_RECORD_FAULTS`)在 §14。
10
13
 
11
14
  ---
12
15
 
@@ -116,7 +119,7 @@
116
119
  - **读侧的新形**:`ModelEntry` 钥匙二选一(`sealedApiKey` 与 `apiKeyEnv` 同设 ⇒ 拒);`atMention`(`{mode:"all"}` 缺省 /
117
120
  `{mode:"none"}` / `{mode:"only",models}`,roster 位缺席 = 继承,收窄读法一只 `narrowAtMention` —— 收窄到一个都不剩就是 `none`);
118
121
  workers 6.x 字段与 `atModelAllowlist` 是 schema 里原位的**墓碑字段**(在场即拒,句子点名迁移);`readWorkersRows(raw) → { doc, held }`
119
- (workers 域的逐行终判,取代 `migrateWorkersDomain` 的终判半)。
122
+ (workers 域的逐行终判,取代 `migrateWorkersDomain` 的终判半;被扣下的行若还带着旧字段,`held[].field` 指到那个旧字段,`reason` 的文字**不点名它**,说现行位与出路:跑迁移,迁移已拒过这一行的就手写现行形、删旧字段)。
120
123
  - **调度店**:`parseSchedulerStore(text, { nowMs })` / `loadSchedulerStore(path, { nowMs })` 恒返回 `{ records, warnings }`(没有静默模式);
121
124
  整份文件不是 JSON 数组 ⇒ `unreadable-file`,`mutateSchedulerStore(path, fn, { nowMs })` 遇它不调 `fn`、不写(`reason: "unreadable_file"`);
122
125
  会话链上的记录(显式 `lifetime: "session"`)过期 ≥ 7 天 ⇒ 读时丢 + `stale-session-record`(`lifetime` 缺席读作 durable,不丢);所有写者走 `mutateSchedulerStore` 这一只原语(裸 load→save 是丢更新的竞争)。
@@ -214,7 +217,7 @@ server 直接拒启,不是静默降级。上一代 `SEMA_REGISTRY_*` 八名(`URL
214
217
  |---|---|---|
215
218
  | models / roles | `RunnerDeps.models`/`roles` | role 解析不变 |
216
219
  | skills | 本地=全文内联;远程=manifest + `fetchSkillContent(hash)` | 本地无 wire 跳,无需按 hash 回取 |
217
- | mcp | `TaskSpec.mcp`(allowTools + principalHeader) | env/header NAME→值解析 |
220
+ | mcp | `TaskSpec.mcp`(allowTools + principalHeader + sessionMetaKey) | env/header NAME→值解析;`sessionMetaKey` 本包原样承运,交给引擎之前可调引擎的 `judgeSessionMetaKey` 早判 |
218
221
  | limits(0.19.0,cost/限流族 14 键;11.0.0 起五个限额键的唯一位) | 消费方的限额面(server:`stage-limits`) | `.optional()` 无默认;本包只判结构,业务域值(下限/0 哨兵/跨键不变量)由消费方响亮拒 |
219
222
  | governance.autonomy / commandPolicy | 见 §6(小心区) | 经 tightenTaskSpec / combinePolicies |
220
223
  | rosters | control-plane only | `/effective` wire 经 `resolveEffectiveForWorker` 清空/剥离 |
@@ -236,6 +239,7 @@ server 直接拒启,不是静默降级。上一代 `SEMA_REGISTRY_*` 八名(`URL
236
239
  命令行 `migrate` 与这只函数同一份实现;写盘用的就是本包那一只原子写器(契约文档新建 0o644、已有的沿用原模式、符号链接保留)。
237
240
  手里已有存量文档原文、不经目录的消费方(例:命令行壳按层读 `settings` 里的 models 域,要的是「引擎起服那一次迁移之后这份文档整域读不读得进」)调同一个内核的同步口 `migrateConfigDocuments(docs, { documents })`(14.5.0,`./node`):
238
241
  同一个闭集的无 io 形(`refused` ⇒ 引擎同样不写回、整域落缺省;**反向不成立** —— 引擎对整个目录一判,别的文档被拒也会让整目录不写,单层单域的 `noop` / `migrated` 不保证引擎那一次放行;`docs` 是壳的写手要的迁移后那一份)。一层一次调用;**别自己把 `migrateStoredDocuments` 与 `parseDomain` 按这个顺序再组装一遍**。
242
+ - **路径基址判官与公告地址**:「别人要往它后面拼路径的基址」座位(中心基址三席、公告地址、会话链接基址)的禁用成分集 `PATH_BASE_URL_FORBIDDEN_PARTS` 与判官 `pathBaseUrlFlaws` 在本包,公告地址的 env 名是 `FLEET_ADVERTISE_ADDRESS_ENV`;**别手写 env 名、别手抄那三个词** —— 两方读法见 §13。
239
243
  - **会话网页链接**:要给用户一个 web-admin 里的会话链接,调 `webAdminSessionUrl(webBaseUrl, { worker, sessionId })`(`webBaseUrl` 取引擎 `/health` 自报的人用界面根 URL,
240
244
  `worker` 取引擎向 web-admin 登记用的 worker 名),得到 `<webBaseUrl>/chat?agent=<worker>&session=<sessionId>`;**别按地址形手拼** —— 路由属于 web-admin,模板与读回的
241
245
  `parseWebAdminSessionUrl(link)` 同在本包,路径与参数名只此一份。两位必填:只带 `session` 的链接会落到页面自己挑的 worker 上、可能找不到会话。
@@ -283,3 +287,247 @@ server 直接拒启,不是静默降级。上一代 `SEMA_REGISTRY_*` 八名(`URL
283
287
  这份档里重复展开。
284
288
  - 今天真接了这道门的:server(`wire` + `localRoot` 两条读腿)、管理面(`domains` 往返腿,钉在 6.x);cli 显式拒接 kit 读腿
285
289
  (壳不走上游 effective 读腿),client-core 零 import。8.0.0 起两家接线方都要对四条腿逐条表态(§0.3)。
290
+
291
+ ## 12. 沙箱 git 凭据平面(14.7.0 起)—— web-admin 与 server 两方的读法
292
+
293
+ 沙箱里的 git 用**成员本人**的凭据:凭据住在 web-admin 的凭据库,引擎的数据面按 run 的身份向取值口取,只在该成员自己的沙箱里经代理使用,永不进模型可读的容器。
294
+ 本节说**本包发什么、两方各自怎么读**。本包只有**形与词表**(纯、浏览器安全,零 IO);鉴权、委托、活表复核、行 MAC、租约与续期都是两方自己的事(§12.9 逐条列出)。
295
+
296
+ ### 12.1 本包发什么
297
+
298
+ | 件 | 在哪 | 是什么 |
299
+ |---|---|---|
300
+ | `isSandboxGitOrigin` · `SandboxGitOrigin` · `SandboxGitOriginList` · `SANDBOX_GIT_MAX_ORIGINS` | 主桶(`src/sandbox-git.ts`) | origin 的规范形判官与 zod 形;一个 origin 就是它自己的 WHATWG origin |
301
+ | `SandboxGitConfig` · `SandboxGitOriginEntry` · `SandboxGitConnectUrl` | 主桶 | 有效配置块 `sandboxGit` 的形 |
302
+ | `SandboxGitCredentialRequest` · `CredentialHandleAnswer` · `CredentialResolveRequest` · `SandboxGitCredentialAnswer` · `SandboxGitOriginAnswer` · `SandboxGitCredentialRefusal` | 主桶(`src/api/credentials.ts`,不开子路径) | 取值口两步的 wire 型 |
303
+ | `SANDBOX_GIT_ORIGIN_VERDICTS` → `SANDBOX_GIT_ORIGIN_STATES` · `SANDBOX_GIT_ORIGIN_REASONS`;`SANDBOX_GIT_REFUSALS` → `SANDBOX_GIT_REFUSAL_ERRORS`;`SANDBOX_GIT_PERMANENCE` | 主桶 | 三张词表(每个词只在 `src/api/credentials.ts` 里拼一次;状态词、原因词、错误词表与类型全由表派生) |
304
+ | `PRINCIPAL_INC_CLAIM`(`"sub_inc"`) · `PrincipalIncarnation` · `VerifiedIdentity.principalInc` | 主桶与 `./api/auth-bridge` | 令牌里的化身号声明 |
305
+ | `EffectiveWire.sandboxGit?: unknown` | 主桶(`types`) | `/effective` 载荷上的非域顶层键,逐字承运 |
306
+
307
+ 全部是加性(新导出 / 可选键),既有导出对既有输入的答案不变。
308
+
309
+ ### 12.2 有效配置块 `sandboxGit`
310
+
311
+ ```json
312
+ {
313
+ "sandboxGit": {
314
+ "origins": [
315
+ { "origin": "https://git.example.com:9999", "connectUrl": "https://console.example.com/connect/git" },
316
+ { "origin": "http://git.legacy.example:8080", "connectUrl": "https://console.example.com/connect/git" }
317
+ ]
318
+ }
319
+ }
320
+ ```
321
+
322
+ - **非域顶层键**:web-admin 按部署登记册**投影**,不是存储域 —— `buildEffective` 不产它、`FileConfigStore` 没有 `sandboxGit.json`(单机模式没有这个平面)。**可选、无默认**:键缺席 = 这个部署没有投影这一块。
323
+ - `readEffectiveWire` 对它走 open-world:**逐字承运,不校验、不丢**(`EffectiveWire.sandboxGit` 是 `unknown`)。**判它的唯一座位是 `SandboxGitConfig`**:消费方在用之前对 `wire.sandboxGit` 跑 `safeParse`。
324
+ - `origins` ≤ 16(`SANDBOX_GIT_MAX_ORIGINS`)、按 `origin` 两两不同,空表合法;解析剥未知键(前向兼容)。
325
+ - **规范形只有一条律**:`origin` 逐字等于 `new URL(origin).origin`,且 scheme ∈ {http, https}。小写 host、去缺省端口(443 / 80)、无尾斜杠、无 userinfo / 路径 / 查询 / 片段都是它的推论 ——
326
+ 凡 WHATWG 会改写的串(大写、缺省端口、IPv4 简写、百分号编码的 host、前后空白……)都不是规范形。**origin 不表达子路径部署**:`https://host/gitea` 不是 origin,判官拒;本包没有「削成 origin」的规范化器(把运维写的路径静默削掉会把凭据送到他没写的地方)。
327
+ - 🔴 **块里 http origin 可读**。它为什么送不出凭据是**逐 origin 应答里的一个词**(§12.4 第 1 行 `insecure_transport`)与能力读数里的一个词,不是块的校验拒:块若因一个 http origin 整块不可读,同块里的 https origin 一并失效,「逐 origin 说拒因」就无从谈起。
328
+ http origin 只配路由、永不取值,是 server 的事。
329
+ - `connectUrl` = 控制台「连接 Gitea(git)」页的绝对 **https** URL(`SandboxGitConnectUrl`:`NON_SECRET_URL_NO_MIGRATION` 的判据 + https)。
330
+
331
+ ### 12.3 取值口两步(wire 型)
332
+
333
+ ```
334
+ ① POST /api/v1/credentials/handles 请求 SandboxGitCredentialRequest → 200 CredentialHandleAnswer { handle, expiresAt }
335
+ ② POST /api/v1/credentials/resolve 请求 CredentialResolveRequest { handle } → 200 SandboxGitCredentialAnswer
336
+ → 非 2xx 体 SandboxGitCredentialRefusal { error, permanence, message }
337
+ ```
338
+
339
+ ```json
340
+ { "kind": "sandbox_git", "principal": "alice", "principalInc": "<化身号>", "scope": "team-android",
341
+ "origins": ["https://git.example.com:9999"], "sid": "<会话 id,审计标签>" }
342
+ ```
343
+
344
+ - `kind` 是字面量 `"sandbox_git"`;`principal` 的长度界同令牌 `sub`(`PRINCIPAL_MAX_LENGTH`);`principalInc` 就是 `PrincipalIncarnation`(与令牌 `sub_inc`、`VerifiedIdentity.principalInc` 是**同一只 schema 对象**);
345
+ `scope` 非空串(与 `readTokenScope` 读令牌声明同一条规则);`origins` 1–16 个、规范形、两两不同 —— **http origin 也收**(中心对它答判定序第 1 行,请求形不抢先拒)。
346
+ - 应答(200)里的 `principal` / `principalInc` / `scope` 是请求的**回显**;`answeredAt`(应答时刻)、`cacheUntil`(句柄到期)与 `active` 行里的 `expiresAt` 是**同一只钟**(中心的)给的毫秒:收方只该用它们的**差**,不拿它们和自己的钟比。
347
+ - 每个 origin 一行 `SandboxGitOriginAnswer`,按 `state` 判别。`active` 独有 `credentialId` `version` `username` `secret` `expiresAt`(OAuth 令牌:到期毫秒;个人访问令牌:`null`);`needs_reauth` 行带 `credentialId`;其余只有 `origin` / `state` / `reason`。
348
+ **解析一律剥未知键**,`secret` 只在 `active` 臂的形里 —— 别的臂收到也剥掉。`secret` 是应答里唯一的秘密位;`credentialId` / `version` / `auditId` 是不带值的审计位,日志里记它们、不记 `secret`。
349
+
350
+ ### 12.4 逐 origin 判定序表(`SANDBOX_GIT_ORIGIN_VERDICTS`,11 行,序即判定序)
351
+
352
+ 每个 origin 独立判,**首条命中即答**,一个 origin 的结果不影响别的 origin。`state` 六词、`reason` 十词都由这张表派生。
353
+
354
+ | 序 | 条件(什么事实命中) | `state` | `reason` |
355
+ |---|---|---|---|
356
+ | 1 | origin 的 scheme 不是 `https` | `insecure_transport` | `not_https` |
357
+ | 2 | 本部署本 scope 的登记册里没有这个 origin 的 git 应用 | `not_offered` | `not_in_registry` |
358
+ | 3 | 选行键下没有行 | `not_connected` | `no_row` |
359
+ | 4 | 行 `status = revoked`(吊销后无密文、留作审计锚的行) | `not_connected` | `revoked` |
360
+ | 5 | 行 `status = revoking` | `needs_reauth` | `revoking` |
361
+ | 6 | 行 `status = suspended` | `needs_reauth` | `suspended` |
362
+ | 7 | 行 `status = needs_reauth` | `needs_reauth` | `row_needs_reauth` |
363
+ | 8 | 行 `active`,但行 MAC 或解密 AAD 校验不过 | `needs_reauth` | `integrity_failed` |
364
+ | 9 | 行 `active`、OAuth、剩余寿命 < 600 s,单飞刷新得上游 `invalid_grant` 或其余 4xx(`invalid_grant` 时行同时置 `needs_reauth`) | `needs_reauth` | `refresh_rejected` |
365
+ | 10 | 同 9,刷新遇网络错 / 5xx / 超时,且现令牌剩余 < 60 s | `temporarily_unavailable` | `refresh_unavailable` |
366
+ | 11 | 其余(行 `active`;不需刷新,或刷新成功,或刷新暂不可用但现令牌剩余 ≥ 60 s) | `active` | — |
367
+
368
+ 选行键 = (scope, 属主键 = 主体 + 化身号, `sandbox_git`, origin);「条件」列是 web-admin 的判定逻辑,**不进运行期表**(本包不知道行状态、登记册、MAC)。状态 × 原因的配对由表定:`SandboxGitOriginAnswer` 每个状态一个臂,臂里 `reason` 的值域 = 表里该状态的行,原因贴在不属于它的状态上一律拒(状态 × 原因的整个叉积里,恰好表里那 10 对加上无原因的 `active` 被收下)。
369
+
370
+ ### 12.5 整次拒答表(`SANDBOX_GIT_REFUSALS`)
371
+
372
+ 体 = `{ "error", "permanence", "message" }`。`permanence` 两词:`terminal` = 不按定时重试;`transient` = 退避重试。**一个错误词的 permanence 是固定的**,拒体里再带一份只为收方不必查表 —— 两处不一致是畸形应答(`SandboxGitCredentialRefusal` 拒)。
373
+
374
+ | `error` | HTTP | `permanence` | 说明 |
375
+ |---|---|---|---|
376
+ | `caller_not_admitted` | 401 / 403 | terminal | 调用方不是被承认的舰队 worker |
377
+ | `scope_mismatch` | 403 | terminal | 请求的 scope 不等于调用方凭据的 scope |
378
+ | `incarnation_mismatch` | 403 | terminal | 请求的化身号不等于该主体当前的化身号 |
379
+ | `request_invalid` | 400 | terminal | 请求形不合(含 `principalInc` 缺或空) |
380
+ | `principal_not_live` | 403 | terminal | 主体活表复核不过 |
381
+ | `delegation_required` | 403 | terminal | 没有活的委托 |
382
+ | `vault_disabled` | 503 | terminal | 凭据库关着 |
383
+ | `vault_frozen` | 503 | terminal | 凭据库冻结 |
384
+ | `handle_invalid` | 401 | transient | 句柄验不过 / 已用 / 已过期 |
385
+ | `vault_unavailable` | 503 | transient | 凭据库暂不可用 |
386
+
387
+ 收方怎么处置某个词(例如哪些 terminal 可由用户动作恢复、哪些不可恢复)是收方的状态机,不在本包里。**错误词不在闭集 ⇒ 畸形应答,不是「当 transient 重试」。**
388
+
389
+ ### 12.6 `VerifiedIdentity.principalInc` 与令牌声明 `sub_inc`
390
+
391
+ 同名主体删号重建之后是**另一个人**:`sub` 只命名一个槽位,化身号才区分「同一个名字」与「同一个人」。
392
+
393
+ - `toVerifiedIdentity` 读声明 `PRINCIPAL_INC_CLAIM`(`sub_inc`):**在场且是非空串 ⇒ `identity.principalInc` 原样**(不 trim、不折大小写);**缺席 ⇒ 读出形里不铸键**(从不读成 `0` / 空串 / 别的占位);
394
+ **在场而不是非空串(数字含 0 / 空串 / `null` / 布尔 / 对象 / 数组)⇒ 该令牌 `malformed`**(与 `sub`、`iat` 同律:声明形是垃圾,不降级成缺席 —— 降级会把坏掉的签发方读成「没有化身号」)。
395
+ - **缺化身号不是本契约的拒**:读方要化身号而令牌没有时,答什么是读方的事(server 把它记成「化身号未记录」,取值一律不放)。
396
+ - 行为面唯一变化:此前令牌带了 `sub_inc` 声明也被忽略;从本版起它在场而形不对就拒。
397
+
398
+ ### 12.7 web-admin 做什么
399
+
400
+ - **铸令牌**:用 `PRINCIPAL_INC_CLAIM` 铸 `sub_inc`(值 = 会话建立时绑定的化身号,非空串)。「会话化身 = 用户行当前化身」的签发不变量是 web-admin 的,不是本包的。
401
+ - **投影 `sandboxGit`**:`origin` 必须已经是规范形(`isSandboxGitOrigin`),`connectUrl` 是 https;自己的出口先 `SandboxGitConfig.parse` 再发,拒掉的是运维配置的问题,不要静默改写。
402
+ - **收请求**:`SandboxGitCredentialRequest.safeParse` 不过 ⇒ `request_invalid`。
403
+ - **答应答**:按 `SANDBOX_GIT_ORIGIN_VERDICTS` 的序逐 origin 判,首条命中即答;用 `SandboxGitCredentialAnswer.parse` 过一遍再发(臂的键集错了在自己这里红,不要等收方判畸形)。
404
+ - **答拒**:`permanence` 取自 `SANDBOX_GIT_REFUSALS[error].permanence`,HTTP 状态取表里该词的状态集之一。
405
+
406
+ ### 12.8 server 做什么
407
+
408
+ - **读块**:`wire.sandboxGit` 缺席 ⇒ 没有这一块;在场 ⇒ `SandboxGitConfig.safeParse`,不过 ⇒ 当作没有任何 origin,并响亮说(坐标可记,拒句不回显值)。http origin 只配路由、永不取值。
409
+ - **读令牌**:`toVerifiedIdentity` 之后用 `identity.principalInc`;缺 ⇒ 化身号未记录(本契约不拒令牌)。
410
+ - **发请求 / 收应答**:`SandboxGitCredentialRequest` 构造后再发;应答先 `SandboxGitCredentialAnswer.safeParse`,**再**核逐条对应与回显(§12.9);`secret` 只存在于 `active` 行,日志里不出现。
411
+ - **收拒**:体过 `SandboxGitCredentialRefusal` 才算认得;`permanence` 读表(或读体 —— 二者已被形保证相等)。
412
+ - **时刻**:`answeredAt` / `cacheUntil` / `expiresAt` 只取差;不拿它们和 server 自己的钟比。
413
+
414
+ ### 12.9 本包不做的(如实)
415
+
416
+ - **应答与请求的逐条对应 / 回显相等**(`origins` 同序同长、`principal` / `principalInc` / `scope` 等于请求)是收方在 `safeParse` 之后要核的事,不在形里。
417
+ - **租约算术与续期状态机**(`cacheUntil` / `expiresAt` − `answeredAt` 的差、封顶、重试退避、「踢」)、哪些 terminal 词可恢复,都是 server 自己的。
418
+ - **取值口的另两种凭据**(`model` / `mcp_static`)的请求与应答形不在本节:它们落地时与 `sandbox_git` 形并成按 `kind` 判别的联合,`sandbox_git` 形不动(`kind` 字面量已经在)。`CredentialHandleAnswer` / `CredentialResolveRequest` 与种类无关,三种共用。
419
+ - **两个端点的路径常量**不在包里(上面的路径是文字,不是导出)。
420
+ - **调用方鉴权、委托、活表复核、行 MAC、冻结**:全是 web-admin 的。
421
+ - **一致性门**:没有新腿 —— `sandboxGit` 是 wire 专属键,走 §11 里 T4 那一条(open-world 逐字承运),既有语料的读数不变。新增两条语料(`c84` 合格块含一个 http origin、`c85` 不合格块):wire 腿都要把块**逐字承运、不出告警**,判它是消费方用 `SandboxGitConfig` 的事 —— 你的 wire 读腿若校验后丢掉坏块,跑语料时会在 `c85` 上红。
422
+
423
+ ## 13. 路径基址判官与公告地址 `FLEET_ADVERTISE_ADDRESS`(14.7.0 起)—— web-admin 编排器与 server 两方的读法
424
+
425
+ 有一种座位的值是「别人要往它后面拼路径的基址」:中心基址三席(`WEB_ADMIN_ENV.url` / `liveUrl` / `webUrl`,值 `SEMA_WEB_ADMIN_URL` / `SEMA_WEB_ADMIN_LIVE_URL` / `SEMA_WEB_ADMIN_WEB_URL`)、
426
+ fleet 成员对中心公告的可达地址(`FLEET_ADVERTISE_ADDRESS`,中心往它后面拼路径)、会话网页链接的基址(`webAdminSessionUrl` 的第一个参数)。这种座位有同一条规则:
427
+ 不许带凭据,也不许带 query / fragment(`http://x?a=1` 拼上 `/v1/…` 是 `http://x?a=1/v1/…`);路径前缀放行(要拼的路径接在前缀后面)。
428
+ 本节说**本包发什么、两方各自怎么读**。本包只有**判这种座位的那一只判官、它禁用的成分集与公告地址的 env 名**(纯、浏览器安全,零 IO);值从哪来、占位怎么展开、地址是不是真打得到,都是两方自己的事(§13.4)。
429
+
430
+ ### 13.1 本包发什么
431
+
432
+ | 件 | 是什么 |
433
+ |---|---|
434
+ | `PATH_BASE_URL_FORBIDDEN_PARTS` | 「后面要拼路径的基址」座位禁用的 URL 成分,闭集、冻结、判序:`userinfo` · `query` · `fragment`(**策略集,独立于判官词表 `HTTP_URL_PARTS`**:词表说 URL 有哪些成分,本集说这种座位禁哪些;今天碰巧同三词,但不由词表派生,词表加词时要显式裁);这种座位的策略只此一张,没有第二份抄本;包根 |
435
+ | `pathBaseUrlFlaws(url)` | = `httpUrlFlaws(url, PATH_BASE_URL_FORBIDDEN_PARTS)`(本包唯一的 URL 形判官,不另写判法)。合格 ⇒ `[]`;否则按判序交回规则词(`not-http-url` / `userinfo` / `query` / `fragment`),词的规则句取 `httpUrlRule(词)`;答案只有词,不含值的任何片段;包根 |
436
+ | `FLEET_ADVERTISE_ADDRESS_ENV` | 公告地址的 env 名 `"FLEET_ADVERTISE_ADDRESS"`(字面量类型),与 `FLEET_GENERATION_ENV` / `FLEET_SCOPE_ENV` 同文件同形;写的一方和读的一方都 import,不各自拼;包根与 `./fleet` |
437
+
438
+ 本包自己的 `webAdminSessionUrl` 已改读这一只判官(读数逐字不变)。判官今天的答案(逐行钉在 `test/path-base-url-forbids-14.7.0.test.ts`):
439
+
440
+ - `http://$(POD_IP):8090` ⇒ `[]`(占位在主机位:`$` `(` `)` 都是合法主机码点);`http://10.0.0.5:8090`、`http://[fd00::1]:8090`、`https://worker.example.com` ⇒ `[]`。
441
+ - `http://[$(POD_IP)]:8090` ⇒ `["not-http-url"]`:方括号里必须是 IPv6 字面量,占位不是 —— **判占位展开之后的值**,不判模板。
442
+ - 路径前缀 `http://10.0.0.5:8090/prefix` ⇒ `[]`(路径不在禁用集里:要拼的路径接在前缀后面)。
443
+ - `…?a=1`(含空 `?`)⇒ `["query"]`;`…#f`(含空 `#`)⇒ `["fragment"]`;`http://user:pw@host`(只有用户名也算)⇒ `["userinfo"]`;三件齐 ⇒ 三个词,按判序。
444
+ - `127.0.0.1:8121`(缺 scheme)、`ftp://x:1`、`file:///etc/passwd`、`data:…`、空串 ⇒ 含 `not-http-url`(`fetch` 认 `file://` / `data:`,配错的地址不许变成读本地文件)。
445
+
446
+ ### 13.2 web-admin 编排器做什么
447
+
448
+ - **渲染**:往成员 env 写公告地址时,键名取 `FLEET_ADVERTISE_ADDRESS_ENV`,不手写字面量。k8s 后端写 `http://$(POD_IP):<端口>` 这种形,`$(POD_IP)` 由部署后端展开。
449
+ - **发出前判**:对**展开之后**的值调 `pathBaseUrlFlaws`,长度非 0 就是渲染器自己的配置问题 —— 拒掉并点名规则词(规则句取 `httpUrlRule`),不要静默改写(例如悄悄削掉 query):改写会把地址送到运维没写的地方。
450
+ - **不手抄集**:不要在编排器里再写一遍 `["userinfo", "query", "fragment"]` 或自己的 URL 判法;集与判官只有本包这一份,它与引擎起服时判的是同一个答案。给用户铸会话链接用 `webAdminSessionUrl`,它判基址用的也是这一只。
451
+
452
+ ### 13.3 server 做什么
453
+
454
+ - **读 env**:`process.env[FLEET_ADVERTISE_ADDRESS_ENV]`;不手写字面量。缺席或空串(compose 的 `${NAME:-}` 常态)⇒ 没声明地址 —— 这个读法是 server 的,不在判官里(判官对 `""` 答 `not-http-url`)。
455
+ - **判**:非空值调 `pathBaseUrlFlaws`;长度非 0 ⇒ 拒启。运维旋钮律:无条件解析,没接中心的机器也判,形错的值不躺着等哪天生效。拒句点名没过的规则(`httpUrlRule`),**不回显值**(值里可能有凭据)。
456
+ - **中心基址三席同一只**:`WEB_ADMIN_ENV.url` / `liveUrl` / `webUrl` 的值(起服时与请求期)和公告地址都调 `pathBaseUrlFlaws`;server 里原先本地的禁用集副本与公告地址 env 名字面量改读本包后删除,不留第二份。判官读数与改前逐字相同(词与判官同一只)。
457
+
458
+ ### 13.4 本包不做的(如实)
459
+
460
+ - **占位展开**(`$(POD_IP)` 等):是部署后端的事,不是本包的;判官看到的永远是一个字符串。
461
+ - **可达性**:地址真不真打得到是运维的话,判官只判形;引擎不自猜可达地址。
462
+ - **缺席 / 空串的处置**:见 §13.3 —— 读的一方自己答。
463
+ - **座位名册**:一个值算不算「后面要拼路径的基址」是读它的一方的事;本包给的是判这种座位的那一只判官,不维护座位清单(§13 开头列的是今天已知的读者)。
464
+ - **不进保留 env 名表**:`FLEET_ADVERTISE_ADDRESS` 与 generation / scope 两只不同 —— 那两只只有渲染器能写,所以进 `RESERVED_WORKER_ENV`;公告地址是运维可以声明的值(渲染器也可以写),`worker.env` 设它照旧不被拒。
465
+
466
+ ## 14. 中心引用解析口 `resolveCenterRefs` 与记录读器 `readPlainStringRecord` —— 服务端中心腿与客户端核心两方的读法
467
+
468
+ 中心名册里 MCP server 的传输带两张**引用表**:stdio 的 `envRefs`(目标 env 键 → 变量名)、http 的 `headerRefs`(目标头名 → 变量名)。名册只存变量名、从不存值;值要在消费方自己的宿主环境里读。
469
+ 「变量没设」「设了但读到的不是串」「读它的时候抛了」「引用表本身不成样子」四种情形,本包此前只发引用表的形、不发读法,留给每个宿主自己写。本节说**本包发什么、两方各自怎么读**:本包只有**读引用表的那一个读法**(纯、浏览器安全、零 IO、不读环境);
470
+ 读哪一层环境、要不要缓存、解不开时挂不挂(§14.4),都是两方自己的事。
471
+
472
+ ### 14.1 本包发什么
473
+
474
+ | 件 | 是什么 |
475
+ |---|---|
476
+ | `resolveCenterRefs(refs, lookup)` | 解析口。`refs` = 名册里 `envRefs` / `headerRefs` 的值(`undefined` = 没声明);`lookup(name) => string \| undefined` = **调用方给的**查找函数(必给)。返回 `CenterRefsResolution`,按 `verdict` 分三臂;包根 |
477
+ | `CENTER_REF_FAULTS` / `CenterRefFault` | 一个成员没解到的原因词,闭集:`missing_name` · `not_a_string` · `read_threw`;包根 |
478
+ | `CENTER_REFS_VERDICTS` / `CenterRefsVerdict` | 整台结论的词,闭集:`resolved` · `unresolved` · `refs_unreadable`;包根 |
479
+ | `CenterRefMember` / `CenterRefMemberVerdict` / `CenterRefLookup` / `CenterRefsResolution` | 型:成员行 `{ key, ref, verdict }`(`verdict` = `resolved` 或上面三词之一)· 判定词 · 查找函数型 · 读数;包根 |
480
+ | `readPlainStringRecord(v)` | 「名 → 串」记录的读器(传输读器读 `env` / `headers` 用的就是它,同一个函数);包根 |
481
+ | `PLAIN_STRING_RECORD_FAULTS` / `PlainStringRecordFault` / `PlainStringRecordRead` / `PLAIN_STRING_RECORD_RESERVED_MEMBER` | 读器的原因词表(三词)· 词的型 · 读数型 · 保留成员名 `"__proto__"`;包根 |
482
+
483
+ ### 14.2 解析口的读法(一条律:每成员一句判定,整台一个结论)
484
+
485
+ 1. 引用表经 `readPlainStringRecord` 读。读不出(整张不是纯数据、有成员的变量名不是串、读成员就抛、叫 `__proto__` 的成员)⇒ **整台 `refs_unreadable`**,`fault` 是读器的词、坏在某个成员时 `member` 点名它的回显形;**一个变量都没问**。
486
+ 读器会把叫 `__proto__` 的串值成员剔出副本;解析口不许这样悄悄丢一条引用再挂,所以同样答 `refs_unreadable` / `member_name_reserved`。
487
+ 2. 每个成员恰问一次 `lookup(变量名)`(按引用表副本的自有键序:整数形的键在前、其余按记录列出的次序;实参只有变量名),判成**一个词**。一个成员坏了不早停 —— 每个成员都有自己的判定,调用方一次点名所有缺的变量:
488
+
489
+ | `lookup` 的答案 | 成员词 |
490
+ |---|---|
491
+ | 一个串(空串也是串) | `resolved` |
492
+ | `undefined`(变量没设) | `missing_name` |
493
+ | 别的种类(数、`null`、对象、函数……) | `not_a_string` |
494
+ | 抛了(任何抛出值,含撤销的 Proxy) | `read_threw`(不传出) |
495
+
496
+ 3. 整台结论:每个成员都 `resolved`(零成员也是)⇒ `resolved`,带 `values`(目标键 → 串,新铸的朴素对象);有成员不是 ⇒ `unresolved`,带 `members`(**行里没有变量的值**,失败读数可以进日志);引用表读不出 ⇒ `refs_unreadable`。
497
+ 4. `refs` 是 `undefined` ⇒ `resolved`、零成员、零次查找,与空表同答;别的非记录值(`null`、数组、串)是 `refs_unreadable`,不当缺席。
498
+ 5. `lookup` 没给 / 不是函数 ⇒ **`TypeError`**(调用方的编程错;不折成 `read_threw`,更不回落任何环境 —— 本包不读 `process.env`)。
499
+
500
+ `lookup` 的写法是调用方的事,有一条提醒:对普通对象做 `obj[name]` 会读到继承位(`toString` / `constructor`),解析口把它判成 `not_a_string`(响亮,不当作已设);想让这类名字落成「没设」就按自有键读
501
+ (`Object.hasOwn(table, name) ? table[name] : undefined`)。同一个变量被两个目标键引用会被问两次 —— 缓存(每名读一次、跨轮不缓存)是查找函数的事。
502
+
503
+ ### 14.3 读器的原因词(`PLAIN_STRING_RECORD_FAULTS`,三词)
504
+
505
+ | 词 | 说的是 | 记录交不交 |
506
+ |---|---|---|
507
+ | `not_plain_record` | 整张不是纯数据(`null` / 数组 / 原始值 / `Map` / 类实例 / 函数,或读形状就抛的对象) | 不交 |
508
+ | `member_not_string` | 某个成员的值不是串(读成了别的种类),或它读不出(它的访问器抛了,或读它的描述符时代理陷阱抛了)—— 两种情形 `detail` 句子分说 | 不交,`member` 点名它 |
509
+ | `member_name_reserved` | 某个成员叫 `__proto__`(引擎的声明收据拒这个名);名坏优先 —— 值也坏或读不出时句子并列说全,词仍是这一个 | 值是串:交其余、`reservedMember: true`;否则不交 |
510
+
511
+ 按词分派;读器从不抛。传输读器的 `lost[].fault` 就是这张表(读成员就抛的那一形,词是 `member_not_string`,句子 `could not be read (its getter threw)`)。
512
+
513
+ ### 14.4 两方做什么
514
+
515
+ - **客户端核心 / 服务端中心腿**:
516
+ ```ts
517
+ const r = resolveCenterRefs(transport.envRefs, (name) => hostEnv.read(name)); // hostEnv = 你的宿主环境座位;headerRefs 同
518
+ switch (r.verdict) {
519
+ case "resolved": return mount(r.values);
520
+ case "unresolved": for (const m of r.members) if (m.verdict !== "resolved") warn(m.verdict, m.key, m.ref); return skipWholeServer();
521
+ case "refs_unreadable": warn(r.fault, r.member); return skipWholeServer();
522
+ default: { const unhandled: never = r; throw new Error(`unhandled ${String(unhandled)}`); }
523
+ }
524
+ ```
525
+ 解析不了时挂不挂是你这条腿的规则(「整台不挂 + 点名」是一台少了鉴权头或凭据 env 的 server 不拨号的那条);本口只判。
526
+ - **不手抄**:不要在自己这边再写一遍「变量没设 / 读到的不是串 / 读抛」的判法或这三个词的字面量;词表与读数型从本包 import,穷尽 `switch` 加 `never` 兜底(加词时编译红)。
527
+
528
+ ### 14.5 本包不做的(如实)
529
+
530
+ - **读哪一层环境**:`lookup` 读什么(进程环境、合并后的环境、远端环境)是调用方的事;本包不读 `process.env`,也不缓存。
531
+ - **挂不挂**:读数是判决,不是处置。
532
+ - **变量名的形**:名册的 schema 已把变量名限在 env 名的字符集内;本口把变量名当不透明串交给 `lookup`,不再判一遍形。
533
+ - **值的好坏**:解到串就是 `resolved`,空串、很长的串都不另判;值是不是凭据、扣不扣留,是读数之后的另一道判官的事。