@sema-agent/core 7.54.1 → 7.56.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 (621) hide show
  1. package/CHANGELOG.md +950 -0
  2. package/dist/agents/agent-transcript-tool.js +2 -1
  3. package/dist/agents/builtin-agents.d.ts +12 -14
  4. package/dist/agents/cascade.js +1 -1
  5. package/dist/agents/cc-peer-directory.d.ts +36 -0
  6. package/dist/agents/cc-peer-directory.js +139 -0
  7. package/dist/agents/cc-peer-wire.d.ts +105 -0
  8. package/dist/agents/cc-peer-wire.js +98 -0
  9. package/dist/agents/cc-uds-peer-channel.d.ts +40 -0
  10. package/dist/agents/cc-uds-peer-channel.js +457 -0
  11. package/dist/agents/child-model-seat.d.ts +0 -11
  12. package/dist/agents/child-model-seat.js +0 -3
  13. package/dist/agents/cross-session-envelope.d.ts +4 -1
  14. package/dist/agents/cross-session-envelope.js +8 -1
  15. package/dist/agents/cross-session-judge.d.ts +2 -2
  16. package/dist/agents/list-agents-tool.d.ts +3 -1
  17. package/dist/agents/list-agents-tool.js +9 -8
  18. package/dist/agents/observer.d.ts +4 -5
  19. package/dist/agents/observer.js +2 -1
  20. package/dist/agents/peer-admission.d.ts +6 -0
  21. package/dist/agents/peer-admission.js +4 -1
  22. package/dist/agents/peer-directory.d.ts +65 -13
  23. package/dist/agents/peer-directory.js +90 -25
  24. package/dist/agents/peer-notices.d.ts +1 -1
  25. package/dist/agents/peer-session-drain.d.ts +3 -1
  26. package/dist/agents/peer-session-drain.js +3 -2
  27. package/dist/agents/read-inbox-tool.js +2 -1
  28. package/dist/agents/repair-loop.js +2 -2
  29. package/dist/agents/retain-ledger.d.ts +1 -1
  30. package/dist/agents/roster-store.d.ts +1 -1
  31. package/dist/agents/send-message-tool.d.ts +10 -0
  32. package/dist/agents/send-message-tool.js +37 -8
  33. package/dist/agents/subagent.d.ts +39 -82
  34. package/dist/agents/subagent.js +109 -106
  35. package/dist/agents/tool-filter.d.ts +31 -46
  36. package/dist/agents/tool-filter.js +13 -33
  37. package/dist/agents/verify.d.ts +6 -5
  38. package/dist/agents/verify.js +3 -3
  39. package/dist/brain/anthropic.js +43 -81
  40. package/dist/brain/errors.d.ts +15 -0
  41. package/dist/brain/errors.js +10 -0
  42. package/dist/brain/media-degrade.d.ts +18 -7
  43. package/dist/brain/media-degrade.js +13 -2
  44. package/dist/brain/model-capability.d.ts +37 -0
  45. package/dist/brain/model-capability.js +34 -0
  46. package/dist/brain/model-presets.d.ts +6 -12
  47. package/dist/brain/model-presets.js +1 -6
  48. package/dist/brain/open-responses.js +27 -35
  49. package/dist/brain/openai.js +30 -98
  50. package/dist/brain/provider-dialect.d.ts +39 -3
  51. package/dist/brain/provider-dialect.js +28 -0
  52. package/dist/brain/reasoning-request.d.ts +96 -0
  53. package/dist/brain/reasoning-request.js +174 -0
  54. package/dist/brain/reasoning.d.ts +12 -12
  55. package/dist/brain/reasoning.js +4 -3
  56. package/dist/brain/request-params.d.ts +62 -9
  57. package/dist/brain/request-params.js +42 -7
  58. package/dist/brain/retry.d.ts +1 -1
  59. package/dist/brain/route-adjudicator.d.ts +15 -0
  60. package/dist/brain/route-adjudicator.js +15 -0
  61. package/dist/brain/status-sink.d.ts +20 -0
  62. package/dist/brain/status-sink.js +7 -0
  63. package/dist/brain/stream-engine.js +6 -5
  64. package/dist/brain/stream-shared.d.ts +1 -1
  65. package/dist/core/a2a.d.ts +2 -1
  66. package/dist/core/a2a.js +19 -13
  67. package/dist/core/advisor-verdict.d.ts +120 -0
  68. package/dist/core/advisor-verdict.js +92 -0
  69. package/dist/core/agent-definition.d.ts +17 -8
  70. package/dist/core/allow-entry.d.ts +69 -36
  71. package/dist/core/allow-entry.js +81 -52
  72. package/dist/core/allow-rule-shadow.d.ts +10 -3
  73. package/dist/core/approval-object.d.ts +2 -1
  74. package/dist/core/approval-object.js +6 -6
  75. package/dist/core/ask-origin.d.ts +127 -29
  76. package/dist/core/ask-origin.js +87 -25
  77. package/dist/core/ask-question.d.ts +51 -8
  78. package/dist/core/ask-question.js +12 -7
  79. package/dist/core/ask-unresolvable-notice.d.ts +8 -3
  80. package/dist/core/ask-unresolvable-notice.js +16 -2
  81. package/dist/core/auto-compaction.d.ts +11 -8
  82. package/dist/core/auto-compaction.js +4 -2
  83. package/dist/core/auto-mode-arming.d.ts +2 -2
  84. package/dist/core/auto-mode-defaults.d.ts +8 -8
  85. package/dist/core/auto-mode-prompt-assets.d.ts +3 -3
  86. package/dist/core/auto-mode-prompt.d.ts +1 -1
  87. package/dist/core/auto-mode.d.ts +17 -9
  88. package/dist/core/auto-mode.js +9 -6
  89. package/dist/core/background-agent-store.d.ts +3 -3
  90. package/dist/core/canonical-json.d.ts +1 -1
  91. package/dist/core/canonical-json.js +2 -2
  92. package/dist/core/checkpoint-generation.d.ts +53 -0
  93. package/dist/core/checkpoint-generation.js +35 -0
  94. package/dist/core/checkpoint-queries.d.ts +180 -0
  95. package/dist/core/checkpoint-queries.js +272 -0
  96. package/dist/core/checkpoint-requirements.d.ts +19 -4
  97. package/dist/core/checkpoint-requirements.js +8 -14
  98. package/dist/core/checkpoint-store.d.ts +165 -72
  99. package/dist/core/checkpoint-store.js +79 -82
  100. package/dist/core/child-clamp-seats.d.ts +6 -0
  101. package/dist/core/child-clamp-seats.js +3 -16
  102. package/dist/core/compliance.d.ts +2 -2
  103. package/dist/core/context-edit.d.ts +6 -7
  104. package/dist/core/cross-boundary-taint.d.ts +11 -4
  105. package/dist/core/cross-boundary-taint.js +3 -3
  106. package/dist/core/decision-receipt.d.ts +37 -3
  107. package/dist/core/decision-receipt.js +19 -19
  108. package/dist/core/delegation-not-started.d.ts +6 -0
  109. package/dist/core/delegation-not-started.js +17 -0
  110. package/dist/core/effective-path-target.d.ts +1 -1
  111. package/dist/core/engine-attestation.d.ts +93 -0
  112. package/dist/core/engine-attestation.js +70 -0
  113. package/dist/core/engine-capabilities.d.ts +4 -1
  114. package/dist/core/engine-capabilities.js +1 -1
  115. package/dist/core/engine-notice.d.ts +45 -12
  116. package/dist/core/exec-output-tail.d.ts +1 -1
  117. package/dist/core/file-history-retention.d.ts +1 -1
  118. package/dist/core/file-history-store.d.ts +147 -21
  119. package/dist/core/file-history-store.js +58 -32
  120. package/dist/core/gate-fold.d.ts +1 -1
  121. package/dist/core/gate-fold.js +24 -11
  122. package/dist/core/gate-lanes.js +81 -68
  123. package/dist/core/gate-outcome.d.ts +40 -6
  124. package/dist/core/gate-outcome.js +56 -0
  125. package/dist/core/governance-codes.d.ts +17 -3
  126. package/dist/core/governance-codes.js +16 -0
  127. package/dist/core/hands-band.d.ts +1 -1
  128. package/dist/core/hooks.d.ts +21 -20
  129. package/dist/core/hooks.js +3 -1
  130. package/dist/core/host-floor.d.ts +128 -0
  131. package/dist/core/host-floor.js +206 -0
  132. package/dist/core/host-target.d.ts +84 -0
  133. package/dist/core/host-target.js +92 -0
  134. package/dist/core/image-downsample.d.ts +1 -1
  135. package/dist/core/lsp-diagnostics.d.ts +4 -4
  136. package/dist/core/lsp.d.ts +3 -3
  137. package/dist/core/mailbox-store.d.ts +4 -0
  138. package/dist/core/mcp-connection-pool.d.ts +18 -2
  139. package/dist/core/mcp-connection-pool.js +53 -6
  140. package/dist/core/mcp-failure.d.ts +23 -4
  141. package/dist/core/mcp-failure.js +26 -11
  142. package/dist/core/mcp-listing-drift.d.ts +10 -0
  143. package/dist/core/mcp-listing-drift.js +6 -0
  144. package/dist/core/mcp-server-link.d.ts +173 -0
  145. package/dist/core/mcp-server-link.js +127 -0
  146. package/dist/core/mcp-server-spec.d.ts +4 -2
  147. package/dist/core/mcp-session-end.d.ts +26 -0
  148. package/dist/core/mcp-session-end.js +29 -0
  149. package/dist/core/mcp-startup-request.d.ts +17 -0
  150. package/dist/core/mcp-startup-request.js +17 -0
  151. package/dist/core/mcp.d.ts +17 -13
  152. package/dist/core/mcp.js +240 -189
  153. package/dist/core/media-byte-cap.d.ts +1 -1
  154. package/dist/core/memory-engine/delegation-settlement.js +15 -24
  155. package/dist/core/memory-engine/engine.d.ts +9 -9
  156. package/dist/core/memory-engine/engine.js +4 -4
  157. package/dist/core/memory-engine/layout.d.ts +60 -8
  158. package/dist/core/memory-engine/layout.js +65 -6
  159. package/dist/core/memory-engine/provenance-wording.d.ts +1 -1
  160. package/dist/core/memory-engine/tools.js +4 -1
  161. package/dist/core/mode-policy.d.ts +1 -1
  162. package/dist/core/model-seat.d.ts +10 -3
  163. package/dist/core/mods/classic-events.d.ts +67 -0
  164. package/dist/core/mods/classic-events.js +1 -0
  165. package/dist/core/mods/dollar.d.ts +13 -0
  166. package/dist/core/mods/extension-call.d.ts +31 -0
  167. package/dist/core/mods/extension-call.js +43 -0
  168. package/dist/core/mods/kernel/dispatch.d.ts +20 -3
  169. package/dist/core/mods/kernel/dispatch.js +140 -69
  170. package/dist/core/mods/kernel/events.d.ts +47 -11
  171. package/dist/core/mods/kernel/events.js +66 -42
  172. package/dist/core/mods/kernel/index.d.ts +4 -4
  173. package/dist/core/mods/kernel/index.js +2 -2
  174. package/dist/core/mods/kernel/receive.d.ts +39 -5
  175. package/dist/core/mods/kernel/receive.js +290 -17
  176. package/dist/core/mods/kernel/registration.d.ts +33 -2
  177. package/dist/core/mods/kernel/registration.js +6 -7
  178. package/dist/core/mods/kernel/site-rules.d.ts +44 -16
  179. package/dist/core/mods/kernel/site-rules.js +24 -42
  180. package/dist/core/mods/spec-seats.d.ts +69 -0
  181. package/dist/core/mods/spec-seats.js +114 -0
  182. package/dist/core/mods/stations.d.ts +28 -8
  183. package/dist/core/mods/stations.js +29 -13
  184. package/dist/core/mods/tool-call.d.ts +79 -0
  185. package/dist/core/mods/tool-call.js +152 -0
  186. package/dist/core/namespaced-rule-name.d.ts +44 -24
  187. package/dist/core/namespaced-rule-name.js +50 -43
  188. package/dist/core/output-style.d.ts +1 -1
  189. package/dist/core/param-rule-reach.d.ts +15 -0
  190. package/dist/core/param-rule-reach.js +30 -0
  191. package/dist/core/parent-spec-seat.d.ts +13 -1
  192. package/dist/core/parent-spec-seat.js +6 -0
  193. package/dist/core/park-selfcheck.js +1 -0
  194. package/dist/core/pause-registry.d.ts +16 -5
  195. package/dist/core/pause-registry.js +6 -2
  196. package/dist/core/peer-channel.d.ts +70 -0
  197. package/dist/core/peer-channel.js +1 -0
  198. package/dist/core/permission-rule-consent.d.ts +30 -5
  199. package/dist/core/permission-rule-consent.js +147 -50
  200. package/dist/core/permission-rule-model.d.ts +245 -65
  201. package/dist/core/permission-rule-model.js +421 -107
  202. package/dist/core/permission-rule-org.d.ts +6 -2
  203. package/dist/core/permission-rule-org.js +7 -3
  204. package/dist/core/permission-rule-provider.d.ts +6 -2
  205. package/dist/core/permission-rule-provider.js +41 -11
  206. package/dist/core/permission-rule-store.d.ts +22 -26
  207. package/dist/core/permission-rule-store.js +12 -6
  208. package/dist/core/permission-rule-sync.d.ts +11 -2
  209. package/dist/core/permission-rule-sync.js +11 -3
  210. package/dist/core/permission-rule-syntax.d.ts +5 -4
  211. package/dist/core/permission-rule-syntax.js +2 -2
  212. package/dist/core/permission-rules.d.ts +53 -15
  213. package/dist/core/permission-rules.js +125 -100
  214. package/dist/core/persisted-rule-arms.d.ts +6 -4
  215. package/dist/core/persisted-rule-arms.js +10 -12
  216. package/dist/core/present-plan-tool.js +3 -1
  217. package/dist/core/principal-name.d.ts +20 -0
  218. package/dist/core/principal-name.js +22 -0
  219. package/dist/core/prompt-section-seat.js +4 -6
  220. package/dist/core/protocol-http-auth.d.ts +26 -5
  221. package/dist/core/protocol-http-auth.js +137 -4
  222. package/dist/core/protocol-naming.d.ts +2 -2
  223. package/dist/core/read-only-shell-table.d.ts +1 -1
  224. package/dist/core/read-only-shell.d.ts +1 -1
  225. package/dist/core/retired-keys.d.ts +16 -0
  226. package/dist/core/retired-keys.js +16 -4
  227. package/dist/core/rewrite-rejudge.d.ts +60 -0
  228. package/dist/core/rewrite-rejudge.js +36 -0
  229. package/dist/core/roles.d.ts +34 -3
  230. package/dist/core/roles.js +66 -53
  231. package/dist/core/rule-lane-reads.d.ts +20 -15
  232. package/dist/core/rule-lane-reads.js +45 -17
  233. package/dist/core/rule-offer-read.d.ts +53 -0
  234. package/dist/core/rule-offer-read.js +146 -0
  235. package/dist/core/rule-owner.d.ts +46 -0
  236. package/dist/core/rule-owner.js +29 -0
  237. package/dist/core/runner/advisor-instructions.d.ts +70 -0
  238. package/dist/core/runner/advisor-instructions.js +61 -0
  239. package/dist/core/runner/advisor-tool.d.ts +33 -0
  240. package/dist/core/runner/advisor-tool.js +112 -0
  241. package/dist/core/runner/announce-once-ledger.d.ts +18 -26
  242. package/dist/core/runner/announce-once-ledger.js +19 -46
  243. package/dist/core/runner/approval-feedback.js +6 -3
  244. package/dist/core/runner/assemble-result.d.ts +2 -1
  245. package/dist/core/runner/assemble-result.js +1 -1
  246. package/dist/core/runner/call-hook-stations.d.ts +3 -2
  247. package/dist/core/runner/caller-roster.d.ts +21 -2
  248. package/dist/core/runner/caller-roster.js +38 -0
  249. package/dist/core/runner/capability-withheld-seat.d.ts +5 -0
  250. package/dist/core/runner/capability-withheld-seat.js +24 -0
  251. package/dist/core/runner/classifier-ladder.d.ts +33 -13
  252. package/dist/core/runner/classifier-ladder.js +15 -14
  253. package/dist/core/runner/compaction-restate.d.ts +10 -6
  254. package/dist/core/runner/compaction-restate.js +9 -3
  255. package/dist/core/runner/construction-doors.js +3 -0
  256. package/dist/core/runner/contracts.d.ts +40 -33
  257. package/dist/core/runner/conversation-segment.d.ts +28 -0
  258. package/dist/core/runner/conversation-segment.js +42 -0
  259. package/dist/core/runner/cross-boundary-lane.d.ts +21 -16
  260. package/dist/core/runner/cross-boundary-lane.js +58 -34
  261. package/dist/core/runner/decide-continuation.d.ts +7 -4
  262. package/dist/core/runner/decide-continuation.js +2 -2
  263. package/dist/core/runner/denial-limit-arms.d.ts +4 -4
  264. package/dist/core/runner/denial-limit-arms.js +1 -1
  265. package/dist/core/runner/derived-route-fallback.d.ts +24 -24
  266. package/dist/core/runner/derived-route-fallback.js +9 -7
  267. package/dist/core/runner/file-history-request.d.ts +18 -0
  268. package/dist/core/runner/file-history-request.js +21 -13
  269. package/dist/core/runner/file-history-restore.d.ts +45 -0
  270. package/dist/core/runner/file-history-restore.js +46 -0
  271. package/dist/core/runner/gate-exit.d.ts +9 -3
  272. package/dist/core/runner/gate-exit.js +11 -5
  273. package/dist/core/runner/image.d.ts +7 -17
  274. package/dist/core/runner/image.js +9 -60
  275. package/dist/core/runner/initial-run-state.js +1 -1
  276. package/dist/core/runner/permission-rule-lanes.d.ts +6 -6
  277. package/dist/core/runner/permission-rule-lanes.js +38 -15
  278. package/dist/core/runner/person-path-rows.d.ts +12 -9
  279. package/dist/core/runner/person-path-rows.js +19 -8
  280. package/dist/core/runner/prepare-advisor.d.ts +63 -0
  281. package/dist/core/runner/prepare-advisor.js +77 -0
  282. package/dist/core/runner/prepare-ask-lane.d.ts +2 -2
  283. package/dist/core/runner/prepare-ask-lane.js +5 -2
  284. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -6
  285. package/dist/core/runner/prepare-caps-and-workflow.js +5 -4
  286. package/dist/core/runner/prepare-config-doors.d.ts +31 -38
  287. package/dist/core/runner/prepare-config-doors.js +57 -34
  288. package/dist/core/runner/prepare-defer-classify.d.ts +4 -3
  289. package/dist/core/runner/prepare-defer-classify.js +7 -8
  290. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
  291. package/dist/core/runner/prepare-delegation-surface.js +1 -1
  292. package/dist/core/runner/prepare-file-history.d.ts +48 -8
  293. package/dist/core/runner/prepare-file-history.js +41 -73
  294. package/dist/core/runner/prepare-gate-stations.d.ts +2 -5
  295. package/dist/core/runner/prepare-gate-stations.js +12 -8
  296. package/dist/core/runner/prepare-hands-readface.d.ts +2 -8
  297. package/dist/core/runner/prepare-hands-readface.js +15 -14
  298. package/dist/core/runner/prepare-inherited-gate.d.ts +11 -7
  299. package/dist/core/runner/prepare-inherited-gate.js +8 -6
  300. package/dist/core/runner/prepare-memory-engine-session.js +1 -1
  301. package/dist/core/runner/prepare-park-ask.js +12 -12
  302. package/dist/core/runner/prepare-policy-chain.d.ts +7 -4
  303. package/dist/core/runner/prepare-policy-chain.js +68 -81
  304. package/dist/core/runner/prepare-project-context.d.ts +5 -2
  305. package/dist/core/runner/prepare-project-context.js +6 -3
  306. package/dist/core/runner/prepare-prompt-assembly.d.ts +5 -7
  307. package/dist/core/runner/prepare-prompt-assembly.js +10 -8
  308. package/dist/core/runner/prepare-prompt-inputs.d.ts +11 -9
  309. package/dist/core/runner/prepare-prompt-inputs.js +4 -6
  310. package/dist/core/runner/prepare-protocol-tools.d.ts +4 -2
  311. package/dist/core/runner/prepare-protocol-tools.js +5 -4
  312. package/dist/core/runner/prepare-safety-scan.d.ts +9 -12
  313. package/dist/core/runner/prepare-safety-scan.js +8 -23
  314. package/dist/core/runner/prepare-suspend-saga.d.ts +2 -0
  315. package/dist/core/runner/prepare-suspend-saga.js +5 -6
  316. package/dist/core/runner/prepare-task.d.ts +1 -1
  317. package/dist/core/runner/prepare-task.js +41 -35
  318. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +7 -4
  319. package/dist/core/runner/prepare-tool-disclosure-mount.js +24 -18
  320. package/dist/core/runner/prepare-turn-wiring.d.ts +0 -4
  321. package/dist/core/runner/prepare-turn-wiring.js +2 -7
  322. package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -4
  323. package/dist/core/runner/prepare-wiring-manifest.js +3 -3
  324. package/dist/core/runner/resume-admission.js +1 -1
  325. package/dist/core/runner/resume-apply.js +11 -12
  326. package/dist/core/runner/resume-checkpoint-screen.js +3 -0
  327. package/dist/core/runner/resume-claim.d.ts +4 -2
  328. package/dist/core/runner/resume-claim.js +15 -8
  329. package/dist/core/runner/resume-policy-outcome.js +1 -1
  330. package/dist/core/runner/retired-runner-deps.js +2 -1
  331. package/dist/core/runner/rewind-files.d.ts +15 -0
  332. package/dist/core/runner/rewind-files.js +132 -0
  333. package/dist/core/runner/run-attachment-seats.js +2 -2
  334. package/dist/core/runner/run-brain-sinks.d.ts +4 -1
  335. package/dist/core/runner/run-brain-sinks.js +4 -2
  336. package/dist/core/runner/run-compaction-machinery.d.ts +1 -1
  337. package/dist/core/runner/run-compaction-machinery.js +2 -12
  338. package/dist/core/runner/run-git-lane.d.ts +1 -0
  339. package/dist/core/runner/run-harness-handlers.js +14 -7
  340. package/dist/core/runner/run-leg.d.ts +1 -1
  341. package/dist/core/runner/run-leg.js +43 -18
  342. package/dist/core/runner/run-settle-and-teardown.js +3 -2
  343. package/dist/core/runner/run-telemetry-and-budget-seats.js +1 -1
  344. package/dist/core/runner/run-turn-boundary.d.ts +1 -0
  345. package/dist/core/runner/run-turn-boundary.js +15 -22
  346. package/dist/core/runner/runtask.d.ts +3 -0
  347. package/dist/core/runner/runtask.js +8 -9
  348. package/dist/core/runner/session-read-file-states.d.ts +15 -0
  349. package/dist/core/runner/session-read-file-states.js +28 -0
  350. package/dist/core/runner/session-rule-policy.d.ts +22 -21
  351. package/dist/core/runner/session-rule-policy.js +17 -31
  352. package/dist/core/runner/shell-env-withheld.d.ts +33 -0
  353. package/dist/core/runner/shell-env-withheld.js +51 -0
  354. package/dist/core/runner/side-call-account.d.ts +32 -8
  355. package/dist/core/runner/side-call-account.js +23 -1
  356. package/dist/core/runner/skills-seat.js +6 -2
  357. package/dist/core/runner/stream-settle-backstop.js +1 -1
  358. package/dist/core/runner/strict-output-schema.d.ts +1 -1
  359. package/dist/core/runner/sub-agent-deny-lists.js +4 -6
  360. package/dist/core/runner/synthetic-tools.d.ts +16 -13
  361. package/dist/core/runner/synthetic-tools.js +8 -3
  362. package/dist/core/runner/tool-disclosure.d.ts +10 -12
  363. package/dist/core/runner/tool-disclosure.js +3 -4
  364. package/dist/core/runner/tool-end-body.d.ts +1 -1
  365. package/dist/core/runner/tool-end-body.js +10 -9
  366. package/dist/core/runner/tool-face-overlay.d.ts +2 -1
  367. package/dist/core/runner/tool-face-overlay.js +17 -1
  368. package/dist/core/runner/tool-not-executed.d.ts +5 -0
  369. package/dist/core/runner/tool-not-executed.js +11 -0
  370. package/dist/core/runner/tool-occurrence.d.ts +8 -0
  371. package/dist/core/runner/tool-occurrence.js +7 -0
  372. package/dist/core/runner/tool-progress-lane.d.ts +2 -2
  373. package/dist/core/runner/tool-turn-repair-seat.d.ts +3 -2
  374. package/dist/core/runner/turn-attachments.d.ts +91 -80
  375. package/dist/core/runner/turn-attachments.js +62 -37
  376. package/dist/core/runner-deps.d.ts +42 -42
  377. package/dist/core/runtime-caps.d.ts +4 -4
  378. package/dist/core/safety-axis-vocab.d.ts +6 -4
  379. package/dist/core/safety-axis-vocab.js +6 -5
  380. package/dist/core/safety-merge-corpus.js +26 -2
  381. package/dist/core/same-plain-value.d.ts +40 -0
  382. package/dist/core/same-plain-value.js +49 -0
  383. package/dist/core/scheduler.d.ts +1 -1
  384. package/dist/core/secret-env.d.ts +26 -3
  385. package/dist/core/secret-env.js +44 -8
  386. package/dist/core/select-model.js +3 -3
  387. package/dist/core/sensitive-path-policy.d.ts +1 -1
  388. package/dist/core/sensitive-path-policy.js +1 -1
  389. package/dist/core/session-policy-store.d.ts +102 -35
  390. package/dist/core/session-policy-store.js +210 -48
  391. package/dist/core/session-reconcile.d.ts +2 -2
  392. package/dist/core/session-store.d.ts +106 -37
  393. package/dist/core/session-store.js +165 -91
  394. package/dist/core/session.d.ts +101 -57
  395. package/dist/core/session.js +53 -0
  396. package/dist/core/shared-memory/tools.js +3 -1
  397. package/dist/core/shared-memory/types.d.ts +1 -1
  398. package/dist/core/shell-read-silence.d.ts +11 -12
  399. package/dist/core/shell-read-silence.js +9 -5
  400. package/dist/core/shell-run-candidates.js +3 -1
  401. package/dist/core/shell-wrapper-projection.js +1 -1
  402. package/dist/core/shell-wrapper-table.d.ts +14 -7
  403. package/dist/core/shell-wrapper-table.js +5 -4
  404. package/dist/core/side-query.d.ts +10 -0
  405. package/dist/core/side-query.js +15 -1
  406. package/dist/core/skill-grant.d.ts +7 -2
  407. package/dist/core/skill-grant.js +5 -0
  408. package/dist/core/skills-directory.js +6 -2
  409. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +11 -1
  410. package/dist/core/store-contracts/checkpoint-store-contract.js +168 -3
  411. package/dist/core/store-contracts/file-history-store-contract.js +74 -4
  412. package/dist/core/store-contracts/peer-directory-contract.d.ts +7 -2
  413. package/dist/core/store-contracts/peer-directory-contract.js +14 -2
  414. package/dist/core/store-contracts/session-policy-store-contract.d.ts +7 -0
  415. package/dist/core/store-contracts/session-policy-store-contract.js +130 -0
  416. package/dist/core/store-contracts/session-repo-contract.js +176 -0
  417. package/dist/core/store-contracts/session-store-contract.d.ts +6 -8
  418. package/dist/core/store-contracts/session-store-contract.js +361 -51
  419. package/dist/core/store-contracts/workflow-journal-store-contract.js +26 -1
  420. package/dist/core/stub-env.d.ts +2 -0
  421. package/dist/core/stub-env.js +1 -0
  422. package/dist/core/surrogate-safe-slice.d.ts +3 -3
  423. package/dist/core/synthetic-read-verdict.js +3 -3
  424. package/dist/core/task-event.d.ts +42 -8
  425. package/dist/core/task-notification.d.ts +19 -15
  426. package/dist/core/task-registry-agent.d.ts +4 -4
  427. package/dist/core/task-registry-shared.d.ts +4 -4
  428. package/dist/core/task-registry-shared.js +1 -0
  429. package/dist/core/task-registry.d.ts +13 -4
  430. package/dist/core/task-registry.js +14 -2
  431. package/dist/core/task-result.d.ts +21 -3
  432. package/dist/core/task-spec.d.ts +69 -64
  433. package/dist/core/task-stream.d.ts +6 -6
  434. package/dist/core/task-tool-shape.d.ts +4 -4
  435. package/dist/core/tighten-task-spec.d.ts +1 -1
  436. package/dist/core/tighten-task-spec.js +2 -1
  437. package/dist/core/tool-catalog-entries.d.ts +36 -2
  438. package/dist/core/tool-catalog-entries.js +69 -43
  439. package/dist/core/tool-check-reading.d.ts +11 -0
  440. package/dist/core/tool-check-reading.js +11 -6
  441. package/dist/core/tool-conformance.js +1 -0
  442. package/dist/core/tool-errors.d.ts +2 -2
  443. package/dist/core/tool-face-reader.js +5 -3
  444. package/dist/core/tool-face.d.ts +21 -2
  445. package/dist/core/tool-face.js +1 -1
  446. package/dist/core/tool-model-gate.d.ts +5 -5
  447. package/dist/core/tool-name-aliases.d.ts +29 -8
  448. package/dist/core/tool-name-aliases.js +22 -4
  449. package/dist/core/tool-name-readings.d.ts +10 -43
  450. package/dist/core/tool-name-readings.js +2 -11
  451. package/dist/core/tool-policy.d.ts +85 -196
  452. package/dist/core/tool-policy.js +150 -175
  453. package/dist/core/tool-registry.d.ts +14 -7
  454. package/dist/core/tool-registry.js +17 -7
  455. package/dist/core/tool-result-store.js +5 -1
  456. package/dist/core/tool-roster.d.ts +57 -33
  457. package/dist/core/tool-roster.js +56 -68
  458. package/dist/core/tool-spec-members.js +8 -3
  459. package/dist/core/tool-spec.d.ts +53 -31
  460. package/dist/core/tools.js +51 -10
  461. package/dist/core/trace.d.ts +6 -2
  462. package/dist/core/types.d.ts +1 -1
  463. package/dist/core/untrusted-egress.d.ts +1 -1
  464. package/dist/core/untrusted-text.d.ts +1 -1
  465. package/dist/core/user-attachment.d.ts +8 -1
  466. package/dist/core/user-attachment.js +64 -4
  467. package/dist/core/warm-resume.d.ts +1 -1
  468. package/dist/core/wiring-manifest.d.ts +58 -0
  469. package/dist/core/wiring-manifest.js +14 -5
  470. package/dist/core/workflow-journal-store.d.ts +62 -0
  471. package/dist/core/workflow-journal-store.js +78 -2
  472. package/dist/core/workflow-run-store.d.ts +6 -0
  473. package/dist/core/workflow-run-store.js +2 -0
  474. package/dist/engine/compaction/compaction.d.ts +9 -9
  475. package/dist/engine/compaction/compaction.js +3 -2
  476. package/dist/engine/execution-env/node-execution-env.d.ts +26 -8
  477. package/dist/engine/execution-env/node-execution-env.js +54 -24
  478. package/dist/engine/harness/agent-harness.d.ts +39 -9
  479. package/dist/engine/harness/agent-harness.js +87 -33
  480. package/dist/engine/harness/types.d.ts +58 -9
  481. package/dist/engine/harness/types.js +12 -1
  482. package/dist/engine/llm/types.d.ts +36 -19
  483. package/dist/engine/llm/validation.d.ts +4 -1
  484. package/dist/engine/llm/validation.js +13 -1
  485. package/dist/engine/loop/agent-loop.d.ts +23 -1
  486. package/dist/engine/loop/agent-loop.js +26 -34
  487. package/dist/engine/loop/types.d.ts +31 -19
  488. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  489. package/dist/engine/session/memory-repo.d.ts +18 -12
  490. package/dist/engine/session/memory-repo.js +24 -9
  491. package/dist/engine/session/parent-chain-guard.d.ts +3 -2
  492. package/dist/engine/session/parent-chain-guard.js +1 -1
  493. package/dist/engine/session/repo-utils.d.ts +32 -3
  494. package/dist/engine/session/repo-utils.js +50 -5
  495. package/dist/index.d.ts +47 -23
  496. package/dist/index.js +35 -17
  497. package/dist/internal/harness-types.d.ts +1 -1
  498. package/dist/internal/harness.d.ts +3 -3
  499. package/dist/internal/harness.js +2 -2
  500. package/dist/internal/llm.d.ts +2 -2
  501. package/dist/internal/llm.js +1 -1
  502. package/dist/orchestration/goal.js +2 -2
  503. package/dist/orchestration/run-workflow-tool.d.ts +8 -6
  504. package/dist/orchestration/run-workflow-tool.js +10 -6
  505. package/dist/orchestration/workflow-size-guideline.d.ts +4 -4
  506. package/dist/orchestration/workflow-types.d.ts +18 -0
  507. package/dist/orchestration/workflow-types.js +6 -0
  508. package/dist/orchestration/workflow.d.ts +5 -13
  509. package/dist/orchestration/workflow.js +57 -49
  510. package/dist/prompt-assembly/artifact.d.ts +2 -2
  511. package/dist/prompt-assembly/artifact.js +5 -3
  512. package/dist/prompt-assembly/assemble.d.ts +3 -2
  513. package/dist/prompt-assembly/assemble.js +1 -1
  514. package/dist/prompt-assembly/catalog/schema.d.ts +43 -12
  515. package/dist/prompt-assembly/catalog/schema.js +34 -2
  516. package/dist/prompt-assembly/catalog/sections.js +0 -1
  517. package/dist/prompt-assembly/composer.d.ts +3 -1
  518. package/dist/prompt-assembly/composer.js +1 -1
  519. package/dist/prompt-assembly/event-registry.js +2 -0
  520. package/dist/prompt-assembly/overlay.js +3 -3
  521. package/dist/prompt-assembly/renderers.d.ts +1 -1
  522. package/dist/prompt-assembly/renderers.js +0 -3
  523. package/dist/prompt-assembly/role-base.d.ts +15 -0
  524. package/dist/prompt-assembly/role-base.js +9 -0
  525. package/dist/prompt-assembly/select.d.ts +39 -14
  526. package/dist/prompt-assembly/select.js +47 -16
  527. package/dist/prompt-assembly/sugar.d.ts +17 -11
  528. package/dist/prompt-assembly/sugar.js +8 -3
  529. package/dist/prompt-assembly/tool-catalog.d.ts +39 -2
  530. package/dist/prompt-assembly/tool-catalog.js +117 -4
  531. package/dist/prompt-assembly/turn-snapshot.d.ts +4 -10
  532. package/dist/prompt-assembly/turn-snapshot.js +0 -3
  533. package/dist/prompt-assembly/types.d.ts +0 -7
  534. package/dist/prompts/default.d.ts +14 -14
  535. package/dist/scenarios/full-body.d.ts +15 -15
  536. package/dist/scenarios/full-body.js +4 -3
  537. package/dist/shell/lex.js +10 -1
  538. package/dist/stores/file/adoption/adopt.d.ts +4 -3
  539. package/dist/stores/file/adoption/adopt.js +27 -33
  540. package/dist/stores/file/adoption/marker.d.ts +6 -13
  541. package/dist/stores/file/adoption/marker.js +9 -17
  542. package/dist/stores/file/checkpoint-store.d.ts +24 -0
  543. package/dist/stores/file/checkpoint-store.js +45 -7
  544. package/dist/stores/file/file-history-store.d.ts +20 -19
  545. package/dist/stores/file/file-history-store.js +157 -141
  546. package/dist/stores/file/fs-atomic.d.ts +15 -0
  547. package/dist/stores/file/fs-atomic.js +89 -14
  548. package/dist/stores/file/index.d.ts +1 -1
  549. package/dist/stores/file/index.js +2 -1
  550. package/dist/stores/file/mailbox-store.d.ts +3 -0
  551. package/dist/stores/file/mailbox-store.js +3 -1
  552. package/dist/stores/file/permission-rule-adopt.d.ts +1 -1
  553. package/dist/stores/file/permission-rule-adopt.js +18 -18
  554. package/dist/stores/file/permission-rule-store.d.ts +18 -2
  555. package/dist/stores/file/permission-rule-store.js +31 -18
  556. package/dist/stores/file/session-policy-store.d.ts +3 -3
  557. package/dist/stores/file/session-store.d.ts +54 -16
  558. package/dist/stores/file/session-store.js +114 -85
  559. package/dist/stores/file/workflow-journal-store.d.ts +10 -4
  560. package/dist/stores/file/workflow-journal-store.js +28 -13
  561. package/dist/tools/artifact/artifact-text.d.ts +1 -1
  562. package/dist/tools/artifact/artifact-tool.js +5 -3
  563. package/dist/tools/fs/bash-program-position.d.ts +19 -2
  564. package/dist/tools/fs/bash-program-position.js +56 -9
  565. package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -3
  566. package/dist/tools/fs/fs-bash.d.ts +2 -2
  567. package/dist/tools/fs/fs-bash.js +8 -6
  568. package/dist/tools/fs/fs-glob.d.ts +86 -0
  569. package/dist/tools/fs/fs-glob.js +226 -0
  570. package/dist/tools/fs/fs-read.js +14 -14
  571. package/dist/tools/fs/fs-search-tools.js +7 -7
  572. package/dist/tools/fs/fs-shared.d.ts +8 -8
  573. package/dist/tools/fs/gh-rate-limit.d.ts +1 -1
  574. package/dist/tools/fs/notebook.d.ts +2 -2
  575. package/dist/tools/fs/pattern-kill-guard.d.ts +22 -0
  576. package/dist/tools/fs/pattern-kill-guard.js +397 -0
  577. package/dist/tools/fs/pdf.d.ts +9 -6
  578. package/dist/tools/fs/pdf.js +3 -3
  579. package/dist/tools/fs/program-read-model.d.ts +57 -7
  580. package/dist/tools/fs/program-read-model.js +11 -1
  581. package/dist/tools/fs/program-read-model.rows.js +78 -21
  582. package/dist/tools/fs/read-deny-home.js +3 -2
  583. package/dist/tools/fs/read-deny.d.ts +29 -7
  584. package/dist/tools/fs/read-deny.js +63 -22
  585. package/dist/tools/fs/removal-targets.d.ts +18 -8
  586. package/dist/tools/fs/removal-targets.js +47 -20
  587. package/dist/tools/fs/safety.d.ts +9 -9
  588. package/dist/tools/fs/search.d.ts +16 -6
  589. package/dist/tools/fs/search.js +20 -26
  590. package/dist/tools/fs/shell-read-argv.js +89 -12
  591. package/dist/tools/fs/shell-read-bindings.d.ts +31 -0
  592. package/dist/tools/fs/shell-read-bindings.js +41 -0
  593. package/dist/tools/fs/shell-read-check.js +12 -20
  594. package/dist/tools/fs/shell-read-environment.d.ts +5 -1
  595. package/dist/tools/fs/shell-read-environment.js +3 -2
  596. package/dist/tools/fs/shell-read-establish.d.ts +15 -0
  597. package/dist/tools/fs/shell-read-establish.js +19 -20
  598. package/dist/tools/fs/shell-read-judge.d.ts +4 -0
  599. package/dist/tools/fs/shell-read-judge.js +5 -2
  600. package/dist/tools/fs/shell-read-plan.js +24 -16
  601. package/dist/tools/fs/shell-read-start.d.ts +6 -1
  602. package/dist/tools/fs/shell-read-write-targets.d.ts +5 -1
  603. package/dist/tools/fs/shell-read-write-targets.js +2 -3
  604. package/dist/tools/fs/shell-reentry-text.d.ts +9 -0
  605. package/dist/tools/fs/shell-reentry-text.js +40 -2
  606. package/dist/tools/loop-tick.d.ts +2 -2
  607. package/dist/tools/scheduler-tools.js +5 -1
  608. package/dist/tools/task-list.d.ts +7 -7
  609. package/dist/tools/task-list.js +5 -1
  610. package/dist/tools/todo.js +65 -64
  611. package/dist/tools/web.d.ts +20 -15
  612. package/dist/tools/web.js +55 -69
  613. package/dist/tools/worktree.d.ts +3 -3
  614. package/dist/tools/worktree.js +3 -1
  615. package/package.json +1 -1
  616. package/test/export-surface.snapshot.json +5894 -5638
  617. package/wire-changes/core@7.55.0.json +3318 -0
  618. package/wire-changes/core@7.56.0.json +3891 -0
  619. package/wire-changes/mods-kernel@7.56.0.json +303 -0
  620. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +0 -39
  621. package/dist/core/store-contracts/session-store-incarnation-contract.js +0 -95
