harnery 0.32.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (665) hide show
  1. package/README.md +2 -0
  2. package/dist/commander.d.ts.map +1 -1
  3. package/dist/commander.js +7 -1
  4. package/dist/commands/adapter.js +2 -2
  5. package/dist/commands/agents.d.ts +144 -1
  6. package/dist/commands/agents.d.ts.map +1 -1
  7. package/dist/commands/agents.js +1408 -565
  8. package/dist/commands/artifacts.d.ts.map +1 -1
  9. package/dist/commands/artifacts.js +7 -6
  10. package/dist/commands/backup.d.ts +1 -1
  11. package/dist/commands/backup.d.ts.map +1 -1
  12. package/dist/commands/backup.js +29 -16
  13. package/dist/commands/browse.d.ts.map +1 -1
  14. package/dist/commands/browse.js +234 -12
  15. package/dist/commands/checkpoint.d.ts.map +1 -1
  16. package/dist/commands/checkpoint.js +3 -2
  17. package/dist/commands/claude-desktop.d.ts +2 -2
  18. package/dist/commands/claude-desktop.d.ts.map +1 -1
  19. package/dist/commands/claude-desktop.js +2 -2
  20. package/dist/commands/context.js +1 -6
  21. package/dist/commands/decision.d.ts.map +1 -1
  22. package/dist/commands/decision.js +22 -38
  23. package/dist/commands/docs.d.ts.map +1 -1
  24. package/dist/commands/docs.js +91 -28
  25. package/dist/commands/doctor.d.ts +4 -2
  26. package/dist/commands/doctor.d.ts.map +1 -1
  27. package/dist/commands/doctor.js +55 -7
  28. package/dist/commands/events.d.ts +5 -0
  29. package/dist/commands/events.d.ts.map +1 -0
  30. package/dist/commands/events.js +189 -0
  31. package/dist/commands/governor.d.ts.map +1 -1
  32. package/dist/commands/governor.js +13 -4
  33. package/dist/commands/init.d.ts +10 -2
  34. package/dist/commands/init.d.ts.map +1 -1
  35. package/dist/commands/init.js +233 -51
  36. package/dist/commands/instructions.d.ts +4 -0
  37. package/dist/commands/instructions.d.ts.map +1 -0
  38. package/dist/commands/instructions.js +100 -0
  39. package/dist/commands/journal.d.ts.map +1 -1
  40. package/dist/commands/journal.js +4 -13
  41. package/dist/commands/ledger-v3.d.ts +5 -0
  42. package/dist/commands/ledger-v3.d.ts.map +1 -0
  43. package/dist/commands/ledger-v3.js +91 -0
  44. package/dist/commands/presence.d.ts.map +1 -1
  45. package/dist/commands/presence.js +15 -6
  46. package/dist/commands/sync.d.ts +1 -1
  47. package/dist/commands/sync.js +1 -1
  48. package/dist/commands/web.d.ts +6 -0
  49. package/dist/commands/web.d.ts.map +1 -1
  50. package/dist/commands/web.js +67 -7
  51. package/dist/commands/work.d.ts.map +1 -1
  52. package/dist/commands/work.js +22 -5
  53. package/dist/core/adapter.d.ts +5 -0
  54. package/dist/core/adapter.d.ts.map +1 -0
  55. package/dist/core/adapter.js +1 -0
  56. package/dist/core/adapters/attest.d.ts +5 -2
  57. package/dist/core/adapters/attest.d.ts.map +1 -1
  58. package/dist/core/adapters/attest.js +8 -3
  59. package/dist/core/adapters/profiles.d.ts +6 -6
  60. package/dist/core/adapters/profiles.d.ts.map +1 -1
  61. package/dist/core/adapters/profiles.js +4 -4
  62. package/dist/core/agents/canonical-emit.d.ts +17 -15
  63. package/dist/core/agents/canonical-emit.d.ts.map +1 -1
  64. package/dist/core/agents/canonical-emit.js +27 -25
  65. package/dist/core/agents/cli.js +212 -235
  66. package/dist/core/agents/codex-archive-v3.d.ts +14 -0
  67. package/dist/core/agents/codex-archive-v3.d.ts.map +1 -0
  68. package/dist/core/agents/codex-archive-v3.js +110 -0
  69. package/dist/core/agents/coord-client.d.ts +19 -70
  70. package/dist/core/agents/coord-client.d.ts.map +1 -1
  71. package/dist/core/agents/coord-client.js +65 -155
  72. package/dist/core/agents/finalization.d.ts +4 -1
  73. package/dist/core/agents/finalization.d.ts.map +1 -1
  74. package/dist/core/agents/finalization.js +89 -32
  75. package/dist/core/agents/index.d.ts +5 -5
  76. package/dist/core/agents/index.d.ts.map +1 -1
  77. package/dist/core/agents/index.js +5 -5
  78. package/dist/core/agents/live-authority-v3.d.ts +59 -0
  79. package/dist/core/agents/live-authority-v3.d.ts.map +1 -0
  80. package/dist/core/agents/live-authority-v3.js +233 -0
  81. package/dist/core/agents/live-lifecycle-v3.d.ts +20 -0
  82. package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -0
  83. package/dist/core/agents/live-lifecycle-v3.js +91 -0
  84. package/dist/core/agents/live-observation-v3.d.ts +25 -0
  85. package/dist/core/agents/live-observation-v3.d.ts.map +1 -0
  86. package/dist/core/agents/live-observation-v3.js +157 -0
  87. package/dist/core/agents/render/prompt-context.d.ts +10 -4
  88. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  89. package/dist/core/agents/render/prompt-context.js +61 -55
  90. package/dist/core/agents/render/session-context.d.ts +1 -1
  91. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  92. package/dist/core/agents/render/session-context.js +15 -33
  93. package/dist/core/agents/rules/claim-conflict.d.ts +3 -3
  94. package/dist/core/agents/rules/claim-conflict.d.ts.map +1 -1
  95. package/dist/core/agents/rules/claim-conflict.js +79 -127
  96. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  97. package/dist/core/agents/rules/commit-conflict.js +3 -18
  98. package/dist/core/agents/rules/stop-hook.d.ts +9 -50
  99. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  100. package/dist/core/agents/rules/stop-hook.js +193 -236
  101. package/dist/core/agents/session-events.d.ts +5 -7
  102. package/dist/core/agents/session-events.d.ts.map +1 -1
  103. package/dist/core/agents/session-events.js +127 -95
  104. package/dist/core/agents/session-finalization-state-v3.d.ts +30 -0
  105. package/dist/core/agents/session-finalization-state-v3.d.ts.map +1 -0
  106. package/dist/core/agents/session-finalization-state-v3.js +40 -0
  107. package/dist/core/agents/session-finalizer-v3.d.ts +107 -0
  108. package/dist/core/agents/session-finalizer-v3.d.ts.map +1 -0
  109. package/dist/core/agents/session-finalizer-v3.js +734 -0
  110. package/dist/core/agents/session-name-display.d.ts +40 -0
  111. package/dist/core/agents/session-name-display.d.ts.map +1 -0
  112. package/dist/core/agents/session-name-display.js +119 -0
  113. package/dist/core/agents/state/activity-log.d.ts +3 -3
  114. package/dist/core/agents/state/activity-log.d.ts.map +1 -1
  115. package/dist/core/agents/state/activity-log.js +7 -16
  116. package/dist/core/agents/state/heartbeat-writer.d.ts +29 -46
  117. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  118. package/dist/core/agents/state/heartbeat-writer.js +59 -199
  119. package/dist/core/agents/state/live-coordination-view.d.ts +31 -0
  120. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -0
  121. package/dist/core/agents/state/live-coordination-view.js +209 -0
  122. package/dist/core/agents/state/session-state.d.ts +45 -0
  123. package/dist/core/agents/state/session-state.d.ts.map +1 -0
  124. package/dist/core/agents/state/session-state.js +90 -0
  125. package/dist/core/agents/state/stale-sweep.d.ts +1 -1
  126. package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
  127. package/dist/core/agents/state/stale-sweep.js +26 -15
  128. package/dist/core/artifacts/index.d.ts.map +1 -1
  129. package/dist/core/artifacts/index.js +5 -7
  130. package/dist/core/config.d.ts +33 -2
  131. package/dist/core/config.d.ts.map +1 -1
  132. package/dist/core/config.js +98 -2
  133. package/dist/core/context/index.d.ts +1 -4
  134. package/dist/core/context/index.d.ts.map +1 -1
  135. package/dist/core/context/index.js +9 -9
  136. package/dist/core/events/span-parent.d.ts +15 -0
  137. package/dist/core/events/span-parent.d.ts.map +1 -0
  138. package/dist/core/events/span-parent.js +34 -0
  139. package/dist/core/events/v3/advance.d.ts +14 -0
  140. package/dist/core/events/v3/advance.d.ts.map +1 -0
  141. package/dist/core/events/v3/advance.js +134 -0
  142. package/dist/core/events/v3/authority-outbox.d.ts +78 -0
  143. package/dist/core/events/v3/authority-outbox.d.ts.map +1 -0
  144. package/dist/core/events/v3/authority-outbox.js +399 -0
  145. package/dist/core/events/v3/base-builder.d.ts +20 -0
  146. package/dist/core/events/v3/base-builder.d.ts.map +1 -0
  147. package/dist/core/events/v3/base-builder.js +29 -0
  148. package/dist/core/events/v3/base-contract.d.ts +7576 -0
  149. package/dist/core/events/v3/base-contract.d.ts.map +1 -0
  150. package/dist/core/events/v3/base-contract.js +647 -0
  151. package/dist/core/events/v3/bootstrap.d.ts +34 -0
  152. package/dist/core/events/v3/bootstrap.d.ts.map +1 -0
  153. package/dist/core/events/v3/bootstrap.js +175 -0
  154. package/dist/core/events/v3/builder.d.ts +20 -0
  155. package/dist/core/events/v3/builder.d.ts.map +1 -0
  156. package/dist/core/events/v3/builder.js +28 -0
  157. package/dist/core/events/v3/canonical.d.ts +31 -0
  158. package/dist/core/events/v3/canonical.d.ts.map +1 -0
  159. package/dist/core/events/v3/canonical.js +100 -0
  160. package/dist/core/events/v3/capabilities.d.ts +31 -0
  161. package/dist/core/events/v3/capabilities.d.ts.map +1 -0
  162. package/dist/core/events/v3/capabilities.js +107 -0
  163. package/dist/core/events/v3/capability-drift.d.ts +22 -0
  164. package/dist/core/events/v3/capability-drift.d.ts.map +1 -0
  165. package/dist/core/events/v3/capability-drift.js +134 -0
  166. package/dist/core/events/v3/catalog.d.ts +38 -0
  167. package/dist/core/events/v3/catalog.d.ts.map +1 -0
  168. package/dist/core/events/v3/catalog.js +135 -0
  169. package/dist/core/events/v3/clock-order.d.ts +34 -0
  170. package/dist/core/events/v3/clock-order.d.ts.map +1 -0
  171. package/dist/core/events/v3/clock-order.js +35 -0
  172. package/dist/core/events/v3/contract.d.ts +171 -0
  173. package/dist/core/events/v3/contract.d.ts.map +1 -0
  174. package/dist/core/events/v3/contract.js +180 -0
  175. package/dist/core/events/v3/control.d.ts +111 -0
  176. package/dist/core/events/v3/control.d.ts.map +1 -0
  177. package/dist/core/events/v3/control.js +419 -0
  178. package/dist/core/events/v3/coordination-view.d.ts +69 -0
  179. package/dist/core/events/v3/coordination-view.d.ts.map +1 -0
  180. package/dist/core/events/v3/coordination-view.js +119 -0
  181. package/dist/core/events/v3/economics.d.ts +77 -0
  182. package/dist/core/events/v3/economics.d.ts.map +1 -0
  183. package/dist/core/events/v3/economics.js +274 -0
  184. package/dist/core/events/v3/finalization-view.d.ts +26 -0
  185. package/dist/core/events/v3/finalization-view.d.ts.map +1 -0
  186. package/dist/core/events/v3/finalization-view.js +37 -0
  187. package/dist/core/events/v3/fingerprint-keys.d.ts +25 -0
  188. package/dist/core/events/v3/fingerprint-keys.d.ts.map +1 -0
  189. package/dist/core/events/v3/fingerprint-keys.js +217 -0
  190. package/dist/core/events/v3/generated.d.ts +4 -0
  191. package/dist/core/events/v3/generated.d.ts.map +1 -0
  192. package/dist/core/events/v3/generated.js +47 -0
  193. package/dist/core/events/v3/ids.d.ts +9 -0
  194. package/dist/core/events/v3/ids.d.ts.map +1 -0
  195. package/dist/core/events/v3/ids.js +25 -0
  196. package/dist/core/events/v3/index.d.ts +35 -0
  197. package/dist/core/events/v3/index.d.ts.map +1 -0
  198. package/dist/core/events/v3/index.js +33 -0
  199. package/dist/core/events/v3/latency.d.ts +63 -0
  200. package/dist/core/events/v3/latency.d.ts.map +1 -0
  201. package/dist/core/events/v3/latency.js +412 -0
  202. package/dist/core/events/v3/live-feed.d.ts +45 -0
  203. package/dist/core/events/v3/live-feed.d.ts.map +1 -0
  204. package/dist/core/events/v3/live-feed.js +246 -0
  205. package/dist/core/events/v3/live-observation.d.ts +35 -0
  206. package/dist/core/events/v3/live-observation.d.ts.map +1 -0
  207. package/dist/core/events/v3/live-observation.js +1 -0
  208. package/dist/core/events/v3/live-routing.d.ts +57 -0
  209. package/dist/core/events/v3/live-routing.d.ts.map +1 -0
  210. package/dist/core/events/v3/live-routing.js +107 -0
  211. package/dist/core/events/v3/producers/command-recorder.d.ts +67 -0
  212. package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -0
  213. package/dist/core/events/v3/producers/command-recorder.js +477 -0
  214. package/dist/core/events/v3/producers/command.d.ts +50 -0
  215. package/dist/core/events/v3/producers/command.d.ts.map +1 -0
  216. package/dist/core/events/v3/producers/command.js +135 -0
  217. package/dist/core/events/v3/producers/coordination-recorder.d.ts +53 -0
  218. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -0
  219. package/dist/core/events/v3/producers/coordination-recorder.js +376 -0
  220. package/dist/core/events/v3/producers/coordination.d.ts +90 -0
  221. package/dist/core/events/v3/producers/coordination.d.ts.map +1 -0
  222. package/dist/core/events/v3/producers/coordination.js +229 -0
  223. package/dist/core/events/v3/producers/hook-base.d.ts +54 -0
  224. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -0
  225. package/dist/core/events/v3/producers/hook-base.js +424 -0
  226. package/dist/core/events/v3/producers/hook.d.ts +29 -0
  227. package/dist/core/events/v3/producers/hook.d.ts.map +1 -0
  228. package/dist/core/events/v3/producers/hook.js +71 -0
  229. package/dist/core/events/v3/producers/intake.d.ts +65 -0
  230. package/dist/core/events/v3/producers/intake.d.ts.map +1 -0
  231. package/dist/core/events/v3/producers/intake.js +244 -0
  232. package/dist/core/events/v3/producers/recorder.d.ts +240 -0
  233. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -0
  234. package/dist/core/events/v3/producers/recorder.js +2176 -0
  235. package/dist/core/events/v3/projection.d.ts +101 -0
  236. package/dist/core/events/v3/projection.d.ts.map +1 -0
  237. package/dist/core/events/v3/projection.js +479 -0
  238. package/dist/core/events/v3/reader.d.ts +75 -0
  239. package/dist/core/events/v3/reader.d.ts.map +1 -0
  240. package/dist/core/events/v3/reader.js +778 -0
  241. package/dist/core/events/v3/recovery-record.d.ts +47 -0
  242. package/dist/core/events/v3/recovery-record.d.ts.map +1 -0
  243. package/dist/core/events/v3/recovery-record.js +167 -0
  244. package/dist/core/events/v3/recovery.d.ts +22 -0
  245. package/dist/core/events/v3/recovery.d.ts.map +1 -0
  246. package/dist/core/events/v3/recovery.js +227 -0
  247. package/dist/core/events/v3/span-state.d.ts +52 -0
  248. package/dist/core/events/v3/span-state.d.ts.map +1 -0
  249. package/dist/core/events/v3/span-state.js +142 -0
  250. package/dist/core/events/v3/targets.d.ts +23 -0
  251. package/dist/core/events/v3/targets.d.ts.map +1 -0
  252. package/dist/core/events/v3/targets.js +134 -0
  253. package/dist/core/events/v3/turn-telemetry.d.ts +41 -0
  254. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -0
  255. package/dist/core/events/v3/turn-telemetry.js +168 -0
  256. package/dist/core/events/v3/validate.d.ts +9 -0
  257. package/dist/core/events/v3/validate.d.ts.map +1 -0
  258. package/dist/core/events/v3/validate.js +281 -0
  259. package/dist/core/events/v3/writer.d.ts +56 -0
  260. package/dist/core/events/v3/writer.d.ts.map +1 -0
  261. package/dist/core/events/v3/writer.js +335 -0
  262. package/dist/core/governor/index.d.ts +1 -1
  263. package/dist/core/governor/index.d.ts.map +1 -1
  264. package/dist/core/governor/index.js +1 -1
  265. package/dist/core/governor/plan-api.d.ts +2 -1
  266. package/dist/core/governor/plan-api.d.ts.map +1 -1
  267. package/dist/core/governor/plan-api.js +6 -3
  268. package/dist/core/governor/read.d.ts +1 -1
  269. package/dist/core/governor/read.d.ts.map +1 -1
  270. package/dist/core/governor/read.js +1 -1
  271. package/dist/core/governor/state.d.ts +9 -0
  272. package/dist/core/governor/state.d.ts.map +1 -1
  273. package/dist/core/governor/state.js +40 -3
  274. package/dist/core/guard/config.d.ts +5 -0
  275. package/dist/core/guard/config.d.ts.map +1 -0
  276. package/dist/core/guard/config.js +157 -0
  277. package/dist/core/guard/coordinator.d.ts +14 -0
  278. package/dist/core/guard/coordinator.d.ts.map +1 -0
  279. package/dist/core/guard/coordinator.js +173 -0
  280. package/dist/core/guard/evaluator.d.ts +4 -0
  281. package/dist/core/guard/evaluator.d.ts.map +1 -0
  282. package/dist/core/guard/evaluator.js +242 -0
  283. package/dist/core/guard/evidence-v3.d.ts +15 -0
  284. package/dist/core/guard/evidence-v3.d.ts.map +1 -0
  285. package/dist/core/guard/evidence-v3.js +171 -0
  286. package/dist/core/guard/index.d.ts +10 -0
  287. package/dist/core/guard/index.d.ts.map +1 -0
  288. package/dist/core/guard/index.js +6 -0
  289. package/dist/core/guard/live-source-v3.d.ts +40 -0
  290. package/dist/core/guard/live-source-v3.d.ts.map +1 -0
  291. package/dist/core/guard/live-source-v3.js +128 -0
  292. package/dist/core/guard/storage.d.ts +27 -0
  293. package/dist/core/guard/storage.d.ts.map +1 -0
  294. package/dist/core/guard/storage.js +140 -0
  295. package/dist/core/guard/types.d.ts +119 -0
  296. package/dist/core/guard/types.d.ts.map +1 -0
  297. package/dist/core/guard/types.js +1 -0
  298. package/dist/core/hooks/adapter/detect.d.ts +18 -1
  299. package/dist/core/hooks/adapter/detect.d.ts.map +1 -1
  300. package/dist/core/hooks/adapter/detect.js +29 -0
  301. package/dist/core/hooks/adapter/events.d.ts +7 -4
  302. package/dist/core/hooks/adapter/events.d.ts.map +1 -1
  303. package/dist/core/hooks/adapter/events.js +13 -4
  304. package/dist/core/hooks/adapter/output.d.ts +2 -2
  305. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  306. package/dist/core/hooks/adapter/parse.d.ts +7 -4
  307. package/dist/core/hooks/adapter/parse.d.ts.map +1 -1
  308. package/dist/core/hooks/adapter/parse.js +64 -24
  309. package/dist/core/hooks/adapter/wiring.d.ts +30 -4
  310. package/dist/core/hooks/adapter/wiring.d.ts.map +1 -1
  311. package/dist/core/hooks/adapter/wiring.js +89 -11
  312. package/dist/core/hooks/cli.d.ts +1 -1
  313. package/dist/core/hooks/cli.js +345 -400
  314. package/dist/core/hooks/codex-authorization.d.ts +30 -0
  315. package/dist/core/hooks/codex-authorization.d.ts.map +1 -0
  316. package/dist/core/hooks/codex-authorization.js +199 -0
  317. package/dist/core/hooks/effects/image-capture.d.ts +20 -34
  318. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  319. package/dist/core/hooks/effects/image-capture.js +212 -221
  320. package/dist/core/hooks/effects/index.d.ts +1 -9
  321. package/dist/core/hooks/effects/index.d.ts.map +1 -1
  322. package/dist/core/hooks/effects/index.js +1 -24
  323. package/dist/core/hooks/events/input-hash.d.ts +7 -0
  324. package/dist/core/hooks/events/input-hash.d.ts.map +1 -0
  325. package/dist/core/hooks/events/input-hash.js +43 -0
  326. package/dist/core/hooks/index.d.ts +4 -3
  327. package/dist/core/hooks/index.d.ts.map +1 -1
  328. package/dist/core/hooks/index.js +2 -3
  329. package/dist/core/hooks/resolve/coord-root.d.ts +1 -1
  330. package/dist/core/hooks/resolve/coord-root.js +1 -1
  331. package/dist/core/hooks/resolve/owner.d.ts +16 -15
  332. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  333. package/dist/core/hooks/resolve/owner.js +51 -42
  334. package/dist/core/hooks/resolve/transcript.d.ts +33 -3
  335. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  336. package/dist/core/hooks/resolve/transcript.js +155 -14
  337. package/dist/core/hooks/session-name-presence.d.ts +9 -10
  338. package/dist/core/hooks/session-name-presence.d.ts.map +1 -1
  339. package/dist/core/hooks/session-name-presence.js +15 -15
  340. package/dist/core/hooks/unsafe-cross-shell.d.ts +1 -1
  341. package/dist/core/hooks/unsafe-cross-shell.d.ts.map +1 -1
  342. package/dist/core/journal/index.d.ts +2 -2
  343. package/dist/core/journal/index.d.ts.map +1 -1
  344. package/dist/core/journal/index.js +9 -22
  345. package/dist/core/presence/blob.d.ts +8 -3
  346. package/dist/core/presence/blob.d.ts.map +1 -1
  347. package/dist/core/presence/blob.js +54 -41
  348. package/dist/core/presence/codec-digest.d.ts +29 -0
  349. package/dist/core/presence/codec-digest.d.ts.map +1 -0
  350. package/dist/core/presence/codec-digest.js +170 -0
  351. package/dist/core/presence/index.js +15 -1
  352. package/dist/core/presence/relay-client.d.ts +1 -1
  353. package/dist/core/presence/relay-client.d.ts.map +1 -1
  354. package/dist/core/presence/relay-client.js +5 -5
  355. package/dist/core/work/index.d.ts +1 -1
  356. package/dist/core/work/index.d.ts.map +1 -1
  357. package/dist/core/work/index.js +1 -1
  358. package/dist/core/work/read.d.ts +1 -1
  359. package/dist/core/work/read.d.ts.map +1 -1
  360. package/dist/core/work/read.js +1 -1
  361. package/dist/core/work/runner.d.ts.map +1 -1
  362. package/dist/core/work/runner.js +6 -0
  363. package/dist/core/work/state.d.ts +9 -0
  364. package/dist/core/work/state.d.ts.map +1 -1
  365. package/dist/core/work/state.js +17 -3
  366. package/dist/core/workflow/engine.js +24 -25
  367. package/dist/core/workflow/live-session-v3.d.ts +19 -0
  368. package/dist/core/workflow/live-session-v3.d.ts.map +1 -0
  369. package/dist/core/workflow/live-session-v3.js +86 -0
  370. package/dist/core/workflow/scope-id.d.ts +3 -0
  371. package/dist/core/workflow/scope-id.d.ts.map +1 -0
  372. package/dist/core/workflow/scope-id.js +5 -0
  373. package/dist/core/workflow/workspaces/leases.d.ts +4 -0
  374. package/dist/core/workflow/workspaces/leases.d.ts.map +1 -1
  375. package/dist/core/workflow/workspaces/leases.js +53 -19
  376. package/dist/index.d.ts +1 -1
  377. package/dist/index.js +1 -1
  378. package/dist/lib/browser/client.d.ts +41 -0
  379. package/dist/lib/browser/client.d.ts.map +1 -1
  380. package/dist/lib/browser/client.js +203 -0
  381. package/dist/lib/browser/critique.d.ts +28 -2
  382. package/dist/lib/browser/critique.d.ts.map +1 -1
  383. package/dist/lib/browser/critique.js +74 -18
  384. package/dist/lib/browser/geometry.d.ts +1 -1
  385. package/dist/lib/browser/geometry.d.ts.map +1 -1
  386. package/dist/lib/browser/geometry.js +130 -6
  387. package/dist/lib/browser/index.d.ts +3 -0
  388. package/dist/lib/browser/index.d.ts.map +1 -1
  389. package/dist/lib/browser/index.js +3 -0
  390. package/dist/lib/browser/qa-plan.d.ts +174 -0
  391. package/dist/lib/browser/qa-plan.d.ts.map +1 -0
  392. package/dist/lib/browser/qa-plan.js +321 -0
  393. package/dist/lib/browser/qa-reuse.d.ts +99 -0
  394. package/dist/lib/browser/qa-reuse.d.ts.map +1 -0
  395. package/dist/lib/browser/qa-reuse.js +222 -0
  396. package/dist/lib/browser/qa-snapshot.d.ts +64 -0
  397. package/dist/lib/browser/qa-snapshot.d.ts.map +1 -0
  398. package/dist/lib/browser/qa-snapshot.js +171 -0
  399. package/dist/lib/browser/runts.d.ts.map +1 -1
  400. package/dist/lib/browser/runts.js +22 -1
  401. package/dist/lib/browser/tiling.d.ts +71 -0
  402. package/dist/lib/browser/tiling.d.ts.map +1 -0
  403. package/dist/lib/browser/tiling.js +118 -0
  404. package/dist/lib/context/index.d.ts +0 -3
  405. package/dist/lib/context/index.d.ts.map +1 -1
  406. package/dist/lib/context/index.js +20 -42
  407. package/dist/lib/council/index.d.ts +2 -2
  408. package/dist/lib/council/index.d.ts.map +1 -1
  409. package/dist/lib/council/index.js +9 -20
  410. package/dist/lib/docs-frontmatter.d.ts +1 -6
  411. package/dist/lib/docs-frontmatter.d.ts.map +1 -1
  412. package/dist/lib/docs-frontmatter.js +12 -78
  413. package/dist/lib/docs-index.d.ts +9 -0
  414. package/dist/lib/docs-index.d.ts.map +1 -1
  415. package/dist/lib/docs-index.js +32 -3
  416. package/dist/lib/docs-lint.d.ts.map +1 -1
  417. package/dist/lib/docs-lint.js +14 -30
  418. package/dist/lib/docs-metadata-audit.d.ts +19 -0
  419. package/dist/lib/docs-metadata-audit.d.ts.map +1 -0
  420. package/dist/lib/docs-metadata-audit.js +132 -0
  421. package/dist/lib/docs-metadata-managed.d.ts +23 -0
  422. package/dist/lib/docs-metadata-managed.d.ts.map +1 -0
  423. package/dist/lib/docs-metadata-managed.js +78 -0
  424. package/dist/lib/docs-metadata-sync.d.ts +20 -0
  425. package/dist/lib/docs-metadata-sync.d.ts.map +1 -0
  426. package/dist/lib/docs-metadata-sync.js +222 -0
  427. package/dist/lib/docs-metadata-v2-schema.d.ts +273 -0
  428. package/dist/lib/docs-metadata-v2-schema.d.ts.map +1 -0
  429. package/dist/lib/docs-metadata-v2-schema.js +134 -0
  430. package/dist/lib/docs-metadata-v2.d.ts +21 -0
  431. package/dist/lib/docs-metadata-v2.d.ts.map +1 -0
  432. package/dist/lib/docs-metadata-v2.js +424 -0
  433. package/dist/lib/docs-new.d.ts +11 -0
  434. package/dist/lib/docs-new.d.ts.map +1 -0
  435. package/dist/lib/docs-new.js +52 -0
  436. package/dist/lib/docs-sweep.d.ts.map +1 -1
  437. package/dist/lib/docs-sweep.js +45 -29
  438. package/dist/lib/headless/index.d.ts +98 -0
  439. package/dist/lib/headless/index.d.ts.map +1 -0
  440. package/dist/lib/headless/index.js +211 -0
  441. package/dist/lib/identities/assume.d.ts +4 -4
  442. package/dist/lib/identities/assume.d.ts.map +1 -1
  443. package/dist/lib/identities/assume.js +52 -68
  444. package/dist/lib/instructions/apply.d.ts +5 -4
  445. package/dist/lib/instructions/apply.d.ts.map +1 -1
  446. package/dist/lib/instructions/apply.js +32 -20
  447. package/dist/lib/instructions/bundle.d.ts +33 -0
  448. package/dist/lib/instructions/bundle.d.ts.map +1 -0
  449. package/dist/lib/instructions/bundle.js +149 -0
  450. package/dist/lib/instructions/splice.d.ts +0 -1
  451. package/dist/lib/instructions/splice.d.ts.map +1 -1
  452. package/dist/lib/instructions/splice.js +22 -6
  453. package/dist/lib/instructions/templates.d.ts +7 -5
  454. package/dist/lib/instructions/templates.d.ts.map +1 -1
  455. package/dist/lib/instructions/templates.js +79 -9
  456. package/package.json +27 -6
  457. package/schemas/config.schema.json +120 -2
  458. package/schemas/docs-metadata-v2.schema.json +441 -0
  459. package/schemas/event-v3.schema.json +24472 -0
  460. package/src/commander.ts +7 -1
  461. package/src/commands/adapter.ts +2 -2
  462. package/src/commands/agents.ts +1737 -570
  463. package/src/commands/artifacts.ts +7 -6
  464. package/src/commands/backup.ts +29 -21
  465. package/src/commands/browse.ts +349 -8
  466. package/src/commands/checkpoint.ts +4 -3
  467. package/src/commands/claude-desktop.ts +7 -5
  468. package/src/commands/context.ts +1 -6
  469. package/src/commands/decision.ts +27 -44
  470. package/src/commands/docs.ts +100 -33
  471. package/src/commands/doctor.ts +73 -8
  472. package/src/commands/events.ts +256 -0
  473. package/src/commands/governor.ts +18 -4
  474. package/src/commands/init.ts +264 -57
  475. package/src/commands/instructions.ts +129 -0
  476. package/src/commands/journal.ts +4 -13
  477. package/src/commands/ledger-v3.ts +111 -0
  478. package/src/commands/presence.ts +18 -11
  479. package/src/commands/sync.ts +1 -1
  480. package/src/commands/web.ts +67 -8
  481. package/src/commands/work.ts +28 -5
  482. package/src/core/adapter.ts +5 -0
  483. package/src/core/adapters/attest.ts +8 -3
  484. package/src/core/adapters/profiles.ts +4 -6
  485. package/src/core/agents/canonical-emit.ts +39 -28
  486. package/src/core/agents/cli.ts +242 -263
  487. package/src/core/agents/codex-archive-v3.ts +138 -0
  488. package/src/core/agents/coord-client.ts +75 -177
  489. package/src/core/agents/finalization.ts +120 -38
  490. package/src/core/agents/index.ts +5 -5
  491. package/src/core/agents/live-authority-v3.ts +375 -0
  492. package/src/core/agents/live-lifecycle-v3.ts +140 -0
  493. package/src/core/agents/live-observation-v3.ts +216 -0
  494. package/src/core/agents/render/prompt-context.ts +89 -55
  495. package/src/core/agents/render/session-context.ts +23 -32
  496. package/src/core/agents/rules/claim-conflict.ts +85 -126
  497. package/src/core/agents/rules/commit-conflict.ts +3 -14
  498. package/src/core/agents/rules/stop-hook.ts +239 -293
  499. package/src/core/agents/session-events.ts +137 -104
  500. package/src/core/agents/session-finalization-state-v3.ts +90 -0
  501. package/src/core/agents/session-finalizer-v3.ts +953 -0
  502. package/src/core/agents/session-name-display.ts +149 -0
  503. package/src/core/agents/state/activity-log.ts +6 -14
  504. package/src/core/agents/state/heartbeat-writer.ts +98 -242
  505. package/src/core/agents/state/live-coordination-view.ts +290 -0
  506. package/src/core/agents/state/session-state.ts +143 -0
  507. package/src/core/agents/state/stale-sweep.ts +40 -17
  508. package/src/core/artifacts/index.ts +4 -5
  509. package/src/core/config.ts +148 -3
  510. package/src/core/context/index.ts +9 -17
  511. package/src/core/events/span-parent.ts +46 -0
  512. package/src/core/events/v3/advance.ts +168 -0
  513. package/src/core/events/v3/authority-outbox.ts +548 -0
  514. package/src/core/events/v3/base-builder.ts +60 -0
  515. package/src/core/events/v3/base-contract.ts +882 -0
  516. package/src/core/events/v3/bootstrap.ts +226 -0
  517. package/src/core/events/v3/builder.ts +59 -0
  518. package/src/core/events/v3/canonical.ts +153 -0
  519. package/src/core/events/v3/capabilities.ts +171 -0
  520. package/src/core/events/v3/capability-drift.ts +177 -0
  521. package/src/core/events/v3/catalog.ts +202 -0
  522. package/src/core/events/v3/clock-order.ts +41 -0
  523. package/src/core/events/v3/contract.ts +365 -0
  524. package/src/core/events/v3/control.ts +576 -0
  525. package/src/core/events/v3/coordination-view.ts +193 -0
  526. package/src/core/events/v3/economics.ts +384 -0
  527. package/src/core/events/v3/finalization-view.ts +67 -0
  528. package/src/core/events/v3/fingerprint-keys.ts +260 -0
  529. package/src/core/events/v3/generated.ts +48 -0
  530. package/src/core/events/v3/ids.ts +33 -0
  531. package/src/core/events/v3/index.ts +322 -0
  532. package/src/core/events/v3/latency.ts +551 -0
  533. package/src/core/events/v3/live-feed.ts +319 -0
  534. package/src/core/events/v3/live-observation.ts +39 -0
  535. package/src/core/events/v3/live-routing.ts +135 -0
  536. package/src/core/events/v3/producers/command-recorder.ts +631 -0
  537. package/src/core/events/v3/producers/command.ts +201 -0
  538. package/src/core/events/v3/producers/coordination-recorder.ts +538 -0
  539. package/src/core/events/v3/producers/coordination.ts +355 -0
  540. package/src/core/events/v3/producers/hook-base.ts +578 -0
  541. package/src/core/events/v3/producers/hook.ts +119 -0
  542. package/src/core/events/v3/producers/intake.ts +319 -0
  543. package/src/core/events/v3/producers/recorder.ts +2805 -0
  544. package/src/core/events/v3/projection.ts +653 -0
  545. package/src/core/events/v3/reader.ts +1127 -0
  546. package/src/core/events/v3/recovery-record.ts +244 -0
  547. package/src/core/events/v3/recovery.ts +271 -0
  548. package/src/core/events/v3/span-state.ts +187 -0
  549. package/src/core/events/v3/targets.ts +182 -0
  550. package/src/core/events/v3/turn-telemetry.ts +259 -0
  551. package/src/core/events/v3/validate.ts +361 -0
  552. package/src/core/events/v3/writer.ts +419 -0
  553. package/src/core/governor/index.ts +3 -0
  554. package/src/core/governor/plan-api.ts +10 -2
  555. package/src/core/governor/read.ts +3 -0
  556. package/src/core/governor/state.ts +52 -5
  557. package/src/core/guard/config.ts +206 -0
  558. package/src/core/guard/coordinator.ts +227 -0
  559. package/src/core/guard/evaluator.ts +343 -0
  560. package/src/core/guard/evidence-v3.ts +227 -0
  561. package/src/core/guard/index.ts +35 -0
  562. package/src/core/guard/live-source-v3.ts +204 -0
  563. package/src/core/guard/storage.ts +188 -0
  564. package/src/core/guard/types.ts +152 -0
  565. package/src/core/hooks/adapter/detect.ts +28 -1
  566. package/src/core/hooks/adapter/events.ts +15 -6
  567. package/src/core/hooks/adapter/output.ts +7 -2
  568. package/src/core/hooks/adapter/parse.ts +81 -36
  569. package/src/core/hooks/adapter/wiring.ts +119 -13
  570. package/src/core/hooks/cli.ts +398 -422
  571. package/src/core/hooks/codex-authorization.ts +253 -0
  572. package/src/core/hooks/effects/image-capture.ts +228 -238
  573. package/src/core/hooks/effects/index.ts +1 -36
  574. package/src/core/hooks/events/input-hash.ts +47 -0
  575. package/src/core/hooks/index.ts +4 -11
  576. package/src/core/hooks/resolve/coord-root.ts +1 -1
  577. package/src/core/hooks/resolve/owner.ts +52 -45
  578. package/src/core/hooks/resolve/transcript.ts +165 -14
  579. package/src/core/hooks/session-name-presence.ts +14 -15
  580. package/src/core/hooks/unsafe-cross-shell.ts +1 -1
  581. package/src/core/journal/index.ts +15 -22
  582. package/src/core/presence/blob.ts +63 -38
  583. package/src/core/presence/codec-digest.ts +215 -0
  584. package/src/core/presence/index.ts +18 -1
  585. package/src/core/presence/relay-client.ts +5 -5
  586. package/src/core/work/index.ts +3 -0
  587. package/src/core/work/read.ts +3 -0
  588. package/src/core/work/runner.ts +6 -0
  589. package/src/core/work/state.ts +27 -3
  590. package/src/core/workflow/engine.ts +24 -24
  591. package/src/core/workflow/live-session-v3.ts +126 -0
  592. package/src/core/workflow/scope-id.ts +6 -0
  593. package/src/core/workflow/workspaces/leases.ts +56 -19
  594. package/src/index.ts +1 -1
  595. package/src/lib/browser/client.ts +230 -0
  596. package/src/lib/browser/critique.ts +104 -27
  597. package/src/lib/browser/geometry.ts +143 -14
  598. package/src/lib/browser/index.ts +34 -0
  599. package/src/lib/browser/qa-plan.ts +501 -0
  600. package/src/lib/browser/qa-reuse.ts +306 -0
  601. package/src/lib/browser/qa-snapshot.ts +223 -0
  602. package/src/lib/browser/runts.ts +27 -2
  603. package/src/lib/browser/tiling.ts +164 -0
  604. package/src/lib/context/index.ts +22 -46
  605. package/src/lib/council/index.ts +9 -21
  606. package/src/lib/docs-frontmatter.ts +8 -79
  607. package/src/lib/docs-index.ts +33 -3
  608. package/src/lib/docs-lint.ts +15 -29
  609. package/src/lib/docs-metadata-audit.ts +166 -0
  610. package/src/lib/docs-metadata-managed.ts +83 -0
  611. package/src/lib/docs-metadata-sync.ts +262 -0
  612. package/src/lib/docs-metadata-v2-schema.ts +138 -0
  613. package/src/lib/docs-metadata-v2.ts +646 -0
  614. package/src/lib/docs-new.ts +63 -0
  615. package/src/lib/docs-sweep.ts +42 -28
  616. package/src/lib/headless/index.ts +287 -0
  617. package/src/lib/identities/assume.ts +67 -86
  618. package/src/lib/instructions/apply.ts +33 -20
  619. package/src/lib/instructions/bundle.ts +199 -0
  620. package/src/lib/instructions/splice.ts +21 -7
  621. package/src/lib/instructions/templates.ts +85 -13
  622. package/dist/core/agents/cli-emit.d.ts +0 -27
  623. package/dist/core/agents/cli-emit.d.ts.map +0 -1
  624. package/dist/core/agents/cli-emit.js +0 -57
  625. package/dist/core/agents/codex-replay.d.ts +0 -29
  626. package/dist/core/agents/codex-replay.d.ts.map +0 -1
  627. package/dist/core/agents/codex-replay.js +0 -138
  628. package/dist/core/agents/events/consume.d.ts +0 -82
  629. package/dist/core/agents/events/consume.d.ts.map +0 -1
  630. package/dist/core/agents/events/consume.js +0 -195
  631. package/dist/core/agents/events/emit.d.ts +0 -42
  632. package/dist/core/agents/events/emit.d.ts.map +0 -1
  633. package/dist/core/agents/events/emit.js +0 -75
  634. package/dist/core/agents/events/ulid.d.ts +0 -11
  635. package/dist/core/agents/events/ulid.d.ts.map +0 -1
  636. package/dist/core/agents/events/ulid.js +0 -47
  637. package/dist/core/agents/state/heartbeat-projector.d.ts +0 -65
  638. package/dist/core/agents/state/heartbeat-projector.d.ts.map +0 -1
  639. package/dist/core/agents/state/heartbeat-projector.js +0 -527
  640. package/dist/core/hooks/events/emit.d.ts +0 -31
  641. package/dist/core/hooks/events/emit.d.ts.map +0 -1
  642. package/dist/core/hooks/events/emit.js +0 -93
  643. package/dist/core/hooks/events/rotate.d.ts +0 -43
  644. package/dist/core/hooks/events/rotate.d.ts.map +0 -1
  645. package/dist/core/hooks/events/rotate.js +0 -142
  646. package/dist/core/hooks/events/schema.d.ts +0 -312
  647. package/dist/core/hooks/events/schema.d.ts.map +0 -1
  648. package/dist/core/hooks/events/schema.js +0 -12
  649. package/dist/core/hooks/events/ulid.d.ts +0 -10
  650. package/dist/core/hooks/events/ulid.d.ts.map +0 -1
  651. package/dist/core/hooks/events/ulid.js +0 -47
  652. package/dist/lib/docs-frontmatter-migrate.d.ts +0 -33
  653. package/dist/lib/docs-frontmatter-migrate.d.ts.map +0 -1
  654. package/dist/lib/docs-frontmatter-migrate.js +0 -364
  655. package/src/core/agents/cli-emit.ts +0 -64
  656. package/src/core/agents/codex-replay.ts +0 -163
  657. package/src/core/agents/events/consume.ts +0 -254
  658. package/src/core/agents/events/emit.ts +0 -115
  659. package/src/core/agents/events/ulid.ts +0 -51
  660. package/src/core/agents/state/heartbeat-projector.ts +0 -582
  661. package/src/core/hooks/events/emit.ts +0 -125
  662. package/src/core/hooks/events/rotate.ts +0 -151
  663. package/src/core/hooks/events/schema.ts +0 -538
  664. package/src/core/hooks/events/ulid.ts +0 -51
  665. package/src/lib/docs-frontmatter-migrate.ts +0 -427
