open-multi-agent-kit 0.90.7 → 0.90.9

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 (331) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +17 -10
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +5 -1
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/commands/doctor-provider-cli.d.ts +33 -0
  7. package/dist/commands/doctor-provider-cli.d.ts.map +1 -0
  8. package/dist/commands/doctor-provider-cli.js +215 -0
  9. package/dist/commands/doctor-provider-cli.js.map +1 -0
  10. package/dist/commands/doctor-provider-transport.d.ts +35 -0
  11. package/dist/commands/doctor-provider-transport.d.ts.map +1 -0
  12. package/dist/commands/doctor-provider-transport.js +185 -0
  13. package/dist/commands/doctor-provider-transport.js.map +1 -0
  14. package/dist/commands/doctor-provider.d.ts +121 -7
  15. package/dist/commands/doctor-provider.d.ts.map +1 -1
  16. package/dist/commands/doctor-provider.js +1295 -102
  17. package/dist/commands/doctor-provider.js.map +1 -1
  18. package/dist/commands/session-doctor-cli.d.ts +43 -0
  19. package/dist/commands/session-doctor-cli.d.ts.map +1 -0
  20. package/dist/commands/session-doctor-cli.js +494 -0
  21. package/dist/commands/session-doctor-cli.js.map +1 -0
  22. package/dist/commands/verify-ci.d.ts +21 -0
  23. package/dist/commands/verify-ci.d.ts.map +1 -0
  24. package/dist/commands/verify-ci.js +66 -0
  25. package/dist/commands/verify-ci.js.map +1 -0
  26. package/dist/core/agent-session-services.d.ts +3 -0
  27. package/dist/core/agent-session-services.d.ts.map +1 -1
  28. package/dist/core/agent-session-services.js +3 -0
  29. package/dist/core/agent-session-services.js.map +1 -1
  30. package/dist/core/agent-session.d.ts +116 -2
  31. package/dist/core/agent-session.d.ts.map +1 -1
  32. package/dist/core/agent-session.js +1015 -71
  33. package/dist/core/agent-session.js.map +1 -1
  34. package/dist/core/agent-tool-settings.d.ts +35 -0
  35. package/dist/core/agent-tool-settings.d.ts.map +1 -0
  36. package/dist/core/agent-tool-settings.js +155 -0
  37. package/dist/core/agent-tool-settings.js.map +1 -0
  38. package/dist/core/atomic-session-file.d.ts +14 -0
  39. package/dist/core/atomic-session-file.d.ts.map +1 -0
  40. package/dist/core/atomic-session-file.js +104 -0
  41. package/dist/core/atomic-session-file.js.map +1 -0
  42. package/dist/core/compaction/compaction.d.ts +6 -0
  43. package/dist/core/compaction/compaction.d.ts.map +1 -1
  44. package/dist/core/compaction/compaction.js +12 -1
  45. package/dist/core/compaction/compaction.js.map +1 -1
  46. package/dist/core/compaction/hysteresis.d.ts +27 -0
  47. package/dist/core/compaction/hysteresis.d.ts.map +1 -0
  48. package/dist/core/compaction/hysteresis.js +84 -0
  49. package/dist/core/compaction/hysteresis.js.map +1 -0
  50. package/dist/core/compaction/index.d.ts +2 -0
  51. package/dist/core/compaction/index.d.ts.map +1 -1
  52. package/dist/core/compaction/index.js +2 -0
  53. package/dist/core/compaction/index.js.map +1 -1
  54. package/dist/core/compaction/transaction.d.ts +172 -0
  55. package/dist/core/compaction/transaction.d.ts.map +1 -0
  56. package/dist/core/compaction/transaction.js +824 -0
  57. package/dist/core/compaction/transaction.js.map +1 -0
  58. package/dist/core/context-budget-governor-v2.d.ts +2 -1
  59. package/dist/core/context-budget-governor-v2.d.ts.map +1 -1
  60. package/dist/core/context-budget-governor-v2.js +2 -1
  61. package/dist/core/context-budget-governor-v2.js.map +1 -1
  62. package/dist/core/context-budget-headroom.d.ts.map +1 -1
  63. package/dist/core/context-budget-headroom.js +5 -1
  64. package/dist/core/context-budget-headroom.js.map +1 -1
  65. package/dist/core/context-budget-reserved-tokens.d.ts +110 -0
  66. package/dist/core/context-budget-reserved-tokens.d.ts.map +1 -0
  67. package/dist/core/context-budget-reserved-tokens.js +188 -0
  68. package/dist/core/context-budget-reserved-tokens.js.map +1 -0
  69. package/dist/core/context-budget-v2-cache-invalidation.d.ts +133 -0
  70. package/dist/core/context-budget-v2-cache-invalidation.d.ts.map +1 -0
  71. package/dist/core/context-budget-v2-cache-invalidation.js +452 -0
  72. package/dist/core/context-budget-v2-cache-invalidation.js.map +1 -0
  73. package/dist/core/context-budget-v2-cache-keys.d.ts +3 -0
  74. package/dist/core/context-budget-v2-cache-keys.d.ts.map +1 -1
  75. package/dist/core/context-budget-v2-cache-keys.js +6 -0
  76. package/dist/core/context-budget-v2-cache-keys.js.map +1 -1
  77. package/dist/core/context-budget-v2-cache-provider.d.ts +8 -2
  78. package/dist/core/context-budget-v2-cache-provider.d.ts.map +1 -1
  79. package/dist/core/context-budget-v2-cache-provider.js +28 -5
  80. package/dist/core/context-budget-v2-cache-provider.js.map +1 -1
  81. package/dist/core/context-budget-v2-plan-cache-keys.d.ts.map +1 -1
  82. package/dist/core/context-budget-v2-plan-cache-keys.js +1 -0
  83. package/dist/core/context-budget-v2-plan-cache-keys.js.map +1 -1
  84. package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
  85. package/dist/core/context-budget-v2-planner.js +1 -0
  86. package/dist/core/context-budget-v2-planner.js.map +1 -1
  87. package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
  88. package/dist/core/context-budget-v2-selection.js +9 -0
  89. package/dist/core/context-budget-v2-selection.js.map +1 -1
  90. package/dist/core/context-budget-v2-types.d.ts +4 -0
  91. package/dist/core/context-budget-v2-types.d.ts.map +1 -1
  92. package/dist/core/context-budget-v2-types.js.map +1 -1
  93. package/dist/core/durable-file-directory.d.ts +4 -0
  94. package/dist/core/durable-file-directory.d.ts.map +1 -0
  95. package/dist/core/durable-file-directory.js +76 -0
  96. package/dist/core/durable-file-directory.js.map +1 -0
  97. package/dist/core/durable-file-identity.d.ts +26 -0
  98. package/dist/core/durable-file-identity.d.ts.map +1 -0
  99. package/dist/core/durable-file-identity.js +118 -0
  100. package/dist/core/durable-file-identity.js.map +1 -0
  101. package/dist/core/durable-file-io.d.ts +29 -0
  102. package/dist/core/durable-file-io.d.ts.map +1 -0
  103. package/dist/core/durable-file-io.js +179 -0
  104. package/dist/core/durable-file-io.js.map +1 -0
  105. package/dist/core/durable-file-lock-cleanup.d.ts +12 -0
  106. package/dist/core/durable-file-lock-cleanup.d.ts.map +1 -0
  107. package/dist/core/durable-file-lock-cleanup.js +39 -0
  108. package/dist/core/durable-file-lock-cleanup.js.map +1 -0
  109. package/dist/core/durable-file-lock-owner.d.ts +18 -0
  110. package/dist/core/durable-file-lock-owner.d.ts.map +1 -0
  111. package/dist/core/durable-file-lock-owner.js +78 -0
  112. package/dist/core/durable-file-lock-owner.js.map +1 -0
  113. package/dist/core/durable-file-lock-storage.d.ts +35 -0
  114. package/dist/core/durable-file-lock-storage.d.ts.map +1 -0
  115. package/dist/core/durable-file-lock-storage.js +263 -0
  116. package/dist/core/durable-file-lock-storage.js.map +1 -0
  117. package/dist/core/durable-file-mode.d.ts +8 -0
  118. package/dist/core/durable-file-mode.d.ts.map +1 -0
  119. package/dist/core/durable-file-mode.js +41 -0
  120. package/dist/core/durable-file-mode.js.map +1 -0
  121. package/dist/core/extensions/loader.d.ts +12 -0
  122. package/dist/core/extensions/loader.d.ts.map +1 -1
  123. package/dist/core/extensions/loader.js +50 -37
  124. package/dist/core/extensions/loader.js.map +1 -1
  125. package/dist/core/extensions/types.d.ts +2 -0
  126. package/dist/core/extensions/types.d.ts.map +1 -1
  127. package/dist/core/extensions/types.js.map +1 -1
  128. package/dist/core/index.d.ts +6 -2
  129. package/dist/core/index.d.ts.map +1 -1
  130. package/dist/core/index.js +5 -0
  131. package/dist/core/index.js.map +1 -1
  132. package/dist/core/loop-gates.d.ts.map +1 -1
  133. package/dist/core/loop-gates.js +25 -1
  134. package/dist/core/loop-gates.js.map +1 -1
  135. package/dist/core/model-resolver.d.ts.map +1 -1
  136. package/dist/core/model-resolver.js +1 -1
  137. package/dist/core/model-resolver.js.map +1 -1
  138. package/dist/core/pi-package-intake.d.ts +1 -0
  139. package/dist/core/pi-package-intake.d.ts.map +1 -1
  140. package/dist/core/pi-package-intake.js +7 -0
  141. package/dist/core/pi-package-intake.js.map +1 -1
  142. package/dist/core/redaction.d.ts +8 -0
  143. package/dist/core/redaction.d.ts.map +1 -0
  144. package/dist/core/redaction.js +31 -0
  145. package/dist/core/redaction.js.map +1 -0
  146. package/dist/core/resource-loader.d.ts.map +1 -1
  147. package/dist/core/resource-loader.js +36 -0
  148. package/dist/core/resource-loader.js.map +1 -1
  149. package/dist/core/run-journal-store.d.ts +53 -0
  150. package/dist/core/run-journal-store.d.ts.map +1 -0
  151. package/dist/core/run-journal-store.js +278 -0
  152. package/dist/core/run-journal-store.js.map +1 -0
  153. package/dist/core/run-journal.d.ts +172 -0
  154. package/dist/core/run-journal.d.ts.map +1 -0
  155. package/dist/core/run-journal.js +1053 -0
  156. package/dist/core/run-journal.js.map +1 -0
  157. package/dist/core/sdk.d.ts +7 -0
  158. package/dist/core/sdk.d.ts.map +1 -1
  159. package/dist/core/sdk.js +94 -3
  160. package/dist/core/sdk.js.map +1 -1
  161. package/dist/core/session-doctor-plan.d.ts +128 -0
  162. package/dist/core/session-doctor-plan.d.ts.map +1 -0
  163. package/dist/core/session-doctor-plan.js +833 -0
  164. package/dist/core/session-doctor-plan.js.map +1 -0
  165. package/dist/core/session-file-compaction.d.ts +6 -0
  166. package/dist/core/session-file-compaction.d.ts.map +1 -0
  167. package/dist/core/session-file-compaction.js +169 -0
  168. package/dist/core/session-file-compaction.js.map +1 -0
  169. package/dist/core/session-file-head.d.ts +10 -0
  170. package/dist/core/session-file-head.d.ts.map +1 -0
  171. package/dist/core/session-file-head.js +78 -0
  172. package/dist/core/session-file-head.js.map +1 -0
  173. package/dist/core/session-file-persistence.d.ts +30 -0
  174. package/dist/core/session-file-persistence.d.ts.map +1 -0
  175. package/dist/core/session-file-persistence.js +106 -0
  176. package/dist/core/session-file-persistence.js.map +1 -0
  177. package/dist/core/session-integrity.d.ts +43 -0
  178. package/dist/core/session-integrity.d.ts.map +1 -0
  179. package/dist/core/session-integrity.js +420 -0
  180. package/dist/core/session-integrity.js.map +1 -0
  181. package/dist/core/session-manager.d.ts +24 -4
  182. package/dist/core/session-manager.d.ts.map +1 -1
  183. package/dist/core/session-manager.js +242 -125
  184. package/dist/core/session-manager.js.map +1 -1
  185. package/dist/core/session-owner-lease.d.ts +22 -0
  186. package/dist/core/session-owner-lease.d.ts.map +1 -0
  187. package/dist/core/session-owner-lease.js +176 -0
  188. package/dist/core/session-owner-lease.js.map +1 -0
  189. package/dist/core/session-path-policy.d.ts +132 -0
  190. package/dist/core/session-path-policy.d.ts.map +1 -0
  191. package/dist/core/session-path-policy.js +780 -0
  192. package/dist/core/session-path-policy.js.map +1 -0
  193. package/dist/core/session-repair-plan.d.ts +49 -0
  194. package/dist/core/session-repair-plan.d.ts.map +1 -0
  195. package/dist/core/session-repair-plan.js +202 -0
  196. package/dist/core/session-repair-plan.js.map +1 -0
  197. package/dist/core/session-termination.d.ts +100 -0
  198. package/dist/core/session-termination.d.ts.map +1 -0
  199. package/dist/core/session-termination.js +403 -0
  200. package/dist/core/session-termination.js.map +1 -0
  201. package/dist/core/settings-manager.d.ts +32 -0
  202. package/dist/core/settings-manager.d.ts.map +1 -1
  203. package/dist/core/settings-manager.js +52 -5
  204. package/dist/core/settings-manager.js.map +1 -1
  205. package/dist/core/system-prompt.d.ts.map +1 -1
  206. package/dist/core/system-prompt.js +1 -1
  207. package/dist/core/system-prompt.js.map +1 -1
  208. package/dist/core/verified-bash-adapter.d.ts +36 -0
  209. package/dist/core/verified-bash-adapter.d.ts.map +1 -0
  210. package/dist/core/verified-bash-adapter.js +90 -0
  211. package/dist/core/verified-bash-adapter.js.map +1 -0
  212. package/dist/guardrails/command-redaction.d.ts +32 -0
  213. package/dist/guardrails/command-redaction.d.ts.map +1 -0
  214. package/dist/guardrails/command-redaction.js +776 -0
  215. package/dist/guardrails/command-redaction.js.map +1 -0
  216. package/dist/guardrails/evidence-attestation.d.ts +31 -0
  217. package/dist/guardrails/evidence-attestation.d.ts.map +1 -0
  218. package/dist/guardrails/evidence-attestation.js +178 -0
  219. package/dist/guardrails/evidence-attestation.js.map +1 -0
  220. package/dist/guardrails/evidence-receipt-store.d.ts +33 -0
  221. package/dist/guardrails/evidence-receipt-store.d.ts.map +1 -0
  222. package/dist/guardrails/evidence-receipt-store.js +446 -0
  223. package/dist/guardrails/evidence-receipt-store.js.map +1 -0
  224. package/dist/guardrails/evidence-receipt.d.ts +58 -0
  225. package/dist/guardrails/evidence-receipt.d.ts.map +1 -0
  226. package/dist/guardrails/evidence-receipt.js +389 -0
  227. package/dist/guardrails/evidence-receipt.js.map +1 -0
  228. package/dist/guardrails/evidence-system.d.ts +40 -9
  229. package/dist/guardrails/evidence-system.d.ts.map +1 -1
  230. package/dist/guardrails/evidence-system.js +379 -83
  231. package/dist/guardrails/evidence-system.js.map +1 -1
  232. package/dist/guardrails/replay-ledger-io.d.ts +6 -0
  233. package/dist/guardrails/replay-ledger-io.d.ts.map +1 -0
  234. package/dist/guardrails/replay-ledger-io.js +42 -0
  235. package/dist/guardrails/replay-ledger-io.js.map +1 -0
  236. package/dist/guardrails/replay-ledger-lock-owner.d.ts +32 -0
  237. package/dist/guardrails/replay-ledger-lock-owner.d.ts.map +1 -0
  238. package/dist/guardrails/replay-ledger-lock-owner.js +138 -0
  239. package/dist/guardrails/replay-ledger-lock-owner.js.map +1 -0
  240. package/dist/guardrails/replay-ledger-lock.d.ts +24 -0
  241. package/dist/guardrails/replay-ledger-lock.d.ts.map +1 -0
  242. package/dist/guardrails/replay-ledger-lock.js +135 -0
  243. package/dist/guardrails/replay-ledger-lock.js.map +1 -0
  244. package/dist/guardrails/replay-ledger-mutation-gate.d.ts +24 -0
  245. package/dist/guardrails/replay-ledger-mutation-gate.d.ts.map +1 -0
  246. package/dist/guardrails/replay-ledger-mutation-gate.js +205 -0
  247. package/dist/guardrails/replay-ledger-mutation-gate.js.map +1 -0
  248. package/dist/guardrails/replay-ledger-quarantine.d.ts +2 -0
  249. package/dist/guardrails/replay-ledger-quarantine.d.ts.map +1 -0
  250. package/dist/guardrails/replay-ledger-quarantine.js +19 -0
  251. package/dist/guardrails/replay-ledger-quarantine.js.map +1 -0
  252. package/dist/guardrails/replay-ledger-store.d.ts +32 -0
  253. package/dist/guardrails/replay-ledger-store.d.ts.map +1 -0
  254. package/dist/guardrails/replay-ledger-store.js +211 -0
  255. package/dist/guardrails/replay-ledger-store.js.map +1 -0
  256. package/dist/guardrails/shell-command-name-glob.d.ts +3 -0
  257. package/dist/guardrails/shell-command-name-glob.d.ts.map +1 -0
  258. package/dist/guardrails/shell-command-name-glob.js +233 -0
  259. package/dist/guardrails/shell-command-name-glob.js.map +1 -0
  260. package/dist/guardrails/shell-command-option.d.ts +7 -0
  261. package/dist/guardrails/shell-command-option.d.ts.map +1 -0
  262. package/dist/guardrails/shell-command-option.js +24 -0
  263. package/dist/guardrails/shell-command-option.js.map +1 -0
  264. package/dist/guardrails/shell-command-tokenizer.d.ts +29 -0
  265. package/dist/guardrails/shell-command-tokenizer.d.ts.map +1 -0
  266. package/dist/guardrails/shell-command-tokenizer.js +145 -0
  267. package/dist/guardrails/shell-command-tokenizer.js.map +1 -0
  268. package/dist/guardrails/shell-command-wrapper.d.ts +18 -0
  269. package/dist/guardrails/shell-command-wrapper.d.ts.map +1 -0
  270. package/dist/guardrails/shell-command-wrapper.js +42 -0
  271. package/dist/guardrails/shell-command-wrapper.js.map +1 -0
  272. package/dist/guardrails/verified-executor.d.ts +65 -0
  273. package/dist/guardrails/verified-executor.d.ts.map +1 -0
  274. package/dist/guardrails/verified-executor.js +171 -0
  275. package/dist/guardrails/verified-executor.js.map +1 -0
  276. package/dist/guardrails/workspace-fingerprint.d.ts +23 -0
  277. package/dist/guardrails/workspace-fingerprint.d.ts.map +1 -0
  278. package/dist/guardrails/workspace-fingerprint.js +634 -0
  279. package/dist/guardrails/workspace-fingerprint.js.map +1 -0
  280. package/dist/index.d.ts +15 -3
  281. package/dist/index.d.ts.map +1 -1
  282. package/dist/index.js +13 -1
  283. package/dist/index.js.map +1 -1
  284. package/dist/main.d.ts.map +1 -1
  285. package/dist/main.js +12 -0
  286. package/dist/main.js.map +1 -1
  287. package/dist/modes/interactive/components/control-panel-layout.d.ts.map +1 -1
  288. package/dist/modes/interactive/components/control-panel-layout.js +1 -1
  289. package/dist/modes/interactive/components/control-panel-layout.js.map +1 -1
  290. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  291. package/dist/modes/interactive/components/footer.js +1 -1
  292. package/dist/modes/interactive/components/footer.js.map +1 -1
  293. package/dist/modes/interactive/interactive-mode.d.ts +3 -0
  294. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  295. package/dist/modes/interactive/interactive-mode.js +59 -9
  296. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  297. package/dist/modes/print-mode.d.ts.map +1 -1
  298. package/dist/modes/print-mode.js +43 -2
  299. package/dist/modes/print-mode.js.map +1 -1
  300. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  301. package/dist/modes/rpc/rpc-mode.js +23 -5
  302. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  303. package/dist/modes/rpc/rpc-types.d.ts +3 -0
  304. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  305. package/dist/modes/rpc/rpc-types.js.map +1 -1
  306. package/dist/types/evidence.d.ts +215 -1
  307. package/dist/types/evidence.d.ts.map +1 -1
  308. package/dist/types/evidence.js.map +1 -1
  309. package/dist/verify-ci.d.ts +3 -0
  310. package/dist/verify-ci.d.ts.map +1 -0
  311. package/dist/verify-ci.js +30 -0
  312. package/dist/verify-ci.js.map +1 -0
  313. package/docs/compaction.md +44 -4
  314. package/docs/extensions.md +2 -0
  315. package/docs/providers.md +6 -0
  316. package/docs/sdk.md +238 -1
  317. package/docs/settings.md +67 -4
  318. package/docs/usage.md +38 -0
  319. package/examples/extensions/correctness-wall/README.md +6 -6
  320. package/examples/extensions/correctness-wall/index.ts +37 -11
  321. package/examples/extensions/custom-provider-anthropic/package-lock.json +5 -5
  322. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  323. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  324. package/examples/extensions/gondolin/package-lock.json +2 -2
  325. package/examples/extensions/gondolin/package.json +1 -1
  326. package/examples/extensions/sandbox/package-lock.json +2 -2
  327. package/examples/extensions/sandbox/package.json +1 -1
  328. package/examples/extensions/with-deps/package-lock.json +4 -4
  329. package/examples/extensions/with-deps/package.json +1 -1
  330. package/npm-shrinkwrap.json +12 -12
  331. package/package.json +4 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-doctor-plan.js","sourceRoot":"","sources":["../../src/core/session-doctor-plan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure, browser-safe session doctor planner (task I38).\n *\n * The doctor rederives every repair decision from caller-attested,\n * accessor-free plain data plus four pure runtime dependencies:\n * - {@link createSessionRepairPlan} (session transcript repair),\n * - {@link inspectRunJournal} / {@link serializeRunJournalLine} (journal\n * integrity and terminal-record serialization),\n * - {@link decideSessionPathAccess} (per-artifact path authorization),\n * - {@link decideCompactionCommit} (compaction commit authorization).\n *\n * Runtime purity: no I/O, no wall clock, no entropy, no cryptographic\n * primitives, and no Node-only APIs. Every journal hash is recomputed by a\n * caller-injected synchronous hash function; the doctor never mints a\n * termination or a hash. {@link SessionIntegrityReport} is imported as a type\n * only, so the session-integrity module is never on this planner's runtime\n * dependency graph. All inputs are validated strictly (plain data, exact keys,\n * accessor-free) and the returned plan is a deep-frozen copy.\n */\n\nimport type { ToolResultMessage } from \"omk-ai\";\nimport type {\n\tCompactionCommitDecision,\n\tDecideCompactionCommitInput,\n\tSessionRevisionToken,\n} from \"./compaction/transaction.ts\";\nimport { decideCompactionCommit } from \"./compaction/transaction.ts\";\nimport type { RunJournalCompletePrefix, RunJournalHashFn, RunJournalTerminalRecord } from \"./run-journal.ts\";\nimport { GENESIS_HASH, inspectRunJournal, serializeRunJournalLine } from \"./run-journal.ts\";\nimport type { SessionByteDigest, SessionCompletePrefix, SessionIntegrityReport } from \"./session-integrity.ts\";\nimport type {\n\tSessionPathAccessInput,\n\tSessionPathDecision,\n\tSessionPathIntent,\n\tSessionPathPlatform,\n} from \"./session-path-policy.ts\";\nimport { decideSessionPathAccess } from \"./session-path-policy.ts\";\nimport { createSessionRepairPlan } from \"./session-repair-plan.ts\";\n\nexport const SESSION_DOCTOR_PLAN_SCHEMA_VERSION = 1 as const;\n\nconst MAX_IDENTIFIER_LENGTH = 128;\nconst MAX_NORMALIZED_CHECKS = 128;\nconst MAX_FINDING_IDS = 64;\nconst MAX_PLAIN_DATA_DEPTH = 64;\nconst MAX_PLAIN_DATA_NODES = 200_000;\nconst CONTROL_CHAR_RE = /[\\u0000-\\u001f\\u007f]/;\n/** High-confidence credential shapes; rejected at every trust boundary. */\nconst CREDENTIAL_SHAPES = [\n\t/-----BEGIN [A-Z ]*PRIVATE KEY-----/i,\n\t/\\bsk-[A-Za-z0-9_-]{16,}\\b/,\n\t/\\bgh[pousr]_[A-Za-z0-9]{16,}\\b/,\n\t/\\bgithub_pat_[A-Za-z0-9_]{16,}\\b/,\n\t/\\bxox[baprs]-[A-Za-z0-9-]{16,}\\b/,\n\t/\\bAKIA[A-Z0-9]{16}\\b/,\n\t/\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\b/,\n\t/\\bBearer\\s+[A-Za-z0-9._~+/-]{8,}={0,2}\\b/i,\n\t/(?:^|[^A-Za-z0-9])(?:[A-Za-z0-9]+[_-])*(?:authorization|api[-_ ]?key|access[-_ ]?token|token|password|secret(?:[-_ ]?key)?|private[-_ ]?key|cookie)[\"']?\\s*[:=]/i,\n] as const;\n\n// -------------------------------------------------------------------------------------------------\n// Public types.\n// -------------------------------------------------------------------------------------------------\n\nexport type SessionDoctorMode = \"inspect\" | \"repair_dry_run\" | \"repair\";\nexport type SessionDoctorStatus = \"healthy\" | \"issues\" | \"refused\";\nexport type SessionDoctorExitCode = 0 | 1 | 2;\n\nexport type SessionDoctorArtifact = \"session\" | \"journal\" | \"path\" | \"compaction\" | \"normalized\";\n\nexport type SessionDoctorFindingSeverity = \"advisory\" | \"blocked\";\n\nexport type SessionDoctorFindingReason =\n\t| \"session_trailing_fragment\"\n\t| \"session_missing_tool_result\"\n\t| \"session_blocked\"\n\t| \"session_inspection_incomplete\"\n\t| \"journal_trailing_fragment\"\n\t| \"journal_unclosed\"\n\t| \"journal_blocked\"\n\t| \"session_path_unauthorized\"\n\t| \"journal_path_unauthorized\"\n\t| \"compaction_stale\"\n\t| \"compaction_deferred\"\n\t| \"compaction_failed\"\n\t| \"compaction_committed\"\n\t| \"compaction_duplicate\"\n\t| \"normalized_check_unhealthy\"\n\t| \"contract_violation\";\n\nexport interface SessionDoctorFinding {\n\treadonly artifact: SessionDoctorArtifact;\n\treadonly reason: SessionDoctorFindingReason;\n\treadonly severity: SessionDoctorFindingSeverity;\n\t/** Bounded upstream reason/code (e.g. an integrity reason, journal finding code, path decision reason). */\n\treadonly code?: string;\n\t/** Bounded identifiers (toolCallIds, runIds, ...). */\n\treadonly ids?: readonly string[];\n}\n\nexport type SessionDoctorActionArtifact = \"session\" | \"journal\";\n\nexport type SessionDoctorActionSpec =\n\t| {\n\t\t\treadonly kind: \"quarantine_session_trailing_fragment\";\n\t\t\treadonly artifact: \"session\";\n\t\t\treadonly retainPrefix: SessionCompletePrefix;\n\t\t\treadonly fragment: SessionByteDigest;\n\t }\n\t| {\n\t\t\treadonly kind: \"append_synthetic_tool_result\";\n\t\t\treadonly artifact: \"session\";\n\t\t\treadonly toolCallId: string;\n\t\t\treadonly toolName: string;\n\t\t\treadonly repairSequence: number;\n\t\t\treadonly message: Readonly<ToolResultMessage>;\n\t }\n\t| {\n\t\t\treadonly kind: \"quarantine_journal_trailing_fragment\";\n\t\t\treadonly artifact: \"journal\";\n\t\t\treadonly completePrefix: RunJournalCompletePrefix;\n\t\t\treadonly lastCompleteHash: string;\n\t }\n\t| {\n\t\t\treadonly kind: \"recover_run\";\n\t\t\treadonly artifact: \"journal\";\n\t\t\treadonly runId: string;\n\t\t\treadonly terminalRecord: RunJournalTerminalRecord;\n\t\t\treadonly completePrefix: RunJournalCompletePrefix;\n\t\t\treadonly lastCompleteHash: string;\n\t }\n\t| {\n\t\t\treadonly kind: \"remove_stale_lock\";\n\t\t\treadonly artifact: SessionDoctorActionArtifact;\n\t\t\treadonly platform: SessionPathPlatform;\n\t\t\treadonly targetLexical: string;\n\t\t\treadonly targetRealpath: string;\n\t\t\treadonly holderPid: string | null;\n\t\t\treadonly artifacts: readonly SessionDoctorActionArtifact[];\n\t }\n\t| {\n\t\t\treadonly kind: \"abandon_stale_compaction\";\n\t\t\treadonly artifact: \"session\";\n\t\t\treadonly transactionId: string;\n\t\t\treadonly baseRevision: Readonly<SessionRevisionToken>;\n\t\t\treadonly sourceSha256: string;\n\t\t\treadonly staleReason: \"revision_mismatch\" | \"source_mismatch\";\n\t };\n\nexport type SessionDoctorAction = SessionDoctorActionSpec & { readonly sequence: number };\n\nexport interface SessionDoctorPlan {\n\treadonly schemaVersion: typeof SESSION_DOCTOR_PLAN_SCHEMA_VERSION;\n\treadonly mode: SessionDoctorMode;\n\treadonly sessionId: string;\n\treadonly repairId: string;\n\treadonly status: SessionDoctorStatus;\n\treadonly exitCode: SessionDoctorExitCode;\n\treadonly repairable: boolean;\n\treadonly requiresReinspection: boolean;\n\treadonly scheduledWrites: number;\n\treadonly findings: readonly SessionDoctorFinding[];\n\treadonly actions: readonly SessionDoctorAction[];\n}\n\nexport type SessionDoctorNormalizedCheckArtifact =\n\t| \"compaction_envelope\"\n\t| \"evidence_link\"\n\t| \"workspace\"\n\t| \"provider_model\";\n\nexport interface SessionDoctorNormalizedCheck {\n\treadonly artifact: SessionDoctorNormalizedCheckArtifact;\n\treadonly id: string;\n\treadonly status: \"ok\" | \"missing\" | \"invalid\" | \"unavailable\";\n}\n\nexport interface SessionDoctorJournalObservation {\n\treadonly bytes: Uint8Array;\n\treadonly hashFn: RunJournalHashFn;\n\t/** Caller-supplied terminal record for unclosed-run recovery. The doctor never mints it. */\n\treadonly terminalRecord?: RunJournalTerminalRecord;\n}\n\nexport interface SessionDoctorPathObservation {\n\treadonly session?: Omit<SessionPathAccessInput, \"intent\">;\n\treadonly journal?: Omit<SessionPathAccessInput, \"intent\">;\n}\n\nexport interface SessionDoctorPlanInput {\n\treadonly schemaVersion?: typeof SESSION_DOCTOR_PLAN_SCHEMA_VERSION;\n\treadonly mode: SessionDoctorMode;\n\treadonly sessionId: string;\n\treadonly repairId: string;\n\t/** Deterministic caller-provided epoch milliseconds. */\n\treadonly timestamp: number;\n\treadonly report: SessionIntegrityReport;\n\treadonly journal?: SessionDoctorJournalObservation;\n\treadonly paths?: SessionDoctorPathObservation;\n\treadonly compaction?: DecideCompactionCommitInput;\n\treadonly normalizedChecks?: readonly SessionDoctorNormalizedCheck[];\n}\n\n// -------------------------------------------------------------------------------------------------\n// Generic plain-data / exact-key / accessor-free guards (fail closed).\n// -------------------------------------------------------------------------------------------------\n\nconst TEXT_ENCODER = new TextEncoder();\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isPlainDataObject(value: unknown): value is Record<string, unknown> {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n\tif (Object.getPrototypeOf(value) !== null && Object.getPrototypeOf(value) !== Object.prototype) return false;\n\tif (Object.getOwnPropertySymbols(value).length > 0) return false;\n\tfor (const key of Object.keys(value)) {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(value, key);\n\t\tif (\n\t\t\tdescriptor === undefined ||\n\t\t\tdescriptor.get !== undefined ||\n\t\t\tdescriptor.set !== undefined ||\n\t\t\t!(\"value\" in descriptor)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n/**\n * Strictly validate a plain dense array before any indexed value access: it\n * must be a real Array whose prototype is exactly Array.prototype, carry no\n * symbol properties or extra own properties, and expose every index 0..length-1\n * as an own data descriptor (no holes, no getters/setters). Accessor indices are\n * rejected without their getters ever executing. The length is captured once.\n */\nfunction assertStrictPlainArray(value: unknown, label: string): asserts value is unknown[] {\n\tif (typeof value !== \"object\" || value === null || !Array.isArray(value)) {\n\t\tthrow new TypeError(`${label} must be an array`);\n\t}\n\tif (Object.getPrototypeOf(value) !== Array.prototype) {\n\t\tthrow new TypeError(`${label} must use the Array prototype`);\n\t}\n\tif (Object.getOwnPropertySymbols(value).length > 0) {\n\t\tthrow new TypeError(`${label} must not carry symbol properties`);\n\t}\n\tconst length = value.length;\n\tfor (const name of Object.getOwnPropertyNames(value)) {\n\t\tif (name === \"length\") continue;\n\t\tconst index = Number(name);\n\t\tif (!Number.isSafeInteger(index) || index < 0 || index >= length || String(index) !== name) {\n\t\t\tthrow new TypeError(`${label} must not carry extra own properties`);\n\t\t}\n\t}\n\tfor (let i = 0; i < length; i += 1) {\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(value, String(i));\n\t\tif (descriptor === undefined) throw new TypeError(`${label} must be dense (no holes)`);\n\t\tif (descriptor.get !== undefined || descriptor.set !== undefined || !(\"value\" in descriptor)) {\n\t\t\tthrow new TypeError(`${label} must not expose accessor or non-data element descriptors`);\n\t\t}\n\t}\n}\n\nfunction looksLikeCredential(value: string): boolean {\n\treturn CREDENTIAL_SHAPES.some((pattern) => pattern.test(value));\n}\n\nfunction assertPlainData(value: unknown, label: string): asserts value is Record<string, unknown> {\n\tif (!isPlainDataObject(value)) {\n\t\tthrow new TypeError(`${label} must be a plain data object without accessors or a foreign prototype`);\n\t}\n}\n\n/**\n * Bounded recursive plain-data validator for trust boundaries. Walks the full\n * value tree (plain objects and dense arrays) and rejects any accessor\n * property, symbol property, foreign prototype, or sparse array slot without\n * ever executing a getter (descriptors are inspected, never read). Guards\n * SessionIntegrityReport / journal terminalRecord / compaction before any of\n * their fields are read. Primitives pass; Uint8Array and functions are not\n * validated here (callers handle those explicitly).\n */\nfunction assertPlainDataTree(value: unknown, label: string): void {\n\tlet nodes = 0;\n\tconst stack: Array<{ value: unknown; label: string; depth: number }> = [{ value, label, depth: 0 }];\n\twhile (stack.length > 0) {\n\t\tconst frame = stack.pop() as { value: unknown; label: string; depth: number };\n\t\tnodes += 1;\n\t\tif (nodes > MAX_PLAIN_DATA_NODES) {\n\t\t\tthrow new TypeError(`${label}: plain-data tree exceeds the maximum node budget`);\n\t\t}\n\t\tconst { value: current, label: currentLabel, depth } = frame;\n\t\tif (depth > MAX_PLAIN_DATA_DEPTH) {\n\t\t\tthrow new TypeError(`${currentLabel}: plain-data tree exceeds the maximum depth`);\n\t\t}\n\t\tif (current === null || typeof current !== \"object\") continue;\n\t\tif (Array.isArray(current)) {\n\t\t\tassertStrictPlainArray(current, currentLabel);\n\t\t\tfor (let index = 0; index < current.length; index += 1) {\n\t\t\t\tstack.push({ value: current[index], label: `${currentLabel}[${index}]`, depth: depth + 1 });\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tconst prototype = Object.getPrototypeOf(current);\n\t\tif (prototype !== null && prototype !== Object.prototype) {\n\t\t\tthrow new TypeError(`${currentLabel} must be a plain data object without a foreign prototype`);\n\t\t}\n\t\tif (Object.getOwnPropertySymbols(current).length > 0) {\n\t\t\tthrow new TypeError(`${currentLabel} must be a plain data object without symbol properties`);\n\t\t}\n\t\tfor (const key of Object.keys(current)) {\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(current, key);\n\t\t\tif (descriptor === undefined || !(\"value\" in descriptor)) {\n\t\t\t\tthrow new TypeError(`${currentLabel}.${key} must be a plain data property without accessors`);\n\t\t\t}\n\t\t\tstack.push({ value: descriptor.value, label: `${currentLabel}.${key}`, depth: depth + 1 });\n\t\t}\n\t}\n}\n\nfunction assertIdentifier(value: unknown, label: string): asserts value is string {\n\tif (typeof value !== \"string\" || value.length === 0 || value.length > MAX_IDENTIFIER_LENGTH) {\n\t\tthrow new TypeError(`${label} must be 1-${MAX_IDENTIFIER_LENGTH} characters of bounded text`);\n\t}\n\tif (CONTROL_CHAR_RE.test(value)) {\n\t\tthrow new TypeError(`${label} must not contain C0 or DEL control characters`);\n\t}\n\tif (looksLikeCredential(value)) {\n\t\tthrow new TypeError(`${label} must not contain a credential-shaped literal`);\n\t}\n}\n\nfunction assertSafeNonNegativeInt(value: unknown, label: string): asserts value is number {\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) {\n\t\tthrow new TypeError(`${label} must be a non-negative safe integer`);\n\t}\n}\n\nfunction assertOnlyKeys(value: Record<string, unknown>, allowed: readonly string[], label: string): void {\n\tfor (const key of Object.keys(value)) {\n\t\tif (!allowed.includes(key)) {\n\t\t\tthrow new TypeError(`${label} contains an unsupported field: ${key}`);\n\t\t}\n\t}\n}\n\n// -------------------------------------------------------------------------------------------------\n// Input validation.\n// -------------------------------------------------------------------------------------------------\n\nconst INPUT_ALLOWED_KEYS = [\n\t\"schemaVersion\",\n\t\"mode\",\n\t\"sessionId\",\n\t\"repairId\",\n\t\"timestamp\",\n\t\"report\",\n\t\"journal\",\n\t\"paths\",\n\t\"compaction\",\n\t\"normalizedChecks\",\n];\nconst MODES = new Set<SessionDoctorMode>([\"inspect\", \"repair_dry_run\", \"repair\"]);\nconst JOURNAL_KEYS = [\"bytes\", \"hashFn\", \"terminalRecord\"];\nconst PATHS_KEYS = [\"session\", \"journal\"];\nconst PATH_INPUT_KEYS = [\"platform\", \"root\", \"target\", \"identity\", \"evidence\", \"lock\"];\nconst COMPACTION_KEYS = [\"transaction\", \"currentRevision\", \"currentSource\", \"barrier\", \"priorCommittedSourceDigests\"];\nconst NORMALIZED_KEYS = [\"artifact\", \"id\", \"status\"];\nconst NORMALIZED_ARTIFACTS = new Set<SessionDoctorNormalizedCheckArtifact>([\n\t\"compaction_envelope\",\n\t\"evidence_link\",\n\t\"workspace\",\n\t\"provider_model\",\n]);\nconst NORMALIZED_STATUSES = new Set([\"ok\", \"missing\", \"invalid\", \"unavailable\"]);\n\nfunction validateNormalizedChecks(value: unknown): readonly SessionDoctorNormalizedCheck[] {\n\tassertStrictPlainArray(value, \"normalizedChecks\");\n\tif (value.length > MAX_NORMALIZED_CHECKS) {\n\t\tthrow new TypeError(`normalizedChecks must contain at most ${MAX_NORMALIZED_CHECKS} entries`);\n\t}\n\tconst checks: SessionDoctorNormalizedCheck[] = [];\n\tfor (let index = 0; index < value.length; index++) {\n\t\tconst entry = value[index];\n\t\tassertPlainData(entry, `normalizedChecks[${index}]`);\n\t\tassertOnlyKeys(entry, NORMALIZED_KEYS, `normalizedChecks[${index}]`);\n\t\tif (!NORMALIZED_ARTIFACTS.has(entry.artifact as SessionDoctorNormalizedCheckArtifact)) {\n\t\t\tthrow new TypeError(`normalizedChecks[${index}].artifact is out of bounds`);\n\t\t}\n\t\tassertIdentifier(entry.id, `normalizedChecks[${index}].id`);\n\t\tif (!NORMALIZED_STATUSES.has(entry.status as string)) {\n\t\t\tthrow new TypeError(`normalizedChecks[${index}].status is out of bounds`);\n\t\t}\n\t\tchecks.push({\n\t\t\tartifact: entry.artifact as SessionDoctorNormalizedCheckArtifact,\n\t\t\tid: entry.id,\n\t\t\tstatus: entry.status as SessionDoctorNormalizedCheck[\"status\"],\n\t\t});\n\t}\n\treturn Object.freeze(checks);\n}\n\nfunction validatePathSubject(value: unknown, label: string): Omit<SessionPathAccessInput, \"intent\"> {\n\tassertPlainData(value, label);\n\tassertOnlyKeys(value, PATH_INPUT_KEYS, label);\n\tif (typeof value.platform !== \"string\" || (value.platform !== \"posix\" && value.platform !== \"win32\")) {\n\t\tthrow new TypeError(`${label}.platform must be posix|win32`);\n\t}\n\tif (typeof value.root !== \"string\") throw new TypeError(`${label}.root must be a string`);\n\tif (typeof value.target !== \"string\") throw new TypeError(`${label}.target must be a string`);\n\tif (!Object.hasOwn(value, \"evidence\")) throw new TypeError(`${label}.evidence is required`);\n\treturn value as unknown as Omit<SessionPathAccessInput, \"intent\">;\n}\n\ninterface ValidatedInput {\n\treadonly mode: SessionDoctorMode;\n\treadonly sessionId: string;\n\treadonly repairId: string;\n\treadonly timestamp: number;\n\treadonly report: SessionIntegrityReport;\n\treadonly journal: SessionDoctorJournalObservation | null;\n\treadonly paths: {\n\t\treadonly session: Omit<SessionPathAccessInput, \"intent\"> | null;\n\t\treadonly journal: Omit<SessionPathAccessInput, \"intent\"> | null;\n\t};\n\treadonly compaction: DecideCompactionCommitInput | null;\n\treadonly normalizedChecks: readonly SessionDoctorNormalizedCheck[];\n}\n\nfunction validateInput(rawInput: unknown): ValidatedInput {\n\tassertPlainData(rawInput, \"input\");\n\tassertOnlyKeys(rawInput, INPUT_ALLOWED_KEYS, \"input\");\n\tif (rawInput.schemaVersion !== undefined && rawInput.schemaVersion !== SESSION_DOCTOR_PLAN_SCHEMA_VERSION) {\n\t\tthrow new TypeError(\"unsupported session doctor plan schema version\");\n\t}\n\tif (!MODES.has(rawInput.mode as SessionDoctorMode)) {\n\t\tthrow new TypeError(\"mode must be inspect|repair_dry_run|repair\");\n\t}\n\tassertIdentifier(rawInput.sessionId, \"sessionId\");\n\tassertIdentifier(rawInput.repairId, \"repairId\");\n\tassertSafeNonNegativeInt(rawInput.timestamp, \"timestamp\");\n\tassertPlainData(rawInput.report, \"report\");\n\tassertPlainDataTree(rawInput.report, \"report\");\n\n\tlet journal: SessionDoctorJournalObservation | null = null;\n\tif (Object.hasOwn(rawInput, \"journal\") && rawInput.journal !== undefined) {\n\t\tassertPlainData(rawInput.journal, \"journal\");\n\t\tassertOnlyKeys(rawInput.journal, JOURNAL_KEYS, \"journal\");\n\t\tconst sourceBytes = rawInput.journal.bytes;\n\t\tif (!(sourceBytes instanceof Uint8Array)) {\n\t\t\tthrow new TypeError(\"journal.bytes must be a Uint8Array\");\n\t\t}\n\t\t// Defensive copy: isolate the plan from caller buffer aliasing and from\n\t\t// hashFn closures that mutate the caller's bytes. The plan inspects and\n\t\t// re-inspects this stable private copy.\n\t\tconst bytes = new Uint8Array(sourceBytes);\n\t\tif (typeof rawInput.journal.hashFn !== \"function\") {\n\t\t\tthrow new TypeError(\"journal.hashFn must be a function\");\n\t\t}\n\t\tlet terminalRecord: RunJournalTerminalRecord | undefined;\n\t\tif (Object.hasOwn(rawInput.journal, \"terminalRecord\") && rawInput.journal.terminalRecord !== undefined) {\n\t\t\tassertPlainData(rawInput.journal.terminalRecord, \"journal.terminalRecord\");\n\t\t\tassertPlainDataTree(rawInput.journal.terminalRecord, \"journal.terminalRecord\");\n\t\t\tterminalRecord = rawInput.journal.terminalRecord as unknown as RunJournalTerminalRecord;\n\t\t}\n\t\tjournal = Object.freeze({\n\t\t\tbytes,\n\t\t\thashFn: rawInput.journal.hashFn as RunJournalHashFn,\n\t\t\t...(terminalRecord === undefined ? {} : { terminalRecord }),\n\t\t});\n\t}\n\n\tlet pathsSession: Omit<SessionPathAccessInput, \"intent\"> | null = null;\n\tlet pathsJournal: Omit<SessionPathAccessInput, \"intent\"> | null = null;\n\tif (Object.hasOwn(rawInput, \"paths\") && rawInput.paths !== undefined) {\n\t\tassertPlainData(rawInput.paths, \"paths\");\n\t\tassertOnlyKeys(rawInput.paths, PATHS_KEYS, \"paths\");\n\t\tif (Object.hasOwn(rawInput.paths, \"session\") && rawInput.paths.session !== undefined) {\n\t\t\tpathsSession = validatePathSubject(rawInput.paths.session, \"paths.session\");\n\t\t}\n\t\tif (Object.hasOwn(rawInput.paths, \"journal\") && rawInput.paths.journal !== undefined) {\n\t\t\tpathsJournal = validatePathSubject(rawInput.paths.journal, \"paths.journal\");\n\t\t}\n\t}\n\n\tlet compaction: DecideCompactionCommitInput | null = null;\n\tif (Object.hasOwn(rawInput, \"compaction\") && rawInput.compaction !== undefined) {\n\t\tassertPlainData(rawInput.compaction, \"compaction\");\n\t\tassertOnlyKeys(rawInput.compaction, COMPACTION_KEYS, \"compaction\");\n\t\tassertPlainDataTree(rawInput.compaction, \"compaction\");\n\t\tcompaction = rawInput.compaction as unknown as DecideCompactionCommitInput;\n\t}\n\n\tconst normalizedChecks =\n\t\tObject.hasOwn(rawInput, \"normalizedChecks\") && rawInput.normalizedChecks !== undefined\n\t\t\t? validateNormalizedChecks(rawInput.normalizedChecks)\n\t\t\t: Object.freeze([] as readonly SessionDoctorNormalizedCheck[]);\n\n\treturn {\n\t\tmode: rawInput.mode as SessionDoctorMode,\n\t\tsessionId: rawInput.sessionId,\n\t\trepairId: rawInput.repairId,\n\t\ttimestamp: rawInput.timestamp,\n\t\treport: rawInput.report as unknown as SessionIntegrityReport,\n\t\tjournal,\n\t\tpaths: Object.freeze({ session: pathsSession, journal: pathsJournal }),\n\t\tcompaction,\n\t\tnormalizedChecks,\n\t};\n}\n\n// -------------------------------------------------------------------------------------------------\n// Pure helpers.\n// -------------------------------------------------------------------------------------------------\n\nfunction intentForMode(mode: SessionDoctorMode): SessionPathIntent {\n\tif (mode === \"inspect\") return \"inspect_content\";\n\tif (mode === \"repair_dry_run\") return \"repair_dry_run\";\n\treturn \"repair\";\n}\n\nfunction finding(\n\tartifact: SessionDoctorArtifact,\n\treason: SessionDoctorFindingReason,\n\tseverity: SessionDoctorFindingSeverity,\n\tcode?: string,\n\tids?: readonly string[],\n): SessionDoctorFinding {\n\tconst result: {\n\t\tartifact: SessionDoctorArtifact;\n\t\treason: SessionDoctorFindingReason;\n\t\tseverity: SessionDoctorFindingSeverity;\n\t\tcode?: string;\n\t\tids?: readonly string[];\n\t} = { artifact, reason, severity };\n\tif (code !== undefined && code.length > 0) {\n\t\tif (code.length > MAX_IDENTIFIER_LENGTH) {\n\t\t\tthrow new TypeError(\"finding code exceeds the bounded length\");\n\t\t}\n\t\tresult.code = code;\n\t}\n\tif (ids !== undefined && ids.length > 0) {\n\t\tif (ids.length > MAX_FINDING_IDS) {\n\t\t\tthrow new TypeError(`finding ids exceed the bounded limit of ${MAX_FINDING_IDS}; failing closed`);\n\t\t}\n\t\tfor (const id of ids) assertIdentifier(id, \"finding id\");\n\t\tresult.ids = Object.freeze([...ids]);\n\t}\n\treturn Object.freeze(result) as SessionDoctorFinding;\n}\n\nfunction deepFreeze<T>(value: T): T {\n\tif (typeof value !== \"object\" || value === null || Object.isFrozen(value)) return value;\n\tif (Array.isArray(value)) {\n\t\tfor (const item of value) deepFreeze(item);\n\t} else {\n\t\tfor (const child of Object.values(value as Record<string, unknown>)) deepFreeze(child);\n\t}\n\treturn Object.freeze(value);\n}\n\nfunction deepCopy<T>(value: T): T {\n\tif (typeof value !== \"object\" || value === null) return value;\n\tif (Array.isArray(value)) return deepFreeze(value.map(deepCopy)) as T;\n\tconst out: Record<string, unknown> = {};\n\tfor (const key of Object.keys(value as Record<string, unknown>)) {\n\t\tout[key] = deepCopy((value as Record<string, unknown>)[key]);\n\t}\n\treturn deepFreeze(out) as T;\n}\n\nfunction appendRecoveryRecord(\n\tbytes: Uint8Array,\n\tcompletePrefix: RunJournalCompletePrefix,\n\trecord: RunJournalTerminalRecord,\n): Uint8Array {\n\tconst suffix = TEXT_ENCODER.encode(`${serializeRunJournalLine(record)}\\n`);\n\tconst out = new Uint8Array(completePrefix.byteCount + suffix.byteLength);\n\tout.set(bytes.subarray(0, completePrefix.byteCount));\n\tout.set(suffix, completePrefix.byteCount);\n\treturn out;\n}\n\nfunction dedupPreserveOrder(values: readonly string[]): string[] {\n\tconst seen = new Set<string>();\n\tconst out: string[] = [];\n\tfor (const value of values) {\n\t\tif (!seen.has(value)) {\n\t\t\tseen.add(value);\n\t\t\tout.push(value);\n\t\t}\n\t}\n\treturn out;\n}\n\n/** The remove_stale_lock variant of {@link SessionDoctorActionSpec}. */\ntype StaleLockActionSpec = Extract<SessionDoctorActionSpec, { kind: \"remove_stale_lock\" }>;\n\nconst STALE_LOCK_ARTIFACT_RANK: Record<SessionDoctorActionArtifact, number> = {\n\tsession: 0,\n\tjournal: 1,\n};\n\n/**\n * Canonical physical target key for stale-lock dedup. Win32 compares\n * case-insensitively (lower-cased); POSIX is exact. The platform is intentionally\n * not part of the key, so a target described under conflicting platforms is\n * surfaced as a contract violation rather than silently duplicated.\n */\nfunction canonicalStaleLockTargetKey(\n\tplatform: SessionPathPlatform,\n\ttargetLexical: string,\n\ttargetRealpath: string,\n): string {\n\tconst lexical = platform === \"win32\" ? targetLexical.toLowerCase() : targetLexical;\n\tconst realpath = platform === \"win32\" ? targetRealpath.toLowerCase() : targetRealpath;\n\treturn JSON.stringify([lexical, realpath]);\n}\n\n/**\n * Deduplicate stale-lock actions from the session and journal paths by their\n * canonical physical target, merging the contributing artifacts deterministically\n * (sorted by artifact rank). A target described under conflicting platforms or\n * conflicting holder pids is a contract violation: the plan is refused and no\n * actions are reported for that target.\n */\nfunction dedupStaleLockActions(specs: readonly StaleLockActionSpec[], acc: Accumulators): StaleLockActionSpec[] {\n\tif (specs.length <= 1) return [...specs];\n\tconst groups = new Map<string, StaleLockActionSpec[]>();\n\tfor (const spec of specs) {\n\t\tconst key = canonicalStaleLockTargetKey(spec.platform, spec.targetLexical, spec.targetRealpath);\n\t\tconst group = groups.get(key);\n\t\tif (group === undefined) {\n\t\t\tgroups.set(key, [spec]);\n\t\t} else {\n\t\t\tgroup.push(spec);\n\t\t}\n\t}\n\tconst out: StaleLockActionSpec[] = [];\n\tfor (const group of groups.values()) {\n\t\tif (group.length === 1) {\n\t\t\tout.push(group[0]);\n\t\t\tcontinue;\n\t\t}\n\t\tconst platforms = new Set(group.map((spec) => spec.platform));\n\t\tconst holders = new Set(group.map((spec) => spec.holderPid));\n\t\tif (platforms.size > 1 || holders.size > 1) {\n\t\t\tacc.findings.push(finding(\"path\", \"contract_violation\", \"blocked\", \"stale_lock_target_conflict\"));\n\t\t\tacc.refused = true;\n\t\t\tcontinue;\n\t\t}\n\t\tconst mergedArtifacts = Array.from(new Set(group.flatMap((spec) => spec.artifacts))).sort(\n\t\t\t(a, b) => STALE_LOCK_ARTIFACT_RANK[a] - STALE_LOCK_ARTIFACT_RANK[b],\n\t\t);\n\t\tout.push({ ...group[0], artifacts: Object.freeze(mergedArtifacts) });\n\t}\n\treturn out;\n}\n\n// Finding sort: stable total ordering by artifact, reason, code, then ids.\nconst ARTIFACT_RANK: Record<SessionDoctorArtifact, number> = {\n\tsession: 0,\n\tjournal: 1,\n\tpath: 2,\n\tcompaction: 3,\n\tnormalized: 4,\n};\n\nfunction findingSortKey(value: SessionDoctorFinding): string {\n\treturn `${ARTIFACT_RANK[value.artifact]}|${value.reason}|${value.code ?? \"\"}|${(value.ids ?? []).join(\",\")}`;\n}\n\nfunction sortFindings(findings: SessionDoctorFinding[]): SessionDoctorFinding[] {\n\treturn [...findings].sort((a, b) => {\n\t\tconst left = findingSortKey(a);\n\t\tconst right = findingSortKey(b);\n\t\treturn left < right ? -1 : left > right ? 1 : 0;\n\t});\n}\n\n// -------------------------------------------------------------------------------------------------\n// Artifact derivations. Each mutates the shared accumulators and the refused flag.\n// -------------------------------------------------------------------------------------------------\n\ninterface Accumulators {\n\treadonly findings: SessionDoctorFinding[];\n\treadonly sessionSpecs: SessionDoctorActionSpec[];\n\treadonly journalSpecs: SessionDoctorActionSpec[];\n\treadonly pathSpecs: StaleLockActionSpec[];\n\treadonly compactionSpecs: SessionDoctorActionSpec[];\n\trefused: boolean;\n}\n\nconst REPAIRABLE_SESSION_BLOCKER_REASONS = new Set([\n\t\"integrity_finding\",\n\t\"inspection_incomplete\",\n\t\"ambiguous_transcript\",\n\t\"inconsistent_report\",\n]);\n\nfunction deriveSession(input: ValidatedInput, acc: Accumulators): void {\n\tconst report = input.report;\n\n\t// Cross-bind the session header identity to the doctored session id.\n\tconst header = report.header;\n\tif (header !== null && isRecord(header) && typeof header.id === \"string\" && header.id !== input.sessionId) {\n\t\tacc.findings.push(finding(\"session\", \"contract_violation\", \"blocked\", \"session_identity_mismatch\"));\n\t\tacc.refused = true;\n\t}\n\n\t// Ignore report.ok: createSessionRepairPlan rederives consistency and the\n\t// repairable action set with a fixed doctor_repair reason.\n\tconst sessionPlan = createSessionRepairPlan(report, {\n\t\trepairId: input.repairId,\n\t\treason: \"doctor_repair\",\n\t\ttimestamp: input.timestamp,\n\t});\n\n\tif (sessionPlan.status === \"repairable\") {\n\t\tlet quarantined = false;\n\t\tconst missingIds: string[] = [];\n\t\tconst appendSpecs: {\n\t\t\treadonly kind: \"append_synthetic_tool_result\";\n\t\t\treadonly artifact: \"session\";\n\t\t\treadonly toolCallId: string;\n\t\t\treadonly toolName: string;\n\t\t\treadonly repairSequence: number;\n\t\t\treadonly message: Readonly<ToolResultMessage>;\n\t\t}[] = [];\n\t\tfor (const action of sessionPlan.actions) {\n\t\t\tif (action.kind === \"quarantine_trailing_fragment\") {\n\t\t\t\tquarantined = true;\n\t\t\t\tacc.sessionSpecs.push({\n\t\t\t\t\tkind: \"quarantine_session_trailing_fragment\",\n\t\t\t\t\tartifact: \"session\",\n\t\t\t\t\tretainPrefix: { ...action.retainPrefix },\n\t\t\t\t\tfragment: { ...action.fragment },\n\t\t\t\t});\n\t\t\t} else if (action.kind === \"append_synthetic_tool_result\") {\n\t\t\t\tmissingIds.push(action.toolCallId);\n\t\t\t\t// Prevalidate the synthetic message as plain data before deep-copying\n\t\t\t\t// it into the action, so a non-plain runtime payload fails closed.\n\t\t\t\tassertPlainDataTree(action.message, \"session synthetic tool result message\");\n\t\t\t\tappendSpecs.push({\n\t\t\t\t\tkind: \"append_synthetic_tool_result\",\n\t\t\t\t\tartifact: \"session\",\n\t\t\t\t\ttoolCallId: action.toolCallId,\n\t\t\t\t\ttoolName: action.toolName,\n\t\t\t\t\trepairSequence: action.sequence,\n\t\t\t\t\tmessage: deepCopy(action.message),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\t// Normalize session action order regardless of upstream: quarantine first,\n\t\t// then synthetic appends sorted by their upstream repair sequence.\n\t\tappendSpecs.sort((a, b) => a.repairSequence - b.repairSequence);\n\t\tfor (const spec of appendSpecs) acc.sessionSpecs.push(spec);\n\t\tif (quarantined) {\n\t\t\tacc.findings.push(finding(\"session\", \"session_trailing_fragment\", \"blocked\"));\n\t\t}\n\t\tif (missingIds.length > 0) {\n\t\t\tacc.findings.push(finding(\"session\", \"session_missing_tool_result\", \"blocked\", undefined, missingIds));\n\t\t}\n\t\treturn;\n\t}\n\n\tif (sessionPlan.status === \"blocked\") {\n\t\tfor (const blocker of sessionPlan.blockers) {\n\t\t\tif (!REPAIRABLE_SESSION_BLOCKER_REASONS.has(blocker.reason)) {\n\t\t\t\tacc.findings.push(finding(\"session\", \"contract_violation\", \"blocked\", \"unknown_blocker\"));\n\t\t\t\tacc.refused = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tswitch (blocker.reason) {\n\t\t\t\tcase \"inconsistent_report\":\n\t\t\t\t\tacc.findings.push(finding(\"session\", \"contract_violation\", \"blocked\", \"inconsistent_report\"));\n\t\t\t\t\tacc.refused = true;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"inspection_incomplete\":\n\t\t\t\t\tacc.findings.push(finding(\"session\", \"session_inspection_incomplete\", \"blocked\"));\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"ambiguous_transcript\":\n\t\t\t\t\tacc.findings.push(finding(\"session\", \"session_blocked\", \"blocked\", \"ambiguous_transcript\"));\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"integrity_finding\": {\n\t\t\t\t\tconst ids: string[] = [];\n\t\t\t\t\tif (blocker.entryId !== undefined) ids.push(blocker.entryId);\n\t\t\t\t\tif (blocker.toolCallId !== undefined) ids.push(blocker.toolCallId);\n\t\t\t\t\tacc.findings.push(\n\t\t\t\t\t\tfinding(\n\t\t\t\t\t\t\t\"session\",\n\t\t\t\t\t\t\t\"session_blocked\",\n\t\t\t\t\t\t\t\"blocked\",\n\t\t\t\t\t\t\tblocker.findingReason,\n\t\t\t\t\t\t\tids.length > 0 ? ids : undefined,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tacc.findings.push(finding(\"session\", \"contract_violation\", \"blocked\", \"unknown_blocker\"));\n\t\t\t\t\tacc.refused = true;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t// status \"not_needed\": nothing to observe for the session artifact.\n}\n\nfunction deriveJournal(input: ValidatedInput, acc: Accumulators): void {\n\tconst observation = input.journal;\n\tif (observation === null) return;\n\n\tconst report = inspectRunJournal(observation.bytes, observation.hashFn);\n\tconst records = report.records;\n\tconst findingCodes = report.findings.map((f) => f.code);\n\tconst codeSet = new Set(findingCodes);\n\tconst hasSessionMismatch = codeSet.has(\"session_mismatch\");\n\tconst allBound = records.length === 0 || records.every((record) => record.sessionId === input.sessionId);\n\n\t// Cross-bind every journal record session id to the doctored session id.\n\tif (!allBound || hasSessionMismatch) {\n\t\tacc.findings.push(finding(\"journal\", \"contract_violation\", \"blocked\", \"session_identity_mismatch\"));\n\t\tacc.refused = true;\n\t}\n\n\tconst trailing = codeSet.has(\"trailing_fragment\");\n\tconst unclosed = codeSet.has(\"run_unclosed\");\n\tconst hardCodes = dedupPreserveOrder(\n\t\tfindingCodes.filter(\n\t\t\t(code) => code !== \"trailing_fragment\" && code !== \"run_unclosed\" && code !== \"session_mismatch\",\n\t\t),\n\t);\n\tconst journalCanAct = hardCodes.length === 0 && allBound && !hasSessionMismatch;\n\n\tfor (const code of hardCodes) {\n\t\tacc.findings.push(finding(\"journal\", \"journal_blocked\", \"blocked\", code));\n\t}\n\n\t// Unclosed-run recovery: only when findings are a subset of {run_unclosed, trailing_fragment}.\n\tconst recoverableState = unclosed && journalCanAct;\n\tlet recoverySucceeded = false;\n\tif (unclosed) {\n\t\tconst runIds = report.openRunId !== null ? [report.openRunId] : undefined;\n\t\tacc.findings.push(finding(\"journal\", \"journal_unclosed\", \"blocked\", undefined, runIds));\n\t\tconst supplied = Object.hasOwn(observation, \"terminalRecord\") ? observation.terminalRecord : undefined;\n\t\tif (supplied !== undefined) {\n\t\t\tif (!recoverableState) {\n\t\t\t\t// Spurious: a recovery record was supplied for a journal that is not in the recoverable state.\n\t\t\t\tacc.findings.push(finding(\"journal\", \"contract_violation\", \"blocked\", \"spurious_terminal_record\"));\n\t\t\t\tacc.refused = true;\n\t\t\t} else {\n\t\t\t\tconst recheck = inspectRunJournal(\n\t\t\t\t\tappendRecoveryRecord(observation.bytes, report.completePrefix, supplied),\n\t\t\t\t\tobservation.hashFn,\n\t\t\t\t);\n\t\t\t\tconst last = recheck.records.length > 0 ? recheck.records[recheck.records.length - 1] : null;\n\t\t\t\tconst identityOk = last !== null && serializeRunJournalLine(last) === serializeRunJournalLine(supplied);\n\t\t\t\tif (\n\t\t\t\t\trecheck.ok &&\n\t\t\t\t\trecheck.openRunId === null &&\n\t\t\t\t\tlast !== null &&\n\t\t\t\t\tlast.event === \"run_recovered\" &&\n\t\t\t\t\tidentityOk\n\t\t\t\t) {\n\t\t\t\t\trecoverySucceeded = true;\n\t\t\t\t\tconst lastCompleteHash = records.length > 0 ? records[records.length - 1].hash : GENESIS_HASH;\n\t\t\t\t\tacc.journalSpecs.push({\n\t\t\t\t\t\tkind: \"recover_run\",\n\t\t\t\t\t\tartifact: \"journal\",\n\t\t\t\t\t\trunId: last.runId,\n\t\t\t\t\t\tterminalRecord: deepCopy(supplied),\n\t\t\t\t\t\tcompletePrefix: {\n\t\t\t\t\t\t\tbyteCount: report.completePrefix.byteCount,\n\t\t\t\t\t\t\tlineCount: report.completePrefix.lineCount,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tlastCompleteHash,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tacc.findings.push(finding(\"journal\", \"contract_violation\", \"blocked\", \"forged_terminal_record\"));\n\t\t\t\t\tacc.refused = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tconst supplied = Object.hasOwn(observation, \"terminalRecord\") ? observation.terminalRecord : undefined;\n\t\tif (supplied !== undefined) {\n\t\t\t// Spurious: a recovery record was supplied with no unclosed run to recover.\n\t\t\tacc.findings.push(finding(\"journal\", \"contract_violation\", \"blocked\", \"spurious_terminal_record\"));\n\t\t\tacc.refused = true;\n\t\t}\n\t}\n\n\t// Trailing fragment: quarantine the journal tail, anchored on the complete\n\t// prefix and the last complete hash (genesis if none). When recovery\n\t// succeeded the recover_run action carries completePrefix + lastCompleteHash,\n\t// explicitly anchoring a truncate-to-prefix-then-append that already discards\n\t// the trailing fragment, so it subsumes the quarantine action.\n\tif (trailing && journalCanAct && !recoverySucceeded) {\n\t\tacc.findings.push(finding(\"journal\", \"journal_trailing_fragment\", \"blocked\"));\n\t\tconst lastCompleteHash = records.length > 0 ? records[records.length - 1].hash : GENESIS_HASH;\n\t\tacc.journalSpecs.push({\n\t\t\tkind: \"quarantine_journal_trailing_fragment\",\n\t\t\tartifact: \"journal\",\n\t\t\tcompletePrefix: { byteCount: report.completePrefix.byteCount, lineCount: report.completePrefix.lineCount },\n\t\t\tlastCompleteHash,\n\t\t});\n\t}\n}\n\nfunction deriveCompaction(input: ValidatedInput, acc: Accumulators): void {\n\tconst observation = input.compaction;\n\tif (observation === null) return;\n\n\t// Cross-bind the transaction base/source session id before rederiving.\n\tconst tx = observation.transaction;\n\tconst baseSessionId =\n\t\tisRecord(tx) && isRecord(tx.baseRevision) && typeof tx.baseRevision.sessionId === \"string\"\n\t\t\t? (tx.baseRevision.sessionId as string)\n\t\t\t: null;\n\tconst sourceSessionId =\n\t\tisRecord(tx) && isRecord(tx.source) && typeof tx.source.sessionId === \"string\"\n\t\t\t? (tx.source.sessionId as string)\n\t\t\t: null;\n\tif (baseSessionId !== input.sessionId || sourceSessionId !== input.sessionId) {\n\t\tacc.findings.push(finding(\"compaction\", \"contract_violation\", \"blocked\", \"session_identity_mismatch\"));\n\t\tacc.refused = true;\n\t\treturn;\n\t}\n\n\tconst decision: CompactionCommitDecision = decideCompactionCommit(observation);\n\tswitch (decision.decision) {\n\t\tcase \"stale\":\n\t\t\tacc.findings.push(finding(\"compaction\", \"compaction_stale\", \"blocked\"));\n\t\t\tacc.compactionSpecs.push({\n\t\t\t\tkind: \"abandon_stale_compaction\",\n\t\t\t\tartifact: \"session\",\n\t\t\t\ttransactionId: decision.transactionId,\n\t\t\t\tbaseRevision: deepCopy(tx.baseRevision),\n\t\t\t\tsourceSha256: tx.source.sourceSha256,\n\t\t\t\tstaleReason: decision.reason,\n\t\t\t});\n\t\t\tbreak;\n\t\tcase \"defer\":\n\t\t\tacc.findings.push(finding(\"compaction\", \"compaction_deferred\", \"blocked\", decision.barrierReason));\n\t\t\tbreak;\n\t\tcase \"fail_closed\":\n\t\t\tif (decision.reason === \"barrier_fail_closed\") {\n\t\t\t\tacc.findings.push(finding(\"compaction\", \"compaction_failed\", \"blocked\", decision.barrierReason));\n\t\t\t} else {\n\t\t\t\tacc.findings.push(finding(\"compaction\", \"contract_violation\", \"blocked\", decision.reason));\n\t\t\t\tacc.refused = true;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase \"commit\":\n\t\t\tacc.findings.push(finding(\"compaction\", \"compaction_committed\", \"advisory\"));\n\t\t\tbreak;\n\t\tcase \"duplicate\":\n\t\t\tacc.findings.push(finding(\"compaction\", \"compaction_duplicate\", \"advisory\"));\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tacc.findings.push(finding(\"compaction\", \"contract_violation\", \"blocked\", \"unknown_decision\"));\n\t\t\tacc.refused = true;\n\t\t\tbreak;\n\t}\n}\n\ninterface StaleLockTarget {\n\treadonly platform: SessionPathPlatform;\n\treadonly targetLexical: string;\n\treadonly targetRealpath: string;\n\treadonly holderPid: string | null;\n}\n\ninterface PathAuthorization {\n\treadonly decision: SessionPathDecision | null;\n\treadonly authorized: boolean;\n\treadonly staleLock: StaleLockTarget | null;\n}\n\nfunction evaluatePath(\n\tsubject: Omit<SessionPathAccessInput, \"intent\"> | null,\n\tintent: SessionPathIntent,\n): PathAuthorization {\n\tif (subject === null) {\n\t\treturn { decision: null, authorized: false, staleLock: null };\n\t}\n\tconst decision = decideSessionPathAccess({ ...subject, intent });\n\tif (decision.status === \"authorized\") {\n\t\tconst stale = decision.plannedActions.find((action) => action.kind === \"remove_stale_lock\");\n\t\tif (stale !== undefined && stale.kind === \"remove_stale_lock\") {\n\t\t\treturn {\n\t\t\t\tdecision,\n\t\t\t\tauthorized: true,\n\t\t\t\tstaleLock: {\n\t\t\t\t\tplatform: decision.platform,\n\t\t\t\t\ttargetLexical: decision.targetLexical,\n\t\t\t\t\ttargetRealpath: decision.targetRealpath,\n\t\t\t\t\tholderPid: stale.holderPid,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn { decision, authorized: true, staleLock: null };\n\t}\n\treturn { decision, authorized: false, staleLock: null };\n}\n\nfunction derivePaths(\n\tinput: ValidatedInput,\n\tacc: Accumulators,\n\tsessionPathNeeded: boolean,\n\tjournalPathNeeded: boolean,\n): void {\n\tconst intent = intentForMode(input.mode);\n\tconst requiresAuthorized = input.mode === \"repair\" || input.mode === \"repair_dry_run\";\n\n\tconst sessionAuth = evaluatePath(input.paths.session, intent);\n\tauthorizeArtifact(acc, sessionAuth, sessionPathNeeded, \"session\", \"session_path_unauthorized\", requiresAuthorized);\n\tconst journalAuth = evaluatePath(input.paths.journal, intent);\n\tauthorizeArtifact(acc, journalAuth, journalPathNeeded, \"journal\", \"journal_path_unauthorized\", requiresAuthorized);\n}\n\nfunction authorizeArtifact(\n\tacc: Accumulators,\n\tauth: PathAuthorization,\n\tneeded: boolean,\n\tartifact: SessionDoctorActionArtifact,\n\treason: SessionDoctorFindingReason,\n\trequiresAuthorized: boolean,\n): void {\n\tif (auth.authorized) {\n\t\t// Eligible stale-lock cleanup from this path decision only.\n\t\tif (auth.staleLock !== null) {\n\t\t\tacc.pathSpecs.push({\n\t\t\t\tkind: \"remove_stale_lock\",\n\t\t\t\tartifact,\n\t\t\t\tplatform: auth.staleLock.platform,\n\t\t\t\ttargetLexical: auth.staleLock.targetLexical,\n\t\t\t\ttargetRealpath: auth.staleLock.targetRealpath,\n\t\t\t\tholderPid: auth.staleLock.holderPid,\n\t\t\t\tartifacts: [artifact],\n\t\t\t});\n\t\t}\n\t\treturn;\n\t}\n\t// Not authorized (rejected, blocked, or not provided).\n\tif (needed && requiresAuthorized) {\n\t\tacc.findings.push(finding(\"path\", reason, \"blocked\", auth.decision?.reason ?? \"missing\"));\n\t\tacc.refused = true;\n\t} else if (auth.decision !== null) {\n\t\t// Provided but rejected/blocked: always a diagnostic issue.\n\t\tacc.findings.push(finding(\"path\", reason, \"blocked\", auth.decision.reason));\n\t}\n\t// Not provided and not needed (or inspect mode): nothing to report.\n}\n\nfunction deriveNormalizedChecks(input: ValidatedInput, acc: Accumulators): void {\n\tfor (const check of input.normalizedChecks) {\n\t\tif (check.status !== \"ok\") {\n\t\t\tacc.findings.push(\n\t\t\t\tfinding(\"normalized\", \"normalized_check_unhealthy\", \"blocked\", `${check.artifact}:${check.status}`),\n\t\t\t);\n\t\t}\n\t}\n}\n\n// -------------------------------------------------------------------------------------------------\n// Plan assembly.\n// -------------------------------------------------------------------------------------------------\n\nexport function planSessionDoctor(rawInput: unknown): SessionDoctorPlan {\n\tconst input = validateInput(rawInput);\n\tconst acc: Accumulators = {\n\t\tfindings: [],\n\t\tsessionSpecs: [],\n\t\tjournalSpecs: [],\n\t\tpathSpecs: [],\n\t\tcompactionSpecs: [],\n\t\trefused: false,\n\t};\n\n\tderiveSession(input, acc);\n\tderiveJournal(input, acc);\n\tderiveCompaction(input, acc);\n\n\t// Paths gate prospective repair actions. Session actions and compaction\n\t// abandon require an authorized session path; journal actions require an\n\t// authorized journal path. Inspect mode never performs writes, so paths are\n\t// only gating in dry/repair.\n\tconst writesPlanned = input.mode !== \"inspect\";\n\tconst sessionPathNeeded = writesPlanned && (acc.sessionSpecs.length > 0 || acc.compactionSpecs.length > 0);\n\tconst journalPathNeeded = writesPlanned && acc.journalSpecs.length > 0;\n\tderivePaths(input, acc, sessionPathNeeded, journalPathNeeded);\n\n\tderiveNormalizedChecks(input, acc);\n\n\t// Deduplicate stale-lock actions (session + journal paths may target the same\n\t// physical file) before sequence assignment so reported actions stay contiguous.\n\tconst dedupedPathSpecs = dedupStaleLockActions(acc.pathSpecs, acc);\n\tconst orderedSpecs: SessionDoctorActionSpec[] = [\n\t\t...acc.sessionSpecs,\n\t\t...acc.journalSpecs,\n\t\t...dedupedPathSpecs,\n\t\t...acc.compactionSpecs,\n\t];\n\tconst eligibleActions: SessionDoctorAction[] = orderedSpecs.map((spec, index) =>\n\t\tdeepFreeze({ ...spec, sequence: index }),\n\t);\n\tconst sortedFindings = Object.freeze(sortFindings(acc.findings).map((f) => deepCopy(f)));\n\n\tconst refused = acc.refused;\n\tconst reportedActions = refused || input.mode === \"inspect\" ? ([] as SessionDoctorAction[]) : eligibleActions;\n\tconst scheduledWrites = input.mode === \"repair\" && !refused ? eligibleActions.length : 0;\n\tconst requiresReinspection = scheduledWrites > 0;\n\n\t// \"healthy\" permits advisory findings (e.g. compaction_committed /\n\t// compaction_duplicate); only a blocked finding or an eligible action\n\t// downgrades the status to \"issues\".\n\tconst hasBlockingFinding = sortedFindings.some((f) => f.severity === \"blocked\");\n\tconst clean = !hasBlockingFinding && eligibleActions.length === 0;\n\tconst status: SessionDoctorStatus = refused ? \"refused\" : clean ? \"healthy\" : \"issues\";\n\tconst exitCode: SessionDoctorExitCode = refused ? 2 : clean ? 0 : 1;\n\n\treturn deepFreeze({\n\t\tschemaVersion: SESSION_DOCTOR_PLAN_SCHEMA_VERSION,\n\t\tmode: input.mode,\n\t\tsessionId: input.sessionId,\n\t\trepairId: input.repairId,\n\t\tstatus,\n\t\texitCode,\n\t\trepairable: !refused && eligibleActions.length > 0,\n\t\trequiresReinspection,\n\t\tscheduledWrites,\n\t\tfindings: sortedFindings,\n\t\tactions: Object.freeze([...reportedActions]),\n\t}) as SessionDoctorPlan;\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import type { FileEntry, SessionEntry, SessionHeader } from "./session-manager.ts";
