@sema-agent/server 7.139.0 → 7.141.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 (328) hide show
  1. package/MIGRATION.md +471 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +94 -26
  5. package/dist/adoption/runner.js +1 -1
  6. package/dist/adoption/sql.js +1 -1
  7. package/dist/approval-batch-census.d.ts +27 -0
  8. package/dist/approval-batch-census.js +27 -0
  9. package/dist/approval-card.d.ts +37 -22
  10. package/dist/approval-card.js +6 -3
  11. package/dist/approval.d.ts +15 -0
  12. package/dist/approval.js +10 -0
  13. package/dist/audit.d.ts +4 -2
  14. package/dist/audit.js +2 -2
  15. package/dist/bench/s1/live-deps.js +3 -2
  16. package/dist/bench/s1/row.d.ts +5 -2
  17. package/dist/bench/s1/row.js +2 -22
  18. package/dist/boot/adoption.js +1 -1
  19. package/dist/boot/device-lane.d.ts +11 -0
  20. package/dist/boot/device-lane.js +16 -0
  21. package/dist/boot/engine-lease.d.ts +24 -3
  22. package/dist/boot/engine-lease.js +9 -2
  23. package/dist/boot/execution-env.js +18 -12
  24. package/dist/boot/execution-lane.d.ts +8 -0
  25. package/dist/boot/execution-lane.js +6 -1
  26. package/dist/boot/memory-boundary.d.ts +16 -53
  27. package/dist/boot/memory-boundary.js +10 -20
  28. package/dist/boot/memory-consolidation.d.ts +16 -12
  29. package/dist/boot/memory-consolidation.js +24 -13
  30. package/dist/boot/reapers.d.ts +2 -2
  31. package/dist/boot/resolve-spec.d.ts +3 -5
  32. package/dist/boot/resolve-spec.js +9 -8
  33. package/dist/boot/runner-deps.d.ts +3 -3
  34. package/dist/boot/runner-deps.js +1 -0
  35. package/dist/boot/session-faces.d.ts +1 -1
  36. package/dist/boot/session-faces.js +4 -3
  37. package/dist/boot/shutdown.js +5 -0
  38. package/dist/boot/stage-03-store-backend.d.ts +2 -6
  39. package/dist/boot/stage-03-store-backend.js +2 -3
  40. package/dist/boot/stage-04-stores.d.ts +2 -6
  41. package/dist/boot/stage-04-stores.js +5 -5
  42. package/dist/boot/stage-05-execution-env.d.ts +2 -6
  43. package/dist/boot/stage-05-execution-env.js +3 -1
  44. package/dist/boot/stage-06-runners.d.ts +2 -8
  45. package/dist/boot/stage-06-runners.js +3 -3
  46. package/dist/boot/stage-07-capability-layer.d.ts +2 -7
  47. package/dist/boot/stage-07-capability-layer.js +8 -10
  48. package/dist/boot/stage-08-reapers.d.ts +2 -7
  49. package/dist/boot/stage-09-leader.d.ts +2 -7
  50. package/dist/boot/stage-10-http-server.d.ts +2 -7
  51. package/dist/boot/stage-10-http-server.js +6 -4
  52. package/dist/boot/stores.d.ts +3 -6
  53. package/dist/boot/stores.js +37 -44
  54. package/dist/boot/task-list-lane.d.ts +1 -1
  55. package/dist/boot/task-list-lane.js +1 -1
  56. package/dist/boot/web-admin.js +36 -9
  57. package/dist/capabilities/execution-lane.d.ts +2 -2
  58. package/dist/capabilities/scenarios.d.ts +1 -1
  59. package/dist/capability-facts.d.ts +9 -0
  60. package/dist/capability-facts.js +9 -0
  61. package/dist/card-void.d.ts +38 -0
  62. package/dist/card-void.js +23 -0
  63. package/dist/config-catalog.js +12 -8
  64. package/dist/config-provider.d.ts +18 -17
  65. package/dist/config-provider.js +28 -36
  66. package/dist/config-types.d.ts +36 -9
  67. package/dist/config.js +56 -46
  68. package/dist/delegated-session-owner.d.ts +23 -20
  69. package/dist/delegated-session-owner.js +2 -2
  70. package/dist/deployment-shape.d.ts +9 -8
  71. package/dist/deployment-shape.js +4 -4
  72. package/dist/device-store.d.ts +7 -0
  73. package/dist/device-store.js +3 -0
  74. package/dist/execution-config-root.d.ts +22 -0
  75. package/dist/execution-config-root.js +35 -0
  76. package/dist/execution-lane-caps.d.ts +145 -107
  77. package/dist/execution-lane-caps.js +144 -83
  78. package/dist/execution-placement.d.ts +3 -0
  79. package/dist/execution-placement.js +7 -0
  80. package/dist/fleet/drain-entry.d.ts +3 -0
  81. package/dist/hosted-posture.d.ts +8 -0
  82. package/dist/hosted-posture.js +4 -0
  83. package/dist/http/admission.js +3 -3
  84. package/dist/http/caller-trust.d.ts +3 -2
  85. package/dist/http/caller-trust.js +2 -1
  86. package/dist/http/dispatch.js +4 -0
  87. package/dist/http/live-frame.d.ts +24 -0
  88. package/dist/http/live-frame.js +16 -0
  89. package/dist/http/memory-compliance-failure-reply.d.ts +3 -1
  90. package/dist/http/memory-compliance-failure-reply.js +5 -0
  91. package/dist/http/memory-layer-reply.d.ts +30 -0
  92. package/dist/http/memory-layer-reply.js +24 -0
  93. package/dist/http/resume-legs.js +49 -35
  94. package/dist/http/retired-service-deps.d.ts +1 -1
  95. package/dist/http/retired-service-deps.js +1 -1
  96. package/dist/http/route-table.js +2 -0
  97. package/dist/http/routes/adoption.js +1 -1
  98. package/dist/http/routes/approvals-assistant.js +1 -0
  99. package/dist/http/routes/capabilities.js +5 -4
  100. package/dist/http/routes/diagnostics.d.ts +0 -19
  101. package/dist/http/routes/diagnostics.js +16 -2
  102. package/dist/http/routes/memory-bundle.d.ts +2 -2
  103. package/dist/http/routes/memory-bundle.js +4 -1
  104. package/dist/http/routes/memory-compliance.js +9 -2
  105. package/dist/http/routes/memory-consolidation.js +12 -1
  106. package/dist/http/routes/memory-origin.js +14 -2
  107. package/dist/http/routes/memory-policy.js +7 -2
  108. package/dist/http/routes/run-permission-mode.d.ts +75 -0
  109. package/dist/http/routes/run-permission-mode.js +170 -0
  110. package/dist/http/routes/session-sync.d.ts +3 -6
  111. package/dist/http/routes/session-sync.js +7 -2
  112. package/dist/http/routes/sessions.js +33 -15
  113. package/dist/http/routes/tasks.js +67 -68
  114. package/dist/http/run-read-face.js +3 -3
  115. package/dist/http/send.d.ts +1 -1
  116. package/dist/http/send.js +2 -2
  117. package/dist/http/server.d.ts +14 -27
  118. package/dist/http/server.js +2 -2
  119. package/dist/http/sse-log.d.ts +3 -8
  120. package/dist/http/stored-body-replay.d.ts +3 -3
  121. package/dist/http/stored-body-replay.js +3 -1
  122. package/dist/identity-source.d.ts +1 -1
  123. package/dist/identity-source.js +1 -1
  124. package/dist/instruction-source-notice.d.ts +7 -0
  125. package/dist/instruction-source-notice.js +6 -6
  126. package/dist/lane-home-probe.d.ts +68 -42
  127. package/dist/lane-home-probe.js +53 -30
  128. package/dist/leader/wire.js +5 -4
  129. package/dist/mcp-assertion-header.d.ts +4 -0
  130. package/dist/mcp-assertion-header.js +5 -0
  131. package/dist/memory-bundle-engine.d.ts +16 -9
  132. package/dist/memory-bundle-engine.js +29 -6
  133. package/dist/memory-operator-faces.d.ts +85 -30
  134. package/dist/memory-operator-faces.js +136 -30
  135. package/dist/memory-posture.d.ts +1 -1
  136. package/dist/memory-project-layer.d.ts +3 -21
  137. package/dist/memory-project-layer.js +11 -8
  138. package/dist/memory-scope-stores.d.ts +73 -0
  139. package/dist/memory-scope-stores.js +86 -0
  140. package/dist/memory-scope.d.ts +33 -9
  141. package/dist/memory-scope.js +17 -5
  142. package/dist/memory-sync-client.d.ts +34 -9
  143. package/dist/memory-sync-client.js +108 -28
  144. package/dist/observability/fail-open.d.ts +30 -2
  145. package/dist/observability/fail-open.js +30 -2
  146. package/dist/observability/metrics.js +0 -1
  147. package/dist/observability/run-terminal.d.ts +6 -2
  148. package/dist/observability/run-terminal.js +25 -26
  149. package/dist/observability/secret-env-scrub.d.ts +20 -1
  150. package/dist/observability/secret-env-scrub.js +14 -0
  151. package/dist/orchestration/workflow-completion-inbox.d.ts +5 -2
  152. package/dist/orchestration/workflow-completion-inbox.js +13 -5
  153. package/dist/orchestration/workflow-notify-journal.d.ts +5 -3
  154. package/dist/orchestration/workflow-notify-journal.js +2 -1
  155. package/dist/permission-mode-admission.d.ts +68 -0
  156. package/dist/permission-mode-admission.js +23 -0
  157. package/dist/permission-rule-list.d.ts +55 -6
  158. package/dist/permission-rule-list.js +52 -5
  159. package/dist/plugins/adoption-log-sql.js +4 -4
  160. package/dist/plugins/approval-ask-store-sql.js +14 -14
  161. package/dist/plugins/approval-nonce-store.js +4 -4
  162. package/dist/plugins/blob-backend.d.ts +4 -4
  163. package/dist/plugins/blob-backend.js +7 -7
  164. package/dist/plugins/breaker-state-sql.js +2 -2
  165. package/dist/plugins/caching-session-store.d.ts +6 -0
  166. package/dist/plugins/caching-session-store.js +3 -0
  167. package/dist/plugins/checkpoint-index-columns.js +2 -2
  168. package/dist/plugins/checkpoint-store-sql.d.ts +65 -17
  169. package/dist/plugins/checkpoint-store-sql.js +90 -19
  170. package/dist/plugins/device-store-sql.d.ts +5 -2
  171. package/dist/plugins/device-store-sql.js +23 -20
  172. package/dist/plugins/ensure-index.d.ts +1 -2
  173. package/dist/plugins/execution-placement-sql.d.ts +19 -9
  174. package/dist/plugins/execution-placement-sql.js +20 -9
  175. package/dist/plugins/file-history-store-sql.d.ts +2 -2
  176. package/dist/plugins/file-history-store-sql.js +4 -4
  177. package/dist/plugins/file-run-store.d.ts +2 -2
  178. package/dist/plugins/file-run-store.js +1 -1
  179. package/dist/plugins/fork-routing-session-store.d.ts +10 -32
  180. package/dist/plugins/fork-routing-session-store.js +2 -61
  181. package/dist/plugins/image-bake-store-sql.js +9 -9
  182. package/dist/plugins/image-index-sql.js +11 -11
  183. package/dist/plugins/k8s-exec-protocol.d.ts +4 -1
  184. package/dist/plugins/k8s-exec-protocol.js +6 -1
  185. package/dist/plugins/leader-run-store-sql.js +4 -4
  186. package/dist/plugins/local-checkpoint-store.d.ts +10 -1
  187. package/dist/plugins/local-checkpoint-store.js +22 -0
  188. package/dist/plugins/local-session-store.d.ts +227 -35
  189. package/dist/plugins/local-session-store.js +518 -37
  190. package/dist/plugins/local-session-window.d.ts +17 -3
  191. package/dist/plugins/local-session-window.js +7 -13
  192. package/dist/plugins/mailbox-store-sql.d.ts +2 -1
  193. package/dist/plugins/mailbox-store-sql.js +4 -4
  194. package/dist/plugins/memory-engine-tidb.js +5 -5
  195. package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
  196. package/dist/plugins/memory-run-store.d.ts +2 -2
  197. package/dist/plugins/memory-run-store.js +1 -1
  198. package/dist/plugins/memory-sync-store-tidb.js +3 -3
  199. package/dist/plugins/one-time-migrations.d.ts +52 -11
  200. package/dist/plugins/one-time-migrations.js +101 -39
  201. package/dist/plugins/org-delivery-quota-store.js +2 -2
  202. package/dist/plugins/outcome-ledger-sql.js +2 -2
  203. package/dist/plugins/permission-rule-store-sql.d.ts +4 -4
  204. package/dist/plugins/permission-rule-store-sql.js +16 -16
  205. package/dist/plugins/pg-pool.js +3 -2
  206. package/dist/plugins/pg-session-storage.d.ts +2 -0
  207. package/dist/plugins/pg-session-storage.js +3 -2
  208. package/dist/plugins/remote-env-adb.d.ts +7 -24
  209. package/dist/plugins/remote-env-adb.js +22 -5
  210. package/dist/plugins/remote-env-device.d.ts +2 -28
  211. package/dist/plugins/remote-env-device.js +2 -1
  212. package/dist/plugins/remote-env-e2b.d.ts +40 -27
  213. package/dist/plugins/remote-env-e2b.js +180 -20
  214. package/dist/plugins/remote-env-file-error.d.ts +1 -1
  215. package/dist/plugins/remote-env-file-error.js +8 -2
  216. package/dist/plugins/remote-env-host.d.ts +19 -35
  217. package/dist/plugins/remote-env-host.js +26 -3
  218. package/dist/plugins/remote-env-k8s.d.ts +22 -14
  219. package/dist/plugins/remote-env-k8s.js +150 -26
  220. package/dist/plugins/remote-env-local-docker.d.ts +27 -24
  221. package/dist/plugins/remote-env-local-docker.js +91 -24
  222. package/dist/plugins/remote-env-ssh.d.ts +4 -24
  223. package/dist/plugins/remote-env-ssh.js +4 -3
  224. package/dist/plugins/resume-anchor-store-sql.js +2 -2
  225. package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
  226. package/dist/plugins/retention-lane-store-sql.js +2 -2
  227. package/dist/plugins/retention-store-sql.d.ts +1 -1
  228. package/dist/plugins/retention-store-sql.js +6 -6
  229. package/dist/plugins/run-store-sql.d.ts +3 -3
  230. package/dist/plugins/run-store-sql.js +19 -18
  231. package/dist/plugins/sandbox-read-floor.d.ts +273 -0
  232. package/dist/plugins/sandbox-read-floor.js +608 -0
  233. package/dist/plugins/schema-consistency.d.ts +6 -6
  234. package/dist/plugins/schema-consistency.js +1 -1
  235. package/dist/plugins/schema-ensure-legs.d.ts +2 -3
  236. package/dist/plugins/schema-ensure-legs.js +2 -2
  237. package/dist/plugins/schema-live-columns.d.ts +1 -1
  238. package/dist/plugins/session-capture-record-store-sql.js +1 -1
  239. package/dist/plugins/session-ownership.d.ts +2 -1
  240. package/dist/plugins/session-placement.d.ts +17 -4
  241. package/dist/plugins/session-placement.js +2 -1
  242. package/dist/plugins/session-rules-column.d.ts +1 -1
  243. package/dist/plugins/session-rules-column.js +1 -1
  244. package/dist/plugins/session-store.d.ts +18 -20
  245. package/dist/plugins/session-store.js +4 -12
  246. package/dist/plugins/session-workspace-cell.d.ts +1 -1
  247. package/dist/plugins/session-workspace-cell.js +1 -1
  248. package/dist/plugins/shared-memory-store-sql.js +2 -2
  249. package/dist/plugins/sql-driver.d.ts +10 -5
  250. package/dist/plugins/sql-driver.js +6 -6
  251. package/dist/plugins/sql-errors.js +1 -1
  252. package/dist/plugins/store-backend.d.ts +35 -6
  253. package/dist/plugins/store-backend.js +27 -10
  254. package/dist/plugins/store-contracts.d.ts +9 -2
  255. package/dist/plugins/task-list-store-sql.js +11 -11
  256. package/dist/plugins/tidb-pool.js +7 -6
  257. package/dist/plugins/tidb-session-storage.js +4 -4
  258. package/dist/plugins/tidb-session-store.d.ts +4 -1
  259. package/dist/plugins/tidb-session-store.js +16 -15
  260. package/dist/plugins/tool-result-store-sql.d.ts +2 -2
  261. package/dist/plugins/tool-result-store-sql.js +3 -3
  262. package/dist/plugins/user-input-ledger-sql.js +2 -2
  263. package/dist/plugins/workflow-journal-store-sql.js +5 -5
  264. package/dist/plugins/workflow-run-store-sql.js +19 -19
  265. package/dist/plugins/write-behind-counter.d.ts +2 -3
  266. package/dist/plugins/write-behind-counter.js +5 -5
  267. package/dist/resource-suspend.d.ts +14 -12
  268. package/dist/resource-suspend.js +1 -1
  269. package/dist/resource-window.d.ts +4 -3
  270. package/dist/run-cancel-context.d.ts +34 -0
  271. package/dist/run-cancel-context.js +7 -0
  272. package/dist/run-local.js +14 -19
  273. package/dist/runs.d.ts +47 -16
  274. package/dist/runs.js +112 -113
  275. package/dist/security.d.ts +2 -2
  276. package/dist/server-secret-env.d.ts +2 -1
  277. package/dist/server-secret-env.js +2 -4
  278. package/dist/session-error-wire.d.ts +22 -4
  279. package/dist/session-error-wire.js +16 -0
  280. package/dist/session-incarnation.d.ts +10 -4
  281. package/dist/session-incarnation.js +1 -1
  282. package/dist/session-policy-wire.d.ts +1 -1
  283. package/dist/session-sync-kernel.d.ts +42 -1
  284. package/dist/session-sync-kernel.js +17 -0
  285. package/dist/session-sync.js +16 -4
  286. package/dist/sql-engine-coordinates.d.ts +49 -0
  287. package/dist/sql-engine-coordinates.js +27 -0
  288. package/dist/sql-engine-posture.d.ts +1 -1
  289. package/dist/sql-engine-posture.js +1 -1
  290. package/dist/standing-answer-grant.d.ts +31 -2
  291. package/dist/standing-answer-grant.js +14 -2
  292. package/dist/store-posture.d.ts +1 -1
  293. package/dist/{plugins → stores-sql}/background-agent-store-sql.d.ts +2 -2
  294. package/dist/{plugins → stores-sql}/background-agent-store-sql.js +8 -8
  295. package/dist/{plugins → stores-sql}/session-policy-store-sql.d.ts +7 -5
  296. package/dist/{plugins → stores-sql}/session-policy-store-sql.js +12 -12
  297. package/dist/{plugins → stores-sql}/usage-window-store-sql.d.ts +1 -1
  298. package/dist/{plugins → stores-sql}/usage-window-store-sql.js +3 -3
  299. package/dist/task-a2a.d.ts +1 -1
  300. package/dist/task-a2a.js +5 -6
  301. package/dist/task-mcp.d.ts +21 -8
  302. package/dist/task-mcp.js +17 -9
  303. package/dist/task-settings.d.ts +52 -25
  304. package/dist/task-settings.js +91 -28
  305. package/dist/terminal.d.ts +103 -19
  306. package/dist/terminal.js +72 -20
  307. package/dist/trace/core-keyset-guard.d.ts +79 -2
  308. package/dist/trace/exit-seat.d.ts +7 -0
  309. package/dist/trace/exit-seat.js +1 -0
  310. package/dist/trace/model-segment.d.ts +2 -2
  311. package/dist/trace/redact.d.ts +3 -1
  312. package/dist/trace/redact.js +395 -110
  313. package/dist/trace/self-minted-wire.d.ts +226 -2
  314. package/dist/trace/self-minted-wire.js +79 -0
  315. package/dist/verifier-pause-card.d.ts +8 -0
  316. package/dist/verifier-pause-card.js +19 -0
  317. package/dist/web-admin-client/apply-effective.d.ts +5 -7
  318. package/dist/web-admin-client/apply-effective.js +2 -2
  319. package/dist/web-admin-client/candidate-gate.d.ts +11 -7
  320. package/dist/web-admin-client/candidate-gate.js +1 -1
  321. package/dist/web-admin-client/http-client.d.ts +5 -4
  322. package/dist/web-admin-client/http-client.js +2 -2
  323. package/dist/web-admin-client/read-warnings.d.ts +7 -17
  324. package/dist/web-admin-client/read-warnings.js +5 -9
  325. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +3 -2
  326. package/package.json +2 -2
  327. package/wire-changes/server@7.140.0.json +184 -0
  328. package/wire-changes/server@7.141.0.json +367 -0
