@sema-agent/server 7.148.0 → 7.149.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 (247) hide show
  1. package/MIGRATION.md +429 -0
  2. package/README.md +16 -1
  3. package/README.zh-CN.md +4 -0
  4. package/USAGE.md +89 -55
  5. package/dist/adoption/wire.d.ts +3 -3
  6. package/dist/approval-card.d.ts +32 -32
  7. package/dist/approval-leg-origin.d.ts +33 -0
  8. package/dist/approval-leg-origin.js +4 -0
  9. package/dist/auth-bridge.d.ts +9 -1
  10. package/dist/auth-bridge.js +4 -4
  11. package/dist/auth-keys.d.ts +10 -1
  12. package/dist/auth-keys.js +8 -0
  13. package/dist/boot/execution-env.js +10 -11
  14. package/dist/boot/execution-lane.d.ts +6 -4
  15. package/dist/boot/execution-lane.js +3 -1
  16. package/dist/boot/org-delivery.d.ts +3 -2
  17. package/dist/boot/resolve-spec.js +6 -4
  18. package/dist/boot/runner-deps.js +3 -1
  19. package/dist/boot/stage-01-config.d.ts +1 -0
  20. package/dist/boot/stage-01-config.js +4 -3
  21. package/dist/boot/stage-02-web-admin-pull.d.ts +1 -0
  22. package/dist/boot/stage-02-web-admin-pull.js +10 -2
  23. package/dist/boot/stage-03-store-backend.d.ts +1 -0
  24. package/dist/boot/stage-03-store-backend.js +2 -2
  25. package/dist/boot/stage-04-stores.d.ts +1 -0
  26. package/dist/boot/stage-05-execution-env.d.ts +1 -0
  27. package/dist/boot/stage-06-runners.d.ts +2 -1
  28. package/dist/boot/stage-07-capability-layer.d.ts +2 -1
  29. package/dist/boot/stage-08-reapers.d.ts +2 -1
  30. package/dist/boot/stage-09-leader.d.ts +2 -1
  31. package/dist/boot/stage-10-http-server.d.ts +2 -1
  32. package/dist/boot/stores.d.ts +3 -0
  33. package/dist/boot/stores.js +22 -19
  34. package/dist/capabilities/tool-defer.d.ts +1 -1
  35. package/dist/capability-facts.d.ts +5 -4
  36. package/dist/capability-facts.js +3 -14
  37. package/dist/card-settle-stored-scope.d.ts +56 -0
  38. package/dist/card-settle-stored-scope.js +27 -0
  39. package/dist/card-void.d.ts +7 -12
  40. package/dist/card-void.js +2 -7
  41. package/dist/config-catalog.d.ts +12 -0
  42. package/dist/config-catalog.js +36 -32
  43. package/dist/config-invariants.d.ts +5 -4
  44. package/dist/config-invariants.js +4 -4
  45. package/dist/config-types.d.ts +37 -5
  46. package/dist/config.d.ts +6 -5
  47. package/dist/config.js +35 -24
  48. package/dist/context-window-notice.d.ts +31 -0
  49. package/dist/context-window-notice.js +28 -0
  50. package/dist/deployment-shape.d.ts +20 -11
  51. package/dist/deployment-shape.js +1 -0
  52. package/dist/env-name-allowlist-knobs.d.ts +6 -5
  53. package/dist/env-name-allowlist-knobs.js +5 -0
  54. package/dist/execution-lane-caps.d.ts +20 -5
  55. package/dist/execution-lane-caps.js +18 -4
  56. package/dist/hooks/command-spawn.d.ts +7 -2
  57. package/dist/hooks/command-spawn.js +13 -6
  58. package/dist/hooks/hook-runner.d.ts +5 -0
  59. package/dist/hooks/hook-runner.js +11 -7
  60. package/dist/http/admission.js +3 -3
  61. package/dist/http/approval-sweeps.js +3 -2
  62. package/dist/http/claim-heartbeat.d.ts +3 -3
  63. package/dist/http/claim-heartbeat.js +3 -3
  64. package/dist/http/claimed-run.d.ts +16 -9
  65. package/dist/http/claimed-run.js +8 -0
  66. package/dist/http/dispatch.js +5 -3
  67. package/dist/http/durable-run-leg.d.ts +8 -1
  68. package/dist/http/durable-run-leg.js +30 -11
  69. package/dist/http/execution-context.d.ts +115 -14
  70. package/dist/http/execution-context.js +130 -40
  71. package/dist/http/owner-access.d.ts +3 -2
  72. package/dist/http/owner-access.js +2 -3
  73. package/dist/http/principal-gate.d.ts +18 -11
  74. package/dist/http/principal-gate.js +3 -1
  75. package/dist/http/resume-ctx-read.d.ts +14 -3
  76. package/dist/http/resume-ctx-read.js +8 -2
  77. package/dist/http/resume-legs.d.ts +35 -3
  78. package/dist/http/resume-legs.js +244 -92
  79. package/dist/http/route-ctx.d.ts +6 -0
  80. package/dist/http/routes/a2a-serve.js +2 -0
  81. package/dist/http/routes/approvals-assistant.js +3 -2
  82. package/dist/http/routes/capabilities.js +1 -1
  83. package/dist/http/routes/diagnostics.d.ts +3 -1
  84. package/dist/http/routes/diagnostics.js +30 -5
  85. package/dist/http/routes/principal-inbox.d.ts +3 -1
  86. package/dist/http/routes/principal-inbox.js +3 -2
  87. package/dist/http/routes/runs.js +10 -7
  88. package/dist/http/routes/session-sync.d.ts +24 -5
  89. package/dist/http/routes/session-sync.js +46 -34
  90. package/dist/http/routes/sessions-list.d.ts +1 -1
  91. package/dist/http/routes/tasks.js +127 -93
  92. package/dist/http/server.d.ts +4 -5
  93. package/dist/http/server.js +30 -5
  94. package/dist/http/submit-ctx.d.ts +1 -0
  95. package/dist/http/submit-ctx.js +2 -3
  96. package/dist/index.d.ts +3 -1
  97. package/dist/index.js +1 -0
  98. package/dist/leg-facts.d.ts +7 -2
  99. package/dist/leg-facts.js +1 -0
  100. package/dist/local-store-declaration.d.ts +54 -0
  101. package/dist/local-store-declaration.js +59 -0
  102. package/dist/mcp-assertion-header.d.ts +1 -1
  103. package/dist/mcp-assertion-header.js +1 -1
  104. package/dist/memory-project-layer.js +1 -1
  105. package/dist/memory-scope.d.ts +4 -4
  106. package/dist/memory-scope.js +4 -4
  107. package/dist/memory-sync-client.js +2 -2
  108. package/dist/model-context-window.d.ts +50 -11
  109. package/dist/model-context-window.js +20 -1
  110. package/dist/model-entry-refusal.d.ts +5 -4
  111. package/dist/model-entry-refusal.js +17 -3
  112. package/dist/model-reach-scope.d.ts +2 -1
  113. package/dist/observability/fail-open.d.ts +14 -2
  114. package/dist/observability/fail-open.js +14 -2
  115. package/dist/observability/metrics.js +1 -1
  116. package/dist/observability/run-terminal.js +1 -0
  117. package/dist/observability/secret-env-scrub.d.ts +1 -1
  118. package/dist/observability/secret-env-scrub.js +1 -1
  119. package/dist/org-delivery-gate.d.ts +31 -6
  120. package/dist/org-delivery-gate.js +7 -4
  121. package/dist/owner-faces.d.ts +3 -2
  122. package/dist/park-row-commit.d.ts +67 -0
  123. package/dist/park-row-commit.js +76 -0
  124. package/dist/parked-decide.d.ts +9 -7
  125. package/dist/parked-decide.js +25 -6
  126. package/dist/peer-directory.d.ts +1 -1
  127. package/dist/plugins/adoption-log-sql.d.ts +3 -3
  128. package/dist/plugins/adoption-log-sql.js +19 -19
  129. package/dist/plugins/approval-ask-store-sql.d.ts +1 -1
  130. package/dist/plugins/approval-ask-store-sql.js +3 -5
  131. package/dist/plugins/approval-exemption-skill-cutoff.d.ts +64 -0
  132. package/dist/plugins/approval-exemption-skill-cutoff.js +122 -0
  133. package/dist/plugins/approval-exemption-skill-m46.d.ts +0 -6
  134. package/dist/plugins/approval-exemption-skill-m46.js +6 -10
  135. package/dist/plugins/approval-exemption-store.d.ts +26 -1
  136. package/dist/plugins/approval-exemption-store.js +28 -19
  137. package/dist/plugins/ensure-schema-lock-policy.d.ts +36 -3
  138. package/dist/plugins/ensure-schema-lock-policy.js +75 -9
  139. package/dist/plugins/file-run-store.d.ts +22 -9
  140. package/dist/plugins/file-run-store.js +50 -22
  141. package/dist/plugins/local-checkpoint-store.d.ts +4 -0
  142. package/dist/plugins/local-checkpoint-store.js +2 -1
  143. package/dist/plugins/local-data-root-admission.d.ts +52 -0
  144. package/dist/plugins/local-data-root-admission.js +100 -0
  145. package/dist/plugins/local-engine-high-water.d.ts +28 -7
  146. package/dist/plugins/local-engine-high-water.js +27 -22
  147. package/dist/plugins/local-session-store.d.ts +134 -49
  148. package/dist/plugins/local-session-store.js +149 -108
  149. package/dist/plugins/memory-run-store.d.ts +14 -9
  150. package/dist/plugins/memory-run-store.js +47 -21
  151. package/dist/plugins/one-time-migration-marker.d.ts +19 -3
  152. package/dist/plugins/one-time-migration-marker.js +7 -1
  153. package/dist/plugins/one-time-migrations.d.ts +46 -20
  154. package/dist/plugins/one-time-migrations.js +102 -79
  155. package/dist/plugins/org-delivery-quota-store.d.ts +34 -11
  156. package/dist/plugins/org-delivery-quota-store.js +29 -14
  157. package/dist/plugins/permission-rule-store-sql.d.ts +1 -1
  158. package/dist/plugins/permission-rule-store-sql.js +5 -9
  159. package/dist/plugins/pg-pool.d.ts +1 -1
  160. package/dist/plugins/pg-pool.js +10 -12
  161. package/dist/plugins/remote-env-device.d.ts +3 -2
  162. package/dist/plugins/remote-env-e2b.d.ts +1 -7
  163. package/dist/plugins/remote-env-e2b.js +10 -7
  164. package/dist/plugins/remote-env-host.d.ts +50 -9
  165. package/dist/plugins/remote-env-host.js +77 -20
  166. package/dist/plugins/remote-env-k8s.js +4 -2
  167. package/dist/plugins/remote-env-local-docker.d.ts +6 -3
  168. package/dist/plugins/remote-env-local-docker.js +8 -23
  169. package/dist/plugins/run-store-sql.d.ts +26 -7
  170. package/dist/plugins/run-store-sql.js +44 -16
  171. package/dist/plugins/scenario-prefix-switch-m42.d.ts +3 -1
  172. package/dist/plugins/scenario-prefix-switch-m42.js +4 -3
  173. package/dist/plugins/schema-consistency.d.ts +89 -5
  174. package/dist/plugins/schema-consistency.js +176 -7
  175. package/dist/plugins/schema-drift-sentence.d.ts +6 -5
  176. package/dist/plugins/schema-drift-sentence.js +13 -5
  177. package/dist/plugins/session-placement.d.ts +5 -4
  178. package/dist/plugins/shell-sentinel-owner-m48.d.ts +22 -0
  179. package/dist/plugins/shell-sentinel-owner-m48.js +6 -0
  180. package/dist/plugins/stop-then-start-sentence.d.ts +16 -0
  181. package/dist/plugins/stop-then-start-sentence.js +7 -0
  182. package/dist/plugins/store-backend.d.ts +22 -8
  183. package/dist/plugins/store-backend.js +58 -24
  184. package/dist/plugins/store-contracts.d.ts +33 -3
  185. package/dist/plugins/store-contracts.js +16 -0
  186. package/dist/plugins/tidb-pool.d.ts +11 -6
  187. package/dist/plugins/tidb-pool.js +18 -12
  188. package/dist/plugins/workspace-custody.d.ts +44 -0
  189. package/dist/plugins/workspace-custody.js +47 -0
  190. package/dist/project-identity.d.ts +8 -7
  191. package/dist/project-identity.js +40 -17
  192. package/dist/project-layer-key.d.ts +13 -2
  193. package/dist/project-layer-key.js +9 -1
  194. package/dist/read-deny-floor-notice.d.ts +36 -0
  195. package/dist/read-deny-floor-notice.js +40 -0
  196. package/dist/{plain-string-record.d.ts → request-declaration-disposition.d.ts} +9 -23
  197. package/dist/request-declaration-disposition.js +39 -0
  198. package/dist/run-cancel-card.d.ts +28 -0
  199. package/dist/run-cancel-card.js +19 -0
  200. package/dist/run-cancel-context.d.ts +10 -0
  201. package/dist/run-cancel-context.js +1 -0
  202. package/dist/run-local.js +28 -13
  203. package/dist/runs.d.ts +31 -7
  204. package/dist/runs.js +34 -16
  205. package/dist/security.d.ts +2 -2
  206. package/dist/server-secret-env.d.ts +34 -20
  207. package/dist/server-secret-env.js +61 -18
  208. package/dist/session-agent.d.ts +3 -2
  209. package/dist/session-children-retire.d.ts +6 -3
  210. package/dist/session-children-retire.js +2 -5
  211. package/dist/session-workspace.d.ts +3 -3
  212. package/dist/store-admission.d.ts +33 -0
  213. package/dist/store-admission.js +49 -0
  214. package/dist/store-posture.d.ts +5 -0
  215. package/dist/store-posture.js +18 -1
  216. package/dist/stores-sql/checkpoint-store-sql.d.ts +1 -1
  217. package/dist/stores-sql/checkpoint-store-sql.js +3 -5
  218. package/dist/stores-sql/file-history-store-sql.d.ts +1 -1
  219. package/dist/stores-sql/file-history-store-sql.js +3 -5
  220. package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
  221. package/dist/stores-sql/tool-result-store-sql.js +4 -6
  222. package/dist/task-a2a.d.ts +3 -8
  223. package/dist/task-a2a.js +25 -27
  224. package/dist/task-cwd.d.ts +23 -7
  225. package/dist/task-cwd.js +3 -0
  226. package/dist/task-mcp.d.ts +3 -3
  227. package/dist/task-mcp.js +1 -1
  228. package/dist/task-settings.js +1 -0
  229. package/dist/terminal.d.ts +2 -0
  230. package/dist/terminal.js +21 -6
  231. package/dist/tool-approval.d.ts +44 -36
  232. package/dist/tool-approval.js +66 -47
  233. package/dist/trace/engine-notice-wire.d.ts +24 -21
  234. package/dist/trace/engine-notice-wire.js +7 -3
  235. package/dist/trace/ledger-sink.d.ts +3 -1
  236. package/dist/trace/project.d.ts +4 -2
  237. package/dist/trace/project.js +8 -7
  238. package/dist/trace/redact.d.ts +12 -0
  239. package/dist/trace/redact.js +5 -1
  240. package/dist/trace/self-minted-wire.d.ts +131 -52
  241. package/dist/trace/self-minted-wire.js +71 -39
  242. package/dist/web-admin-client/apply-effective.js +22 -9
  243. package/docs/error-text-lexicon.json +317 -0
  244. package/package.json +3 -1
  245. package/scripts/embed-minimal.mjs +183 -0
  246. package/wire-changes/server@7.149.0.json +372 -0
  247. package/dist/plain-string-record.js +0 -70