@@ -0,0 +1,1127 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { createHash } from "node:crypto";
3
+ import {
4
+ closeSync,
5
+ existsSync,
6
+ lstatSync,
7
+ openSync,
8
+ readdirSync,
9
+ readFileSync,
10
+ readSync,
11
+ statSync,
12
+ } from "node:fs";
13
+ import { join, relative, resolve } from "node:path";
14
+ import { canonicalJsonV3, sha256V3 } from "./canonical.ts";
15
+ import {
16
+ type EventV3Catalog,
17
+ type EventV3SegmentManifest,
18
+ readEventV3Catalog,
19
+ readEventV3SegmentManifest,
20
+ } from "./catalog.ts";
21
+ import type { EventV3 } from "./contract.ts";
22
+ import { EVENT_V3_SCHEMA_DIGEST } from "./generated.ts";
23
+ import {
24
+ type EventV3RecoveryFailure,
25
+ type EventV3RecoveryReceipt,
26
+ eventV3RecoveryRecordsRoot,
27
+ listEventV3RecoveryReceipts,
28
+ } from "./recovery-record.ts";
29
+ import { validateEventV3 } from "./validate.ts";
30
+
31
+ export type LedgerDiagnosticCodeV3 =
32
+ | "malformed_json"
33
+ | "partial_final_frame"
34
+ | "unsupported_major"
35
+ | "invalid_contract"
36
+ | "unsupported_schema_digest"
37
+ | "unexpected_schema_digest"
38
+ | "noncanonical_frame"
39
+ | "conflicting_event_id"
40
+ | "causal_parent_missing"
41
+ | "wall_clock_regression_unmarked"
42
+ | "monotonic_clock_regression"
43
+ | "producer_sequence_gap"
44
+ | "unresolved_attestation"
45
+ | "missing_genesis"
46
+ | "multiple_genesis"
47
+ | "genesis_not_first"
48
+ | "genesis_digest_mismatch"
49
+ | "missing_activation"
50
+ | "activation_genesis_mismatch"
51
+ | "advance_prior_mismatch"
52
+ | "advance_reader_incompatible"
53
+ | "advance_digest_unsupported"
54
+ | "advance_boundary_invalid"
55
+ | "advance_boundary_missed"
56
+ | "cursor_genesis_mismatch"
57
+ | "cursor_position_missing"
58
+ | "catalog_invalid"
59
+ | "missing_segment"
60
+ | "segment_digest_mismatch"
61
+ | "manifest_digest_mismatch"
62
+ | "manifest_segment_mismatch"
63
+ | "active_replaced"
64
+ | "recovery_record_invalid";
65
+
66
+ export interface LedgerDiagnosticV3 {
67
+ code: LedgerDiagnosticCodeV3;
68
+ byte_offset: number;
69
+ segment_ordinal: number;
70
+ event_id?: string;
71
+ }
72
+
73
+ export interface LedgerFrameV3 {
74
+ raw: string;
75
+ position: {
76
+ segment_ordinal: number;
77
+ byte_offset: number;
78
+ };
79
+ }
80
+
81
+ export interface PositionedEventV3 {
82
+ event: EventV3;
83
+ position: LedgerFrameV3["position"];
84
+ }
85
+
86
+ export interface SchemaAdvanceV3 {
87
+ event_id: string;
88
+ prior_schema_digest: string;
89
+ next_schema_digest: string;
90
+ effective_position: LedgerFrameV3["position"];
91
+ }
92
+
93
+ export interface ReadLedgerV3Options {
94
+ authority?: "candidate" | "active";
95
+ reader_build?: string;
96
+ accepted_schema_digests?: readonly string[];
97
+ }
98
+
99
+ export interface ReadLedgerV3Result {
100
+ events: PositionedEventV3[];
101
+ diagnostics: LedgerDiagnosticV3[];
102
+ complete: boolean;
103
+ genesis_id?: string;
104
+ active_schema_digest?: string;
105
+ advances: SchemaAdvanceV3[];
106
+ bytes: number;
107
+ failed_epochs?: EventV3RecoveryReceipt[];
108
+ }
109
+
110
+ export interface LedgerCursorV3 {
111
+ genesis_id: string;
112
+ segment_ordinal: number;
113
+ byte_offset: number;
114
+ event_id: string;
115
+ }
116
+
117
+ export interface ReadLedgerV3SinceResult extends ReadLedgerV3Result {
118
+ cursor?: LedgerCursorV3;
119
+ reset_required: boolean;
120
+ }
121
+
122
+ /** Inspect one failed active authority without weakening the canonical read boundary. */
123
+ export function inspectInvalidActiveAuthorityV3(
124
+ coordRoot: string,
125
+ controlReason: string,
126
+ ): EventV3RecoveryFailure {
127
+ const paths = eventV3Paths(coordRoot);
128
+ const ledger = readLedgerV3(coordRoot, { authority: "active" });
129
+ if (ledger.complete || ledger.diagnostics.length === 0) {
130
+ throw new Error("event_v3_recovery_requires_incomplete_ledger");
131
+ }
132
+ const diagnostic = [...ledger.diagnostics].sort(
133
+ (left, right) =>
134
+ left.segment_ordinal - right.segment_ordinal || left.byte_offset - right.byte_offset,
135
+ )[0]!;
136
+ const activeOrdinal = existsSync(paths.catalog)
137
+ ? readEventV3Catalog(paths.catalog).active.ordinal
138
+ : 1;
139
+ if (diagnostic.segment_ordinal !== activeOrdinal) {
140
+ throw new Error("event_v3_recovery_first_failure_is_not_in_active_authority");
141
+ }
142
+ const active = readFileSync(paths.active);
143
+ if (diagnostic.byte_offset > active.length) {
144
+ throw new Error("event_v3_recovery_diagnostic_offset_exceeds_active_authority");
145
+ }
146
+ return {
147
+ control_reason: controlReason,
148
+ authority_digest: digestEventV3AuthorityDirectoryV3(paths.root),
149
+ active_digest: sha256V3(active),
150
+ active_bytes: active.length,
151
+ validated_prefix_digest: sha256V3(active.subarray(0, diagnostic.byte_offset)),
152
+ validated_prefix_bytes: diagnostic.byte_offset,
153
+ diagnostic: {
154
+ code: diagnostic.code,
155
+ segment_ordinal: diagnostic.segment_ordinal,
156
+ byte_offset: diagnostic.byte_offset,
157
+ ...(diagnostic.event_id ? { event_id: diagnostic.event_id } : {}),
158
+ },
159
+ };
160
+ }
161
+
162
+ /** Hash one preserved V3 authority by relative path, byte count, and file digest. */
163
+ export function digestEventV3AuthorityDirectoryV3(root: string): `sha256:${string}` {
164
+ const base = resolve(root);
165
+ if (!lstatSync(base).isDirectory()) throw new Error("V3 authority root is not a directory");
166
+ const files: Array<{ path: string; bytes: number; digest: `sha256:${string}` }> = [];
167
+ const visit = (directory: string) => {
168
+ for (const entry of readdirSync(directory, { withFileTypes: true })) {
169
+ const path = join(directory, entry.name);
170
+ if (entry.isSymbolicLink()) throw new Error("V3 authority contains a symbolic link");
171
+ if (entry.isDirectory()) {
172
+ visit(path);
173
+ continue;
174
+ }
175
+ if (!entry.isFile()) throw new Error("V3 authority contains a non-regular file");
176
+ const bytes = readFileSync(path);
177
+ files.push({
178
+ path: relative(base, path).replaceAll("\\", "/"),
179
+ bytes: bytes.length,
180
+ digest: sha256V3(bytes),
181
+ });
182
+ }
183
+ };
184
+ visit(base);
185
+ files.sort((left, right) => left.path.localeCompare(right.path));
186
+ return `sha256:${createHash("sha256").update(canonicalJsonV3(files)).digest("hex")}`;
187
+ }
188
+
189
+ interface PendingAdvance {
190
+ event_id: string;
191
+ next_schema_digest: string;
192
+ position: LedgerFrameV3["position"];
193
+ }
194
+
195
+ interface EventShape {
196
+ contract: { schema_digest: string };
197
+ event_id: string;
198
+ event_type: string;
199
+ time: {
200
+ observed_at: string;
201
+ clock_id: string;
202
+ monotonic_ns?: string;
203
+ skew: string;
204
+ };
205
+ producer: { producer_id: string; boot_id: string; sequence: number };
206
+ links: { caused_by: string[] };
207
+ attestation_id?: string;
208
+ payload: Record<string, unknown>;
209
+ }
210
+
211
+ interface DiscoveredFramesV3 {
212
+ frames: LedgerFrameV3[];
213
+ diagnostics: LedgerDiagnosticV3[];
214
+ bytes: number;
215
+ active?: {
216
+ bytes: number;
217
+ path: string;
218
+ segment_ordinal: number;
219
+ };
220
+ }
221
+
222
+ interface LedgerStorageVersionV3 {
223
+ fingerprint: string;
224
+ stable_fingerprint: string;
225
+ active?: {
226
+ path: string;
227
+ size: number;
228
+ };
229
+ }
230
+
231
+ interface LedgerValidationStateV3 {
232
+ diagnostics: LedgerDiagnosticV3[];
233
+ events: PositionedEventV3[];
234
+ advances: SchemaAdvanceV3[];
235
+ accepted: Set<string>;
236
+ reader_build: string;
237
+ seen_ids: Map<string, string>;
238
+ producer_sequences: Map<string, number>;
239
+ attestations: Set<string>;
240
+ clocks: Map<string, { observed_at_ms: number; monotonic_ns?: bigint }>;
241
+ first_position?: LedgerFrameV3["position"];
242
+ genesis_id?: string;
243
+ active_schema_digest?: string;
244
+ pending?: PendingAdvance;
245
+ }
246
+
247
+ interface CachedLedgerReadV3 {
248
+ storage: LedgerStorageVersionV3;
249
+ active?: DiscoveredFramesV3["active"];
250
+ validation_state: LedgerValidationStateV3;
251
+ result: ReadLedgerV3Result;
252
+ }
253
+
254
+ const MAX_CACHED_LEDGER_READS = 4;
255
+ const ledgerReadCacheV3 = new Map<string, CachedLedgerReadV3>();
256
+
257
+ export const EVENT_V3_LEDGER_RELATIVE_ROOT = ".harnery/ledgers/v3" as const;
258
+
259
+ export function eventV3Paths(coordRoot: string) {
260
+ const root = join(resolve(coordRoot), EVENT_V3_LEDGER_RELATIVE_ROOT);
261
+ return {
262
+ root,
263
+ active: join(root, "active.ndjson"),
264
+ catalog: join(root, "catalog.json"),
265
+ segments: join(root, "segments"),
266
+ };
267
+ }
268
+
269
+ /** Stable file target for change notification only; reads still go through readLedgerV3. */
270
+ export function eventV3ActiveWatchPath(coordRoot: string): string {
271
+ return eventV3Paths(coordRoot).active;
272
+ }
273
+
274
+ /** Read the complete V3 ledger through catalog-bound filesystem discovery. */
275
+ export function readLedgerV3(
276
+ coordRoot: string,
277
+ options: ReadLedgerV3Options = {},
278
+ ): ReadLedgerV3Result {
279
+ const cacheKey = ledgerReadCacheKeyV3(coordRoot, options);
280
+ const storage = ledgerStorageVersionV3(coordRoot);
281
+ const cached = ledgerReadCacheV3.get(cacheKey);
282
+ if (cached?.storage.fingerprint === storage.fingerprint) {
283
+ ledgerReadCacheV3.delete(cacheKey);
284
+ ledgerReadCacheV3.set(cacheKey, cached);
285
+ return cached.result;
286
+ }
287
+
288
+ const resumed = cached ? resumeCachedLedgerReadV3(cached, storage, options) : undefined;
289
+ if (resumed) {
290
+ rememberLedgerReadV3(cacheKey, resumed);
291
+ return resumed.result;
292
+ }
293
+
294
+ const discovered = discoverLedgerFramesV3(coordRoot);
295
+ const validated = validateLedgerFramesV3(discovered.frames, options);
296
+ const recovery = discoverRecoveryReceiptsV3(coordRoot);
297
+ const diagnostics = [
298
+ ...discovered.diagnostics,
299
+ ...validated.result.diagnostics,
300
+ ...recovery.diagnostics,
301
+ ];
302
+ const result = {
303
+ ...validated.result,
304
+ diagnostics,
305
+ complete: diagnostics.length === 0,
306
+ bytes: discovered.bytes,
307
+ failed_epochs: recovery.receipts,
308
+ };
309
+ rememberLedgerReadV3(cacheKey, {
310
+ storage,
311
+ active: discovered.active,
312
+ validation_state: isolateValidationStateV3(validated.state),
313
+ result,
314
+ });
315
+ return result;
316
+ }
317
+
318
+ function rememberLedgerReadV3(cacheKey: string, cached: CachedLedgerReadV3): void {
319
+ ledgerReadCacheV3.delete(cacheKey);
320
+ ledgerReadCacheV3.set(cacheKey, cached);
321
+ while (ledgerReadCacheV3.size > MAX_CACHED_LEDGER_READS) {
322
+ const oldestKey = ledgerReadCacheV3.keys().next().value;
323
+ if (oldestKey === undefined) break;
324
+ ledgerReadCacheV3.delete(oldestKey);
325
+ }
326
+ }
327
+
328
+ export function readLedgerV3Since(
329
+ coordRoot: string,
330
+ cursor?: LedgerCursorV3,
331
+ options: ReadLedgerV3Options = {},
332
+ ): ReadLedgerV3SinceResult {
333
+ const discovered = discoverLedgerFramesV3(coordRoot);
334
+ const read = readLedgerFramesV3Since(discovered.frames, cursor, options);
335
+ const recovery = discoverRecoveryReceiptsV3(coordRoot);
336
+ const diagnostics = [...discovered.diagnostics, ...read.diagnostics, ...recovery.diagnostics];
337
+ return {
338
+ ...read,
339
+ events: diagnostics.length === 0 ? read.events : [],
340
+ diagnostics,
341
+ complete: diagnostics.length === 0,
342
+ bytes: discovered.bytes,
343
+ failed_epochs: recovery.receipts,
344
+ };
345
+ }
346
+
347
+ function discoverRecoveryReceiptsV3(coordRoot: string): {
348
+ receipts: EventV3RecoveryReceipt[];
349
+ diagnostics: LedgerDiagnosticV3[];
350
+ } {
351
+ try {
352
+ return { receipts: listEventV3RecoveryReceipts(coordRoot), diagnostics: [] };
353
+ } catch {
354
+ return {
355
+ receipts: [],
356
+ diagnostics: [storageDiagnostic("recovery_record_invalid", 0)],
357
+ };
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Validate an already-discovered V3 event stream in exact physical order.
363
+ * Filesystem/catalog discovery feeds this boundary; every downstream reader
364
+ * and projection consumes its positioned, authority-checked result.
365
+ */
366
+ export function readLedgerFramesV3(
367
+ frames: readonly LedgerFrameV3[],
368
+ options: ReadLedgerV3Options = {},
369
+ ): ReadLedgerV3Result {
370
+ return validateLedgerFramesV3(frames, options).result;
371
+ }
372
+
373
+ function validateLedgerFramesV3(
374
+ frames: readonly LedgerFrameV3[],
375
+ options: ReadLedgerV3Options,
376
+ ): { result: ReadLedgerV3Result; state: LedgerValidationStateV3 } {
377
+ const state: LedgerValidationStateV3 = {
378
+ diagnostics: [],
379
+ events: [],
380
+ advances: [],
381
+ accepted: new Set(options.accepted_schema_digests ?? [EVENT_V3_SCHEMA_DIGEST]),
382
+ reader_build: options.reader_build ?? "build_harnery-v3",
383
+ seen_ids: new Map(),
384
+ producer_sequences: new Map(),
385
+ attestations: new Set(),
386
+ clocks: new Map(),
387
+ };
388
+ validateLedgerFramesIntoStateV3(frames, state);
389
+ return { result: finishLedgerValidationV3(state, options, ledgerFramesBytesV3(frames)), state };
390
+ }
391
+
392
+ function validateLedgerFramesIntoStateV3(
393
+ frames: readonly LedgerFrameV3[],
394
+ state: LedgerValidationStateV3,
395
+ ): void {
396
+ state.first_position ??= frames[0]?.position;
397
+ const {
398
+ diagnostics,
399
+ events,
400
+ advances,
401
+ accepted,
402
+ reader_build: readerBuild,
403
+ seen_ids: seenIds,
404
+ producer_sequences: producerSequences,
405
+ attestations,
406
+ clocks,
407
+ } = state;
408
+
409
+ for (const frame of frames) {
410
+ if (state.pending) {
411
+ const comparison = comparePosition(frame.position, state.pending.position);
412
+ if (comparison === 0) {
413
+ state.active_schema_digest = state.pending.next_schema_digest;
414
+ state.pending = undefined;
415
+ } else if (comparison > 0) {
416
+ diagnostics.push(diagnostic("advance_boundary_missed", frame, state.pending.event_id));
417
+ state.pending = undefined;
418
+ }
419
+ }
420
+
421
+ let parsed: unknown;
422
+ try {
423
+ parsed = JSON.parse(frame.raw);
424
+ } catch {
425
+ diagnostics.push(diagnostic("malformed_json", frame));
426
+ continue;
427
+ }
428
+ const loose = parsed as Record<string, unknown>;
429
+ const looseContract = record(loose.contract);
430
+ if (looseContract.major !== 3) {
431
+ diagnostics.push(diagnostic("unsupported_major", frame));
432
+ continue;
433
+ }
434
+ const validation = validateEventV3(parsed);
435
+ if (!validation.ok || !validation.event) {
436
+ diagnostics.push(diagnostic("invalid_contract", frame));
437
+ continue;
438
+ }
439
+ const event = validation.event;
440
+ const shape = event as unknown as EventShape;
441
+ if (canonicalJsonV3(event) !== frame.raw) {
442
+ diagnostics.push(diagnostic("noncanonical_frame", frame, shape.event_id));
443
+ continue;
444
+ }
445
+ const priorFrame = seenIds.get(shape.event_id);
446
+ if (priorFrame !== undefined) {
447
+ if (priorFrame !== frame.raw) {
448
+ diagnostics.push(diagnostic("conflicting_event_id", frame, shape.event_id));
449
+ }
450
+ continue;
451
+ }
452
+ seenIds.set(shape.event_id, frame.raw);
453
+
454
+ if (shape.event_type === "ledger.genesis") {
455
+ if (state.genesis_id !== undefined) {
456
+ diagnostics.push(diagnostic("multiple_genesis", frame, shape.event_id));
457
+ continue;
458
+ }
459
+ if (events.length !== 0)
460
+ diagnostics.push(diagnostic("genesis_not_first", frame, shape.event_id));
461
+ const payload = shape.payload;
462
+ state.genesis_id = string(payload.genesis_id);
463
+ state.active_schema_digest = string(payload.generated_schema_digest);
464
+ if (state.active_schema_digest !== shape.contract.schema_digest) {
465
+ diagnostics.push(diagnostic("genesis_digest_mismatch", frame, shape.event_id));
466
+ }
467
+ } else if (state.genesis_id === undefined) {
468
+ diagnostics.push(diagnostic("missing_genesis", frame, shape.event_id));
469
+ }
470
+
471
+ if (!accepted.has(shape.contract.schema_digest)) {
472
+ diagnostics.push(diagnostic("unsupported_schema_digest", frame, shape.event_id));
473
+ }
474
+ if (
475
+ state.active_schema_digest !== undefined &&
476
+ shape.contract.schema_digest !== state.active_schema_digest
477
+ ) {
478
+ diagnostics.push(diagnostic("unexpected_schema_digest", frame, shape.event_id));
479
+ }
480
+
481
+ for (const parentId of shape.links.caused_by) {
482
+ if (!seenIds.has(parentId)) {
483
+ diagnostics.push(diagnostic("causal_parent_missing", frame, shape.event_id));
484
+ break;
485
+ }
486
+ }
487
+ validateClock(shape, frame, clocks, diagnostics);
488
+ validateAttestation(shape, frame, attestations, diagnostics);
489
+ validateProducerSequence(shape, frame, producerSequences, diagnostics);
490
+
491
+ if (shape.event_type === "ledger.schema_advanced") {
492
+ const payload = shape.payload;
493
+ const nextDigest = string(payload.next_schema_digest);
494
+ const priorDigest = string(payload.prior_schema_digest);
495
+ const effectivePosition = {
496
+ segment_ordinal: number(payload.effective_segment_ordinal),
497
+ byte_offset: number(payload.effective_byte_offset),
498
+ };
499
+ if (priorDigest !== state.active_schema_digest) {
500
+ diagnostics.push(diagnostic("advance_prior_mismatch", frame, shape.event_id));
501
+ }
502
+ if (!accepted.has(nextDigest)) {
503
+ diagnostics.push(diagnostic("advance_digest_unsupported", frame, shape.event_id));
504
+ }
505
+ const compatibleBuilds = stringArray(payload.compatible_reader_builds);
506
+ if (!compatibleBuilds.includes(readerBuild)) {
507
+ diagnostics.push(diagnostic("advance_reader_incompatible", frame, shape.event_id));
508
+ }
509
+ if (comparePosition(effectivePosition, frame.position) <= 0 || state.pending) {
510
+ diagnostics.push(diagnostic("advance_boundary_invalid", frame, shape.event_id));
511
+ } else {
512
+ state.pending = {
513
+ event_id: shape.event_id,
514
+ next_schema_digest: nextDigest,
515
+ position: effectivePosition,
516
+ };
517
+ advances.push({
518
+ event_id: shape.event_id,
519
+ prior_schema_digest: priorDigest,
520
+ next_schema_digest: nextDigest,
521
+ effective_position: effectivePosition,
522
+ });
523
+ }
524
+ }
525
+
526
+ events.push({ event, position: frame.position });
527
+ }
528
+ }
529
+
530
+ function finishLedgerValidationV3(
531
+ state: LedgerValidationStateV3,
532
+ options: ReadLedgerV3Options,
533
+ bytes: number,
534
+ ): ReadLedgerV3Result {
535
+ const diagnostics = [...state.diagnostics];
536
+ if (
537
+ state.genesis_id === undefined &&
538
+ !diagnostics.some(({ code }) => code === "missing_genesis")
539
+ ) {
540
+ diagnostics.push({
541
+ code: "missing_genesis",
542
+ segment_ordinal: state.first_position?.segment_ordinal ?? 0,
543
+ byte_offset: state.first_position?.byte_offset ?? 0,
544
+ });
545
+ }
546
+ if (options.authority === "active" && state.genesis_id !== undefined) {
547
+ const activations = state.events.filter(
548
+ ({ event }) => (event as unknown as EventShape).event_type === "ledger.activated",
549
+ );
550
+ if (activations.length === 0) {
551
+ diagnostics.push({ code: "missing_activation", segment_ordinal: 0, byte_offset: 0 });
552
+ } else {
553
+ const activation = activations.at(-1)!;
554
+ const payload = (activation.event as unknown as EventShape).payload;
555
+ if (payload.genesis_id !== state.genesis_id) {
556
+ diagnostics.push(
557
+ diagnostic(
558
+ "activation_genesis_mismatch",
559
+ {
560
+ raw: "",
561
+ position: activation.position,
562
+ },
563
+ (activation.event as unknown as EventShape).event_id,
564
+ ),
565
+ );
566
+ }
567
+ }
568
+ }
569
+
570
+ return {
571
+ events: state.events,
572
+ diagnostics,
573
+ complete: diagnostics.length === 0,
574
+ genesis_id: state.genesis_id,
575
+ active_schema_digest: state.active_schema_digest,
576
+ advances: state.advances,
577
+ bytes,
578
+ failed_epochs: [],
579
+ };
580
+ }
581
+
582
+ function ledgerFramesBytesV3(frames: readonly LedgerFrameV3[]): number {
583
+ return frames.reduce((total, frame) => total + Buffer.byteLength(frame.raw, "utf8") + 1, 0);
584
+ }
585
+
586
+ export function readLedgerFramesV3Since(
587
+ frames: readonly LedgerFrameV3[],
588
+ cursor?: LedgerCursorV3,
589
+ options: ReadLedgerV3Options = {},
590
+ ): ReadLedgerV3SinceResult {
591
+ const read = readLedgerFramesV3(frames, options);
592
+ if (!read.genesis_id || !read.complete) {
593
+ return { ...read, events: [], cursor, reset_required: Boolean(cursor) };
594
+ }
595
+ if (cursor?.genesis_id !== undefined && cursor.genesis_id !== read.genesis_id) {
596
+ return withCursorDiagnostic(read, "cursor_genesis_mismatch", cursor);
597
+ }
598
+ let startIndex = 0;
599
+ if (cursor) {
600
+ const index = read.events.findIndex(
601
+ ({ event, position }) =>
602
+ (event as unknown as EventShape).event_id === cursor.event_id &&
603
+ position.segment_ordinal === cursor.segment_ordinal &&
604
+ position.byte_offset === cursor.byte_offset,
605
+ );
606
+ if (index < 0) return withCursorDiagnostic(read, "cursor_position_missing", cursor);
607
+ startIndex = index + 1;
608
+ }
609
+ const last = read.events.at(-1);
610
+ return {
611
+ ...read,
612
+ events: read.events.slice(startIndex),
613
+ cursor: last
614
+ ? {
615
+ genesis_id: read.genesis_id,
616
+ segment_ordinal: last.position.segment_ordinal,
617
+ byte_offset: last.position.byte_offset,
618
+ event_id: (last.event as unknown as EventShape).event_id,
619
+ }
620
+ : cursor,
621
+ reset_required: false,
622
+ };
623
+ }
624
+
625
+ function validateAttestation(
626
+ event: EventShape,
627
+ frame: LedgerFrameV3,
628
+ attestations: Set<string>,
629
+ diagnostics: LedgerDiagnosticV3[],
630
+ ): void {
631
+ if (event.event_type === "session.started") {
632
+ if (event.attestation_id) attestations.add(event.attestation_id);
633
+ return;
634
+ }
635
+ if (event.event_type === "session.attestation_changed") {
636
+ const prior = string(event.payload.prior_attestation_id);
637
+ if (!attestations.has(prior)) {
638
+ diagnostics.push(diagnostic("unresolved_attestation", frame, event.event_id));
639
+ }
640
+ if (event.attestation_id) attestations.add(event.attestation_id);
641
+ return;
642
+ }
643
+ if (event.attestation_id && !attestations.has(event.attestation_id)) {
644
+ diagnostics.push(diagnostic("unresolved_attestation", frame, event.event_id));
645
+ }
646
+ }
647
+
648
+ function validateClock(
649
+ event: EventShape,
650
+ frame: LedgerFrameV3,
651
+ clocks: Map<string, { observed_at_ms: number; monotonic_ns?: bigint }>,
652
+ diagnostics: LedgerDiagnosticV3[],
653
+ ): void {
654
+ const prior = clocks.get(event.time.clock_id);
655
+ const observedAtMs = Date.parse(event.time.observed_at);
656
+ if (prior && observedAtMs < prior.observed_at_ms && event.time.skew !== "regressed") {
657
+ diagnostics.push(diagnostic("wall_clock_regression_unmarked", frame, event.event_id));
658
+ }
659
+ const monotonicNs = event.time.monotonic_ns ? BigInt(event.time.monotonic_ns) : undefined;
660
+ if (
661
+ prior?.monotonic_ns !== undefined &&
662
+ monotonicNs !== undefined &&
663
+ monotonicNs < prior.monotonic_ns
664
+ ) {
665
+ diagnostics.push(diagnostic("monotonic_clock_regression", frame, event.event_id));
666
+ }
667
+ clocks.set(event.time.clock_id, {
668
+ observed_at_ms: observedAtMs,
669
+ ...(monotonicNs !== undefined ? { monotonic_ns: monotonicNs } : {}),
670
+ });
671
+ }
672
+
673
+ function validateProducerSequence(
674
+ event: EventShape,
675
+ frame: LedgerFrameV3,
676
+ sequences: Map<string, number>,
677
+ diagnostics: LedgerDiagnosticV3[],
678
+ ): void {
679
+ const key = `${event.producer.producer_id}\0${event.producer.boot_id}`;
680
+ const prior = sequences.get(key);
681
+ if (
682
+ (prior === undefined && event.producer.sequence !== 1) ||
683
+ (prior !== undefined && event.producer.sequence !== prior + 1)
684
+ ) {
685
+ diagnostics.push(diagnostic("producer_sequence_gap", frame, event.event_id));
686
+ }
687
+ sequences.set(key, event.producer.sequence);
688
+ }
689
+
690
+ function withCursorDiagnostic(
691
+ read: ReadLedgerV3Result,
692
+ code: "cursor_genesis_mismatch" | "cursor_position_missing",
693
+ cursor: LedgerCursorV3,
694
+ ): ReadLedgerV3SinceResult {
695
+ return {
696
+ ...read,
697
+ events: [],
698
+ diagnostics: [
699
+ ...read.diagnostics,
700
+ {
701
+ code,
702
+ segment_ordinal: cursor.segment_ordinal,
703
+ byte_offset: cursor.byte_offset,
704
+ event_id: cursor.event_id,
705
+ },
706
+ ],
707
+ complete: false,
708
+ reset_required: true,
709
+ };
710
+ }
711
+
712
+ function diagnostic(
713
+ code: LedgerDiagnosticCodeV3,
714
+ frame: LedgerFrameV3,
715
+ eventId?: string,
716
+ ): LedgerDiagnosticV3 {
717
+ return {
718
+ code,
719
+ segment_ordinal: frame.position.segment_ordinal,
720
+ byte_offset: frame.position.byte_offset,
721
+ ...(eventId ? { event_id: eventId } : {}),
722
+ };
723
+ }
724
+
725
+ function comparePosition(
726
+ left: LedgerFrameV3["position"],
727
+ right: LedgerFrameV3["position"],
728
+ ): number {
729
+ return left.segment_ordinal - right.segment_ordinal || left.byte_offset - right.byte_offset;
730
+ }
731
+
732
+ function record(value: unknown): Record<string, unknown> {
733
+ return value && typeof value === "object" && !Array.isArray(value)
734
+ ? (value as Record<string, unknown>)
735
+ : {};
736
+ }
737
+
738
+ function string(value: unknown): string {
739
+ return typeof value === "string" ? value : "";
740
+ }
741
+
742
+ function number(value: unknown): number {
743
+ return typeof value === "number" ? value : -1;
744
+ }
745
+
746
+ function stringArray(value: unknown): string[] {
747
+ return Array.isArray(value)
748
+ ? value.filter((item): item is string => typeof item === "string")
749
+ : [];
750
+ }
751
+
752
+ function ledgerReadCacheKeyV3(coordRoot: string, options: ReadLedgerV3Options): string {
753
+ const accepted = [...new Set(options.accepted_schema_digests ?? [EVENT_V3_SCHEMA_DIGEST])].sort();
754
+ return JSON.stringify([
755
+ resolve(coordRoot),
756
+ options.authority ?? "",
757
+ options.reader_build ?? "",
758
+ accepted,
759
+ ]);
760
+ }
761
+
762
+ function resumeCachedLedgerReadV3(
763
+ cached: CachedLedgerReadV3,
764
+ storage: LedgerStorageVersionV3,
765
+ options: ReadLedgerV3Options,
766
+ ): CachedLedgerReadV3 | undefined {
767
+ if (
768
+ !cached.result.complete ||
769
+ !cached.active ||
770
+ !storage.active ||
771
+ cached.storage.stable_fingerprint !== storage.stable_fingerprint ||
772
+ cached.active.path !== storage.active.path ||
773
+ storage.active.size <= cached.active.bytes
774
+ ) {
775
+ return undefined;
776
+ }
777
+ const appended = readActiveRangeV3(
778
+ storage.active.path,
779
+ cached.active.bytes,
780
+ storage.active.size,
781
+ cached.active.segment_ordinal,
782
+ );
783
+ if (!appended) return undefined;
784
+
785
+ const state: LedgerValidationStateV3 = {
786
+ ...cached.validation_state,
787
+ diagnostics: [],
788
+ events: [...cached.validation_state.events],
789
+ advances: [...cached.validation_state.advances],
790
+ };
791
+ validateLedgerFramesIntoStateV3(appended.frames, state);
792
+ const validated = finishLedgerValidationV3(state, options, cached.result.bytes + appended.bytes);
793
+ const diagnostics = [...appended.diagnostics, ...validated.diagnostics];
794
+ return {
795
+ storage,
796
+ active: {
797
+ ...cached.active,
798
+ bytes: storage.active.size,
799
+ },
800
+ validation_state: isolateValidationStateV3(state),
801
+ result: {
802
+ ...validated,
803
+ diagnostics,
804
+ complete: diagnostics.length === 0,
805
+ failed_epochs: cached.result.failed_epochs,
806
+ },
807
+ };
808
+ }
809
+
810
+ function isolateValidationStateV3(state: LedgerValidationStateV3): LedgerValidationStateV3 {
811
+ return {
812
+ ...state,
813
+ diagnostics: [...state.diagnostics],
814
+ events: [...state.events],
815
+ advances: [...state.advances],
816
+ };
817
+ }
818
+
819
+ function readActiveRangeV3(
820
+ path: string,
821
+ start: number,
822
+ end: number,
823
+ segmentOrdinal: number,
824
+ ): DiscoveredFramesV3 | undefined {
825
+ const length = end - start;
826
+ const bytes = Buffer.alloc(length);
827
+ let offset = 0;
828
+ let fd: number | undefined;
829
+ try {
830
+ fd = openSync(path, "r");
831
+ while (offset < length) {
832
+ const read = readSync(fd, bytes, offset, length - offset, start + offset);
833
+ if (read === 0) return undefined;
834
+ offset += read;
835
+ }
836
+ } catch {
837
+ return undefined;
838
+ } finally {
839
+ if (fd !== undefined) closeSync(fd);
840
+ }
841
+ return framesFromBytes(bytes, segmentOrdinal, true, start);
842
+ }
843
+
844
+ /**
845
+ * Cheap identity for every filesystem object that can change discovery.
846
+ * Capture it before reading: a concurrent append then changes the next call's
847
+ * fingerprint, so a read that raced the writer is never retained as current.
848
+ */
849
+ function ledgerStorageVersionV3(coordRoot: string): LedgerStorageVersionV3 {
850
+ const paths = eventV3Paths(coordRoot);
851
+ const catalog = pathStorageVersionV3(paths.catalog);
852
+ const active = pathStorageVersionV3(paths.active);
853
+ const parts = [`catalog:${catalog.fingerprint}`];
854
+ const stableParts = [`catalog:${catalog.fingerprint}`, `active:${active.stable_fingerprint}`];
855
+ let names: string[];
856
+ try {
857
+ names = readdirSync(paths.segments)
858
+ .filter((name) => /^(\d{12})\.(ndjson|manifest\.json)$/.test(name))
859
+ .sort();
860
+ } catch (error) {
861
+ const segmentError = `segments:${filesystemErrorCode(error)}`;
862
+ parts.push(segmentError);
863
+ stableParts.push(segmentError);
864
+ return {
865
+ fingerprint: [...parts, `active:${active.fingerprint}`].join("|"),
866
+ stable_fingerprint: stableParts.join("|"),
867
+ ...(active.regular ? { active: { path: paths.active, size: active.size } } : {}),
868
+ };
869
+ }
870
+ for (const name of names) {
871
+ const part = `segment:${name}:${pathStorageVersionV3(join(paths.segments, name)).fingerprint}`;
872
+ parts.push(part);
873
+ stableParts.push(part);
874
+ }
875
+ const recoveryRoot = eventV3RecoveryRecordsRoot(coordRoot);
876
+ let recoveryNames: string[] = [];
877
+ try {
878
+ recoveryNames = readdirSync(recoveryRoot)
879
+ .filter((name) => name.endsWith(".committed.json"))
880
+ .sort();
881
+ } catch (error) {
882
+ const code = filesystemErrorCode(error);
883
+ if (code !== "ENOENT") {
884
+ const part = `recoveries:${code}`;
885
+ parts.push(part);
886
+ stableParts.push(part);
887
+ }
888
+ }
889
+ for (const name of recoveryNames) {
890
+ const part = `recovery:${name}:${pathStorageVersionV3(join(recoveryRoot, name)).fingerprint}`;
891
+ parts.push(part);
892
+ stableParts.push(part);
893
+ }
894
+ return {
895
+ fingerprint: [...parts, `active:${active.fingerprint}`].join("|"),
896
+ stable_fingerprint: stableParts.join("|"),
897
+ ...(active.regular ? { active: { path: paths.active, size: active.size } } : {}),
898
+ };
899
+ }
900
+
901
+ function pathStorageVersionV3(path: string): {
902
+ fingerprint: string;
903
+ stable_fingerprint: string;
904
+ regular: boolean;
905
+ size: number;
906
+ } {
907
+ try {
908
+ const stat = lstatSync(path, { bigint: true });
909
+ const stableFingerprint = [stat.mode, stat.dev, stat.ino, stat.birthtimeNs].join(":");
910
+ return {
911
+ fingerprint: [stableFingerprint, stat.size, stat.mtimeNs, stat.ctimeNs].join(":"),
912
+ stable_fingerprint: stableFingerprint,
913
+ regular: stat.isFile() && !stat.isSymbolicLink(),
914
+ size: Number(stat.size),
915
+ };
916
+ } catch (error) {
917
+ const code = filesystemErrorCode(error);
918
+ return { fingerprint: code, stable_fingerprint: code, regular: false, size: 0 };
919
+ }
920
+ }
921
+
922
+ function filesystemErrorCode(error: unknown): string {
923
+ return error && typeof error === "object" && "code" in error
924
+ ? String((error as NodeJS.ErrnoException).code)
925
+ : "unavailable";
926
+ }
927
+
928
+ function discoverLedgerFramesV3(coordRoot: string): DiscoveredFramesV3 {
929
+ const paths = eventV3Paths(coordRoot);
930
+ if (!existsSync(paths.catalog)) {
931
+ if (hasSealedV3Metadata(paths.segments)) {
932
+ return {
933
+ frames: [],
934
+ diagnostics: [storageDiagnostic("catalog_invalid", 0)],
935
+ bytes: 0,
936
+ };
937
+ }
938
+ if (!existsSync(paths.active)) return { frames: [], diagnostics: [], bytes: 0 };
939
+ const bytes = readFileSync(paths.active);
940
+ return {
941
+ ...framesFromBytes(bytes, 1, true),
942
+ active: { bytes: bytes.length, path: paths.active, segment_ordinal: 1 },
943
+ };
944
+ }
945
+
946
+ let catalog: EventV3Catalog;
947
+ try {
948
+ catalog = readEventV3Catalog(paths.catalog);
949
+ } catch {
950
+ return {
951
+ frames: [],
952
+ diagnostics: [storageDiagnostic("catalog_invalid", 0)],
953
+ bytes: 0,
954
+ };
955
+ }
956
+
957
+ const discovered: DiscoveredFramesV3 = { frames: [], diagnostics: [], bytes: 0 };
958
+ for (const entry of catalog.segments) {
959
+ discoverSealedSegment(paths.segments, entry, discovered);
960
+ }
961
+ discoverActiveSegment(paths.active, catalog, discovered);
962
+ return discovered;
963
+ }
964
+
965
+ function discoverSealedSegment(
966
+ segmentsRoot: string,
967
+ entry: EventV3Catalog["segments"][number],
968
+ discovered: DiscoveredFramesV3,
969
+ ): void {
970
+ const segmentPath = join(segmentsRoot, entry.segment_file);
971
+ const manifestPath = join(segmentsRoot, entry.manifest_file);
972
+ if (!regularFile(segmentPath) || !regularFile(manifestPath)) {
973
+ discovered.diagnostics.push(storageDiagnostic("missing_segment", entry.ordinal));
974
+ return;
975
+ }
976
+ const segmentBytes = readFileSync(segmentPath);
977
+ const manifestBytes = readFileSync(manifestPath);
978
+ discovered.bytes += segmentBytes.length;
979
+ if (segmentBytes.length !== entry.bytes || sha256V3(segmentBytes) !== entry.segment_digest) {
980
+ discovered.diagnostics.push(storageDiagnostic("segment_digest_mismatch", entry.ordinal));
981
+ return;
982
+ }
983
+ if (sha256V3(manifestBytes) !== entry.manifest_digest) {
984
+ discovered.diagnostics.push(storageDiagnostic("manifest_digest_mismatch", entry.ordinal));
985
+ return;
986
+ }
987
+ let manifest: EventV3SegmentManifest;
988
+ try {
989
+ manifest = readEventV3SegmentManifest(manifestPath);
990
+ } catch {
991
+ discovered.diagnostics.push(storageDiagnostic("manifest_segment_mismatch", entry.ordinal));
992
+ return;
993
+ }
994
+ const segment = framesFromBytes(segmentBytes, entry.ordinal, false);
995
+ if (
996
+ !manifestMatchesCatalog(manifest, entry) ||
997
+ !manifestMatchesFrames(manifest, segment.frames)
998
+ ) {
999
+ discovered.diagnostics.push(storageDiagnostic("manifest_segment_mismatch", entry.ordinal));
1000
+ return;
1001
+ }
1002
+ discovered.frames.push(...segment.frames);
1003
+ discovered.diagnostics.push(...segment.diagnostics);
1004
+ }
1005
+
1006
+ function discoverActiveSegment(
1007
+ activePath: string,
1008
+ catalog: EventV3Catalog,
1009
+ discovered: DiscoveredFramesV3,
1010
+ ): void {
1011
+ if (!regularFile(activePath)) {
1012
+ discovered.diagnostics.push(storageDiagnostic("active_replaced", catalog.active.ordinal));
1013
+ return;
1014
+ }
1015
+ const stat = statSync(activePath);
1016
+ const bigintStat = statSync(activePath, { bigint: true });
1017
+ if (
1018
+ String(stat.dev) !== catalog.active.device ||
1019
+ String(stat.ino) !== catalog.active.inode ||
1020
+ String(bigintStat.birthtimeNs) !== catalog.active.birthtime_ns
1021
+ ) {
1022
+ discovered.diagnostics.push(storageDiagnostic("active_replaced", catalog.active.ordinal));
1023
+ return;
1024
+ }
1025
+ const bytes = readFileSync(activePath);
1026
+ const active = framesFromBytes(bytes, catalog.active.ordinal, true);
1027
+ discovered.frames.push(...active.frames);
1028
+ discovered.diagnostics.push(...active.diagnostics);
1029
+ discovered.bytes += bytes.length;
1030
+ discovered.active = {
1031
+ bytes: bytes.length,
1032
+ path: activePath,
1033
+ segment_ordinal: catalog.active.ordinal,
1034
+ };
1035
+ }
1036
+
1037
+ function framesFromBytes(
1038
+ bytes: Buffer,
1039
+ segmentOrdinal: number,
1040
+ allowPartialFinalFrame: boolean,
1041
+ initialByteOffset = 0,
1042
+ ): DiscoveredFramesV3 {
1043
+ const raw = bytes.toString("utf8");
1044
+ const frames: LedgerFrameV3[] = [];
1045
+ const diagnostics: LedgerDiagnosticV3[] = [];
1046
+ const lines = raw.split("\n");
1047
+ let byteOffset = initialByteOffset;
1048
+ for (const [index, line] of lines.entries()) {
1049
+ const final = index === lines.length - 1;
1050
+ const lineBytes = Buffer.byteLength(line, "utf8");
1051
+ if (line.length === 0) {
1052
+ if (!final) {
1053
+ diagnostics.push(storageDiagnostic("malformed_json", segmentOrdinal, byteOffset));
1054
+ byteOffset += 1;
1055
+ }
1056
+ continue;
1057
+ }
1058
+ if (final && !raw.endsWith("\n")) {
1059
+ diagnostics.push(
1060
+ storageDiagnostic(
1061
+ allowPartialFinalFrame ? "partial_final_frame" : "malformed_json",
1062
+ segmentOrdinal,
1063
+ byteOffset,
1064
+ ),
1065
+ );
1066
+ break;
1067
+ }
1068
+ frames.push({
1069
+ raw: line,
1070
+ position: { segment_ordinal: segmentOrdinal, byte_offset: byteOffset },
1071
+ });
1072
+ byteOffset += lineBytes + 1;
1073
+ }
1074
+ return { frames, diagnostics, bytes: bytes.length };
1075
+ }
1076
+
1077
+ function manifestMatchesCatalog(
1078
+ manifest: EventV3SegmentManifest,
1079
+ entry: EventV3Catalog["segments"][number],
1080
+ ): boolean {
1081
+ return (
1082
+ manifest.ordinal === entry.ordinal &&
1083
+ manifest.segment_file === entry.segment_file &&
1084
+ manifest.segment_digest === entry.segment_digest &&
1085
+ manifest.bytes === entry.bytes &&
1086
+ manifest.row_count === entry.row_count
1087
+ );
1088
+ }
1089
+
1090
+ function manifestMatchesFrames(
1091
+ manifest: EventV3SegmentManifest,
1092
+ frames: readonly LedgerFrameV3[],
1093
+ ): boolean {
1094
+ if (frames.length !== manifest.row_count) return false;
1095
+ try {
1096
+ const records = frames.map(({ raw }) => record(JSON.parse(raw)));
1097
+ const schemaDigests = [
1098
+ ...new Set(records.map((event) => string(record(event.contract).schema_digest))),
1099
+ ].sort();
1100
+ return (
1101
+ records[0]?.event_id === manifest.first_event_id &&
1102
+ records.at(-1)?.event_id === manifest.last_event_id &&
1103
+ schemaDigests.join("\0") === manifest.schema_digests.join("\0")
1104
+ );
1105
+ } catch {
1106
+ return false;
1107
+ }
1108
+ }
1109
+
1110
+ function hasSealedV3Metadata(segmentsPath: string): boolean {
1111
+ if (!existsSync(segmentsPath)) return false;
1112
+ return readdirSync(segmentsPath).some((name) => /^(\d{12})\.(ndjson|manifest\.json)$/.test(name));
1113
+ }
1114
+
1115
+ function regularFile(path: string): boolean {
1116
+ if (!existsSync(path)) return false;
1117
+ const stat = lstatSync(path);
1118
+ return stat.isFile() && !stat.isSymbolicLink();
1119
+ }
1120
+
1121
+ function storageDiagnostic(
1122
+ code: LedgerDiagnosticCodeV3,
1123
+ segmentOrdinal: number,
1124
+ byteOffset = 0,
1125
+ ): LedgerDiagnosticV3 {
1126
+ return { code, segment_ordinal: segmentOrdinal, byte_offset: byteOffset };
1127
+ }