@@ -2,7 +2,7 @@ import { createHash, randomBytes } from "node:crypto";
2
2
  import { appendFileSync, closeSync, existsSync, fsyncSync, openSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { thrownText } from "../../core/thrown-value.js";
5
- import { applyFileRestoreViaEnv, boundaryPublishVerdict, worldStillMatchesMint, captureFileBackupViaEnv, modeProvenDifferent, previewFileDelta, describeTrackKey, fileHistoryExportDigest, resolveTrackKey, trackKeyOf, validateFileHistoryExport, } from "../../core/file-history-store.js";
5
+ import { applyFileRestoreViaEnv, boundaryPublishVerdict, worldStillMatchesMint, annulProofFailure, captureFileBackupViaEnv, modeProvenDifferent, previewFileDelta, describeTrackKey, fileHistoryExportDigest, caughtFault, DAMAGED_RECORD, resolveTrackKey, trackKeyOf, validateFileHistoryExport, } from "../../core/file-history-store.js";
6
6
  import { fileHistoryBoundariesToKeep, resolveFileHistoryRetention } from "../../core/file-history-retention.js";
7
7
  import { atomicWriteFile, ensureDir, sanitizePathComponent, sanitizeScope, writeThenLink } from "./fs-atomic.js";
8
8
  import { guardCorruptSink } from "./corrupt-read-sink.js";
@@ -109,6 +109,12 @@ function nestedMapSet(map, scope, key, value) {
109
109
  map.set(scope, (inner = new Map()));
110
110
  inner.set(key, value);
111
111
  }
112
+ function worstFault(faults) {
113
+ const terminal = faults.find((f) => f.permanence === "terminal");
114
+ if (terminal !== undefined)
115
+ return terminal;
116
+ return faults.length > 0 && faults.every((f) => f.permanence === "transient") ? faults[0] : {};
117
+ }
112
118
  function safeRm(path) {
113
119
  try {
114
120
  rmSync(path, { force: true, recursive: true });
@@ -227,21 +233,21 @@ export class FileFileHistoryStore {
227
233
  if (err.code === "ENOENT")
228
234
  return { corrupt: false, tracked: new Map() };
229
235
  this.disclose(path, `tracked set unreadable (${err.code ?? "unknown"}) — this scope's history is UNUSABLE until it is repaired`);
230
- return { corrupt: true, tracked: new Map() };
236
+ return { corrupt: true, tracked: new Map(), fault: caughtFault(err) };
231
237
  }
232
238
  const parsed = parseJsonRecord(raw);
233
239
  if (parsed === null) {
234
240
  this.disclose(path, "unparseable tracked set (torn/zero-byte write?) — this scope's history is UNUSABLE until it is repaired");
235
- return { corrupt: true, tracked: new Map() };
241
+ return { corrupt: true, tracked: new Map(), fault: DAMAGED_RECORD };
236
242
  }
237
243
  const rows = trackedRowsOf(parsed);
238
244
  if (rows === null) {
239
245
  this.disclose(path, "tracked set is not a pair array of [key, record] rows — this scope's history is UNUSABLE until it is repaired");
240
- return { corrupt: true, tracked: new Map() };
246
+ return { corrupt: true, tracked: new Map(), fault: DAMAGED_RECORD };
241
247
  }
242
248
  if (parsed.digest !== undefined && (typeof parsed.digest !== "string" || parsed.digest !== trackedDigest(rows))) {
243
249
  this.disclose(path, "tracked set fails its own integrity digest (edited in place, or written by something that is not this store) — this scope's history is UNUSABLE until it is repaired");
244
- return { corrupt: true, tracked: new Map() };
250
+ return { corrupt: true, tracked: new Map(), fault: DAMAGED_RECORD };
245
251
  }
246
252
  return { corrupt: false, tracked: new Map(rows) };
247
253
  }
@@ -256,6 +262,10 @@ export class FileFileHistoryStore {
256
262
  atomicWriteFile(join(this.base, "tmp"), this.trackedPath(scope), JSON.stringify(doc));
257
263
  }
258
264
  readBoundary(path) {
265
+ const read = this.readBoundaryState(path);
266
+ return read instanceof Map ? read : null;
267
+ }
268
+ readBoundaryState(path) {
259
269
  let raw;
260
270
  try {
261
271
  raw = readFileSync(path, "utf8");
@@ -263,33 +273,33 @@ export class FileFileHistoryStore {
263
273
  catch (err) {
264
274
  if (err.code === "ENOENT")
265
275
  return null;
266
- this.disclose(path, `boundary unreadable (${err.code ?? "unknown"}) — read as no boundary`);
267
- return null;
276
+ this.disclose(path, `boundary unreadable (${err.code ?? "unknown"}) — not a usable boundary`);
277
+ return caughtFault(err);
268
278
  }
269
279
  {
270
280
  const doc = parseJsonRecord(raw);
271
281
  if (doc === null) {
272
- this.disclose(path, "unparseable boundary (torn/zero-byte write?) — read as no boundary");
273
- return null;
282
+ this.disclose(path, "unparseable boundary (torn/zero-byte write?) — not a usable boundary");
283
+ return DAMAGED_RECORD;
274
284
  }
275
285
  if (doc.formatVersion !== "file-history/1" || !Array.isArray(doc.files)) {
276
- this.disclose(path, "boundary is not a file-history/1 pair array — read as no boundary");
277
- return null;
286
+ this.disclose(path, "boundary is not a file-history/1 pair array — not a usable boundary");
287
+ return DAMAGED_RECORD;
278
288
  }
279
289
  const parsed = { formatVersion: doc.formatVersion, files: doc.files, digest: doc.digest };
280
290
  for (const pair of parsed.files) {
281
291
  if (!Array.isArray(pair) || pair.length !== 2 || typeof pair[0] !== "string" || !Number.isInteger(pair[1]) || pair[1] < 1) {
282
- this.disclose(path, "boundary carries a malformed mapping row — read as no boundary");
283
- return null;
292
+ this.disclose(path, "boundary carries a malformed mapping row — not a usable boundary");
293
+ return DAMAGED_RECORD;
284
294
  }
285
295
  }
286
296
  if (new Set(parsed.files.map(([k]) => k)).size !== parsed.files.length) {
287
- this.disclose(path, "boundary maps the same path twice — read as no boundary");
288
- return null;
297
+ this.disclose(path, "boundary maps the same path twice — not a usable boundary");
298
+ return DAMAGED_RECORD;
289
299
  }
290
300
  if (typeof parsed.digest !== "string" || parsed.digest !== boundaryDigest(parsed.files)) {
291
- this.disclose(path, "boundary fails its own integrity digest (rows added or dropped?) — read as no boundary");
292
- return null;
301
+ this.disclose(path, "boundary fails its own integrity digest (rows added or dropped?) — not a usable boundary");
302
+ return DAMAGED_RECORD;
293
303
  }
294
304
  return new Map(parsed.files);
295
305
  }
@@ -304,23 +314,11 @@ export class FileFileHistoryStore {
304
314
  return undefined;
305
315
  }
306
316
  }
307
- unjudgeableBoundaryIdsOf(scope) {
308
- const dir = this.boundaryDir(scope);
309
- let names;
310
- try {
311
- names = readdirSync(dir);
312
- }
313
- catch (err) {
314
- return err.code === "ENOENT" ? null : [];
315
- }
316
- const bad = names.filter((f) => f.endsWith(".json") && this.readBoundary(join(dir, f)) === null).map((f) => f.slice(0, -".json".length));
317
- return bad.length > 0 ? bad : null;
318
- }
319
317
  carryConsumedIds(fromScope, toScope) {
320
318
  const spent = this.readReapedIds(fromScope);
321
- if (spent === null) {
319
+ if (!(spent instanceof Set)) {
322
320
  this.disclose(this.reapedLogPath(fromScope), "source consumed-id ledger unreadable — the adoption is refused rather than published without its lineage's tombstones");
323
- return false;
321
+ return spent;
324
322
  }
325
323
  if (spent.size === 0)
326
324
  return true;
@@ -339,7 +337,7 @@ export class FileFileHistoryStore {
339
337
  if (err.code === "ENOENT")
340
338
  return new Set();
341
339
  this.disclose(path, `consumed-id ledger unreadable (${err.code ?? "unknown"})`);
342
- return null;
340
+ return caughtFault(err);
343
341
  }
344
342
  const cached = this.reapedCache.get(scope);
345
343
  if (cached !== undefined && cached.size === size)
@@ -354,7 +352,7 @@ export class FileFileHistoryStore {
354
352
  }
355
353
  catch (err) {
356
354
  this.disclose(path, `consumed-id ledger unreadable (${err.code ?? "unknown"})`);
357
- return null;
355
+ return caughtFault(err);
358
356
  }
359
357
  }
360
358
  markReaped(scope, ids) {
@@ -381,7 +379,7 @@ export class FileFileHistoryStore {
381
379
  }
382
380
  catch (err) {
383
381
  this.disclose(path, `consumed-id ledger could not be appended (${err.code ?? "unknown"}) — the boundaries it names are NOT being reaped, so this scope is not bounded until it can be written`);
384
- return false;
382
+ return caughtFault(err);
385
383
  }
386
384
  }
387
385
  boundaryOrderOf(path) {
@@ -409,7 +407,7 @@ export class FileFileHistoryStore {
409
407
  const { key, kind, family } = describeTrackKey(root, absPath);
410
408
  const before = this.readTrackedState(scope);
411
409
  if (before.corrupt)
412
- return { ok: false, error: { code: "track_failed", message: `file history for scope "${scope}" is unreadable — refusing to mint a first-touch record over an unusable graph` } };
410
+ return { ok: false, error: { code: "track_failed", message: `file history for scope "${scope}" is unreadable — refusing to mint a first-touch record over an unusable graph`, ...before.fault } };
413
411
  const existing = before.tracked.get(key);
414
412
  if (existing !== undefined) {
415
413
  if (existing.observedByLaterTouch !== true) {
@@ -421,7 +419,7 @@ export class FileFileHistoryStore {
421
419
  const cap = await captureFileBackupViaEnv(env, absPath, root, signal);
422
420
  const after = this.readTrackedState(scope);
423
421
  if (after.corrupt)
424
- return { ok: false, error: { code: "track_failed", message: `file history for scope "${scope}" became unreadable during the first-touch capture — nothing was recorded` } };
422
+ return { ok: false, error: { code: "track_failed", message: `file history for scope "${scope}" became unreadable during the first-touch capture — nothing was recorded`, ...after.fault } };
425
423
  const tracked = after.tracked;
426
424
  const raced = tracked.get(key);
427
425
  if (raced !== undefined) {
@@ -452,7 +450,7 @@ export class FileFileHistoryStore {
452
450
  return { ok: true, minted: true };
453
451
  }
454
452
  catch (err) {
455
- return { ok: false, error: { code: "track_failed", message: `first-touch record for ${absPath} could not be persisted: ${thrownText(err)}` } };
453
+ return { ok: false, error: { code: "track_failed", message: `first-touch record for ${absPath} could not be persisted: ${thrownText(err)}`, ...caughtFault(err) } };
456
454
  }
457
455
  }
458
456
  async annulTrack(scope, absPath, root, verify) {
@@ -460,13 +458,16 @@ export class FileFileHistoryStore {
460
458
  const key = trackKeyOf(root, absPath);
461
459
  const state = this.readTrackedState(scope);
462
460
  if (state.corrupt) {
463
- return { ok: false, error: { code: "conflict", message: `file history for scope "${scope}" is unreadable — the first-touch record (if any) was left in place; repair the graph before retraction can be judged` } };
461
+ return { ok: false, error: { code: "track_failed", message: `file history for scope "${scope}" is unreadable — the first-touch record (if any) was left in place; repair the graph before retraction can be judged`, ...state.fault } };
464
462
  }
465
463
  const tracked = state.tracked;
466
464
  const rec = tracked.get(key);
467
465
  if (rec === undefined)
468
466
  return { ok: true };
469
- for (const entryId of this.listBoundaryIds(scope)) {
467
+ const listed = this.listBoundaryIds(scope);
468
+ if (!Array.isArray(listed))
469
+ return { ok: false, error: { code: "track_failed", message: `scope "${scope}" has ${listed.what} — the first-touch record for ${absPath} was left in place, since whether a boundary references it cannot be judged`, ...listed.fault } };
470
+ for (const entryId of listed) {
470
471
  const bp = this.tryBoundaryPath(scope, entryId);
471
472
  const mapping = bp === null ? null : this.readBoundary(bp);
472
473
  if (mapping?.has(key) === true) {
@@ -480,12 +481,11 @@ export class FileFileHistoryStore {
480
481
  return { ok: false, error: { code: "conflict", message: `first-touch record for ${absPath} has since been served to another edit of the same path — it is that edit's baseline now, not a retractable mint` } };
481
482
  }
482
483
  const proof = verify === undefined ? undefined : await worldStillMatchesMint(verify.env, absPath, root, rec.baseAvailable, rec.versions[0]?.blobHash ?? null, verify.signal);
483
- if (proof !== undefined && !proof.unchanged) {
484
- return { ok: false, error: { code: "conflict", message: `first-touch record for ${absPath} is NOT retractable: ${proof.reason} — the write this retraction compensates for may have changed the file` } };
485
- }
484
+ if (proof !== undefined && proof.verdict !== "unchanged")
485
+ return annulProofFailure(proof, absPath);
486
486
  const fresh = this.readTrackedState(scope);
487
487
  if (fresh.corrupt)
488
- return { ok: false, error: { code: "conflict", message: `file history for scope "${scope}" became unreadable — the record was left in place` } };
488
+ return { ok: false, error: { code: "track_failed", message: `file history for scope "${scope}" became unreadable — the record was left in place`, ...fresh.fault } };
489
489
  const still = fresh.tracked.get(key);
490
490
  if (still === undefined)
491
491
  return { ok: true };
@@ -495,7 +495,10 @@ export class FileFileHistoryStore {
495
495
  if (still.mintId !== rec.mintId || still.baseAvailable !== rec.baseAvailable || still.versions.length !== rec.versions.length || still.versions[0]?.blobHash !== rec.versions[0]?.blobHash || still.versions[0]?.backupTime !== rec.versions[0]?.backupTime) {
496
496
  return { ok: false, error: { code: "conflict", message: `first-touch record for ${absPath} was replaced while this retraction was being proven — the record now there belongs to a newer edit` } };
497
497
  }
498
- for (const entryId of this.listBoundaryIds(scope)) {
498
+ const relisted = this.listBoundaryIds(scope);
499
+ if (!Array.isArray(relisted))
500
+ return { ok: false, error: { code: "track_failed", message: `scope "${scope}" came to have ${relisted.what} while this retraction was being proven — the record was left in place`, ...relisted.fault } };
501
+ for (const entryId of relisted) {
499
502
  const bp2 = this.tryBoundaryPath(scope, entryId);
500
503
  const mapping2 = bp2 === null ? null : this.readBoundary(bp2);
501
504
  if (mapping2?.has(key) === true) {
@@ -507,53 +510,65 @@ export class FileFileHistoryStore {
507
510
  return { ok: true };
508
511
  }
509
512
  catch (err) {
510
- return { ok: false, error: { code: "track_failed", message: `annulling the first-touch record for ${absPath} failed: ${thrownText(err)}` } };
513
+ return { ok: false, error: { code: "track_failed", message: `annulling the first-touch record for ${absPath} failed: ${thrownText(err)}`, ...caughtFault(err) } };
511
514
  }
512
515
  }
513
516
  scopeIsEmptySync(scope) {
514
517
  const state = this.readTrackedState(scope);
515
518
  if (state.corrupt)
516
- return false;
517
- return state.tracked.size === 0 && this.listBoundaryIds(scope).length === 0;
519
+ return { fault: state.fault, what: "an unreadable tracked set" };
520
+ const listed = this.listBoundaryIds(scope);
521
+ if (!Array.isArray(listed))
522
+ return listed;
523
+ return state.tracked.size === 0 && listed.length === 0 ? "empty" : "not_empty";
524
+ }
525
+ async importTargetOf(scope, data, when) {
526
+ const emptiness = this.scopeIsEmptySync(scope);
527
+ if (emptiness === "empty")
528
+ return "empty";
529
+ if (emptiness !== "not_empty") {
530
+ return { ok: false, error: { code: "adopt_failed", message: `importHistory target "${scope}" ${when === "before" ? "has" : "came to have"} ${emptiness.what} — a scope whose history cannot be judged is not an empty target; nothing was ${when === "before" ? "fetched or " : ""}published`, ...emptiness.fault } };
531
+ }
532
+ const existing = await this.exportHistory(scope);
533
+ if (existing.ok && existing.history !== null && fileHistoryExportDigest(existing.history) === fileHistoryExportDigest(data))
534
+ return "identical";
535
+ const message = when === "before"
536
+ ? `importHistory target "${scope}" was judged not empty and not this envelope — it holds a DIFFERENT history, or it changed (or could not be read) between the two reads that judge it — a first import requires an empty target and a retry is legal only for the identical envelope (atomic visibility prevents half-graphs; this law prevents publishing the wrong complete graph over locally-grown history)`
537
+ : `importHistory target "${scope}" changed while this import was fetching blobs — it gained a DIFFERENT history, or changed (or could not be read) between the two reads that judge it — nothing was published`;
538
+ return { ok: false, error: { code: "conflict", message } };
518
539
  }
519
540
  publishStagedScopeSync(scope, staging) {
520
- if (!this.scopeIsEmptySync(scope))
521
- return "not_empty";
522
- const target = this.scopeDir(scope);
523
- const destroyed = [];
524
- for (const f of (() => {
525
- try {
526
- return readdirSync(this.boundaryDir(scope));
527
- }
528
- catch {
529
- return [];
530
- }
531
- })()) {
532
- if (f.endsWith(".json"))
533
- destroyed.push(f.slice(0, -".json".length));
534
- }
535
- if (!this.markReaped(scope, destroyed))
536
- return "ledger_failed";
537
- safeRm(target);
538
- renameSync(staging, target);
541
+ const emptiness = this.scopeIsEmptySync(scope);
542
+ if (emptiness !== "empty")
543
+ return emptiness;
544
+ safeRm(this.scopeDir(scope));
545
+ renameSync(staging, this.scopeDir(scope));
539
546
  return "published";
540
547
  }
541
548
  listBoundaryIds(scope) {
542
549
  const dir = this.boundaryDir(scope);
543
- let entries;
550
+ let names;
544
551
  try {
545
- entries = readdirSync(dir);
552
+ names = readdirSync(dir).filter((f) => f.endsWith(".json"));
546
553
  }
547
554
  catch (err) {
548
- if (err.code !== "ENOENT") {
549
- this.disclose(dir, `boundary directory unreadable (${err.code ?? "unknown"}) — listed as no boundaries`);
550
- }
551
- return [];
552
- }
553
- return entries
554
- .filter((f) => f.endsWith(".json"))
555
- .filter((f) => this.readBoundary(join(dir, f)) !== null)
556
- .map((f) => f.slice(0, -".json".length));
555
+ if (err.code === "ENOENT")
556
+ return [];
557
+ this.disclose(dir, `boundary directory unreadable (${err.code ?? "unknown"}) — this scope's history cannot be judged until it can be listed`);
558
+ return { fault: caughtFault(err), what: "a boundary directory that cannot be listed" };
559
+ }
560
+ const ids = [];
561
+ const unusable = [];
562
+ const faults = [];
563
+ for (const f of names) {
564
+ const read = this.readBoundaryState(join(dir, f));
565
+ (read instanceof Map ? ids : unusable).push(f.slice(0, -".json".length));
566
+ if (!(read instanceof Map))
567
+ faults.push(read ?? {});
568
+ }
569
+ if (unusable.length === 0)
570
+ return ids;
571
+ return { fault: worstFault(faults), what: `boundaries that cannot be used (${unusable.slice(0, 3).map((i) => JSON.stringify(i)).join(", ")}${unusable.length > 3 ? ", …" : ""})` };
557
572
  }
558
573
  async snapshot(scope, entryId, env, root, signal) {
559
574
  const bpath = this.tryBoundaryPath(scope, entryId);
@@ -562,8 +577,8 @@ export class FileFileHistoryStore {
562
577
  if (this.readBoundary(bpath) !== null)
563
578
  return { ok: true };
564
579
  const consumed = this.readReapedIds(scope);
565
- if (consumed === null) {
566
- return { ok: false, error: { code: "snapshot_failed", message: `the consumed-entry ledger for scope "${scope}" cannot be read — refusing to mint a boundary while it is impossible to tell a fresh entry id from one retention already reaped` } };
580
+ if (!(consumed instanceof Set)) {
581
+ return { ok: false, error: { code: "snapshot_failed", message: `the consumed-entry ledger for scope "${scope}" cannot be read — refusing to mint a boundary while it is impossible to tell a fresh entry id from one retention already reaped`, ...consumed } };
567
582
  }
568
583
  if (consumed.has(entryId)) {
569
584
  return { ok: false, error: { code: "snapshot_failed", message: `entry "${entryId}" already had a boundary and it was reaped by retention — a fresh capture now would record post-turn bytes under a pre-turn key, so this entry has no boundary and cannot get one back` } };
@@ -582,7 +597,7 @@ export class FileFileHistoryStore {
582
597
  const state = this.readTrackedState(scope);
583
598
  if (state.corrupt) {
584
599
  nestedSetAdd(this.spentAttempts, scope, entryId);
585
- return { ok: false, error: { code: "snapshot_failed", message: `file history for scope "${scope}" is unreadable — a boundary minted over an unusable graph would claim to restore state that is not there` } };
600
+ return { ok: false, error: { code: "snapshot_failed", message: `file history for scope "${scope}" is unreadable — a boundary minted over an unusable graph would claim to restore state that is not there`, ...state.fault } };
586
601
  }
587
602
  const tracked = state.tracked;
588
603
  const staged = new Map();
@@ -628,7 +643,7 @@ export class FileFileHistoryStore {
628
643
  const currentState = this.readTrackedState(scope);
629
644
  if (currentState.corrupt) {
630
645
  nestedSetAdd(this.spentAttempts, scope, entryId);
631
- return { ok: false, error: { code: "snapshot_failed", message: `file history for scope "${scope}" became unreadable during the capture — no boundary was published` } };
646
+ return { ok: false, error: { code: "snapshot_failed", message: `file history for scope "${scope}" became unreadable during the capture — no boundary was published`, ...currentState.fault } };
632
647
  }
633
648
  const current = currentState.tracked;
634
649
  for (const [key, cap] of staged) {
@@ -663,9 +678,10 @@ export class FileFileHistoryStore {
663
678
  catch (err) {
664
679
  if (err.code !== "EEXIST")
665
680
  throw err;
666
- if (this.readBoundary(bpath) === null) {
681
+ const existing = this.readBoundaryState(bpath);
682
+ if (!(existing instanceof Map)) {
667
683
  nestedSetAdd(this.spentAttempts, scope, entryId);
668
- return { ok: false, error: { code: "snapshot_failed", message: `a boundary file for entry "${entryId}" already exists but cannot be read — this turn has no usable boundary (the unreadable file is left in place for an operator rather than silently replaced)` } };
684
+ return { ok: false, error: { code: "snapshot_failed", message: `a boundary file for entry "${entryId}" already exists but cannot be read — this turn has no usable boundary (the unreadable file is left in place for an operator rather than silently replaced)`, ...existing } };
669
685
  }
670
686
  }
671
687
  this.applyBoundaryRetention(scope, entryId);
@@ -673,7 +689,7 @@ export class FileFileHistoryStore {
673
689
  }
674
690
  catch (err) {
675
691
  nestedSetAdd(this.spentAttempts, scope, entryId);
676
- return { ok: false, error: { code: "snapshot_failed", message: `boundary for entry "${entryId}" could not be committed: ${thrownText(err)}` } };
692
+ return { ok: false, error: { code: "snapshot_failed", message: `boundary for entry "${entryId}" could not be committed: ${thrownText(err)}`, ...caughtFault(err) } };
677
693
  }
678
694
  finally {
679
695
  this.activeCaptures.get(scope)?.delete(entryId);
@@ -685,13 +701,16 @@ export class FileFileHistoryStore {
685
701
  let modeNotPreserved = 0;
686
702
  try {
687
703
  const bpath = this.tryBoundaryPath(scope, entryId);
688
- const boundary = bpath === null ? null : this.readBoundary(bpath);
704
+ const boundary = bpath === null ? null : this.readBoundaryState(bpath);
689
705
  if (boundary === null) {
690
706
  return { outcome: "failed", ...ledger, error: { code: "not_found", message: `no history boundary for entry "${entryId}"` } };
691
707
  }
708
+ if (!(boundary instanceof Map)) {
709
+ return { outcome: "failed", ...ledger, error: { code: "restore_failed", message: `the history boundary for entry "${entryId}" is there but cannot be used — NOTHING was restored`, ...boundary } };
710
+ }
692
711
  const state = this.readTrackedState(scope);
693
712
  if (state.corrupt) {
694
- return { outcome: "failed", ...ledger, error: { code: "restore_failed", message: `file history for scope "${scope}" is unreadable — the boundary exists but its version records cannot be read, so NOTHING was restored` } };
713
+ return { outcome: "failed", ...ledger, error: { code: "restore_failed", message: `file history for scope "${scope}" is unreadable — the boundary exists but its version records cannot be read, so NOTHING was restored`, ...state.fault } };
695
714
  }
696
715
  const tracked = state.tracked;
697
716
  for (const key of [...tracked.keys()].sort()) {
@@ -703,7 +722,7 @@ export class FileFileHistoryStore {
703
722
  let targetVersion = boundary.get(key);
704
723
  if (targetVersion === undefined) {
705
724
  if (!rec.baseAvailable) {
706
- ledger.refused.push({ path: key, reason: "base_unavailable" });
725
+ ledger.refused.push({ path: key, reason: "base_unavailable", class: "base_unavailable" });
707
726
  continue;
708
727
  }
709
728
  targetVersion = 1;
@@ -715,7 +734,7 @@ export class FileFileHistoryStore {
715
734
  }
716
735
  const resolved = resolveTrackKey(root, key, descriptorOf(rec));
717
736
  if (!resolved.ok) {
718
- ledger.refused.push({ path: key, reason: resolved.reason });
737
+ ledger.refused.push({ path: key, reason: resolved.reason, class: resolved.class });
719
738
  continue;
720
739
  }
721
740
  let target;
@@ -757,7 +776,7 @@ export class FileFileHistoryStore {
757
776
  else if (applied.outcome === "identical")
758
777
  ledger.identicalSkipped.push(key);
759
778
  else if (applied.outcome === "refused")
760
- ledger.refused.push({ path: key, reason: applied.reason });
779
+ ledger.refused.push({ path: key, reason: applied.reason, class: applied.class });
761
780
  else
762
781
  ledger.failed.push({ path: key, reason: applied.reason });
763
782
  if ((applied.outcome === "applied" || applied.outcome === "identical") && applied.modeNotPreserved === true)
@@ -767,7 +786,7 @@ export class FileFileHistoryStore {
767
786
  }
768
787
  catch (err) {
769
788
  const touched = ledger.filesChanged.length > 0 || ledger.identicalSkipped.length > 0 || ledger.refused.length > 0 || ledger.failed.length > 0;
770
- return { outcome: touched ? "partial" : "failed", ...ledger, error: { code: "restore_failed", message: thrownText(err) } };
789
+ return { outcome: touched ? "partial" : "failed", ...ledger, error: { code: "restore_failed", message: thrownText(err), ...caughtFault(err) } };
771
790
  }
772
791
  }
773
792
  async canRestore(scope, entryId) {
@@ -854,7 +873,7 @@ export class FileFileHistoryStore {
854
873
  const id = file.slice(0, -".json".length);
855
874
  if (keep.has(id))
856
875
  continue;
857
- if (!this.markReaped(scope, [id])) {
876
+ if (this.markReaped(scope, [id]) !== true) {
858
877
  survivors.add(id);
859
878
  continue;
860
879
  }
@@ -1006,28 +1025,25 @@ export class FileFileHistoryStore {
1006
1025
  try {
1007
1026
  if (fromScope === toScope)
1008
1027
  return { ok: true };
1009
- const targetState = this.readTrackedState(toScope);
1010
- if (targetState.corrupt) {
1011
- return { ok: false, error: { code: "adopt_failed", message: `adoptScope target "${toScope}" has an unreadable tracked set — a scope whose bytes cannot be judged is not an empty target` } };
1012
- }
1013
- const targetTracked = targetState.tracked;
1014
- const targetBoundaries = this.listBoundaryIds(toScope);
1015
- if (targetTracked.size > 0 || targetBoundaries.length > 0) {
1028
+ const target = this.scopeIsEmptySync(toScope);
1029
+ if (target === "not_empty") {
1016
1030
  return { ok: false, error: { code: "conflict", message: `adoptScope target "${toScope}" already has history of its own — adoption is legal only onto an EMPTY scope (the fork/resume boundary before the new session's first turn)` } };
1017
1031
  }
1032
+ if (target !== "empty")
1033
+ return { ok: false, error: { code: "adopt_failed", message: `adoptScope target "${toScope}" has ${target.what} — a scope whose history cannot be judged is not an empty target; nothing was published`, ...target.fault } };
1018
1034
  const sourceState = this.readTrackedState(fromScope);
1019
1035
  if (sourceState.corrupt) {
1020
- return { ok: false, error: { code: "adopt_failed", message: `adoptScope source "${fromScope}" has an unreadable tracked set — adopting it would publish boundaries with no version records behind them` } };
1036
+ return { ok: false, error: { code: "adopt_failed", message: `adoptScope source "${fromScope}" has an unreadable tracked set — adopting it would publish boundaries with no version records behind them`, ...sourceState.fault } };
1021
1037
  }
1022
1038
  const source = sourceState.tracked;
1023
- const unjudgeable = this.unjudgeableBoundaryIdsOf(fromScope);
1024
- if (unjudgeable !== null) {
1025
- return { ok: false, error: { code: "adopt_failed", message: `adoptScope source "${fromScope}" has ${unjudgeable.length > 0 ? `boundaries that cannot be judged (${unjudgeable.slice(0, 3).map((i) => JSON.stringify(i)).join(", ")}${unjudgeable.length > 3 ? ", …" : ""})` : "a boundary directory that cannot be listed"} — adopting it would publish a graph that silently drops those turns and hands their entry ids back to the fork; nothing was published` } };
1026
- }
1027
1039
  const sourceBoundaries = this.listBoundaryIds(fromScope);
1040
+ if (!Array.isArray(sourceBoundaries)) {
1041
+ return { ok: false, error: { code: "adopt_failed", message: `adoptScope source "${fromScope}" has ${sourceBoundaries.what} — adopting it would publish a graph that silently drops those turns and hands their entry ids back to the fork; nothing was published`, ...sourceBoundaries.fault } };
1042
+ }
1028
1043
  if (source.size === 0 && sourceBoundaries.length === 0) {
1029
- if (!this.carryConsumedIds(fromScope, toScope)) {
1030
- return { ok: false, error: { code: "adopt_failed", message: `adoptScope could not carry the consumed-entry ledger from "${fromScope}" to "${toScope}" — refusing rather than reporting a carry that would let an already-consumed entry id be minted again in the fork` } };
1044
+ const carried = this.carryConsumedIds(fromScope, toScope);
1045
+ if (carried !== true) {
1046
+ return { ok: false, error: { code: "adopt_failed", message: `adoptScope could not carry the consumed-entry ledger from "${fromScope}" to "${toScope}" — refusing rather than reporting a carry that would let an already-consumed entry id be minted again in the fork`, ...carried } };
1031
1047
  }
1032
1048
  return { ok: true };
1033
1049
  }
@@ -1035,15 +1051,16 @@ export class FileFileHistoryStore {
1035
1051
  for (const v of rec.versions) {
1036
1052
  if (v.blobHash === null)
1037
1053
  continue;
1038
- let bytes;
1054
+ let fault;
1039
1055
  try {
1040
- bytes = readFileSync(this.blobPath(v.blobHash));
1056
+ if (createHash("sha256").update(readFileSync(this.blobPath(v.blobHash))).digest("hex") !== v.blobHash)
1057
+ fault = DAMAGED_RECORD;
1041
1058
  }
1042
- catch {
1043
- bytes = undefined;
1059
+ catch (err) {
1060
+ fault = err.code === "ENOENT" ? DAMAGED_RECORD : caughtFault(err);
1044
1061
  }
1045
- if (bytes === undefined || createHash("sha256").update(bytes).digest("hex") !== v.blobHash) {
1046
- return { ok: false, error: { code: "adopt_failed", message: `adoptScope source "${fromScope}" references blob ${v.blobHash} for ${key}@v${v.version}, which is missing or fails content-address integrity — nothing was published` } };
1062
+ if (fault !== undefined) {
1063
+ return { ok: false, error: { code: "adopt_failed", message: `adoptScope source "${fromScope}" references blob ${v.blobHash} for ${key}@v${v.version}, which is missing or fails content-address integrity — nothing was published`, ...fault } };
1047
1064
  }
1048
1065
  }
1049
1066
  }
@@ -1068,16 +1085,17 @@ export class FileFileHistoryStore {
1068
1085
  const bdoc = { formatVersion: "file-history/1", files: [...mapping], digest: boundaryDigest([...mapping]), ...(sourceCommittedAt !== undefined ? { committedAt: sourceCommittedAt } : {}) };
1069
1086
  atomicWriteFile(join(this.base, "tmp"), join(staging, "boundaries", `${historyPathComponent(id)}.json`), JSON.stringify(bdoc));
1070
1087
  }
1071
- if (!this.carryConsumedIds(fromScope, toScope)) {
1088
+ const carried = this.carryConsumedIds(fromScope, toScope);
1089
+ if (carried !== true) {
1072
1090
  safeRm(staging);
1073
- return { ok: false, error: { code: "adopt_failed", message: `adoptScope could not carry the consumed-entry ledger from "${fromScope}" to "${toScope}" — nothing was published, because a fork missing its lineage's tombstones can mint an already-consumed entry id` } };
1091
+ return { ok: false, error: { code: "adopt_failed", message: `adoptScope could not carry the consumed-entry ledger from "${fromScope}" to "${toScope}" — nothing was published, because a fork missing its lineage's tombstones can mint an already-consumed entry id`, ...carried } };
1074
1092
  }
1075
1093
  const published = this.publishStagedScopeSync(toScope, staging);
1076
1094
  if (published !== "published") {
1077
1095
  safeRm(staging);
1078
1096
  return published === "not_empty"
1079
1097
  ? { ok: false, error: { code: "conflict", message: `adoptScope target "${toScope}" gained history of its own while this adoption was being staged — nothing was published` } }
1080
- : { ok: false, error: { code: "adopt_failed", message: `adoptScope could not record the consumed-entry tombstones for target "${toScope}"'s unreadable boundary residue — nothing was published, because replacing records nothing remembers would hand their already-consumed entry ids back to the fork` } };
1098
+ : { ok: false, error: { code: "adopt_failed", message: `adoptScope target "${toScope}" came to have ${published.what} while this adoption was being staged — a scope whose history cannot be judged is not an empty target; nothing was published`, ...published.fault } };
1081
1099
  }
1082
1100
  }
1083
1101
  catch (err) {
@@ -1087,27 +1105,29 @@ export class FileFileHistoryStore {
1087
1105
  return { ok: true };
1088
1106
  }
1089
1107
  catch (err) {
1090
- return { ok: false, error: { code: "adopt_failed", message: `adoptScope failed: ${thrownText(err)}` } };
1108
+ return { ok: false, error: { code: "adopt_failed", message: `adoptScope failed: ${thrownText(err)}`, ...caughtFault(err) } };
1091
1109
  }
1092
1110
  }
1093
1111
  async exportHistory(scope) {
1112
+ const unexportable = (what, fault) => ({ ok: false, error: { code: "adopt_failed", message: `exportHistory scope "${scope}" has ${what} — its history cannot be exported whole, so nothing was exported`, ...fault } });
1094
1113
  const state = this.readTrackedState(scope);
1095
- if (state.corrupt) {
1096
- return null;
1097
- }
1114
+ if (state.corrupt)
1115
+ return unexportable("an unreadable tracked set", state.fault);
1098
1116
  const tracked = state.tracked;
1099
1117
  const boundaryIds = this.listBoundaryIds(scope);
1118
+ if (!Array.isArray(boundaryIds))
1119
+ return unexportable(boundaryIds.what, boundaryIds.fault);
1100
1120
  if (tracked.size === 0 && boundaryIds.length === 0)
1101
- return null;
1121
+ return { ok: true, history: null };
1102
1122
  const boundaries = [];
1103
1123
  for (const entryId of [...boundaryIds].sort()) {
1104
1124
  const bp = this.tryBoundaryPath(scope, entryId);
1105
1125
  const mapping = bp === null ? null : this.readBoundary(bp);
1106
1126
  if (mapping === null)
1107
- continue;
1127
+ return unexportable(`a boundary ("${entryId}") that stopped being usable while it was exported`, {});
1108
1128
  boundaries.push({ entryId, files: [...mapping.entries()].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)).map(([relOrAbsPath, version]) => ({ relOrAbsPath, version })) });
1109
1129
  }
1110
- return {
1130
+ const history = {
1111
1131
  formatVersion: "file-history/1",
1112
1132
  tracked: [...tracked.entries()]
1113
1133
  .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
@@ -1120,20 +1140,17 @@ export class FileFileHistoryStore {
1120
1140
  })),
1121
1141
  boundaries,
1122
1142
  };
1143
+ return { ok: true, history };
1123
1144
  }
1124
1145
  async importHistory(scope, data, srcGetBlob) {
1125
1146
  try {
1126
1147
  const shaped = validateFileHistoryExport(data);
1127
1148
  if (!shaped.ok)
1128
1149
  return shaped;
1129
- const existing = await this.exportHistory(scope);
1130
- let identicalRepublish = false;
1131
- if (existing !== null) {
1132
- if (fileHistoryExportDigest(existing) === fileHistoryExportDigest(data))
1133
- identicalRepublish = true;
1134
- else
1135
- return { ok: false, error: { code: "conflict", message: `importHistory target "${scope}" already holds a DIFFERENT history — a first import requires an empty target and a retry is legal only for the identical envelope (atomic visibility prevents half-graphs; this law prevents publishing the wrong complete graph over locally-grown history)` } };
1136
- }
1150
+ const target = await this.importTargetOf(scope, data, "before");
1151
+ if (typeof target === "object")
1152
+ return target;
1153
+ const identicalRepublish = target === "identical";
1137
1154
  const importJournal = join(this.scopeDir(scope), "staging", `import-${Date.now().toString(36)}-${randomBytes(6).toString("hex")}.jsonl`);
1138
1155
  ensureDir(join(this.scopeDir(scope), "staging"));
1139
1156
  appendFileSync(importJournal, `${JSON.stringify({ entryId: `import:${scope}`, pid: process.pid, startedAt: new Date().toISOString() })}\n`);
@@ -1147,7 +1164,7 @@ export class FileFileHistoryStore {
1147
1164
  return await this.runImport(scope, data, srcGetBlob, importJournal, identicalRepublish);
1148
1165
  }
1149
1166
  catch (err) {
1150
- return { ok: false, error: { code: "unsupported_format", message: `importHistory failed: ${thrownText(err)}` } };
1167
+ return { ok: false, error: { code: "unsupported_format", message: `importHistory failed: ${thrownText(err)}`, ...caughtFault(err) } };
1151
1168
  }
1152
1169
  }
1153
1170
  async runImport(scope, data, srcGetBlob, importJournal, identicalRepublish) {
@@ -1174,10 +1191,10 @@ export class FileFileHistoryStore {
1174
1191
  bytes = await srcGetBlob(v.blobHash);
1175
1192
  }
1176
1193
  catch (err) {
1177
- return { ok: false, error: { code: "unsupported_format", message: `source blob ${v.blobHash} fetch failed: ${thrownText(err)}` } };
1194
+ return { ok: false, error: { code: "unsupported_format", message: `source blob ${v.blobHash} fetch failed: ${thrownText(err)}`, ...caughtFault(err) } };
1178
1195
  }
1179
1196
  if (bytes === undefined)
1180
- return { ok: false, error: { code: "not_found", message: `source blob ${v.blobHash} is missing — the envelope's graph cannot be completed, so nothing is published` } };
1197
+ return { ok: false, error: { code: "adopt_failed", message: `source blob ${v.blobHash} is missing — the envelope's graph cannot be completed, so nothing is published` } };
1181
1198
  if (createHash("sha256").update(bytes).digest("hex") !== v.blobHash) {
1182
1199
  return { ok: false, error: { code: "unsupported_format", message: `source blob ${v.blobHash} fails content-address integrity — refused, nothing published` } };
1183
1200
  }
@@ -1186,12 +1203,11 @@ export class FileFileHistoryStore {
1186
1203
  }
1187
1204
  if (identicalRepublish)
1188
1205
  return { ok: true };
1189
- const now = await this.exportHistory(scope);
1190
- if (now !== null) {
1191
- if (fileHistoryExportDigest(now) === fileHistoryExportDigest(data))
1192
- return { ok: true };
1193
- return { ok: false, error: { code: "conflict", message: `importHistory target "${scope}" gained a DIFFERENT history while this import was fetching blobs — nothing was published` } };
1194
- }
1206
+ const now = await this.importTargetOf(scope, data, "after");
1207
+ if (now === "identical")
1208
+ return { ok: true };
1209
+ if (now !== "empty")
1210
+ return now;
1195
1211
  const staging = `${this.scopeDir(scope)}.importing-${process.pid}-${randomBytes(6).toString("hex")}`;
1196
1212
  safeRm(staging);
1197
1213
  try {
@@ -1218,13 +1234,13 @@ export class FileFileHistoryStore {
1218
1234
  }
1219
1235
  catch (err) {
1220
1236
  safeRm(staging);
1221
- return { ok: false, error: { code: "adopt_failed", message: `importHistory could not publish the staged graph for "${scope}": ${thrownText(err)} — nothing was published (a local storage fault, not a malformed envelope)` } };
1237
+ return { ok: false, error: { code: "adopt_failed", message: `importHistory could not publish the staged graph for "${scope}": ${thrownText(err)} — nothing was published (a local storage fault, not a malformed envelope)`, ...caughtFault(err) } };
1222
1238
  }
1223
1239
  if (published !== "published") {
1224
1240
  safeRm(staging);
1225
1241
  return published === "not_empty"
1226
1242
  ? { ok: false, error: { code: "conflict", message: `importHistory target "${scope}" gained history of its own while this import was being staged — nothing was published` } }
1227
- : { ok: false, error: { code: "adopt_failed", message: `importHistory could not record the consumed-entry tombstones for target "${scope}"'s unreadable boundary residue — nothing was published, because replacing records nothing remembers would hand their already-consumed entry ids back to this scope` } };
1243
+ : { ok: false, error: { code: "adopt_failed", message: `importHistory target "${scope}" came to have ${published.what} while this import was being staged — a scope whose history cannot be judged is not an empty target; nothing was published`, ...published.fault } };
1228
1244
  }
1229
1245
  }
1230
1246
  catch (err) {
@@ -1234,7 +1250,7 @@ export class FileFileHistoryStore {
1234
1250
  return { ok: true };
1235
1251
  }
1236
1252
  catch (err) {
1237
- return { ok: false, error: { code: "unsupported_format", message: `importHistory failed: ${thrownText(err)}` } };
1253
+ return { ok: false, error: { code: "unsupported_format", message: `importHistory failed: ${thrownText(err)}`, ...caughtFault(err) } };
1238
1254
  }
1239
1255
  finally {
1240
1256
  safeRm(importJournal);