@@ -12,18 +12,25 @@ import { defaultModelRefusal, refusedNameMintedRefusal } from "../model-entry-re
12
12
  import { isRosterGateArmed } from "../config.js";
13
13
  import { judgeServedModelRoute } from "../model-route-endpoint.js";
14
14
  import { servedModelTableLeg } from "../model-select.js";
15
+ import { warnAssumedContextWindows } from "../context-window-notice.js";
15
16
  import { captureBootStoreEvidence } from "./store-evidence.js";
17
+ import { admitStoreDurability } from "../store-admission.js";
18
+ import { provisionSemaConfigDir } from "../sema-config-dir.js";
16
19
  export async function runStage02(ctx) {
17
20
  const { config: loaded, localRoot, logger, metrics } = ctx;
18
21
  const storeEvidence = await captureBootStoreEvidence({ config: loaded, localRoot });
19
22
  const configSource = configSourceKind(loaded);
20
23
  if (configSource === "local") {
21
24
  await assertLocalConfigDirTrusted({ root: localRoot, declaredOwnerUid: loaded.configLocalOwnerUid });
22
- const envModelsMigration = { root: localRoot, env: process.env, envTableIsPlaceholder: isRosterGateArmed(loaded.webAdmin) };
23
- logEnvModelsMigration(logger, envModelsMigration, await runEnvModelsMigration(envModelsMigration));
24
25
  logConfigDirMigration(logger, await migrateLocalConfigDirectory(localRoot));
25
26
  }
26
27
  const config = await composeExecutionLane(loaded, { configSource, localRoot, logger, entry: HTTP_SERVICE_LANE_ENTRY });
28
+ admitStoreDurability(config, storeEvidence);
29
+ provisionSemaConfigDir(config, logger);
30
+ if (configSource === "local") {
31
+ const envModelsMigration = { root: localRoot, env: process.env, envTableIsPlaceholder: isRosterGateArmed(config.webAdmin) };
32
+ logEnvModelsMigration(logger, envModelsMigration, await runEnvModelsMigration(envModelsMigration));
33
+ }
27
34
  announceConfigRootEnclosingWorkspace(config, logger, launchWorkspaceOf(config));
28
35
  const webAdmin = await createWebAdminRuntime({ config, logger, metrics, localRoot });
29
36
  const servedLeg = servedModelTableLeg(config);
@@ -40,6 +47,7 @@ export async function runStage02(ctx) {
40
47
  if (mintedRefused !== undefined) {
41
48
  throw new Error(mintedRefused);
42
49
  }
50
+ warnAssumedContextWindows(config, logger, { envTableIsPlaceholder: isRosterGateArmed(config.webAdmin) });
43
51
  const ceilingVerdict = createUnpricedCeilingVerdict({ config, logger });
44
52
  ceilingVerdict.judge();
45
53
  return { ...ctx, config, ceilingVerdict, storeEvidence, webAdmin };
@@ -30,6 +30,7 @@ export declare function runStage03(ctx: Awaited<ReturnType<typeof runStage02>>):
30
30
  ceilingVerdict: import("./unpriced-ceiling-verdict.js").UnpricedCeilingVerdict;
31
31
  storeEvidence: import("../store-posture.js").StoreEvidence;
32
32
  webAdmin: import("./web-admin.js").WebAdminRuntime;
33
+ localAdmission: import("../plugins/local-data-root-admission.js").LocalDataRootAdmission | undefined;
33
34
  localRoot: string;
34
35
  logger: import("../index.js").Logger;
35
36
  metrics: import("../index.js").Metrics;
@@ -1,8 +1,8 @@
1
1
  import { uuidv7 } from "@sema-agent/core";
2
2
  import { openStores } from "./stores.js";
3
3
  export async function runStage03(ctx) {
4
- const { config, localRoot, logger, metrics, storeEvidence } = ctx;
5
- const { backend, storePosture, memoryEngine, engineDataRoot, memorySyncCursors, rosterStore, backgroundAgentStore, sessionCaptureRecords, taskAttachmentStore, mailboxStore, mailboxRecipientLifecycle, memoryExportStores, memorySyncRunner, sessionStore, breakerState, usageWindowStore, memoryPosture, taskListLane, sqlEngine, storeSweep, } = await openStores({ config, logger, metrics, localRoot, storeEvidence });
4
+ const { config, localAdmission, localRoot, logger, metrics, storeEvidence } = ctx;
5
+ const { backend, storePosture, memoryEngine, engineDataRoot, memorySyncCursors, rosterStore, backgroundAgentStore, sessionCaptureRecords, taskAttachmentStore, mailboxStore, mailboxRecipientLifecycle, memoryExportStores, memorySyncRunner, sessionStore, breakerState, usageWindowStore, memoryPosture, taskListLane, sqlEngine, storeSweep, } = await openStores({ config, logger, metrics, localRoot, storeEvidence, localAdmission });
6
6
  const adoptionWiring = { memoryEngine: memoryExportStores !== undefined, taskAttachment: taskAttachmentStore !== undefined };
7
7
  const instanceId = uuidv7();
8
8
  return { ...ctx, adoptionWiring, backend, backgroundAgentStore, breakerState, engineDataRoot, instanceId, mailboxRecipientLifecycle, mailboxStore, memoryEngine, memoryExportStores, memoryPosture, memorySyncCursors, memorySyncRunner, rosterStore, sessionCaptureRecords, sessionStore, sqlEngine, storePosture, storeSweep, taskAttachmentStore, taskListLane, usageWindowStore };
@@ -59,6 +59,7 @@ export declare function runStage04(ctx: Awaited<ReturnType<typeof runStage03>>):
59
59
  ceilingVerdict: import("./unpriced-ceiling-verdict.js").UnpricedCeilingVerdict;
60
60
  storeEvidence: import("../store-posture.js").StoreEvidence;
61
61
  webAdmin: import("./web-admin.js").WebAdminRuntime;
62
+ localAdmission: import("../plugins/local-data-root-admission.js").LocalDataRootAdmission | undefined;
62
63
  localRoot: string;
63
64
  logger: import("../index.js").Logger;
64
65
  metrics: import("../index.js").Metrics;
@@ -82,6 +82,7 @@ export declare function runStage05(ctx: Awaited<ReturnType<typeof runStage04>>):
82
82
  ceilingVerdict: import("./unpriced-ceiling-verdict.js").UnpricedCeilingVerdict;
83
83
  storeEvidence: import("../store-posture.js").StoreEvidence;
84
84
  webAdmin: import("./web-admin.js").WebAdminRuntime;
85
+ localAdmission: import("../plugins/local-data-root-admission.js").LocalDataRootAdmission | undefined;
85
86
  localRoot: string;
86
87
  logger: import("../index.js").Logger;
87
88
  metrics: import("../index.js").Metrics;
@@ -54,7 +54,7 @@ export declare function runStage06(ctx: Awaited<ReturnType<typeof runStage05>>):
54
54
  };
55
55
  workflowRunStore: import("../orchestration/workflow-notify-journal.js").JournalingWorkflowRunStore | undefined;
56
56
  workflowsCapable: boolean;
57
- orgDeliveryGate: import("@sema-agent/core").OrgDeliveryGate | undefined;
57
+ orgDeliveryGate: import("../org-delivery-gate.js").ServerOrgDeliveryGate | undefined;
58
58
  deploymentMods: readonly import("@sema-agent/core").ModRegistration<import("@sema-agent/core").EngineDollar>[];
59
59
  deploymentModsLoaded: readonly import("./deployment-mods.js").LoadedModPackage[];
60
60
  belowTaskChainPatterns: readonly string[];
@@ -137,6 +137,7 @@ export declare function runStage06(ctx: Awaited<ReturnType<typeof runStage05>>):
137
137
  ceilingVerdict: import("./unpriced-ceiling-verdict.js").UnpricedCeilingVerdict;
138
138
  storeEvidence: import("../store-posture.js").StoreEvidence;
139
139
  webAdmin: import("./web-admin.js").WebAdminRuntime;
140
+ localAdmission: import("../plugins/local-data-root-admission.js").LocalDataRootAdmission | undefined;
140
141
  localRoot: string;
141
142
  logger: import("../index.js").Logger;
142
143
  metrics: import("../index.js").Metrics;
@@ -76,7 +76,7 @@ export declare function runStage07(ctx: Awaited<ReturnType<typeof runStage06>>):
76
76
  };
77
77
  workflowRunStore: import("../orchestration/workflow-notify-journal.js").JournalingWorkflowRunStore | undefined;
78
78
  workflowsCapable: boolean;
79
- orgDeliveryGate: import("@sema-agent/core").OrgDeliveryGate | undefined;
79
+ orgDeliveryGate: import("../org-delivery-gate.js").ServerOrgDeliveryGate | undefined;
80
80
  deploymentMods: readonly import("@sema-agent/core").ModRegistration<import("@sema-agent/core").EngineDollar>[];
81
81
  deploymentModsLoaded: readonly import("./deployment-mods.js").LoadedModPackage[];
82
82
  belowTaskChainPatterns: readonly string[];
@@ -159,6 +159,7 @@ export declare function runStage07(ctx: Awaited<ReturnType<typeof runStage06>>):
159
159
  ceilingVerdict: import("./unpriced-ceiling-verdict.js").UnpricedCeilingVerdict;
160
160
  storeEvidence: import("../store-posture.js").StoreEvidence;
161
161
  webAdmin: import("./web-admin.js").WebAdminRuntime;
162
+ localAdmission: import("../plugins/local-data-root-admission.js").LocalDataRootAdmission | undefined;
162
163
  localRoot: string;
163
164
  logger: import("../index.js").Logger;
164
165
  metrics: import("../index.js").Metrics;
@@ -89,7 +89,7 @@ export declare function runStage08(ctx: Awaited<ReturnType<typeof runStage07>>):
89
89
  };