2
+ /** Recompute persisted compaction provenance instead of trusting its envelope. */
3
+ export declare function validatePersistedCompactionEnvelopes(path: string, entries: readonly FileEntry[], sessionId: string): void;
4
+ /** Copy one branch while rebinding nested compaction provenance in source order. */
5
+ export declare function rebindBranchedCompactionEnvelopes(header: SessionHeader, entries: readonly SessionEntry[]): SessionEntry[];
6
+ //# sourceMappingURL=session-file-compaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-file-compaction.d.ts","sourceRoot":"","sources":["../../src/core/session-file-compaction.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAmB,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA4EpG,kFAAkF;AAClF,wBAAgB,oCAAoC,CACnD,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,SAAS,SAAS,EAAE,EAC7B,SAAS,EAAE,MAAM,GACf,IAAI,CAyCN;AAED,oFAAoF;AACpF,wBAAgB,iCAAiC,CAChD,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,SAAS,YAAY,EAAE,GAC9B,YAAY,EAAE,CAkDhB","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport {\n\ttype CompactionEnvelope,\n\tcreateSessionRevisionToken,\n\tvalidateCompactionEnvelope,\n} from \"./compaction/transaction.ts\";\nimport type { CompactionEntry, FileEntry, SessionEntry, SessionHeader } from \"./session-manager.ts\";\n\nfunction envelopeFromEntry(entry: CompactionEntry): CompactionEnvelope | null {\n\tif (typeof entry.details !== \"object\" || entry.details === null || Array.isArray(entry.details)) return null;\n\tif (!Object.hasOwn(entry.details, \"compactionEnvelope\")) return null;\n\treturn validateCompactionEnvelope(Reflect.get(entry.details, \"compactionEnvelope\"));\n}\n\nfunction branchFromPrefix(prefix: readonly FileEntry[], leafId: string): SessionEntry[] {\n\tconst byId = new Map(\n\t\tprefix.filter((entry): entry is SessionEntry => entry.type !== \"session\").map((entry) => [entry.id, entry]),\n\t);\n\tconst branch: SessionEntry[] = [];\n\tconst seen = new Set<string>();\n\tlet current = byId.get(leafId);\n\twhile (current) {\n\t\tif (seen.has(current.id)) throw new Error(`Compaction source at ${leafId} contains a cycle`);\n\t\tseen.add(current.id);\n\t\tbranch.unshift(current);\n\t\tcurrent = current.parentId === null ? undefined : byId.get(current.parentId);\n\t}\n\tif (branch.at(-1)?.id !== leafId)\n\t\tthrow new Error(`Compaction source leaf ${leafId} is outside the persisted prefix`);\n\treturn branch;\n}\n\nfunction sourceSha256(entries: readonly SessionEntry[]): string {\n\treturn createHash(\"sha256\")\n\t\t.update(entries.map((entry) => JSON.stringify(entry)).join(\"\\n\"), \"utf8\")\n\t\t.digest(\"hex\");\n}\n\nfunction serializedPrefix(prefix: readonly FileEntry[]): string {\n\treturn `${prefix.map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`;\n}\n\nfunction prefixRevision(header: SessionHeader, prefix: readonly FileEntry[], leafId: string) {\n\tconst bytes = serializedPrefix(prefix);\n\tconst last = prefix.at(-1);\n\treturn createSessionRevisionToken({\n\t\tsessionId: header.id,\n\t\tcompleteBytes: Buffer.byteLength(bytes),\n\t\trecordCount: prefix.length,\n\t\tleafId,\n\t\tlastEntryId: last?.type === \"session\" ? null : (last?.id ?? null),\n\t\tcompletePrefixSha256: createHash(\"sha256\").update(bytes, \"utf8\").digest(\"hex\"),\n\t});\n}\n\nfunction sameOrderedIds(left: readonly string[], right: readonly SessionEntry[]): boolean {\n\treturn left.length === right.length && left.every((id, index) => id === right[index]?.id);\n}\n\nfunction assertSourceMatches(\n\tentry: CompactionEntry,\n\tenvelope: CompactionEnvelope,\n\tsource: readonly SessionEntry[],\n): void {\n\tif (\n\t\tenvelope.source.sessionId === \"\" ||\n\t\t!sameOrderedIds(envelope.source.entryIds, source) ||\n\t\tenvelope.source.sourceSha256 !== sourceSha256(source) ||\n\t\tenvelope.source.activeLeafId !== entry.parentId\n\t) {\n\t\tthrow new Error(`Invalid compaction envelope source in entry ${entry.id}. Run the session doctor.`);\n\t}\n}\n\nfunction persistedRecordStarts(bytes: Uint8Array): number[] {\n\tconst starts = [0];\n\tfor (let index = 0; index < bytes.byteLength; index += 1) {\n\t\tif (bytes[index] === 0x0a && index + 1 < bytes.byteLength) starts.push(index + 1);\n\t}\n\treturn starts;\n}\n\n/** Recompute persisted compaction provenance instead of trusting its envelope. */\nexport function validatePersistedCompactionEnvelopes(\n\tpath: string,\n\tentries: readonly FileEntry[],\n\tsessionId: string,\n): void {\n\tconst header = entries[0];\n\tif (!header || header.type !== \"session\" || header.id !== sessionId) throw new Error(\"Invalid session header\");\n\tconst bytes = readFileSync(path);\n\tconst starts = persistedRecordStarts(bytes);\n\tfor (let index = 0; index < entries.length; index += 1) {\n\t\tconst entry = entries[index];\n\t\tif (!entry || entry.type !== \"compaction\") continue;\n\t\tconst envelope = envelopeFromEntry(entry);\n\t\tif (!envelope) continue;\n\t\tif (entry.parentId === null) throw new Error(`Compaction entry ${entry.id} has no source leaf`);\n\t\tconst prefix = entries.slice(0, index);\n\t\tconst source = branchFromPrefix(prefix, entry.parentId);\n\t\tconst start = starts[index];\n\t\tif (start === undefined) throw new Error(`Compaction entry ${entry.id} has no persisted prefix`);\n\t\tconst last = prefix.at(-1);\n\t\tconst expectedRevision = createSessionRevisionToken({\n\t\t\tsessionId,\n\t\t\tcompleteBytes: start,\n\t\t\trecordCount: index,\n\t\t\tleafId: entry.parentId,\n\t\t\tlastEntryId: last?.type === \"session\" ? null : (last?.id ?? null),\n\t\t\tcompletePrefixSha256: createHash(\"sha256\").update(bytes.subarray(0, start)).digest(\"hex\"),\n\t\t});\n\t\tconst base = envelope.baseRevision;\n\t\tconst summarySha256 = createHash(\"sha256\").update(entry.summary, \"utf8\").digest(\"hex\");\n\t\tif (\n\t\t\tbase.sessionId !== expectedRevision.sessionId ||\n\t\t\tbase.completeBytes !== expectedRevision.completeBytes ||\n\t\t\tbase.recordCount !== expectedRevision.recordCount ||\n\t\t\tbase.leafId !== expectedRevision.leafId ||\n\t\t\tbase.lastEntryId !== expectedRevision.lastEntryId ||\n\t\t\tbase.completePrefixSha256 !== expectedRevision.completePrefixSha256 ||\n\t\t\tenvelope.source.sessionId !== sessionId ||\n\t\t\tenvelope.summary !== entry.summary ||\n\t\t\tenvelope.summarySha256 !== summarySha256\n\t\t) {\n\t\t\tthrow new Error(`Invalid compaction envelope binding in entry ${entry.id}. Run the session doctor.`);\n\t\t}\n\t\tassertSourceMatches(entry, envelope, source);\n\t}\n}\n\n/** Copy one branch while rebinding nested compaction provenance in source order. */\nexport function rebindBranchedCompactionEnvelopes(\n\theader: SessionHeader,\n\tentries: readonly SessionEntry[],\n): SessionEntry[] {\n\tconst referencedLabels = new Set<string>();\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"compaction\") continue;\n\t\tfor (const id of envelopeFromEntry(entry)?.source.entryIds ?? []) referencedLabels.add(id);\n\t}\n\tconst originalPrefix: FileEntry[] = [];\n\tconst copiedPrefix: FileEntry[] = [header];\n\tconst copied: SessionEntry[] = [];\n\tfor (const entry of entries) {\n\t\tlet copy = entry;\n\t\tif (entry.type === \"compaction\") {\n\t\t\tconst details = entry.details;\n\t\t\tconst envelope = envelopeFromEntry(entry);\n\t\t\tif (envelope) {\n\t\t\t\tif (typeof details !== \"object\" || details === null || Array.isArray(details))\n\t\t\t\t\tthrow new Error(`Compaction entry ${entry.id} has invalid details`);\n\t\t\t\tif (entry.parentId === null) throw new Error(`Compaction entry ${entry.id} has no source leaf`);\n\t\t\t\tassertSourceMatches(entry, envelope, branchFromPrefix(originalPrefix, entry.parentId));\n\t\t\t\tconst source = branchFromPrefix(copiedPrefix, entry.parentId);\n\t\t\t\tconst first = source[0];\n\t\t\t\tconst last = source.at(-1);\n\t\t\t\tif (!first || !last) throw new Error(`Compaction entry ${entry.id} has no source entries`);\n\t\t\t\tcopy = {\n\t\t\t\t\t...entry,\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\t...details,\n\t\t\t\t\t\tcompactionEnvelope: validateCompactionEnvelope({\n\t\t\t\t\t\t\t...envelope,\n\t\t\t\t\t\t\tbaseRevision: prefixRevision(header, copiedPrefix, entry.parentId),\n\t\t\t\t\t\t\tsource: {\n\t\t\t\t\t\t\t\t...envelope.source,\n\t\t\t\t\t\t\t\tsessionId: header.id,\n\t\t\t\t\t\t\t\tentryIds: source.map((candidate) => candidate.id),\n\t\t\t\t\t\t\t\tfirstEntryId: first.id,\n\t\t\t\t\t\t\t\tlastEntryId: last.id,\n\t\t\t\t\t\t\t\tsourceSha256: sourceSha256(source),\n\t\t\t\t\t\t\t\tactiveLeafId: entry.parentId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\toriginalPrefix.push(entry);\n\t\tif (entry.type === \"label\" && !referencedLabels.has(entry.id)) continue;\n\t\tcopied.push(copy);\n\t\tcopiedPrefix.push(copy);\n\t}\n\treturn copied;\n}\n"]}
@@ -0,0 +1,169 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFileSync } from "node:fs";
3
+ import { createSessionRevisionToken, validateCompactionEnvelope, } from "./compaction/transaction.js";
4
+ function envelopeFromEntry(entry) {
5
+ if (typeof entry.details !== "object" || entry.details === null || Array.isArray(entry.details))
6
+ return null;
7
+ if (!Object.hasOwn(entry.details, "compactionEnvelope"))
8
+ return null;
9
+ return validateCompactionEnvelope(Reflect.get(entry.details, "compactionEnvelope"));
10
+ }
11
+ function branchFromPrefix(prefix, leafId) {
12
+ const byId = new Map(prefix.filter((entry) => entry.type !== "session").map((entry) => [entry.id, entry]));
13
+ const branch = [];
14
+ const seen = new Set();
15
+ let current = byId.get(leafId);
16
+ while (current) {
17
+ if (seen.has(current.id))
18
+ throw new Error(`Compaction source at ${leafId} contains a cycle`);
19
+ seen.add(current.id);
20
+ branch.unshift(current);
21
+ current = current.parentId === null ? undefined : byId.get(current.parentId);
22
+ }
23
+ if (branch.at(-1)?.id !== leafId)
24
+ throw new Error(`Compaction source leaf ${leafId} is outside the persisted prefix`);
25
+ return branch;
26
+ }
27
+ function sourceSha256(entries) {
28
+ return createHash("sha256")
29
+ .update(entries.map((entry) => JSON.stringify(entry)).join("\n"), "utf8")
30
+ .digest("hex");
31
+ }
32
+ function serializedPrefix(prefix) {
33
+ return `${prefix.map((entry) => JSON.stringify(entry)).join("\n")}\n`;
34
+ }
35
+ function prefixRevision(header, prefix, leafId) {
36
+ const bytes = serializedPrefix(prefix);
37
+ const last = prefix.at(-1);
38
+ return createSessionRevisionToken({
39
+ sessionId: header.id,
40
+ completeBytes: Buffer.byteLength(bytes),
41
+ recordCount: prefix.length,
42
+ leafId,
43
+ lastEntryId: last?.type === "session" ? null : (last?.id ?? null),
44
+ completePrefixSha256: createHash("sha256").update(bytes, "utf8").digest("hex"),
45
+ });
46
+ }
47
+ function sameOrderedIds(left, right) {
48
+ return left.length === right.length && left.every((id, index) => id === right[index]?.id);
49
+ }
50
+ function assertSourceMatches(entry, envelope, source) {
51
+ if (envelope.source.sessionId === "" ||
52
+ !sameOrderedIds(envelope.source.entryIds, source) ||
53
+ envelope.source.sourceSha256 !== sourceSha256(source) ||
54
+ envelope.source.activeLeafId !== entry.parentId) {
55
+ throw new Error(`Invalid compaction envelope source in entry ${entry.id}. Run the session doctor.`);
56
+ }
57
+ }
58
+ function persistedRecordStarts(bytes) {
59
+ const starts = [0];
60
+ for (let index = 0; index < bytes.byteLength; index += 1) {
61
+ if (bytes[index] === 0x0a && index + 1 < bytes.byteLength)
62
+ starts.push(index + 1);
63
+ }
64
+ return starts;
65
+ }
66
+ /** Recompute persisted compaction provenance instead of trusting its envelope. */
67
+ export function validatePersistedCompactionEnvelopes(path, entries, sessionId) {
68
+ const header = entries[0];
69
+ if (!header || header.type !== "session" || header.id !== sessionId)
70
+ throw new Error("Invalid session header");
71
+ const bytes = readFileSync(path);
72
+ const starts = persistedRecordStarts(bytes);
73
+ for (let index = 0; index < entries.length; index += 1) {
74
+ const entry = entries[index];
75
+ if (!entry || entry.type !== "compaction")
76
+ continue;
77
+ const envelope = envelopeFromEntry(entry);
78
+ if (!envelope)
79
+ continue;
80
+ if (entry.parentId === null)
81
+ throw new Error(`Compaction entry ${entry.id} has no source leaf`);
82
+ const prefix = entries.slice(0, index);
83
+ const source = branchFromPrefix(prefix, entry.parentId);
84
+ const start = starts[index];
85
+ if (start === undefined)
86
+ throw new Error(`Compaction entry ${entry.id} has no persisted prefix`);
87
+ const last = prefix.at(-1);
88
+ const expectedRevision = createSessionRevisionToken({
89
+ sessionId,
90
+ completeBytes: start,
91
+ recordCount: index,
92
+ leafId: entry.parentId,
93
+ lastEntryId: last?.type === "session" ? null : (last?.id ?? null),
94
+ completePrefixSha256: createHash("sha256").update(bytes.subarray(0, start)).digest("hex"),
95
+ });
96
+ const base = envelope.baseRevision;
97
+ const summarySha256 = createHash("sha256").update(entry.summary, "utf8").digest("hex");
98
+ if (base.sessionId !== expectedRevision.sessionId ||
99
+ base.completeBytes !== expectedRevision.completeBytes ||
100
+ base.recordCount !== expectedRevision.recordCount ||
101
+ base.leafId !== expectedRevision.leafId ||
102
+ base.lastEntryId !== expectedRevision.lastEntryId ||
103
+ base.completePrefixSha256 !== expectedRevision.completePrefixSha256 ||
104
+ envelope.source.sessionId !== sessionId ||
105
+ envelope.summary !== entry.summary ||
106
+ envelope.summarySha256 !== summarySha256) {
107
+ throw new Error(`Invalid compaction envelope binding in entry ${entry.id}. Run the session doctor.`);
108
+ }
109
+ assertSourceMatches(entry, envelope, source);
110
+ }
111
+ }
112
+ /** Copy one branch while rebinding nested compaction provenance in source order. */
113
+ export function rebindBranchedCompactionEnvelopes(header, entries) {
114
+ const referencedLabels = new Set();
115
+ for (const entry of entries) {
116
+ if (entry.type !== "compaction")
117
+ continue;
118
+ for (const id of envelopeFromEntry(entry)?.source.entryIds ?? [])
119
+ referencedLabels.add(id);
120
+ }
121
+ const originalPrefix = [];
122
+ const copiedPrefix = [header];
123
+ const copied = [];
124
+ for (const entry of entries) {
125
+ let copy = entry;
126
+ if (entry.type === "compaction") {
127
+ const details = entry.details;
128
+ const envelope = envelopeFromEntry(entry);
129
+ if (envelope) {
130
+ if (typeof details !== "object" || details === null || Array.isArray(details))
131
+ throw new Error(`Compaction entry ${entry.id} has invalid details`);
132
+ if (entry.parentId === null)
133
+ throw new Error(`Compaction entry ${entry.id} has no source leaf`);
134
+ assertSourceMatches(entry, envelope, branchFromPrefix(originalPrefix, entry.parentId));
135
+ const source = branchFromPrefix(copiedPrefix, entry.parentId);
136
+ const first = source[0];
137
+ const last = source.at(-1);
138
+ if (!first || !last)
139
+ throw new Error(`Compaction entry ${entry.id} has no source entries`);
140
+ copy = {
141
+ ...entry,
142
+ details: {
143
+ ...details,
144
+ compactionEnvelope: validateCompactionEnvelope({
145
+ ...envelope,
146
+ baseRevision: prefixRevision(header, copiedPrefix, entry.parentId),
147
+ source: {
148
+ ...envelope.source,
149
+ sessionId: header.id,
150
+ entryIds: source.map((candidate) => candidate.id),
151
+ firstEntryId: first.id,
152
+ lastEntryId: last.id,
153
+ sourceSha256: sourceSha256(source),
154
+ activeLeafId: entry.parentId,
155
+ },
156
+ }),
157
+ },
158
+ };
159
+ }
160
+ }
161
+ originalPrefix.push(entry);
162
+ if (entry.type === "label" && !referencedLabels.has(entry.id))
163
+ continue;
164
+ copied.push(copy);
165
+ copiedPrefix.push(copy);
166
+ }
167
+ return copied;
168
+ }
169
+ //# sourceMappingURL=session-file-compaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-file-compaction.js","sourceRoot":"","sources":["../../src/core/session-file-compaction.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport {\n\ttype CompactionEnvelope,\n\tcreateSessionRevisionToken,\n\tvalidateCompactionEnvelope,\n} from \"./compaction/transaction.ts\";\nimport type { CompactionEntry, FileEntry, SessionEntry, SessionHeader } from \"./session-manager.ts\";\n\nfunction envelopeFromEntry(entry: CompactionEntry): CompactionEnvelope | null {\n\tif (typeof entry.details !== \"object\" || entry.details === null || Array.isArray(entry.details)) return null;\n\tif (!Object.hasOwn(entry.details, \"compactionEnvelope\")) return null;\n\treturn validateCompactionEnvelope(Reflect.get(entry.details, \"compactionEnvelope\"));\n}\n\nfunction branchFromPrefix(prefix: readonly FileEntry[], leafId: string): SessionEntry[] {\n\tconst byId = new Map(\n\t\tprefix.filter((entry): entry is SessionEntry => entry.type !== \"session\").map((entry) => [entry.id, entry]),\n\t);\n\tconst branch: SessionEntry[] = [];\n\tconst seen = new Set<string>();\n\tlet current = byId.get(leafId);\n\twhile (current) {\n\t\tif (seen.has(current.id)) throw new Error(`Compaction source at ${leafId} contains a cycle`);\n\t\tseen.add(current.id);\n\t\tbranch.unshift(current);\n\t\tcurrent = current.parentId === null ? undefined : byId.get(current.parentId);\n\t}\n\tif (branch.at(-1)?.id !== leafId)\n\t\tthrow new Error(`Compaction source leaf ${leafId} is outside the persisted prefix`);\n\treturn branch;\n}\n\nfunction sourceSha256(entries: readonly SessionEntry[]): string {\n\treturn createHash(\"sha256\")\n\t\t.update(entries.map((entry) => JSON.stringify(entry)).join(\"\\n\"), \"utf8\")\n\t\t.digest(\"hex\");\n}\n\nfunction serializedPrefix(prefix: readonly FileEntry[]): string {\n\treturn `${prefix.map((entry) => JSON.stringify(entry)).join(\"\\n\")}\\n`;\n}\n\nfunction prefixRevision(header: SessionHeader, prefix: readonly FileEntry[], leafId: string) {\n\tconst bytes = serializedPrefix(prefix);\n\tconst last = prefix.at(-1);\n\treturn createSessionRevisionToken({\n\t\tsessionId: header.id,\n\t\tcompleteBytes: Buffer.byteLength(bytes),\n\t\trecordCount: prefix.length,\n\t\tleafId,\n\t\tlastEntryId: last?.type === \"session\" ? null : (last?.id ?? null),\n\t\tcompletePrefixSha256: createHash(\"sha256\").update(bytes, \"utf8\").digest(\"hex\"),\n\t});\n}\n\nfunction sameOrderedIds(left: readonly string[], right: readonly SessionEntry[]): boolean {\n\treturn left.length === right.length && left.every((id, index) => id === right[index]?.id);\n}\n\nfunction assertSourceMatches(\n\tentry: CompactionEntry,\n\tenvelope: CompactionEnvelope,\n\tsource: readonly SessionEntry[],\n): void {\n\tif (\n\t\tenvelope.source.sessionId === \"\" ||\n\t\t!sameOrderedIds(envelope.source.entryIds, source) ||\n\t\tenvelope.source.sourceSha256 !== sourceSha256(source) ||\n\t\tenvelope.source.activeLeafId !== entry.parentId\n\t) {\n\t\tthrow new Error(`Invalid compaction envelope source in entry ${entry.id}. Run the session doctor.`);\n\t}\n}\n\nfunction persistedRecordStarts(bytes: Uint8Array): number[] {\n\tconst starts = [0];\n\tfor (let index = 0; index < bytes.byteLength; index += 1) {\n\t\tif (bytes[index] === 0x0a && index + 1 < bytes.byteLength) starts.push(index + 1);\n\t}\n\treturn starts;\n}\n\n/** Recompute persisted compaction provenance instead of trusting its envelope. */\nexport function validatePersistedCompactionEnvelopes(\n\tpath: string,\n\tentries: readonly FileEntry[],\n\tsessionId: string,\n): void {\n\tconst header = entries[0];\n\tif (!header || header.type !== \"session\" || header.id !== sessionId) throw new Error(\"Invalid session header\");\n\tconst bytes = readFileSync(path);\n\tconst starts = persistedRecordStarts(bytes);\n\tfor (let index = 0; index < entries.length; index += 1) {\n\t\tconst entry = entries[index];\n\t\tif (!entry || entry.type !== \"compaction\") continue;\n\t\tconst envelope = envelopeFromEntry(entry);\n\t\tif (!envelope) continue;\n\t\tif (entry.parentId === null) throw new Error(`Compaction entry ${entry.id} has no source leaf`);\n\t\tconst prefix = entries.slice(0, index);\n\t\tconst source = branchFromPrefix(prefix, entry.parentId);\n\t\tconst start = starts[index];\n\t\tif (start === undefined) throw new Error(`Compaction entry ${entry.id} has no persisted prefix`);\n\t\tconst last = prefix.at(-1);\n\t\tconst expectedRevision = createSessionRevisionToken({\n\t\t\tsessionId,\n\t\t\tcompleteBytes: start,\n\t\t\trecordCount: index,\n\t\t\tleafId: entry.parentId,\n\t\t\tlastEntryId: last?.type === \"session\" ? null : (last?.id ?? null),\n\t\t\tcompletePrefixSha256: createHash(\"sha256\").update(bytes.subarray(0, start)).digest(\"hex\"),\n\t\t});\n\t\tconst base = envelope.baseRevision;\n\t\tconst summarySha256 = createHash(\"sha256\").update(entry.summary, \"utf8\").digest(\"hex\");\n\t\tif (\n\t\t\tbase.sessionId !== expectedRevision.sessionId ||\n\t\t\tbase.completeBytes !== expectedRevision.completeBytes ||\n\t\t\tbase.recordCount !== expectedRevision.recordCount ||\n\t\t\tbase.leafId !== expectedRevision.leafId ||\n\t\t\tbase.lastEntryId !== expectedRevision.lastEntryId ||\n\t\t\tbase.completePrefixSha256 !== expectedRevision.completePrefixSha256 ||\n\t\t\tenvelope.source.sessionId !== sessionId ||\n\t\t\tenvelope.summary !== entry.summary ||\n\t\t\tenvelope.summarySha256 !== summarySha256\n\t\t) {\n\t\t\tthrow new Error(`Invalid compaction envelope binding in entry ${entry.id}. Run the session doctor.`);\n\t\t}\n\t\tassertSourceMatches(entry, envelope, source);\n\t}\n}\n\n/** Copy one branch while rebinding nested compaction provenance in source order. */\nexport function rebindBranchedCompactionEnvelopes(\n\theader: SessionHeader,\n\tentries: readonly SessionEntry[],\n): SessionEntry[] {\n\tconst referencedLabels = new Set<string>();\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"compaction\") continue;\n\t\tfor (const id of envelopeFromEntry(entry)?.source.entryIds ?? []) referencedLabels.add(id);\n\t}\n\tconst originalPrefix: FileEntry[] = [];\n\tconst copiedPrefix: FileEntry[] = [header];\n\tconst copied: SessionEntry[] = [];\n\tfor (const entry of entries) {\n\t\tlet copy = entry;\n\t\tif (entry.type === \"compaction\") {\n\t\t\tconst details = entry.details;\n\t\t\tconst envelope = envelopeFromEntry(entry);\n\t\t\tif (envelope) {\n\t\t\t\tif (typeof details !== \"object\" || details === null || Array.isArray(details))\n\t\t\t\t\tthrow new Error(`Compaction entry ${entry.id} has invalid details`);\n\t\t\t\tif (entry.parentId === null) throw new Error(`Compaction entry ${entry.id} has no source leaf`);\n\t\t\t\tassertSourceMatches(entry, envelope, branchFromPrefix(originalPrefix, entry.parentId));\n\t\t\t\tconst source = branchFromPrefix(copiedPrefix, entry.parentId);\n\t\t\t\tconst first = source[0];\n\t\t\t\tconst last = source.at(-1);\n\t\t\t\tif (!first || !last) throw new Error(`Compaction entry ${entry.id} has no source entries`);\n\t\t\t\tcopy = {\n\t\t\t\t\t...entry,\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\t...details,\n\t\t\t\t\t\tcompactionEnvelope: validateCompactionEnvelope({\n\t\t\t\t\t\t\t...envelope,\n\t\t\t\t\t\t\tbaseRevision: prefixRevision(header, copiedPrefix, entry.parentId),\n\t\t\t\t\t\t\tsource: {\n\t\t\t\t\t\t\t\t...envelope.source,\n\t\t\t\t\t\t\t\tsessionId: header.id,\n\t\t\t\t\t\t\t\tentryIds: source.map((candidate) => candidate.id),\n\t\t\t\t\t\t\t\tfirstEntryId: first.id,\n\t\t\t\t\t\t\t\tlastEntryId: last.id,\n\t\t\t\t\t\t\t\tsourceSha256: sourceSha256(source),\n\t\t\t\t\t\t\t\tactiveLeafId: entry.parentId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\toriginalPrefix.push(entry);\n\t\tif (entry.type === \"label\" && !referencedLabels.has(entry.id)) continue;\n\t\tcopied.push(copy);\n\t\tcopiedPrefix.push(copy);\n\t}\n\treturn copied;\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import type { DurableFileGeneration } from "./durable-file-identity.ts";
2
+ export interface SessionFileDurableMetadata {
3
+ readonly completeBytes: number;
4
+ readonly recordCount: number;
5
+ readonly completePrefixSha256: string;
6
+ readonly generation: DurableFileGeneration;
7
+ }
8
+ export declare function sessionFileHasCompleteTail(path: string): boolean;
9
+ export declare function readSessionFileDurableMetadata(path: string): SessionFileDurableMetadata;
10
+ //# sourceMappingURL=session-file-head.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-file-head.d.ts","sourceRoot":"","sources":["../../src/core/session-file-head.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAKxE,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;CAC3C;AAqBD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAchE;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,GAAG,0BAA0B,CAkCvF","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { type BigIntStats, closeSync, fstatSync, openSync, readSync, statSync } from \"node:fs\";\nimport type { DurableFileGeneration } from \"./durable-file-identity.ts\";\nimport { DurableFileReadRaceError } from \"./durable-file-io.ts\";\n\nconst READ_BUFFER_SIZE = 1024 * 1024;\n\nexport interface SessionFileDurableMetadata {\n\treadonly completeBytes: number;\n\treadonly recordCount: number;\n\treadonly completePrefixSha256: string;\n\treadonly generation: DurableFileGeneration;\n}\n\nfunction assertStable(path: string, before: BigIntStats, after: BigIntStats): void {\n\tconst current = statSync(path, { bigint: true });\n\tif (\n\t\tbefore.dev !== after.dev ||\n\t\tbefore.ino !== after.ino ||\n\t\tbefore.size !== after.size ||\n\t\tbefore.mtimeNs !== after.mtimeNs ||\n\t\tbefore.ctimeNs !== after.ctimeNs ||\n\t\tbefore.dev !== current.dev ||\n\t\tbefore.ino !== current.ino ||\n\t\tbefore.size !== current.size ||\n\t\tbefore.mtimeNs !== current.mtimeNs ||\n\t\tbefore.ctimeNs !== current.ctimeNs ||\n\t\tbefore.birthtimeNs !== current.birthtimeNs\n\t) {\n\t\tthrow new DurableFileReadRaceError();\n\t}\n}\n\nexport function sessionFileHasCompleteTail(path: string): boolean {\n\tconst fd = openSync(path, \"r\");\n\ttry {\n\t\tconst before = fstatSync(fd, { bigint: true });\n\t\tif (before.size === 0n) return true;\n\t\tif (before.size > BigInt(Number.MAX_SAFE_INTEGER)) throw new RangeError(\"Session file is too large\");\n\t\tconst tail = Buffer.allocUnsafe(1);\n\t\treadSync(fd, tail, 0, 1, Number(before.size - 1n));\n\t\tconst after = fstatSync(fd, { bigint: true });\n\t\tassertStable(path, before, after);\n\t\treturn tail[0] === 0x0a;\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n\nexport function readSessionFileDurableMetadata(path: string): SessionFileDurableMetadata {\n\tconst fd = openSync(path, \"r\");\n\ttry {\n\t\tconst before = fstatSync(fd, { bigint: true });\n\t\tif (before.size > BigInt(Number.MAX_SAFE_INTEGER)) throw new RangeError(\"Session file is too large\");\n\t\tconst digest = createHash(\"sha256\");\n\t\tconst buffer = Buffer.allocUnsafe(READ_BUFFER_SIZE);\n\t\tlet completeBytes = 0;\n\t\tlet recordCount = 0;\n\t\twhile (true) {\n\t\t\tconst bytesRead = readSync(fd, buffer, 0, buffer.byteLength, null);\n\t\t\tif (bytesRead === 0) break;\n\t\t\tdigest.update(buffer.subarray(0, bytesRead));\n\t\t\tcompleteBytes += bytesRead;\n\t\t\tfor (let index = 0; index < bytesRead; index += 1) {\n\t\t\t\tif (buffer[index] === 0x0a) recordCount += 1;\n\t\t\t}\n\t\t}\n\t\tconst after = fstatSync(fd, { bigint: true });\n\t\tassertStable(path, before, after);\n\t\treturn Object.freeze({\n\t\t\tcompleteBytes,\n\t\t\trecordCount,\n\t\t\tcompletePrefixSha256: digest.digest(\"hex\"),\n\t\t\tgeneration: Object.freeze({\n\t\t\t\tdev: before.dev.toString(),\n\t\t\t\tino: before.ino.toString(),\n\t\t\t\tbirthtimeNs: before.birthtimeNs.toString(),\n\t\t\t\tctimeNs: before.ctimeNs.toString(),\n\t\t\t}),\n\t\t});\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n"]}
@@ -0,0 +1,78 @@
1
+ import { createHash } from "node:crypto";
2
+ import { closeSync, fstatSync, openSync, readSync, statSync } from "node:fs";
3
+ import { DurableFileReadRaceError } from "./durable-file-io.js";
4
+ const READ_BUFFER_SIZE = 1024 * 1024;
5
+ function assertStable(path, before, after) {
6
+ const current = statSync(path, { bigint: true });
7
+ if (before.dev !== after.dev ||
8
+ before.ino !== after.ino ||
9
+ before.size !== after.size ||
10
+ before.mtimeNs !== after.mtimeNs ||
11
+ before.ctimeNs !== after.ctimeNs ||
12
+ before.dev !== current.dev ||
13
+ before.ino !== current.ino ||
14
+ before.size !== current.size ||
15
+ before.mtimeNs !== current.mtimeNs ||
16
+ before.ctimeNs !== current.ctimeNs ||
17
+ before.birthtimeNs !== current.birthtimeNs) {
18
+ throw new DurableFileReadRaceError();
19
+ }
20
+ }
21
+ export function sessionFileHasCompleteTail(path) {
22
+ const fd = openSync(path, "r");
23
+ try {
24
+ const before = fstatSync(fd, { bigint: true });
25
+ if (before.size === 0n)
26
+ return true;
27
+ if (before.size > BigInt(Number.MAX_SAFE_INTEGER))
28
+ throw new RangeError("Session file is too large");
29
+ const tail = Buffer.allocUnsafe(1);
30
+ readSync(fd, tail, 0, 1, Number(before.size - 1n));
31
+ const after = fstatSync(fd, { bigint: true });
32
+ assertStable(path, before, after);
33
+ return tail[0] === 0x0a;
34
+ }
35
+ finally {
36
+ closeSync(fd);
37
+ }
38
+ }
39
+ export function readSessionFileDurableMetadata(path) {
40
+ const fd = openSync(path, "r");
41
+ try {
42
+ const before = fstatSync(fd, { bigint: true });
43
+ if (before.size > BigInt(Number.MAX_SAFE_INTEGER))
44
+ throw new RangeError("Session file is too large");
45
+ const digest = createHash("sha256");
46
+ const buffer = Buffer.allocUnsafe(READ_BUFFER_SIZE);
47
+ let completeBytes = 0;
48
+ let recordCount = 0;
49
+ while (true) {
50
+ const bytesRead = readSync(fd, buffer, 0, buffer.byteLength, null);
51
+ if (bytesRead === 0)
52
+ break;
53
+ digest.update(buffer.subarray(0, bytesRead));
54
+ completeBytes += bytesRead;
55
+ for (let index = 0; index < bytesRead; index += 1) {
56
+ if (buffer[index] === 0x0a)
57
+ recordCount += 1;
58
+ }
59
+ }
60
+ const after = fstatSync(fd, { bigint: true });
61
+ assertStable(path, before, after);
62
+ return Object.freeze({
63
+ completeBytes,
64
+ recordCount,
65
+ completePrefixSha256: digest.digest("hex"),
66
+ generation: Object.freeze({
67
+ dev: before.dev.toString(),
68
+ ino: before.ino.toString(),
69
+ birthtimeNs: before.birthtimeNs.toString(),
70
+ ctimeNs: before.ctimeNs.toString(),
71
+ }),
72
+ });
73
+ }
74
+ finally {
75
+ closeSync(fd);
76
+ }
77
+ }
78
+ //# sourceMappingURL=session-file-head.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-file-head.js","sourceRoot":"","sources":["../../src/core/session-file-head.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { type BigIntStats, closeSync, fstatSync, openSync, readSync, statSync } from \"node:fs\";\nimport type { DurableFileGeneration } from \"./durable-file-identity.ts\";\nimport { DurableFileReadRaceError } from \"./durable-file-io.ts\";\n\nconst READ_BUFFER_SIZE = 1024 * 1024;\n\nexport interface SessionFileDurableMetadata {\n\treadonly completeBytes: number;\n\treadonly recordCount: number;\n\treadonly completePrefixSha256: string;\n\treadonly generation: DurableFileGeneration;\n}\n\nfunction assertStable(path: string, before: BigIntStats, after: BigIntStats): void {\n\tconst current = statSync(path, { bigint: true });\n\tif (\n\t\tbefore.dev !== after.dev ||\n\t\tbefore.ino !== after.ino ||\n\t\tbefore.size !== after.size ||\n\t\tbefore.mtimeNs !== after.mtimeNs ||\n\t\tbefore.ctimeNs !== after.ctimeNs ||\n\t\tbefore.dev !== current.dev ||\n\t\tbefore.ino !== current.ino ||\n\t\tbefore.size !== current.size ||\n\t\tbefore.mtimeNs !== current.mtimeNs ||\n\t\tbefore.ctimeNs !== current.ctimeNs ||\n\t\tbefore.birthtimeNs !== current.birthtimeNs\n\t) {\n\t\tthrow new DurableFileReadRaceError();\n\t}\n}\n\nexport function sessionFileHasCompleteTail(path: string): boolean {\n\tconst fd = openSync(path, \"r\");\n\ttry {\n\t\tconst before = fstatSync(fd, { bigint: true });\n\t\tif (before.size === 0n) return true;\n\t\tif (before.size > BigInt(Number.MAX_SAFE_INTEGER)) throw new RangeError(\"Session file is too large\");\n\t\tconst tail = Buffer.allocUnsafe(1);\n\t\treadSync(fd, tail, 0, 1, Number(before.size - 1n));\n\t\tconst after = fstatSync(fd, { bigint: true });\n\t\tassertStable(path, before, after);\n\t\treturn tail[0] === 0x0a;\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n\nexport function readSessionFileDurableMetadata(path: string): SessionFileDurableMetadata {\n\tconst fd = openSync(path, \"r\");\n\ttry {\n\t\tconst before = fstatSync(fd, { bigint: true });\n\t\tif (before.size > BigInt(Number.MAX_SAFE_INTEGER)) throw new RangeError(\"Session file is too large\");\n\t\tconst digest = createHash(\"sha256\");\n\t\tconst buffer = Buffer.allocUnsafe(READ_BUFFER_SIZE);\n\t\tlet completeBytes = 0;\n\t\tlet recordCount = 0;\n\t\twhile (true) {\n\t\t\tconst bytesRead = readSync(fd, buffer, 0, buffer.byteLength, null);\n\t\t\tif (bytesRead === 0) break;\n\t\t\tdigest.update(buffer.subarray(0, bytesRead));\n\t\t\tcompleteBytes += bytesRead;\n\t\t\tfor (let index = 0; index < bytesRead; index += 1) {\n\t\t\t\tif (buffer[index] === 0x0a) recordCount += 1;\n\t\t\t}\n\t\t}\n\t\tconst after = fstatSync(fd, { bigint: true });\n\t\tassertStable(path, before, after);\n\t\treturn Object.freeze({\n\t\t\tcompleteBytes,\n\t\t\trecordCount,\n\t\t\tcompletePrefixSha256: digest.digest(\"hex\"),\n\t\t\tgeneration: Object.freeze({\n\t\t\t\tdev: before.dev.toString(),\n\t\t\t\tino: before.ino.toString(),\n\t\t\t\tbirthtimeNs: before.birthtimeNs.toString(),\n\t\t\t\tctimeNs: before.ctimeNs.toString(),\n\t\t\t}),\n\t\t});\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n}\n"]}
@@ -0,0 +1,30 @@
1
+ import { type SessionRevisionToken } from "./compaction/transaction.ts";
2
+ import { type DurableFileSnapshot } from "./durable-file-io.ts";
3
+ export interface SessionQuarantineReport {
4
+ readonly artifact: "session";
5
+ readonly path: string;
6
+ readonly quarantinePath: string;
7
+ readonly byteCount: number;
8
+ readonly completePrefixByteCount: number;
9
+ }
10
+ export declare class SessionManagerStaleWriteError extends Error {
11
+ constructor(message?: string);
12
+ }
13
+ export type SessionDurableHead = {
14
+ readonly revision: SessionRevisionToken;
15
+ readonly generation: DurableFileSnapshot["generation"];
16
+ };
17
+ type FileEntryIdentity = {
18
+ readonly type: string;
19
+ readonly id?: unknown;
20
+ };
21
+ type SessionQuarantineResult = {
22
+ readonly report: SessionQuarantineReport | null;
23
+ readonly snapshot: DurableFileSnapshot | null;
24
+ };
25
+ export declare function quarantineSessionTrailingFragment(filePath: string): SessionQuarantineResult;
26
+ export declare function sessionDurableHeadFromSnapshot(snapshot: DurableFileSnapshot, activeLeafId: string | null, entries: readonly FileEntryIdentity[]): SessionDurableHead | null;
27
+ export declare function sessionDurableHeadFromFile(filePath: string, activeLeafId: string | null, entries: readonly FileEntryIdentity[]): SessionDurableHead | null;
28
+ export declare function sameDurableSessionHead(left: SessionDurableHead | null, right: SessionDurableHead | null): boolean;
29
+ export {};
30
+ //# sourceMappingURL=session-file-persistence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-file-persistence.d.ts","sourceRoot":"","sources":["../../src/core/session-file-persistence.ts"],"names":[],"mappings":"AAGA,OAAO,EAA8B,KAAK,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACpG,OAAO,EACN,KAAK,mBAAmB,EAIxB,MAAM,sBAAsB,CAAC;AAG9B,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,uBAAuB,EAAE,MAAM,CAAC;CACzC;AAED,qBAAa,6BAA8B,SAAQ,KAAK;IACvD,YAAY,OAAO,SAAsE,EAGxF;CACD;AAED,MAAM,MAAM,kBAAkB,GAAG;IAChC,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC;CACvD,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC9B,QAAQ,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAChD,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;CAC9C,CAAC;AAEF,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,MAAM,GAAG,uBAAuB,CAoC3F;AAED,wBAAgB,8BAA8B,CAC7C,QAAQ,EAAE,mBAAmB,EAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,OAAO,EAAE,SAAS,iBAAiB,EAAE,GACnC,kBAAkB,GAAG,IAAI,CAsB3B;AAED,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,OAAO,EAAE,SAAS,iBAAiB,EAAE,GACnC,kBAAkB,GAAG,IAAI,CAoB3B;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI,GAAG,OAAO,CAUjH","sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { existsSync, statSync } from \"node:fs\";\nimport { atomicRewriteFileSync } from \"./atomic-session-file.ts\";\nimport { createSessionRevisionToken, type SessionRevisionToken } from \"./compaction/transaction.ts\";\nimport {\n\ttype DurableFileSnapshot,\n\treadDurableFileSnapshot,\n\tsameDurableFileGeneration,\n\twriteExclusiveFileDurablySync,\n} from \"./durable-file-io.ts\";\nimport { readSessionFileDurableMetadata, sessionFileHasCompleteTail } from \"./session-file-head.ts\";\n\nexport interface SessionQuarantineReport {\n\treadonly artifact: \"session\";\n\treadonly path: string;\n\treadonly quarantinePath: string;\n\treadonly byteCount: number;\n\treadonly completePrefixByteCount: number;\n}\n\nexport class SessionManagerStaleWriteError extends Error {\n\tconstructor(message = \"Session file changed since this manager accepted its durable head\") {\n\t\tsuper(message);\n\t\tthis.name = \"SessionManagerStaleWriteError\";\n\t}\n}\n\nexport type SessionDurableHead = {\n\treadonly revision: SessionRevisionToken;\n\treadonly generation: DurableFileSnapshot[\"generation\"];\n};\n\ntype FileEntryIdentity = {\n\treadonly type: string;\n\treadonly id?: unknown;\n};\n\ntype SessionQuarantineResult = {\n\treadonly report: SessionQuarantineReport | null;\n\treadonly snapshot: DurableFileSnapshot | null;\n};\n\nexport function quarantineSessionTrailingFragment(filePath: string): SessionQuarantineResult {\n\tif (sessionFileHasCompleteTail(filePath)) return { report: null, snapshot: null };\n\tif (statSync(filePath).nlink > 1)\n\t\tthrow new Error(\"Session quarantine refused for a target with more than one hard link\");\n\tconst snapshot = readDurableFileSnapshot(filePath);\n\tif (!snapshot) return { report: null, snapshot: null };\n\tlet lastNewline = -1;\n\tfor (let index = snapshot.bytes.byteLength - 1; index >= 0; index -= 1) {\n\t\tif (snapshot.bytes[index] === 0x0a) {\n\t\t\tlastNewline = index;\n\t\t\tbreak;\n\t\t}\n\t}\n\tconst completePrefixByteCount = lastNewline + 1;\n\tconst fragment = snapshot.bytes.subarray(completePrefixByteCount);\n\tconst quarantinePath = `${filePath}.quarantine-${randomUUID()}`;\n\twriteExclusiveFileDurablySync(quarantinePath, fragment);\n\tconst current = readDurableFileSnapshot(filePath);\n\tif (\n\t\t!current ||\n\t\t!sameDurableFileGeneration(snapshot.generation, current.generation) ||\n\t\tBuffer.compare(snapshot.bytes, current.bytes) !== 0\n\t) {\n\t\tthrow new SessionManagerStaleWriteError();\n\t}\n\tatomicRewriteFileSync(filePath, snapshot.bytes.subarray(0, completePrefixByteCount));\n\treturn {\n\t\treport: Object.freeze({\n\t\t\tartifact: \"session\",\n\t\t\tpath: filePath,\n\t\t\tquarantinePath,\n\t\t\tbyteCount: fragment.byteLength,\n\t\t\tcompletePrefixByteCount,\n\t\t}),\n\t\tsnapshot: readDurableFileSnapshot(filePath),\n\t};\n}\n\nexport function sessionDurableHeadFromSnapshot(\n\tsnapshot: DurableFileSnapshot,\n\tactiveLeafId: string | null,\n\tentries: readonly FileEntryIdentity[],\n): SessionDurableHead | null {\n\tconst header = entries[0];\n\tif (!header || header.type !== \"session\" || typeof header.id !== \"string\") return null;\n\tlet recordCount = 0;\n\tfor (const byte of snapshot.bytes) {\n\t\tif (byte === 0x0a) recordCount += 1;\n\t}\n\tconst lastEntry = entries.at(-1);\n\tconst lastEntryId =\n\t\tlastEntry && lastEntry.type !== \"session\" && typeof lastEntry.id === \"string\" ? lastEntry.id : null;\n\treturn Object.freeze({\n\t\trevision: createSessionRevisionToken({\n\t\t\tsessionId: header.id,\n\t\t\tcompleteBytes: snapshot.bytes.byteLength,\n\t\t\trecordCount,\n\t\t\tleafId: activeLeafId,\n\t\t\tlastEntryId,\n\t\t\tcompletePrefixSha256: createHash(\"sha256\").update(snapshot.bytes).digest(\"hex\"),\n\t\t\tfileIdentity: { dev: snapshot.generation.dev, ino: snapshot.generation.ino },\n\t\t}),\n\t\tgeneration: snapshot.generation,\n\t});\n}\n\nexport function sessionDurableHeadFromFile(\n\tfilePath: string,\n\tactiveLeafId: string | null,\n\tentries: readonly FileEntryIdentity[],\n): SessionDurableHead | null {\n\tif (!existsSync(filePath)) return null;\n\tconst header = entries[0];\n\tif (!header || header.type !== \"session\" || typeof header.id !== \"string\") return null;\n\tconst metadata = readSessionFileDurableMetadata(filePath);\n\tconst lastEntry = entries.at(-1);\n\tconst lastEntryId =\n\t\tlastEntry && lastEntry.type !== \"session\" && typeof lastEntry.id === \"string\" ? lastEntry.id : null;\n\treturn Object.freeze({\n\t\trevision: createSessionRevisionToken({\n\t\t\tsessionId: header.id,\n\t\t\tcompleteBytes: metadata.completeBytes,\n\t\t\trecordCount: metadata.recordCount,\n\t\t\tleafId: activeLeafId,\n\t\t\tlastEntryId,\n\t\t\tcompletePrefixSha256: metadata.completePrefixSha256,\n\t\t\tfileIdentity: { dev: metadata.generation.dev, ino: metadata.generation.ino },\n\t\t}),\n\t\tgeneration: metadata.generation,\n\t});\n}\n\nexport function sameDurableSessionHead(left: SessionDurableHead | null, right: SessionDurableHead | null): boolean {\n\tif (left === null || right === null) return left === right;\n\treturn (\n\t\tleft.revision.sessionId === right.revision.sessionId &&\n\t\tleft.revision.completeBytes === right.revision.completeBytes &&\n\t\tleft.revision.recordCount === right.revision.recordCount &&\n\t\tleft.revision.lastEntryId === right.revision.lastEntryId &&\n\t\tleft.revision.completePrefixSha256 === right.revision.completePrefixSha256 &&\n\t\tsameDurableFileGeneration(left.generation, right.generation)\n\t);\n}\n"]}