@@ -1,4 +1,5 @@
1
- import { classifySyncRelationship } from "./session-sync-kernel.js";
1
+ import { anchorEntryDeclared, classifySyncRelationship } from "./session-sync-kernel.js";
2
+ import { recordFailOpen } from "./observability/fail-open.js";
2
3
  import { loosenReasons, normalizeRules } from "@sema-agent/core";
3
4
  import { headReadOf } from "./session-incarnation.js";
4
5
  import { judgeSessionRulesWrite } from "@sema-agent/core";
@@ -60,8 +61,14 @@ export async function replayFileHistory(store, scope, envelope, srcGetBlob, opts
60
61
  function ownerAware(backend) {
61
62
  return backend.session();
62
63
  }
64
+ const DIAG_VALUE_MAX = 96;
65
+ function brief(value) {
66
+ return JSON.stringify(value.length > DIAG_VALUE_MAX ? `${value.slice(0, DIAG_VALUE_MAX)}…(${value.length} chars)` : value);
67
+ }
63
68
  export async function exportSessionManifest(sessionId, srcBackend, historyStore) {
64
69
  const session = ownerAware(srcBackend);
70
+ const anchorStore = srcBackend.resumeAnchor();
71
+ const anchors = await anchorStore.listBySession(sessionId);
65
72
  const listEntryIds = session.listEntryIds?.bind(session);
66
73
  if (!listEntryIds)
67
74
  return null;
@@ -76,15 +83,20 @@ export async function exportSessionManifest(sessionId, srcBackend, historyStore)
76
83
  const policy = typeof policyStore.listBySession === "function"
77
84
  ? await policyStore.listBySession(sessionId)
78
85
  : [];
79
- const anchorStore = srcBackend.resumeAnchor();
80
- const anchors = await anchorStore.listBySession(sessionId);
81
86
  const summaryOf = session.sessionSummaryOf?.bind(session);
82
87
  if (summaryOf === undefined)
83
88
  throw new Error("exportSessionManifest: the session store has no row read face (sessionSummaryOf) — the sessionSync fact should have refused this deployment");
84
89
  const row = await summaryOf(sessionId);
85
90
  const getBlob = blobGetterOf(fs);
91
+ const declared = new Set(entryIds);
92
+ const soundAnchors = anchors.filter((a) => {
93
+ if (anchorEntryDeclared(declared, a.entryId))
94
+ return true;
95
+ recordFailOpen("server.session-sync.dangling-anchor-export", `sessionId=${brief(sessionId)} eventId=${brief(a.eventId)} entryId=${brief(a.entryId)}`);
96
+ return false;
97
+ });
86
98
  return {
87
- manifest: { sessionId, entryIds, entryCount: entryIds.length, leafId, fileHistory, policy, anchors, ...(row !== undefined ? { title: row.title, pinned: row.pinned } : {}) },
99
+ manifest: { sessionId, entryIds, entryCount: entryIds.length, leafId, fileHistory, policy, anchors: soundAnchors, ...(row !== undefined ? { title: row.title, pinned: row.pinned } : {}) },
88
100
  getBlob,
89
101
  };
90
102
  }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * 一只 SQL 引擎「开店所需的坐标」—— 单一来源(纯叶,零依赖)。
3
+ *
4
+ * ## 病
5
+ * 显式 `DB_BACKEND=pg|mysql` 是运维在说「我要这只持久引擎」。可是坐标缺席时,起服在三种 `SESSION_BACKEND` 写法下走三条路:
6
+ * 未设 / `mysql` ⇒ 读坐标抛 `missing required env`(响亮);`auto` ⇒ 「坐标不在就不探测」,**静默落内存**,姿态位却照报 `declared: "pg"` ——
7
+ * 一个自以为在持久化的部署跑在内存里,`/health` 照样 200。`REQUIRE_PRINCIPAL=true` 同形。同一个声明,拒不拒取决于第二个旋钮怎么写。
8
+ *
9
+ * ## 药
10
+ * 声明 ∧ 坐标缺席 ⇒ 配置期拒启,**不看** `SESSION_BACKEND`(判官在 `config.ts` 的 store 域,一只):三种写法同一句拒句,
11
+ * 拒句点名缺的坐标**键名**(不回显值,也读不到值)与两条出路。本模块只出两样东西:各引擎的必需坐标键表,与按这张表铸的两句话
12
+ * ({@link buildDeclaredEngineWithoutCoordinatesRefusal} 给配置判官、{@link buildSqlPoolMissingRefusal} 给 `boot/stores.ts` 的记忆引擎同池门)。
13
+ *
14
+ * ## 为什么键表在这里、`config.ts` 的 `env("MYSQL_HOST")` 读法不动
15
+ * 配置目录的对账门按名字面扫 `env("NAME")` 与 `process.env.NAME`,把读法改成按表取名会让它看不见这些键;所以两块 `env()` 读仍是字面读,
16
+ * 本表与它们的一致由 `test/sql-engine-coordinates.test.ts` 的源码钉守(表里每个键在 `config.ts` 里恰有一处 `env("KEY")` 必需读)。
17
+ */
18
+ /** SQL 引擎词(`DB_BACKEND` 闭集里的两只持久引擎;`local` / `memory` 没有坐标)。 */
19
+ export type SqlEngine = "mysql" | "pg";
20
+ /**
21
+ * 每只引擎开店**必需**的坐标键(缺一 `config.ts` 的对应块抛 `missing required env`)。可选键(`*_PORT` / `*_PASSWORD` / `*_POOL_SIZE`)不在表里 ——
22
+ * 它们缺席有缺省,不是「没有坐标」。主机键是首位:它是「SQL 信号」与 `auto` 探测的唯一判据(`config.ts` `dbHostSet`)。
23
+ */
24
+ export declare const SQL_ENGINE_COORDINATE_KEYS: {
25
+ readonly mysql: readonly ["MYSQL_HOST", "MYSQL_USER", "MYSQL_DATABASE"];
26
+ readonly pg: readonly ["PG_HOST", "PG_USER", "PG_DATABASE"];
27
+ };
28
+ /** 该引擎的主机键(`SQL_ENGINE_COORDINATE_KEYS` 的首位)。 */
29
+ export declare function sqlEngineHostKey(engine: SqlEngine): string;
30
+ /** 必需坐标键里此刻缺席(未设或空串 —— 空串在本仓一律等同未设)的那几个,表序。只读键名,不读值。 */
31
+ export declare function missingSqlCoordinateKeys(engine: SqlEngine, env: NodeJS.ProcessEnv): readonly string[];
32
+ /**
33
+ * 显式 `DB_BACKEND=<engine>` 而该引擎的坐标缺席 ⇒ 配置期拒启句(唯一铸点;**与 `SESSION_BACKEND` 无关**,所以句子里没有它)。
34
+ * `missing` 是 {@link missingSqlCoordinateKeys} 的读数(此时至少含主机键)。
35
+ */
36
+ export declare function buildDeclaredEngineWithoutCoordinatesRefusal(engine: SqlEngine, missing: readonly string[]): string;
37
+ /**
38
+ * 记忆引擎要绑 `<engine>` 的池而店后端没给 ⇒ `boot/stores.ts` 的拒句。记忆持久面的 SQL 方言词与店的引擎词是**同一个字**(`MEMORY_ENGINE_BACKEND=pg|mysql`
39
+ * ↔ `DB_BACKEND=pg|mysql`),所以拒句只收引擎词。分两形(`DB_BACKEND` 是否已经点名该引擎):
40
+ * · 没点名 ⇒ 缺的是声明:`MEMORY_ENGINE_BACKEND=<engine>` 要 `DB_BACKEND=<engine>`;
41
+ * · 已点名 ⇒ 声明没缺,「要 DB_BACKEND=<engine>」指错了修法 —— 点名真正开店的两个条件(持久会话后端、必需坐标)与此刻缺的坐标键。
42
+ * 坐标缺席本身在配置期已被 {@link buildDeclaredEngineWithoutCoordinatesRefusal} 拒掉,走到这里的已点名形 = 坐标齐(或只缺非主机键)而会话后端是 `memory`。
43
+ */
44
+ export declare function buildSqlPoolMissingRefusal(args: {
45
+ readonly engine: SqlEngine;
46
+ readonly declared: boolean;
47
+ readonly missing: readonly string[];
48
+ }): string;
49
+ //# sourceMappingURL=sql-engine-coordinates.d.ts.map
@@ -0,0 +1,27 @@
1
+ export const SQL_ENGINE_COORDINATE_KEYS = {
2
+ mysql: ["MYSQL_HOST", "MYSQL_USER", "MYSQL_DATABASE"],
3
+ pg: ["PG_HOST", "PG_USER", "PG_DATABASE"],
4
+ };
5
+ export function sqlEngineHostKey(engine) {
6
+ return SQL_ENGINE_COORDINATE_KEYS[engine][0];
7
+ }
8
+ export function missingSqlCoordinateKeys(engine, env) {
9
+ return SQL_ENGINE_COORDINATE_KEYS[engine].filter((key) => env[key] === undefined || env[key] === "");
10
+ }
11
+ const ENGINE_LABEL = { mysql: "MySQL-protocol", pg: "PostgreSQL" };
12
+ export function buildDeclaredEngineWithoutCoordinatesRefusal(engine, missing) {
13
+ const required = SQL_ENGINE_COORDINATE_KEYS[engine];
14
+ return (`DB_BACKEND=${engine} declares the ${ENGINE_LABEL[engine]} engine, but its connection coordinates are not set (missing: ${missing.join(", ")}) — ` +
15
+ `no session store can open, so the deployment would run IN MEMORY while declaring a durable engine. ` +
16
+ `Refusing to boot rather than starting non-durable under that declaration (whatever SESSION_BACKEND says). ` +
17
+ `To persist: set ${required.join(", ")} (optional: ${engine === "pg" ? "PG_PORT, PG_PASSWORD" : "MYSQL_PORT, MYSQL_PASSWORD"}); ` +
18
+ `to run without SQL: DB_BACKEND=local (single-user file store) or DB_BACKEND=memory.`);
19
+ }
20
+ export function buildSqlPoolMissingRefusal(args) {
21
+ const { engine, declared, missing } = args;
22
+ if (!declared)
23
+ return `MEMORY_ENGINE_BACKEND=${engine} requires DB_BACKEND=${engine} (the memory engine binds the same ${ENGINE_LABEL[engine]} pool) — refusing to start half-configured`;
24
+ return (`MEMORY_ENGINE_BACKEND=${engine} binds the ${ENGINE_LABEL[engine]} pool of the deployment's store, but none is open although the effective DB_BACKEND is ${engine}: the SQL store opens only under a durable session backend (SESSION_BACKEND unset, mysql or auto — not memory) ` +
25
+ `with ${SQL_ENGINE_COORDINATE_KEYS[engine].join(", ")} set${missing.length > 0 ? ` (not set now: ${missing.join(", ")})` : ""} — refusing to start half-configured`);
26
+ }
27
+ //# sourceMappingURL=sql-engine-coordinates.js.map
@@ -38,7 +38,7 @@ export declare function sqlPoolsOf(backend: Pick<StoreBackend, "mysqlPool" | "pg
38
38
  pgPool: PgPool | undefined;
39
39
  };
40
40
  /**
41
- * `ServiceDeps.sqlEngine` 座的**值形**判:`{ dialect: "tidb" | "pg", facts }`,`facts` 是 `null`(池上连接初始化还没成功)或一份引擎事实 —— 判到墙判官 `sqlWallsOf` 读的那几位
41
+ * `ServiceDeps.sqlEngine` 座的**值形**判:`{ dialect: "mysql" | "pg", facts }`,`facts` 是 `null`(池上连接初始化还没成功)或一份引擎事实 —— 判到墙判官 `sqlWallsOf` 读的那几位
42
42
  * (`maxRowBytes` / `maxPacketBytes` 是 `null` 或数,`wallSources` 两位是出处词)。一个函数(7.131.x 的事实读口 `() => facts` 只改了键名)、缺 `facts` 的对象、错方言词都不是它。
43
43
  * `facts` 是活读(getter):这里读一次,判的是装配这一刻看得到的那一份。
44
44
  */
@@ -2,7 +2,7 @@ import { mysqlDriver, pgDriver } from "./plugins/sql-driver.js";
2
2
  export function sqlPoolsOf(backend) {
3
3
  return { mysqlPool: backend?.mysqlPool?.(), pgPool: backend?.pgPool?.() };
4
4
  }
5
- const DIALECT_WORDS = { tidb: true, pg: true };
5
+ const DIALECT_WORDS = { mysql: true, pg: true };
6
6
  const WALL_SOURCE_WORDS = { reported: true, assumed: true };
7
7
  const isWallBytes = (v) => v === null || (typeof v === "number" && Number.isFinite(v) && v >= 0);
8
8
  const isWallSourceWord = (v) => typeof v === "string" && Object.hasOwn(WALL_SOURCE_WORDS, v);
@@ -1,3 +1,23 @@
1
+ /**
2
+ * 站着的答案的**授予绑定**的唯一读口:这一问的应答授不授予「这一次调用」之外的东西,授予的话绑定是什么。
3
+ *
4
+ * 站着的答案(活的「本会话放行」、耐久的 `remember:"session"`)记下的是**上一次**应答;它只配代答「上一次应答覆盖得到」的问。
5
+ * 有一类卡的应答还**授予**别的东西:批准引擎的 `Skill` = 激活那只技能 + 本 run 内它 `allowedTools` 上的工具免问。这类卡的答案只能按
6
+ * 「工具 + 授予绑定」记、只代答绑定相同的问(core 原句「an answer is remembered by "this tool + this binding"」)。判据本身在
7
+ * `tool-approval.ts` 的 `standingAnswerHome`(本读口是它的一位);本文件只回答「授不授予、绑定是什么」,是叶模块。
8
+ *
9
+ * 🔴 **一条律:只读引擎的词,载体不论**。引擎的绑定工厂给一次调用的每一个载体盖**同一组词**、恰带一臂:`boundGrantDigest`(对引擎 `Skill` 工具的
10
+ * 激活:技能名 + 两只清单规范拼写的摘要)或 `boundGrantAbsence`(闭集 core `BOUND_GRANT_ABSENCES`:`not_bindable` = 不绑任何授予 / `unreadable` = 绑着却读不出)。
11
+ * 载体 = 活的 `AskRequest`、停驻行 `PendingAction.tool_approval`、读这两者的运维队列行 / inbox 行,以及 core 7.59.0 起 Runner 交给策略层的 `ToolCallRequest`
12
+ * (部署名单门、workflow 问句门在交出自己的问之前读它)。读法与 core 自己的 inbox 投影逐臂同一条:摘要是串 ⇒ `bound`;否则摘要不在且词是 `not_bindable`
13
+ * ⇒ `none`;其余(词是 `unreadable`、摘要在而不是串、集外词、两者都不说)⇒ `unreadable`。**不读工具名**。
14
+ * · 两者都不说的载体:7.51.0 之前停驻的行(core:「it does not say」)、宿主不经 Runner 自建的请求 —— 读作 `unreadable`:不可记、不被代答(fail-closed)。
15
+ * · 读面上的那一臂({@link grantBindingArm})是本读口的逆像:停驻行的运维队列行 / `/stream` 的 `pending` 帧投的就是 `grantBindingArm(grantBindingOf(行))` ——
16
+ * 恰带摘要与缺席词之一,与 core 投收件箱行的那一臂同值;卡上显示的臂与「本会话放行」记不记得住由同一次读定,不会两答。
17
+ * · 部署名单自己的问(答案记在 server 的会话豁免店,按 (会话, 工具名))的写侧、名单门的读侧、豁免列表三处读同一组词 —— 7.129.0–7.137.x 读侧手里的请求
18
+ * 不带词,三处只好按工具名读调用载体;那只读口随 core 7.59.0 退役。
19
+ */
20
+ import type { BoundGrantAbsence } from "@sema-agent/core";
1
21
  /** 载体:引擎给一次调用盖过绑定词的任何形(活的 `AskRequest`、停驻行的 `tool_approval` 臂、运维队列行、策略层的 `ToolCallRequest` 都结构上满足)。 */
2
22
  export interface StandingAnswerCard {
3
23
  readonly boundGrantDigest?: unknown;
@@ -12,6 +32,15 @@ export type GrantBinding = {
12
32
  } | {
13
33
  readonly kind: "unreadable";
14
34
  };
15
- /** 载体上的授予绑定 —— 只读引擎的词(读法见文件头注):摘要是串 ⇒ bound;摘要不在且词是 `not_bindable` ⇒ none;其余 ⇒ unreadable。 */
16
- export declare function grantBindingOf(card: StandingAnswerCard): GrantBinding;
35
+ /** 载体上的授予绑定 —— 只读引擎的词(读法见文件头注):摘要是串 ⇒ bound;摘要不在且词是 `not_bindable` ⇒ none;其余 ⇒ unreadable。
36
+ * 形参是任意对象(载体不论):读自持久层的停驻行(运维队列行的投影、`/decide` 的原始行)两座都按 `unknown` 读,结构上满足 {@link StandingAnswerCard} 的载体照传。 */
37
+ export declare function grantBindingOf(card: StandingAnswerCard | object): GrantBinding;
38
+ /** 授予绑定在读面上的形:恰一臂 —— 摘要,或缺席词(闭集 core `BOUND_GRANT_ABSENCES`)。 */
39
+ export type GrantBindingArm = {
40
+ readonly boundGrantDigest: string;
41
+ } | {
42
+ readonly boundGrantAbsence: BoundGrantAbsence;
43
+ };
44
+ /** {@link GrantBinding} 投回读面的那一臂(逐臂穷尽:core 给绑定加一态而这里不跟 ⇒ 编译红):bound ⇒ 摘要;none ⇒ `not_bindable`;unreadable ⇒ `unreadable`。 */
45
+ export declare function grantBindingArm(binding: GrantBinding): GrantBindingArm;
17
46
  //# sourceMappingURL=standing-answer-grant.d.ts.map
@@ -1,8 +1,20 @@
1
1
  const NOT_BINDABLE = "not_bindable";
2
+ const UNREADABLE = "unreadable";
2
3
  export function grantBindingOf(card) {
3
- const digest = card.boundGrantDigest;
4
+ const digest = "boundGrantDigest" in card ? card.boundGrantDigest : undefined;
4
5
  if (typeof digest === "string")
5
6
  return { kind: "bound", digest };
6
- return digest === undefined && card.boundGrantAbsence === NOT_BINDABLE ? { kind: "none" } : { kind: "unreadable" };
7
+ const word = "boundGrantAbsence" in card ? card.boundGrantAbsence : undefined;
8
+ return digest === undefined && word === NOT_BINDABLE ? { kind: "none" } : { kind: "unreadable" };
9
+ }
10
+ export function grantBindingArm(binding) {
11
+ switch (binding.kind) {
12
+ case "bound":
13
+ return { boundGrantDigest: binding.digest };
14
+ case "none":
15
+ return { boundGrantAbsence: NOT_BINDABLE };
16
+ case "unreadable":
17
+ return { boundGrantAbsence: UNREADABLE };
18
+ }
7
19
  }
8
20
  //# sourceMappingURL=standing-answer-grant.js.map
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * ## 形
10
10
  * `declared` = 运维的声明(`DB_BACKEND` 词,含缺省推导);`backend` = **装配出的**后端 kind(没装出后端 = `memory`);两者不等是合法的
11
- * 形(`DB_BACKEND=pg` + `SESSION_BACKEND=memory` = 声明 pg、刻意不持久;缺省推导 local 起不来)—— 两位都上 wire,
11
+ * 形(`DB_BACKEND=pg` + 坐标在场 + `SESSION_BACKEND=memory` = 声明 pg、刻意不持久 —— 坐标缺席的声明在配置期拒启,见 `sql-engine-coordinates.ts`;缺省推导 local 起不来)—— 两位都上 wire,
12
12
  * 由调用方自己读出落差。`degradedReason` present-iff 降级臂走过(按后端族定词,{@link storeDegradedReasonFor})。
13
13
  * 顶层 `sql` 并入 `store.sql`(硬 breaking,零别名;对象逐字同形)。
14
14
  */
@@ -31,8 +31,8 @@
31
31
  */
32
32
  import type { Pool } from "mysql2/promise";
33
33
  import { type BackgroundAgentRecord, type BackgroundAgentRowSummary, type BackgroundAgentStore } from "@sema-agent/core";
34
- import type { PgQueryFn } from "./pg-query.js";
35
- import { type IndexSpec } from "./ensure-index.js";
34
+ import type { PgQueryFn } from "../plugins/pg-query.js";
35
+ import { type IndexSpec } from "../plugins/ensure-index.js";
36
36
  export declare const BACKGROUND_AGENT_TABLE = "background_agent";
37
37
  type ReapOpts = {
38
38
  maxAgeMs?: number;
@@ -1,8 +1,8 @@
1
1
  import { BackgroundAgentStoreError, STALE_RUNNING_REAP_ATTRIBUTION, } from "@sema-agent/core";
2
- import { pgSafeJsonStringify, pgSanitizeText } from "./pg-safe-json.js";
3
- import { isMysqlDupKeyError } from "./sql-errors.js";
4
- import { ensureIndexes } from "./ensure-index.js";
5
- import { createObjectColumnReader, decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, jsonColumnText } from "./sql-json-column.js";
2
+ import { pgSafeJsonStringify, pgSanitizeText } from "../plugins/pg-safe-json.js";
3
+ import { isMysqlDupKeyError } from "../plugins/sql-errors.js";
4
+ import { ensureIndexes } from "../plugins/ensure-index.js";
5
+ import { createObjectColumnReader, decodeJsonColumn, decodeNullableJsonColumn, foldJsonColumn, jsonColumnText } from "../plugins/sql-json-column.js";
6
6
  import { backgroundAgentNameOf } from "../background-agent-name.js";
7
7
  export const BACKGROUND_AGENT_TABLE = "background_agent";
8
8
  function summaryCols(dialect) {
@@ -215,7 +215,7 @@ export class TiDBBackgroundAgentStore {
215
215
  }
216
216
  }
217
217
  async get(handle, scope) {
218
- const [rows] = (await this.pool.query(`SELECT ${jsonColumnText("tidb", "record_json")} FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = ? AND handle = ?`, [scope, handle]));
218
+ const [rows] = (await this.pool.query(`SELECT ${jsonColumnText("mysql", "record_json")} FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = ? AND handle = ?`, [scope, handle]));
219
219
  return rows.length > 0 ? readRecordColumn(rows[0].record_json, handle) : null;
220
220
  }
221
221
  async update(handle, scope, record, expect) {
@@ -234,12 +234,12 @@ export class TiDBBackgroundAgentStore {
234
234
  return res.affectedRows === 1;
235
235
  }
236
236
  async listBySession(scope, sessionId, opts) {
237
- const [rows] = (await this.pool.query(`SELECT ${summaryCols("tidb")} FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = ? AND (session_anchor = ? OR root_session_id = ?)${opts?.status !== undefined ? " AND status = ?" : ""}
237
+ const [rows] = (await this.pool.query(`SELECT ${summaryCols("mysql")} FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = ? AND (session_anchor = ? OR root_session_id = ?)${opts?.status !== undefined ? " AND status = ?" : ""}
238
238
  ORDER BY spawned_at_ms DESC, handle DESC${limitClause(opts?.limit)}`, opts?.status !== undefined ? [scope, sessionId, sessionId, opts.status] : [scope, sessionId, sessionId]));
239
239
  return rows.map(rowToSummary);
240
240
  }
241
241
  async listByScope(scope, opts) {
242
- const [rows] = (await this.pool.query(`SELECT ${summaryCols("tidb")} FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = ?${opts?.status !== undefined ? " AND status = ?" : ""}
242
+ const [rows] = (await this.pool.query(`SELECT ${summaryCols("mysql")} FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = ?${opts?.status !== undefined ? " AND status = ?" : ""}
243
243
  ORDER BY spawned_at_ms DESC, handle DESC${limitClause(opts?.limit)}`, opts?.status !== undefined ? [scope, opts.status] : [scope]));
244
244
  return rows.map(rowToSummary);
245
245
  }
@@ -252,7 +252,7 @@ export class TiDBBackgroundAgentStore {
252
252
  return 0;
253
253
  const flipped = new Set();
254
254
  if (opts.staleRunningMaxAgeMs !== undefined) {
255
- const [stale] = (await this.pool.query(`SELECT handle, ${jsonColumnText("tidb", "record_json")} FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = ? AND status = 'running' AND updated_at_ms < ?`, [scope, now - opts.staleRunningMaxAgeMs]));
255
+ const [stale] = (await this.pool.query(`SELECT handle, ${jsonColumnText("mysql", "record_json")} FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = ? AND status = 'running' AND updated_at_ms < ?`, [scope, now - opts.staleRunningMaxAgeMs]));
256
256
  for (const row of stale) {
257
257
  const live = readRecordColumn(row.record_json, String(row.handle));
258
258
  if (await this.update(String(row.handle), scope, flippedForm(live, now), { rev: live.rev }))
@@ -1,9 +1,8 @@
1
1
  import { type SessionPolicyStore, type SessionPermissionRules, type StoredSessionRules, type SessionRulesRecord, type PutRulesOptions } from "@sema-agent/core";
2
2
  import type { Pool as MySqlPool } from "mysql2/promise";
3
3
  import type { Pool as PgPool } from "pg";
4
- import { type JsonColumnShape } from "./sql-json-column.js";
5
- import { type SqlDriver } from "./sql-driver.js";
6
- import type { Logger } from "../observability/logger.js";
4
+ import { type JsonColumnShape } from "../plugins/sql-json-column.js";
5
+ import { type SqlDriver } from "../plugins/sql-driver.js";
7
6
  /** `session_policy.policy_key` 的**唯一铸造点**(core 复合键的 sha256)。
8
7
  *
9
8
  * 🔴 导出而不是让收编腿再抄一份(clay 宪法「schema 单一属主禁复制」):[ref] form b 的身份重绑要
@@ -45,8 +44,11 @@ export type StoredSessionRulesBody = SessionPermissionRules & Pick<StoredSession
45
44
  * + 恰好解一次 `decodeJsonColumn` + 折码 `foldJsonColumn`);本店只留「形判据是哪一只」与「坏体折成哪个码」。
46
45
  */
47
46
  export declare function readSessionRulesBody(body: unknown): JsonColumnShape<StoredSessionRulesBody>;
48
- /** 本店唯一的日志口:抹除封键那一臂([ref])的点名。缺席 ⇒ 退回 `console.warn`(不静默)。 */
49
- export type SessionPolicyStoreLogger = Pick<Logger, "warn">;
47
+ /** 本店唯一的日志口:抹除封键那一臂([ref])的点名。缺席 ⇒ 退回 `console.warn`(不静默)。
48
+ * 结构型,与服务日志口的 `warn` 逐位同形:本目录对服务的观测模块零依赖(目录的可搬性),服务的日志口照样直接交进来。 */
49
+ export type SessionPolicyStoreLogger = {
50
+ warn(msg: string, fields?: Record<string, unknown>): void;
51
+ };
50
52
  /** Dual-dialect durable SessionPolicyStore. See the file header for the dialect-delta ledger. */
51
53
  export declare class SqlSessionPolicyStore implements SessionPolicyStore {
52
54
  private readonly db;
@@ -1,10 +1,10 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { judgeSessionRulesWrite, readSessionRulesShape, SessionPolicyError } from "@sema-agent/core";
3
- import { SESSION_RULES_COLUMN } from "./session-rules-column.js";
4
- import { decodeJsonColumn, isJsonColumnBodyProblem, jsonColumnText } from "./sql-json-column.js";
5
- import { pgHasUnstorable } from "./pg-safe-json.js";
6
- import { mysqlDriver, pgDriver } from "./sql-driver.js";
7
- import { isDeadlockError, isDupKeyError } from "./sql-errors.js";
3
+ import { SESSION_RULES_COLUMN } from "../plugins/session-rules-column.js";
4
+ import { decodeJsonColumn, isJsonColumnBodyProblem, jsonColumnText } from "../plugins/sql-json-column.js";
5
+ import { pgHasUnstorable } from "../plugins/pg-safe-json.js";
6
+ import { mysqlDriver, pgDriver } from "../plugins/sql-driver.js";
7
+ import { isDeadlockError, isDupKeyError } from "../plugins/sql-errors.js";
8
8
  export const policyKeyFor = (sessionId, principal) => createHash("sha256").update(JSON.stringify([sessionId, principal ?? null])).digest("hex");
9
9
  const policyKey = policyKeyFor;
10
10
  const RETRY_LIMIT = 8;
@@ -63,15 +63,15 @@ export class SqlSessionPolicyStore {
63
63
  this.db = db;
64
64
  this.logger = logger;
65
65
  }
66
- q(tidb, pg) {
67
- return this.db.dialect === "tidb" ? tidb : pg;
66
+ q(mysql, pg) {
67
+ return this.db.dialect === "mysql" ? mysql : pg;
68
68
  }
69
69
  isDupKey(e) {
70
70
  return isDupKeyError(this.db.dialect, e);
71
71
  }
72
72
  async getRules(sessionId, principal) {
73
73
  const key = policyKey(sessionId, principal);
74
- const { rows } = await this.db.query(this.q(`SELECT 'row' AS src, ${jsonColumnText("tidb", RULES)}, rev, gen FROM session_policy WHERE policy_key = ?` +
74
+ const { rows } = await this.db.query(this.q(`SELECT 'row' AS src, ${jsonColumnText("mysql", RULES)}, rev, gen FROM session_policy WHERE policy_key = ?` +
75
75
  " UNION ALL SELECT 'seal', NULL, rev, gen FROM session_policy_rev_mark WHERE policy_key = ? AND rev = ?", `SELECT 'row' AS src, ${jsonColumnText("pg", RULES)}, rev, gen FROM session_policy WHERE policy_key = $1` +
76
76
  " UNION ALL SELECT 'seal', NULL, rev, gen FROM session_policy_rev_mark WHERE policy_key = $2 AND rev = $3"), [key, key, SEALED_MARK_REV]);
77
77
  if (rows.some((r) => r.src === "seal"))
@@ -82,7 +82,7 @@ export class SqlSessionPolicyStore {
82
82
  return rowToStored(row, `for session ${JSON.stringify(sessionId)}`);
83
83
  }
84
84
  async listBySession(sessionId) {
85
- const { rows } = await this.db.query(this.q(`SELECT 'row' AS src, principal, ${jsonColumnText("tidb", RULES)}, rev, gen FROM session_policy WHERE session_id = ?` +
85
+ const { rows } = await this.db.query(this.q(`SELECT 'row' AS src, principal, ${jsonColumnText("mysql", RULES)}, rev, gen FROM session_policy WHERE session_id = ?` +
86
86
  " UNION ALL SELECT 'seal', NULL, NULL, rev, gen FROM session_policy_rev_mark WHERE session_id = ? AND rev = ?", `SELECT 'row' AS src, principal, ${jsonColumnText("pg", RULES)}, rev, gen FROM session_policy WHERE session_id = $1` +
87
87
  " UNION ALL SELECT 'seal', NULL, NULL, rev, gen FROM session_policy_rev_mark WHERE session_id = $2 AND rev = $3"), [sessionId, sessionId, SEALED_MARK_REV]);
88
88
  if (rows.some((r) => r.src === "seal"))
@@ -95,7 +95,7 @@ export class SqlSessionPolicyStore {
95
95
  async putRules(sessionId, principal, rules, opts) {
96
96
  const key = policyKey(sessionId, principal);
97
97
  return this.retrying(() => this.tx(async (conn) => {
98
- const { rows } = await conn.query(this.q(`SELECT ${jsonColumnText("tidb", RULES)}, rev, gen FROM session_policy WHERE policy_key = ? FOR UPDATE`, `SELECT ${jsonColumnText("pg", RULES)}, rev, gen FROM session_policy WHERE policy_key = $1 FOR UPDATE`), [key]);
98
+ const { rows } = await conn.query(this.q(`SELECT ${jsonColumnText("mysql", RULES)}, rev, gen FROM session_policy WHERE policy_key = ? FOR UPDATE`, `SELECT ${jsonColumnText("pg", RULES)}, rev, gen FROM session_policy WHERE policy_key = $1 FOR UPDATE`), [key]);
99
99
  const prior = rows[0] ? rowToStored(rows[0], `for session ${JSON.stringify(sessionId)} (pre-write snapshot)`) : undefined;
100
100
  const priorRev = prior?.rev ?? 0;
101
101
  if (opts?.expectedRev !== undefined && priorRev !== opts.expectedRev) {
@@ -157,12 +157,12 @@ export class SqlSessionPolicyStore {
157
157
  sealedKeys.push({ policyKey: String(r.policy_key), rev: String(r.rev), gen: String(r.gen) });
158
158
  params.push(String(r.policy_key), sessionId, readable ? counters.rev : SEALED_MARK_REV, readable ? counters.gen + 1 : 0, now);
159
159
  const base = params.length - 5;
160
- return this.db.dialect === "tidb" ? "(?,?,?,?,?)" : `($${base + 1},$${base + 2},$${base + 3},$${base + 4},$${base + 5})`;
160
+ return this.db.dialect === "mysql" ? "(?,?,?,?,?)" : `($${base + 1},$${base + 2},$${base + 3},$${base + 4},$${base + 5})`;
161
161
  });
162
162
  await conn.query(this.q(`INSERT INTO session_policy_rev_mark (policy_key, session_id, rev, gen, erased_at) VALUES ${tuples.join(",")}` +
163
163
  " ON DUPLICATE KEY UPDATE rev = GREATEST(session_policy_rev_mark.rev, VALUES(rev)), gen = GREATEST(session_policy_rev_mark.gen + 1, VALUES(gen)), erased_at = VALUES(erased_at)", `INSERT INTO session_policy_rev_mark (policy_key, session_id, rev, gen, erased_at) VALUES ${tuples.join(",")}` +
164
164
  " ON CONFLICT (policy_key) DO UPDATE SET rev = GREATEST(session_policy_rev_mark.rev, EXCLUDED.rev), gen = GREATEST(session_policy_rev_mark.gen + 1, EXCLUDED.gen), erased_at = EXCLUDED.erased_at"), params);
165
- const holes = keys.map((_, i) => (this.db.dialect === "tidb" ? "?" : `$${i + 1}`)).join(",");
165
+ const holes = keys.map((_, i) => (this.db.dialect === "mysql" ? "?" : `$${i + 1}`)).join(",");
166
166
  await conn.query(`DELETE FROM session_policy WHERE policy_key IN (${holes})`, keys);
167
167
  return sealedKeys;
168
168
  }));
@@ -26,7 +26,7 @@
26
26
  import type { Pool as MySqlPool } from "mysql2/promise";
27
27
  import type { Pool as PgPool } from "pg";
28
28
  import type { UsageWindow, UsageWindowReading, UsageWindowRecord, UsageWindowStore } from "@sema-agent/core";
29
- import { type JsonColumnShape } from "./sql-json-column.js";
29
+ import { type JsonColumnShape } from "../plugins/sql-json-column.js";
30
30
  export declare const USAGE_WINDOW_TABLE = "usage_window";
31
31
  /**
32
32
  * `usage_window.record` 的**形读者**([ref] 车③a:本店既有的那一份深度判据逐字搬进来,一个字没改判)。
@@ -1,5 +1,5 @@
1
1
  import { EMPTY_USAGE_WINDOW_RECORD, chargeUsageRecord, readUsageRecord } from "@sema-agent/core";
2
- import { decodeJsonColumn, foldJsonColumn, jsonColumnText } from "./sql-json-column.js";
2
+ import { decodeJsonColumn, foldJsonColumn, jsonColumnText } from "../plugins/sql-json-column.js";
3
3
  export const USAGE_WINDOW_TABLE = "usage_window";
4
4
  class UsageRecordShapeProblem extends Error {
5
5
  }
@@ -84,7 +84,7 @@ export class TiDBUsageWindowStore {
84
84
  try {
85
85
  await c.beginTransaction();
86
86
  await c.query(`INSERT INTO ${USAGE_WINDOW_TABLE} (usage_key, record, updated_at_ms) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE usage_key = usage_key`, [key, JSON.stringify(EMPTY_USAGE_WINDOW_RECORD), at]);
87
- const [rows] = (await c.query(`SELECT ${jsonColumnText("tidb", "record")} FROM ${USAGE_WINDOW_TABLE} WHERE usage_key = ? FOR UPDATE`, [key]));
87
+ const [rows] = (await c.query(`SELECT ${jsonColumnText("mysql", "record")} FROM ${USAGE_WINDOW_TABLE} WHERE usage_key = ? FOR UPDATE`, [key]));
88
88
  if (rows.length === 0) {
89
89
  throw new Error(`usage_window row for key "${key}" vanished between ensure and lock — refusing to drop a governance charge`);
90
90
  }
@@ -102,7 +102,7 @@ export class TiDBUsageWindowStore {
102
102
  }
103
103
  }
104
104
  async read(key, windows, now) {
105
- const [rows] = (await this.pool.query(`SELECT ${jsonColumnText("tidb", "record")} FROM ${USAGE_WINDOW_TABLE} WHERE usage_key = ?`, [key]));
105
+ const [rows] = (await this.pool.query(`SELECT ${jsonColumnText("mysql", "record")} FROM ${USAGE_WINDOW_TABLE} WHERE usage_key = ?`, [key]));
106
106
  const record = rows.length === 0 ? EMPTY_USAGE_WINDOW_RECORD : parseRecord(rows[0].record, key);
107
107
  return readUsageRecord(record, windows, now);
108
108
  }
@@ -57,7 +57,7 @@ export declare const A2A_PEER_DISPOSITION: {
57
57
  readonly toolAxes: "engine";
58
58
  };
59
59
  /** 请求体 `a2aPeers[i]` 的键闭集 = 处置表的键(书写序即判序)。 */
60
- export declare const A2A_PEER_ENTRY_KEYS: readonly ("name" | "headers" | "principalHeader" | "toolAxes" | "url" | "cardUrl" | "allowSkills")[];
60
+ export declare const A2A_PEER_ENTRY_KEYS: readonly ("name" | "headers" | "url" | "principalHeader" | "toolAxes" | "cardUrl" | "allowSkills")[];
61
61
  /**
62
62
  * **请求入口的一次读**(`boot/resolve-spec.ts` 在腿首铸一份,受理门与读器——续跑重放腿只有读器——都吃这一份):`body.a2aPeers` 若是数组,返回同形数组
63
63
  * (每个对象条目换成它的 {@link PeerSnapshot};非对象条目原样;长度保真 —— 界外的条数仍是受理门撞帽拒与读器丢弃留声的依据,只快照界内的条目);不是数组(缺席 / `null` / 别的形)原样返回。
package/dist/task-a2a.js CHANGED
@@ -8,7 +8,7 @@ import { readRequestToolAxes } from "./request-tool-axes.js";
8
8
  import { MAX_KEY_ECHO, echoKeyName, keyClosureClause, scanKeyNames } from "./request-key-closure.js";
9
9
  import { urlCredentialHeaderExit, urlCredentialRefusalReason } from "./url-credential-refusal.js";
10
10
  import { declarationEntryNotObject, declarationIssueFacts, declarationNameIssue, declarationOverCapFacts, declaredName, judgeDeclarationKeys, requestDeclarationRefusal, throwDeclarationRefusal, } from "./request-declaration-refusal.js";
11
- import { principalHeaderOwnershipIssue } from "./task-mcp.js";
11
+ import { sendHeaderOwnershipIssue } from "./task-mcp.js";
12
12
  import { DEPLOYMENT_SHAPE_PREDICATES } from "./deployment-shape.js";
13
13
  export const MAX_REQUEST_A2A_PEERS = 32;
14
14
  export function a2aInjectionHonored(config) {
@@ -52,6 +52,7 @@ function peerUrlIssue(key) {
52
52
  return found === undefined ? undefined : { path: key, reason: urlCredentialRefusalReason(found, urlCredentialHeaderExit(`${at}.headers`)), credential: found };
53
53
  };
54
54
  }
55
+ const A2A_SEND_HEADER_PATHS = { headers: "headers", principalHeader: "principalHeader" };
55
56
  const HEADERS_RESERVED_MEMBER_PATH = "headers.__proto__";
56
57
  const PEER_SNAPSHOT = Symbol("a2aPeerSnapshot");
57
58
  function openCloneNode(v, ancestors) {
@@ -170,11 +171,9 @@ const A2A_PEER_KEY_JUDGES = {
170
171
  const reserved = read.stripped[0];
171
172
  return reserved === undefined ? undefined : { path: HEADERS_RESERVED_MEMBER_PATH, reason: reserved.fault };
172
173
  },
173
- principalHeader: (o) => o.principalHeader === undefined
174
- ? undefined
175
- : typeof o.principalHeader !== "string"
176
- ? { path: "principalHeader", reason: `must be a string (a header name) — got ${describeValueShape(o.principalHeader)}` }
177
- : principalHeaderOwnershipIssue(o.principalHeader, "a2a", "principalHeader"),
174
+ principalHeader: (o) => o.principalHeader !== undefined && typeof o.principalHeader !== "string"
175
+ ? { path: "principalHeader", reason: `must be a string (a header name) — got ${describeValueShape(o.principalHeader)}` }
176
+ : sendHeaderOwnershipIssue({ headers: o.headers?.ok === true ? o.headers.record : undefined, principalHeader: o.principalHeader }, "a2a", A2A_SEND_HEADER_PATHS),
178
177
  allowSkills: (o) => o.allowSkills === undefined || isStringArray(o.allowSkills)
179
178
  ? undefined
180
179
  : { path: "allowSkills", reason: `must be an array of strings (omit the key to leave the peer's skills unrestricted) — got ${describeNotStringArray(o.allowSkills)}` },
@@ -71,7 +71,7 @@ export declare const MCP_SERVER_ENTRY_KEYS: readonly ["allowTools", "contentOrig
71
71
  /** `transport.kind:"stdio"` 的键闭集 = stdio 臂处置表的键(`env` 是件,其余进声明)。 */
72
72
  export declare const STDIO_MCP_TRANSPORT_KEYS: readonly ("env" | "kind" | "args" | "command")[];
73
73
  /** `transport.kind:"http"` 的键闭集 = http 臂处置表的键(`headers` 是件,`assertionHeader` 承载不发送,其余进声明)。 */
74
- export declare const HTTP_MCP_TRANSPORT_KEYS: readonly ("headers" | "kind" | "principalHeader" | "url" | "assertionHeader")[];
74
+ export declare const HTTP_MCP_TRANSPORT_KEYS: readonly ("headers" | "kind" | "url" | "principalHeader" | "assertionHeader")[];
75
75
  /**
76
76
  * Does THIS deployment honor caller-supplied per-request MCP servers? TRUE for a SINGLE-USER deployment
77
77
  * (deployment-shape row `multiTenant` does not hold) — the requester is the super-admin of their own worker, so their `.mcp.json` is
@@ -158,7 +158,7 @@ export declare function requestEntryIdentityIssue(entry: unknown): McpIdentityHe
158
158
  * `name` = `isUsableWireName`;`allowTools` / `transport.args` = {@link isStringArray};`transport.env` / `headers` = 契约包读器 {@link readRequestMcpTransport} 的纯数据记录读法;`elicitation` = {@link isElicitationFlag};
159
159
  * `transport` 的硬字段(`kind` / `command` / `url`)与软字段(`args` / `env` / `headers` / `principalHeader`)= {@link readRequestMcpTransport}(读器投影 transport 的那一只函数,门读它报的 `lost`;读器在契约包,本仓只据 `lost[0]` 拒、据 `lost` 在重放腿逐处点名);
160
160
  * 读器交回的 http `url` 再问「带不带凭据」= 契约包根的 `findUrlCredential`([ref];拒体另带机读 `field` + `reason`,见 {@link transportUrlCredentialIssue});
161
- * http `principalHeader` 再问「这个名有没有别的属主」= 引擎包根的 `headerOwnershipCollision`(见 {@link principalHeaderOwnershipIssue})。
161
+ * http 这次发送的头集合(件头 + `principalHeader`)再问「有没有一个头名两个属主」= 引擎包根的 `headerOwnershipCollision`(见 {@link sendHeaderOwnershipIssue})。
162
162
  * 于是判官受理的条目,读器({@link normalizeServer})交回的就是申报本身(只差判官自己的合法归一:空容器 / `skillScopeEligible:false` 折成缺席、`toolAxes` 取引擎的拷贝)——
163
163
  * 探测口拨的那一份因此就是提交腿会挂的那一份,不另比一遍(另比就是第二只回答者)。唯一按门分的后果是「声明了 `assertionHeader`」这一个事实(本部署不发送断言,
164
164
  * 承载、不发送):新提交照挂 + 运维 info,探测口整条拒 —— 判据是同一只谓词 `specWithholdsMcpAssertionHeader`(开关 `MCP_ASSERTION_HEADER_SENT` 假时「声明了」即「被扣下」),不是第二份判法(见 `readMcpProbeBody`)。
@@ -185,14 +185,27 @@ export declare function requestMcpDeclarationRefusal(list: unknown): Declaration
185
185
  * 交出去的剔掉 `__proto__` 名成员),server 照挂,运维 warn `mcp_transport_members_dropped` 逐处点名 —— 续跑重放腿不静默丢声明。
186
186
  */
187
187
  export declare function assertRequestMcpEntries(bodyMcp: unknown): void;
188
+ /** 一次发送从一份声明里带出的头:件头(调用方原样写的名 → 值,由对端座按原字节作答)与身份头名(引擎按主体写值)。 */
189
+ export interface DeclaredSendHeaders {
190
+ readonly headers?: Readonly<Record<string, string>> | undefined;
191
+ readonly principalHeader?: string | undefined;
192
+ }
188
193
  /**
189
- * `principalHeader` 的**名**有没有别的属主:判官是引擎包根的 `headerOwnershipCollision`(拨号时判同一条的那一只;这里只问身份头这一个名,件头名由引擎在发送时判)——
190
- * 名(任何大小写)是这一协议的传输自己写的头(MCP:`mcp-session-id` · `mcp-protocol-version` · `content-type` · `accept` · `last-event-id`;A2A 没有),或是引擎的断言头
191
- * (`connector-assertion`)⇒ 这一台拨号时必被拒,新提交在门上按名拒。原因句只点名**属主的拼写**(引擎固定表里的规范化小写头名),不回显调用方写的原串 / 大小写形(调用方写的恰是小写时,句里的名与所写相同)。
192
- * 新提交腿上按名 400(MCP 门表的 `transport`、A2A 判官表的 `principalHeader`)。续跑重放腿不 4xx:MCP 的读器不问它 —— 存量体里这一形照挂,由引擎在拨号时拒那一台、兄弟照挂;
193
- * A2A 的读器问同一张判官表 —— 这一条对端整条不进、`a2a_injection_dropped` 点名原因(引擎物化时同样拒那一台;结局同,原因说在本仓这一行)。
194
+ * 一次发送的**头属主** —— 一条规则:这次发送会带的头集合(件头 + 身份头名)只有一只属主判官,引擎包根的 `headerOwnershipCollision`(引擎每次发送时判同一组的那一只);
195
+ * 受理口用**全部**问它一次。MCP 与 A2A 两座都调这一只:MCP 门表的 `transport` 格,A2A 判官表的 `principalHeader` 格(两键里判序靠后的那一格,读两键的读数)。
196
+ * 判官答撞 ⇒ 这一台拨号即拒(`config.protocol_header_collision`)或此后每一次发送都被拒(`credential_unavailable`)⇒ 新提交在门上按格 400:
197
+ * · 身份头名本身是这一协议的传输自己写的头(MCP:`mcp-session-id` · `mcp-protocol-version` · `content-type` · `accept` · `last-event-id`,任何大小写;A2A 没有),或是引擎的断言头
198
+ * (`connector-assertion`)⇒ `paths.principalHeader`;
199
+ * · 件头名是传输自己写的头 ⇒ `paths.headers`;件里同一头名两个拼写、件头名撞身份头名 ⇒ `paths.headers`。
200
+ * 件里名叫 `connector-assertion` 的头不撞(断言头在件里是座的;引擎只在它作身份头名时保留这个名)。原因句只点名**规范化小写**的头名(属主拼写,或调用方所写名字的小写形、经回显清洗),
201
+ * 不回显调用方的大小写形,从不带值。
202
+ * 不在本规则里的件形 —— 件值字节(CR / LF / NUL)、头名不是 HTTP token、stdio 变量名 —— 只由引擎内部的答案读器判(包根不导出),受理口没有同一只判官可问,照旧运行期 `credential_unavailable`。
203
+ * 续跑重放腿不 4xx:MCP 的读器不问门表 —— 存量体里撞属主的那一台照挂,由引擎拨号 / 发送时拒、兄弟照挂;A2A 的读器问同一张判官表 —— 这一条对端整条不进、`a2a_injection_dropped` 点名原因。
194
204
  */
195
- export declare function principalHeaderOwnershipIssue(principalHeader: string | undefined, protocol: "mcp" | "a2a", path: string): DeclarationKeyIssue | undefined;
205
+ export declare function sendHeaderOwnershipIssue(send: DeclaredSendHeaders, protocol: "mcp" | "a2a", paths: {
206
+ readonly headers: string;
207
+ readonly principalHeader: string;
208
+ }): DeclarationKeyIssue | undefined;
196
209
  /**
197
210
  * The ONE predicate for "this MCP server name belongs to the deployment": the scenario baseline (what mounted for
198
211
  * this scenario) ∪ every name the deployment DECLARED (`CenterMcp.reservedNames` — mounted or not, any scenario).
package/dist/task-mcp.js CHANGED
@@ -171,17 +171,25 @@ function transportUrlCredentialIssue(url) {
171
171
  return undefined;
172
172
  return { path: "transport.url", reason: urlCredentialRefusalReason(found, urlCredentialHeaderExit("transport.headers")), credential: found };
173
173
  }
174
- export function principalHeaderOwnershipIssue(principalHeader, protocol, path) {
175
- if (principalHeader === undefined)
176
- return undefined;
177
- const collision = headerOwnershipCollision({ principalHeader }, protocol);
174
+ export function sendHeaderOwnershipIssue(send, protocol, paths) {
175
+ const collision = headerOwnershipCollision({ headers: send.headers === undefined ? undefined : { ...send.headers }, principalHeader: send.principalHeader }, protocol);
178
176
  if (collision === undefined)
179
177
  return undefined;
180
- return {
181
- path,
182
- reason: `names the header "${collision.first}" (header names are case-insensitive), which is not the principal header's to own — it is ${protocol === "mcp" && collision.first !== MCP_ASSERTION_HEADER ? "a header the MCP transport writes itself" : "the engine's connector assertion header"}; name the principal header something of its own`,
183
- };
178
+ if (collision.engineOwned) {
179
+ const owner = echoKeyName("", collision.first);
180
+ const ownedBy = collision.first === MCP_ASSERTION_HEADER ? "the engine's connector assertion header" : "a header the MCP transport writes itself";
181
+ if (collision.second === send.principalHeader) {
182
+ return { path: paths.principalHeader, reason: `names the header "${owner}" (header names are case-insensitive), which is not the principal header's to own — it is ${ownedBy}; name the principal header something of its own` };
183
+ }
184
+ return { path: paths.headers, reason: `carries the header "${owner}" (header names are case-insensitive), which is not this declaration's to send — it is ${ownedBy}; leave it out` };
185
+ }
186
+ const name = echoKeyName("", collision.first.toLowerCase());
187
+ if (collision.first === send.principalHeader || collision.second === send.principalHeader) {
188
+ return { path: paths.headers, reason: `carries a header named as the principal header "${name}" (header names are case-insensitive) — the engine writes the principal under that name; rename one of them` };
189
+ }
190
+ return { path: paths.headers, reason: `carries the header "${name}" under two spellings (header names are case-insensitive) — one send carries one value per header name; keep one` };
184
191
  }
192
+ const MCP_SEND_HEADER_PATHS = { headers: "transport.headers", principalHeader: "transport.principalHeader" };
185
193
  const ENTRY_KEY_JUDGES = {
186
194
  allowTools: (o) => o.allowTools === undefined || isStringArray(o.allowTools)
187
195
  ? undefined
@@ -231,7 +239,7 @@ const ENTRY_KEY_JUDGES = {
231
239
  return read.lost[0];
232
240
  if (read.transport.kind !== "http")
233
241
  return undefined;
234
- return transportUrlCredentialIssue(read.transport.url) ?? principalHeaderOwnershipIssue(read.transport.principalHeader, "mcp", "transport.principalHeader");
242
+ return transportUrlCredentialIssue(read.transport.url) ?? sendHeaderOwnershipIssue({ headers: read.transport.headers, principalHeader: read.transport.principalHeader }, "mcp", MCP_SEND_HEADER_PATHS);
235
243
  },
236
244
  };
237
245
  function requestEntryRefusal(entry, at) {