90
90
  workflowRunStore: import("../orchestration/workflow-notify-journal.js").JournalingWorkflowRunStore | undefined;
91
91
  workflowsCapable: boolean;
92
- orgDeliveryGate: import("@sema-agent/core").OrgDeliveryGate | undefined;
92
+ orgDeliveryGate: import("../org-delivery-gate.js").ServerOrgDeliveryGate | undefined;
93
93
  deploymentMods: readonly import("@sema-agent/core").ModRegistration<import("@sema-agent/core").EngineDollar>[];
94
94
  deploymentModsLoaded: readonly import("./deployment-mods.js").LoadedModPackage[];
95
95
  belowTaskChainPatterns: readonly string[];
@@ -172,6 +172,7 @@ export declare function runStage08(ctx: Awaited<ReturnType<typeof runStage07>>):
172
172
  ceilingVerdict: import("./unpriced-ceiling-verdict.js").UnpricedCeilingVerdict;
173
173
  storeEvidence: import("../store-posture.js").StoreEvidence;
174
174
  webAdmin: import("./web-admin.js").WebAdminRuntime;
175
+ localAdmission: import("../plugins/local-data-root-admission.js").LocalDataRootAdmission | undefined;
175
176
  localRoot: string;
176
177
  logger: import("../index.js").Logger;
177
178
  metrics: import("../index.js").Metrics;
@@ -108,7 +108,7 @@ export declare function runStage09(ctx: Awaited<ReturnType<typeof runStage08>>):
108
108
  };
109
109
  workflowRunStore: import("../orchestration/workflow-notify-journal.js").JournalingWorkflowRunStore | undefined;
110
110
  workflowsCapable: boolean;
111
- orgDeliveryGate: import("@sema-agent/core").OrgDeliveryGate | undefined;
111
+ orgDeliveryGate: import("../org-delivery-gate.js").ServerOrgDeliveryGate | undefined;
112
112
  deploymentMods: readonly import("@sema-agent/core").ModRegistration<import("@sema-agent/core").EngineDollar>[];
113
113
  deploymentModsLoaded: readonly import("./deployment-mods.js").LoadedModPackage[];
114
114
  belowTaskChainPatterns: readonly string[];
@@ -191,6 +191,7 @@ export declare function runStage09(ctx: Awaited<ReturnType<typeof runStage08>>):
191
191
  ceilingVerdict: import("./unpriced-ceiling-verdict.js").UnpricedCeilingVerdict;
192
192
  storeEvidence: import("../store-posture.js").StoreEvidence;
193
193
  webAdmin: import("./web-admin.js").WebAdminRuntime;
194
+ localAdmission: import("../plugins/local-data-root-admission.js").LocalDataRootAdmission | undefined;
194
195
  localRoot: string;
195
196
  logger: import("../index.js").Logger;
196
197
  metrics: import("../index.js").Metrics;
@@ -107,7 +107,7 @@ export declare function runStage10(ctx: Awaited<ReturnType<typeof runStage09>>):
107
107
  };
108
108
  workflowRunStore: import("../orchestration/workflow-notify-journal.js").JournalingWorkflowRunStore | undefined;
109
109
  workflowsCapable: boolean;
110
- orgDeliveryGate: import("@sema-agent/core").OrgDeliveryGate | undefined;
110
+ orgDeliveryGate: import("../org-delivery-gate.js").ServerOrgDeliveryGate | undefined;
111
111
  deploymentMods: readonly import("@sema-agent/core").ModRegistration<import("@sema-agent/core").EngineDollar>[];
112
112
  deploymentModsLoaded: readonly import("./deployment-mods.js").LoadedModPackage[];
113
113
  belowTaskChainPatterns: readonly string[];
@@ -190,6 +190,7 @@ export declare function runStage10(ctx: Awaited<ReturnType<typeof runStage09>>):
190
190
  ceilingVerdict: import("./unpriced-ceiling-verdict.js").UnpricedCeilingVerdict;
191
191
  storeEvidence: import("../store-posture.js").StoreEvidence;
192
192
  webAdmin: import("./web-admin.js").WebAdminRuntime;
193
+ localAdmission: import("../plugins/local-data-root-admission.js").LocalDataRootAdmission | undefined;
193
194
  localRoot: string;
194
195
  logger: import("../index.js").Logger;
195
196
  metrics: import("../index.js").Metrics;
@@ -6,6 +6,7 @@ import type { Metrics } from "../observability/metrics.js";
6
6
  import { type MemorySyncStore } from "../plugins/memory-sync-store-pg.js";
7
7
  import { type TaskAttachmentStore } from "../plugins/task-attachment-store.js";
8
8
  import { type StoreBackend } from "../plugins/store-backend.js";
9
+ import type { LocalDataRootAdmission } from "../plugins/local-data-root-admission.js";
9
10
  import { type MemoryScopeStores } from "../memory-scope-stores.js";
10
11
  import { type StoreEvidence } from "../store-posture.js";
11
12
  export interface OpenStoresCtx {
@@ -15,6 +16,8 @@ export interface OpenStoresCtx {
15
16
  localRoot: string;
16
17
  /** 店的持久性起服证据(起服第 2 段段首 `captureBootStoreEvidence` 取的那一份;直接调本函数的测试同一只取证)。 */
17
18
  storeEvidence: StoreEvidence;
19
+ /** local 数据根准入读数(起服第 1 段在本进程第一笔写之前取的那一只;非 local = `undefined`)。直接调本函数的测试经 `test/helpers/open-stores.ts` 同一只准入取。 */
20
+ localAdmission: LocalDataRootAdmission | undefined;
18
21
  }
19
22
  /**
20
23
  * durable 回决腿的规则位给 `approval_ask` 加了 `rule_command`/`rule_scope_root` 两列,而 `ensureAsk` 的 INSERT 与每一条读**无条件**引用它们 ⇒ 存量表上整条流内审批协议
@@ -21,7 +21,7 @@ import { LocalTaskAttachmentStore } from "../plugins/local-task-attachment-store
21
21
  import { PgTaskAttachmentStore, TiDBTaskAttachmentStore, ensurePgTaskAttachmentSchema, ensureTiDBTaskAttachmentSchema } from "../plugins/task-attachment-store.js";
22
22
  import { createSessionStore } from "../plugins/session-store.js";
23
23
  import { buildSqlPoolMissingRefusal, missingSqlCoordinateKeys } from "../sql-engine-coordinates.js";
24
- import { runAndLogOneTimeMigrations } from "../plugins/one-time-migrations.js";
24
+ import { ONE_TIME_MIGRATIONS, runAndLogOneTimeMigrations } from "../plugins/one-time-migrations.js";
25
25
  import { createTaskListLane } from "./task-list-lane.js";
26
26
  import { ensurePgTaskListSchema, ensureTiDBTaskListSchema } from "../plugins/task-list-store-sql.js";
27
27
  import { assertDeviceAuditRebindEventSchema, ensurePgDeviceSchema, ensureTiDBDeviceSchema } from "../plugins/device-store-sql.js";
@@ -65,19 +65,29 @@ export function buildSessionBoxMountLine(verdict) {
65
65
  : { level: "warn", fields: { peerLaneMountable: false, peerLaneRefusal: verdict.code, reason: verdict.reason } };
66
66
  }
67
67
  export async function openStores(ctx) {
68
- const { config, logger, metrics, localRoot, storeEvidence } = ctx;
68
+ const { config, logger, metrics, localRoot, storeEvidence, localAdmission } = ctx;
69
69
  let backend;
70
70
  let storeDegradedReason;
71
+ if (config.requirePrincipal && config.dbBackend === "local") {
72
+ throw new Error("REQUIRE_PRINCIPAL=true is not supported on the local file backend (DB_BACKEND=local): the lane is single-user " +
73
+ "by construction — a session created before owners were recorded is claimed by the FIRST principal that submits " +
74
+ "to it during the upgrade window, and the lane's mutual-recognition arms assume one user — so it cannot enforce " +
75
+ "a multi-tenant session boundary. Use a SQL backend (DB_BACKEND=mysql|pg) for multi-tenant, or run local " +
76
+ "single-user with REQUIRE_PRINCIPAL=false (a BFF may still inject x-agent-principal per request for memory " +
77
+ "scoping and audit attribution).");
78
+ }
71
79
  const dsnConfigured = !!(config.tidb || config.pg);
72
80
  await ensureSnapshotBuckets(config, logger);
73
81
  const wantDb = config.sessionBackend === "tidb" ||
74
82
  config.dbBackend === "local" ||
75
83
  (config.sessionBackend === "auto" && dsnConfigured);
76
84
  if (wantDb) {
77
- const opened = await openStoreBackendWithFallback(config, logger, { runStallVerdicts: (landed) => metrics.inc("runs_reaped_total", { kind: "stale" }, landed) });
85
+ const opened = await openStoreBackendWithFallback(config, logger, { runStallVerdicts: (landed) => metrics.inc("runs_reaped_total", { kind: "stale" }, landed) }, localAdmission, { dataRootMedium: storeEvidence.dataRoot.verdict });
78
86
  backend = opened.backend;
79
87
  storeDegradedReason = opened.degradedReason;
80
88
  }
89
+ if (backend)
90
+ assertCloudSnapshotBlobPosture(backend.kind, config);
81
91
  {
82
92
  const mysqlPool = backend?.mysqlPool?.();
83
93
  const pgPool = backend?.pgPool?.();
@@ -108,8 +118,6 @@ export async function openStores(ctx) {
108
118
  else if (mysqlPool)
109
119
  await assertSessionExtCascadeOn(mysqlDriver(mysqlPool));
110
120
  }
111
- if (backend)
112
- await runAndLogOneTimeMigrations(logger, backend);
113
121
  if ((process.env.REWIND_SNAPSHOT_MAX_MB ?? "") !== "") {
114
122
  logger.warn("rewind_snapshot_max_mb_retired", {
115
123
  note: "REWIND_SNAPSHOT_MAX_MB no longer has an effect: the whole-tree snapshot epoch is retired (S-15); per-edited-file history captures only files the agent touches, with no tree walk and no size gate. Remove the env var. Per-blob SQL sizing is governed by SNAPSHOT_BLOB_SQL_MAX_BYTES / object storage as before.",
@@ -228,6 +236,7 @@ export async function openStores(ctx) {
228
236
  degradedReason: storeDegradedReason,
229
237
  evidence: storeEvidence,
230
238
  memoryRootWired: config.memoryEngineBackend === "file" && memoryEngine !== undefined,
239
+ localDeclaration: backend?.localStoreDeclaration?.(),
231
240
  });
232
241
  metrics.setGauge("store_backend_degraded", storePosture.degradedReason !== undefined ? 1 : 0);
233
242
  const freshStart = buildStoreFreshStartLine(storePosture, storeEvidence);
@@ -422,25 +431,19 @@ export async function openStores(ctx) {
422
431
  await assertDeviceAuditRebindEventSchema(mysqlDriver(mysqlPool));
423
432
  }
424
433
  }
425
- {
434
+ const reconcileSchema = async (pending) => {
426
435
  const mysqlPool = backend?.mysqlPool?.();
427
436
  const pgPool = backend?.pgPool?.();
428
437
  if (pgPool)
429
- await assertSchemaMatchesCode(async (sql) => (await pgPool.query(sql)).rows, "pg");
438
+ await assertSchemaMatchesCode(async (sql) => (await pgPool.query(sql)).rows, "pg", pending);
430
439
  else if (mysqlPool)
431
- await assertSchemaMatchesCode(async (sql) => (await mysqlPool.query(sql))[0], "mysql");
432
- }
433
- const sessionStore = createSessionStore(config, backend, metrics);
434
- if (config.requirePrincipal && backend?.kind === "local") {
435
- throw new Error("REQUIRE_PRINCIPAL=true is not supported on the local file backend (DB_BACKEND=local): the lane is single-user " +
436
- "by construction — a session created before owners were recorded is claimed by the FIRST principal that submits " +
437
- "to it during the upgrade window, and the lane's mutual-recognition arms assume one user — so it cannot enforce " +
438
- "a multi-tenant session boundary. Use a SQL backend (DB_BACKEND=mysql|pg) for multi-tenant, or run local " +
439
- "single-user with REQUIRE_PRINCIPAL=false (a BFF may still inject x-agent-principal per request for memory " +
440
- "scoping and audit attribution).");
441
- }
440
+ await assertSchemaMatchesCode(async (sql) => (await mysqlPool.query(sql))[0], "mysql", pending);
441
+ };
442
+ await reconcileSchema(ONE_TIME_MIGRATIONS);
442
443
  if (backend)
443
- assertCloudSnapshotBlobPosture(backend.kind, config);
444
+ await runAndLogOneTimeMigrations(logger, backend);
445
+ await reconcileSchema([]);
446
+ const sessionStore = createSessionStore(config, backend, metrics);
444
447
  if (!config.requirePrincipal && headReadOf(sessionStore) !== undefined) {
445
448
  logger.warn("principal_optional", {
446
449
  note: "owner-aware session store with REQUIRE_PRINCIPAL=false — owned sessions are protected, but headerless callers can create/share anonymous sessions; set REQUIRE_PRINCIPAL=true for multi-tenant",
@@ -12,7 +12,7 @@
12
12
  * - 🔴 **候选 ≠ 延迟**(core 7.15.0 [ref] 的行为面收窄,本仓两条真后果见下):候选集整体受**一道**
13
13
  * 阈值门,全或无 —— 候选的内联字节(name+description+schema)≥ `floor(上下文 token × 10%) × 3`
14
14
  * 才延迟,否则**全内联且不挂 `ToolSearch`**。远端协议铸名因此**不再无条件占位**:本仓缺省窗
15
- * (`ASSUMED_CONTEXT_WINDOW`,今天 262144 token)下阈值 = 78 642 字符,一个中小 MCP 名册够不着 ⇒ 首请求带全 schema。
15
+ * (`ASSUMED_CONTEXT_WINDOW`,今天 131072 token)下阈值 = 39 321 字符,一个中小 MCP 名册够不着 ⇒ 首请求带全 schema。
16
16
  * 唯一不受门的是调用方的 `TaskSpec.deferTools` 字面名单(按字面恒延迟、不计量)。
17
17
  * - `RunnerDeps.deferMode:"auto"` 不是第二道门,而是把候选集**拓宽**到全部 caller spec 后走同一道门 ——
18
18
  * 在本仓缺省场景下那会连 Agent 与 Task 四件一起卷进候选(与 CC 姿态相反),所以我们**刻意不开**;
@@ -473,10 +473,11 @@ export declare function deploymentModPackages(d: Pick<Deps, "deploymentModPackag
473
473
  export declare function hostScheduler(c: Pick<ServiceConfig, "schedulerEnabled" | "requirePrincipal" | "remoteExec">): Fact<"scheduler_disabled" | "multi_tenant_deployment" | "not_host_lane">;
474
474
  /**
475
475
  * 前台命令超时转后台(`AUTO_BACKGROUND_ON_TIMEOUT`)在这台部署上生不生效:旋钮开 ∧ 本车道的执行环境能把**运行中的**命令领养成后台任务。
476
- * 「能领养」就是执行环境的 `backgroundCapabilities.supportsDetach`,三只声明它的适配器(host / k8s / e2b)上它与后台 shell 的 `supported` 是同一个值 ——
477
- * 所以按能力表的 `backgroundShell` 一位读:`supported`(k8s / e2b)⇒ 能;`single-user-only`(只有 host 一行)⇒ 单用户且 host 后台 shell 开关开着才能 ——
478
- * 开关是第二参 `hostBackgroundShellOn`,调用方交 `hostBackgroundShellEnabled()`(`HOST_BG_ENABLED`;host 适配器的能力位读同一只;本模块零 I/O,不自己读 env)。
479
- * 对账钉 `test/auto-background-on-timeout.test.ts` 逐车道拿装配出的真执行环境的 `supportsDetach` 与本事实对拍。
476
+ * 「能领养」就是执行环境的 `backgroundCapabilities.supportsDetach`,三只声明它的适配器(host / k8s / e2b)上它与后台 shell 的 `supported` 是同一个值,
477
+ * 这个值的**唯一**答者是部署形行 `DEPLOYMENT_SHAPE_PREDICATES.backgroundShell`(读能力表那一位:k8s / e2b 任何租户,host 只单主)—— 适配器与本事实读同一行,
478
+ * 本事实不再自己读能力表的三档。host 另有一个全局关停开关(`HOST_BG_ENABLED`),是旋钮不是部署形,所以只在 host 车道上、在行之上合取:
479
+ * 开关是第二参 `hostBackgroundShellOn`,调用方交 `hostBackgroundShellEnabled()`(host 适配器的能力位读同一只;本模块零 I/O,不自己读 env)。
480
+ * 同读钉 `test/auto-background-on-timeout.test.ts` ③ 逐车道 × 单主 / 多租拿装配出的真执行环境的 `supported` / `supportsDetach` 与本事实、行对读。
480
481
  * 旋钮先判:关着的部署不论车道都答 `auto_background_off`(运维旋钮无条件,不支持的车道不拒启,只如实报)。
481
482
  * `/health.autoBackgroundOnTimeout` 投它的三词({@link autoBackgroundOnTimeoutWord})。
482
483
  */
@@ -8,7 +8,7 @@ import { WEB_ADMIN_ENV } from "@sema-agent/settings-schema";
8
8
  import { blobExchangeOf, overwriteWipeIncapable } from "./session-sync.js";
9
9
  import { WORKSPACE_PERSIST_DEFAULT, WORKSPACE_SNAPSHOT_KEEP_DEFAULT, workspaceSnapshotTimeoutOf } from "./workspace-space.js";
10
10
  import { deletionHeadReadOf, headReadOf } from "./session-incarnation.js";
11
- import { executionLaneCaps, laneWiresExecutionEnv } from "./execution-lane-caps.js";
11
+ import { laneWiresExecutionEnv } from "./execution-lane-caps.js";
12
12
  export const CAPABILITY_FACT_WHY = {
13
13
  run_store_absent: "no durable run store is wired (DB_BACKEND=mysql|pg|local)",
14
14
  subagent_registry_absent: "the sub-agent steer registry is not wired",
@@ -503,19 +503,8 @@ export function hostScheduler(c) {
503
503
  export function autoBackgroundOnTimeout(c, hostBackgroundShellOn) {
504
504
  if (c.autoBackgroundOnTimeout !== true)
505
505
  return no("auto_background_off");
506
- const cap = executionLaneCaps(c.remoteExec.provider).backgroundShell;
507
- switch (cap) {
508
- case "unsupported":
509
- return no("lane_cannot_adopt_running_command");
510
- case "supported":
511
- return YES;
512
- case "single-user-only":
513
- return c.requirePrincipal !== true && hostBackgroundShellOn ? YES : no("lane_cannot_adopt_running_command");
514
- default: {
515
- const unknownCap = cap;
516
- throw new Error(`auto-background fact: unknown lane capability ${String(unknownCap)}`);
517
- }
518
- }
506
+ const laneCanAdopt = DEPLOYMENT_SHAPE_PREDICATES.backgroundShell.holds(c) && (c.remoteExec.provider !== "host" || hostBackgroundShellOn);
507
+ return laneCanAdopt ? YES : no("lane_cannot_adopt_running_command");
519
508
  }
520
509
  export const AUTO_BACKGROUND_ON_TIMEOUT_WORDS = ["armed", "off", "unsupported"];
521
510
  export function autoBackgroundOnTimeoutWord(f) {
@@ -0,0 +1,56 @@
1
+ /**
2
+ * **按令牌把一张 pending 卡 CAS expire —— 全仓唯一的读法**(状态读 `get` 交出的行状态,属主格读店的列,CAS 吃那一格)。六个读者同读这一只,没有第二份:
3
+ * · `POST /v1/runs/:id/cancel` 的停驻取消腿(`routes/runs.ts` 的 `cancelSuspended`);
4
+ * · 一条续跑腿被取消之后结算它续的那张卡(`resume-legs.ts` 的 `settleCardForCancel`);
5
+ * · 审批 SLA 拒扫腿对「准入策略挡住」的续跑当场过期该卡(`http/approval-sweeps.ts` 的 `expirePolicyBlockedCard`);
6
+ * · 会话删除 / 显式结清口带走停驻子代时作废它的卡(`session-children-retire.ts` 的 `expireParkedCard`);
7
+ * · 停驻写没落定就以失败收场时作废手里那张卡(`card-void.ts` 的 `voidPendingCard`);
8
+ * · 复活不了的停驻子代被 deny 时作废它的卡(`parked-decide.ts` 的 `voidUnrevivableCard`)。
9
+ *
10
+ * ## 规则一条:顺序恒为「先读状态、(要求归属就)再核归属、最后按存储列 expire」,不读行体里的属主格
11
+ * 一张停驻卡的事实在店里有两份:列(令牌、归属 run 的会话、门型、属主格 `scope` —— 引擎停驻时盖下,身份迁移时与行体里那一份一起迁)与行体(`checkpoint` 里的 JSON 快照)。
12
+ * `expire` 的 CAS 谓词吃的是列;拿行体里自带的那一份去配,行体与列不一致(手改 / 外来写者 / 迁移两腿之间)时只会把「列好体坏」说成「被并发决议了」,行体读不成检查点时更是读行体就抛。
13
+ * 1. **状态**:卡已不在待决面(已结 / 已不在)⇒ 不写 —— 已结的卡上 CAS 恒输,写一次只是多一次店写(店写口故障时那一次还会抛,把「本来什么都不用做」的收场变成失败)。
14
+ * 状态读 `get` 交出的行状态(状态列权威,不是行体快照里那一份);**读不成检查点的行体**({@link UnreadableCheckpointRowError})读不出状态 ⇒ 不替 CAS 判(「不知道」不当作「已结」),
15
+ * 下一步吃列的 CAS 自己判;其余读故障(连库 / 超时 / 程序错)原样上抛,店的故障不是答案。
16
+ * 2. **归属**(调用方要求时):卡的归属会话(`hostSessionOfCard`,列)必须就是调用方说的那只 —— 只作废**这一张**;读不出 / 对不上 ⇒ `host_mismatch`,不写。状态在归属之前:已结的卡不因归属对不上而报警。
17
+ * 3. **属主格**:`peekScopeByToken`(SQL = `scope` 列,local = 账本行),`null` 是店契约里的匿名值,按契约换成公共哨兵(两只真店的属主列非空,到不了这一臂)。
18
+ * 找「取消动词会结算哪一张卡」是取消口自己的事(`run-cancel-card.ts`);本模块只管拿到令牌之后怎么结算。
19
+ */
20
+ import type { CheckpointToken } from "@sema-agent/core";
21
+ import type { CheckpointStoreFull } from "./plugins/store-backend.js";
22
+ /** 「这张卡此刻的状态」那一问要的店口(只读 `get` 交出的行状态;结构型 —— 真店的 `get` 直接对上)。 */
23
+ export interface CardStatusPort {
24
+ get(token: CheckpointToken): Promise<{
25
+ readonly status?: string;
26
+ } | null>;
27
+ }
28
+ /** 结算一张卡要的店口:状态 + 属主格(店的列)+ CAS expire。六个读者的依赖型都从这一份取,不各自另写一份 `Pick`。 */
29
+ export type CardSettlePort = CardStatusPort & Pick<CheckpointStoreFull, "peekScopeByToken" | "expire">;
30
+ /** 要求归属时多要的一口:卡归在哪只会话上(归属列)。 */
31
+ export type CardHostPort = Pick<CheckpointStoreFull, "hostSessionOfCard">;
32
+ /**
33
+ * 结算的结局(店的事实,不嗅文案):
34
+ * · `expired` —— 本调用亲手把一张 pending 的卡 expire 了;
35
+ * · `not_pending` —— 卡已不在待决面(已结 / 已不在),没写;
36
+ * · `lost` —— 读状态时还 pending、CAS 输给了并发的结算(决定 / 收割 / 别的作废者);
37
+ * · `host_mismatch` —— 调用方要求的归属对不上(或说不出),没写。
38
+ */
39
+ export declare const CARD_EXPIRE_OUTCOME: {
40
+ readonly expired: "expired";
41
+ readonly notPending: "not_pending";
42
+ readonly lost: "lost";
43
+ readonly hostMismatch: "host_mismatch";
44
+ };
45
+ export type CardExpireOutcome = (typeof CARD_EXPIRE_OUTCOME)[keyof typeof CARD_EXPIRE_OUTCOME];
46
+ /** 调用方要求:这张卡必须归在 `hostSession` 这只会话上(`undefined` = 调用方说不出自己的会话 ⇒ 恒对不上)。 */
47
+ export interface CardHostGuard {
48
+ readonly hostSession: string | undefined;
49
+ }
50
+ /**
51
+ * 按店里的属主格把 `token` 那张卡 CAS expire(≈ deny 的 reaper 终局;不是 resolve —— 取消意味着 run 死掉,deny-RESUME 会把拒绝喂回模型烧 token),次序见模块头注。
52
+ * 要求归属就给 `guard`(店口多带 {@link CardHostPort});不给 ⇒ 不核归属(令牌是调用方按列找来的,如取消口的 `runCancelCardOf`)。
53
+ */
54
+ export declare function expireCardUnderStoredScope(cs: CardSettlePort, token: CheckpointToken): Promise<CardExpireOutcome>;
55
+ export declare function expireCardUnderStoredScope(cs: CardSettlePort & CardHostPort, token: CheckpointToken, guard: CardHostGuard): Promise<CardExpireOutcome>;
56
+ //# sourceMappingURL=card-settle-stored-scope.d.ts.map
@@ -0,0 +1,27 @@
1
+ import { UnreadableCheckpointRowError } from "./plugins/checkpoint-store-face.js";
2
+ import { CHECKPOINT_PUBLIC_SCOPE } from "./security.js";
3
+ export const CARD_EXPIRE_OUTCOME = { expired: "expired", notPending: "not_pending", lost: "lost", hostMismatch: "host_mismatch" };
4
+ async function cardLeftPending(cs, token) {
5
+ try {
6
+ const live = await cs.get(token);
7
+ return live === null || live.status !== "pending";
8
+ }
9
+ catch (e) {
10
+ if (e instanceof UnreadableCheckpointRowError)
11
+ return false;
12
+ throw e;
13
+ }
14
+ }
15
+ export async function expireCardUnderStoredScope(cs, token, guard) {
16
+ if (await cardLeftPending(cs, token))
17
+ return CARD_EXPIRE_OUTCOME.notPending;
18
+ if (guard !== undefined) {
19
+ if (guard.hostSession === undefined || cs.hostSessionOfCard === undefined || (await cs.hostSessionOfCard(token)) !== guard.hostSession)
20
+ return CARD_EXPIRE_OUTCOME.hostMismatch;
21
+ }
22
+ const scope = await cs.peekScopeByToken(token);
23
+ if (scope === undefined)
24
+ return CARD_EXPIRE_OUTCOME.notPending;
25
+ return (await cs.expire(token, scope ?? CHECKPOINT_PUBLIC_SCOPE)) ? CARD_EXPIRE_OUTCOME.expired : CARD_EXPIRE_OUTCOME.lost;
26
+ }
27
+ //# sourceMappingURL=card-settle-stored-scope.js.map
@@ -1,6 +1,7 @@
1
1
  /**
2
- * **结算时作废一张归本 run 会话的、本服务兑现不了的卡** —— 读卡 → 卡仍 pending ∧ 卡归调用方说的那只会话(归属列,`hostSessionOf`)⇒
3
- * 按卡**自己的** scope 走 checkpoint 店的 `expire`(与引擎的本进程仲裁器、续跑的 resolve 同一只 CAS,恰一个赢家)。不新增任何持久态。
2
+ * **结算时作废一张归本 run 会话的、本服务兑现不了的卡** —— 卡仍 pending ∧ 卡归调用方说的那只会话(归属列,`hostSessionOfCard`)⇒
3
+ * 按店里该卡的属主格走 checkpoint 店的 `expire`(全仓唯一的读法 {@link expireCardUnderStoredScope}:先读状态、再核归属、最后按属主列 CAS;与引擎的本进程仲裁器、续跑的 resolve 同一只 CAS,恰一个赢家)。
4
+ * 不新增任何持久态。
4
5
  *
5
6
  * 规则只有一条:**本服务兑现不了的卡不留在待决面上**。产地 = 停驻没落定就以失败收场的腿(`runs.ts` 的 `voidHeldParkCard`:后台腿与
6
7
  * 续跑腿):卡在本 run 的会话上,但兑现它的那条 run 已经 `failed`、认领已放 —— 卡的命运先于认领释放(调用方先调本动词、再放认领)。
@@ -8,20 +9,14 @@
8
9
  * `verifier-pause-card.ts`);那只动词只收验证器的卡,本 run 自己会话上的卡按引擎的读法仍走店级 `expire`。
9
10
  *
10
11
  * 不抛:作废没做成(店读 / 作废抛错、卡的会话对不上、没接店)⇒ 卡回到「留在待决面上、由审批兜底收割收走」的形,按产地登记的 tag
11
- * 响亮留痕(计数 + 探针行 + 一次 warn),结算照常往下走。卡已不 pending / 已不在 ⇒ 什么都不做(CAS 输给了别的结算者,结局相同)。
12
+ * 响亮留痕(计数 + 探针行 + 一次 warn),结算照常往下走。卡已不 pending / 已不在 ⇒ 什么都不做(别的结算者先收走了,结局相同;先于归属判,已结的卡不因归属对不上而报警)。
12
13
  * 店级 `expire` 只作废卡,不动引擎在停驻时给这只会话打的钉(钉在续跑终局 / 续跑失败臂放)。
13
14
  */
14
15
  import type { CheckpointToken } from "@sema-agent/core";
15
16
  import { type FailOpenTag } from "./observability/fail-open.js";
16
- /** 结算点手里那只 checkpoint 店的三个动词:读卡(取它自己的 scope / 状态)、读它归在哪只会话上 → 按卡自己的 scope CAS 作废。 */
17
- export interface CardVoidPort {
18
- get(token: CheckpointToken): Promise<{
19
- readonly scope?: string;
20
- readonly status?: string;
21
- } | null>;
22
- hostSessionOfCard(token: CheckpointToken): Promise<string | null | undefined>;
23
- expire(token: CheckpointToken, scope: string): Promise<boolean>;
24
- }
17
+ import { type CardHostPort, type CardSettlePort } from "./card-settle-stored-scope.js";
18
+ /** 结算点手里那只 checkpoint 店的动词:读卡的状态、读它归在哪只会话上(归属列)、读它的属主格(属主列)→ 按那一格 CAS 作废。 */
19
+ export type CardVoidPort = CardSettlePort & CardHostPort;
25
20
  /** 要作废的那一张:停驻带回的凭据 + 它应归的会话(本 run 的会话;对不上就不动它 —— 只作废**这一张**)。 */
26
21
  export interface CardRef {
27
22
  readonly token: CheckpointToken;
package/dist/card-void.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { errorText } from "./observability/err-text.js";
2
2
  import { recordFailOpen } from "./observability/fail-open.js";
3
+ import { CARD_EXPIRE_OUTCOME, expireCardUnderStoredScope } from "./card-settle-stored-scope.js";
3
4
  export async function voidPendingCard(card, cards, tag, at) {
4
5
  const miss = (reason, err) => recordFailOpen(tag, `reason=${reason}${at === undefined ? "" : ` ${at}`}${err === undefined ? "" : ` err=${err}`}`);
5
6
  if (cards === undefined) {
@@ -7,14 +8,8 @@ export async function voidPendingCard(card, cards, tag, at) {
7
8
  return;
8
9
  }
9
10
  try {
10
- const live = await cards.get(card.token);
11
- if (live === null || live.status !== "pending")
12
- return;
13
- if (card.sessionId === undefined || (await cards.hostSessionOfCard(card.token)) !== card.sessionId || typeof live.scope !== "string") {
11
+ if ((await expireCardUnderStoredScope(cards, card.token, { hostSession: card.sessionId })) === CARD_EXPIRE_OUTCOME.hostMismatch)
14
12
  miss("card_mismatch");
15
- return;
16
- }
17
- await cards.expire(card.token, live.scope);
18
13
  }
19
14
  catch (e) {
20
15
  miss("store_error", errorText(e));
@@ -18,6 +18,16 @@ export type CatalogDangerAxis = (typeof CATALOG_DANGER_AXES)[number];
18
18
  */
19
19
  export declare const URL_CREDENTIAL_POLICIES: readonly ["refuse", "mask"];
20
20
  export type UrlCredentialPolicy = (typeof URL_CREDENTIAL_POLICIES)[number];
21
+ /**
22
+ * secret 行的值**装着几枚凭据、按什么读出来**(闭集;只在 `type: "secret"` 的行上,其余行恒缺席)—— 本服务凭据的颗粒按本服务读这只变量的那一只解析器定:
23
+ * · `whole` —— 整值是一枚(令牌 / 口令 / 私钥 / 一只模型密钥;名单型旋钮的原文也按凭据类整值对待);
24
+ * · `token-table` —— `tok=system` 逗号表,每个 `tok` 是一枚(`SERVICE_AUTH_TOKENS`;读法 = `auth-keys.ts` `parseServiceAuthTokens`,`loadConfig` 同读);
25
+ * · `key-set` —— `{kid,key,status}` JSON 数组,每个 `key` 是一枚(`APPROVAL_HMAC_KEYS`;读法 = `auth-keys.ts` `parseApprovalHmacKeys`,`loadConfig` 同读)。
26
+ * 读者只有一个:自有凭据声明的值臂(`server-secret-env.ts`)—— 整值总在内,列表形另把每一枚交给引擎 ⇒ 一枚令牌换了个变量名放着,与原变量同扣。
27
+ * 词加一个而读者不补 ⇒ 编译红(读者是穷举 switch);secret 行不写 ⇒ 编译红(`r()` 的 secret 重载要它)。不上 wire。
28
+ */
29
+ export declare const SECRET_CREDENTIAL_FORMS: readonly ["whole", "token-table", "key-set"];
30
+ export type SecretCredentialForm = (typeof SECRET_CREDENTIAL_FORMS)[number];
21
31
  /** 域 = 配置九组(类型锁步:组集变了这里跟着红)。 */
22
32
  export type CatalogDomain = keyof ServiceConfigGroups;
23
33
  export declare const CATALOG_RESTART_SLICES: readonly RestartSlice[];
@@ -93,6 +103,8 @@ export interface ConfigCatalogSpec {
93
103
  readonly scope?: "bootstrap-only";
94
104
  /** url 行的凭据处置披露({@link UrlCredentialPolicy});url 行必填(`r()` 的 url 重载要它,缺 ⇒ 编译红),其余行写不进来。 */
95
105
  readonly credentialPolicy?: UrlCredentialPolicy;
106
+ /** secret 行的凭据颗粒({@link SecretCredentialForm});secret 行必填(`r()` 的 secret 重载要它,缺 ⇒ 编译红),其余行写不进来。 */
107
+ readonly credentialForm?: SecretCredentialForm;
96
108
  }
97
109
  export interface ConfigCatalogRowCenter {
98
110
  readonly domain: string;