chainlesschain 0.166.42 → 0.166.44

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 (183) hide show
  1. package/README.md +75 -14
  2. package/package.json +1 -1
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-CdsAAOAu.js → AIOps-HiHMDVK3.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-B8x5S-3u.js → ActionButton-H2RKuS8V.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-C1eOGwSM.js → Analytics-CBPFBB61.js} +3 -3
  7. package/src/assets/web-panel/assets/AppLayout-Da-3Laze.js +9 -0
  8. package/src/assets/web-panel/assets/{Artifacts-B0tiKn2i.js → Artifacts-DiRQ9yzD.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-DzGqTUvG.js → Audit-C9LtWEBh.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-CMXYcy56.js → BackgroundAgents-4rpi7fVg.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-DrN3N1_7.js → Backup-B8VQmHys.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-BC9aoifZ.js → BaseInput-iCVpF2DK.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-F3Z9p0vk.js → Chat-BrQaXBwC.js} +6 -6
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-LMGrVg9Z.js → ChatBubbleRenderer-HIyU-9c0.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-CDXlouzl.js → Checkbox-CsV__0_R.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-9c0RpaYc.js → Codegen-BvFeCIAE.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-C-60iGia.js → Col-CagxV1O8.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-DXE04H2M.js → Community-DAWr4ahG.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-B4jEuBmH.js → Compact-Ba49Tdc2.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-uf13-dcK.js → Compliance-Brk-MSO4.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-D6hpxLI4.js → Cowork-DeKH1v0o.js} +2 -2
  22. package/src/assets/web-panel/assets/{Cron-CSJobmkN.js → Cron-AHB-T-VL.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-B0_rTlsi.js → Crosschain-Zbcrtimh.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-D49FQsiZ.js → DID-ByFa1MWG.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-BvjvIYfC.js → Dashboard-9jKovyuH.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-BYe1gODU.js → Dropdown-DY8TaXi5.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-CJ6znfiH.js → EmailListRenderer-rcaSveQ8.js} +1 -1
  28. package/src/assets/web-panel/assets/EvolutionSettings-B3dcSq1H.js +1 -0
  29. package/src/assets/web-panel/assets/EvolutionSettings-Bdw8ApoT.css +1 -0
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BnoKDllh.js → FamilyGuardDashboard-5ao8smvA.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-AqhVFmd4.js → Federation-RTpNXXHT.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-CNVYBpNg.js → FormItemContext-DWZvRMWv.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-BbdYCfjH.js → GenericCardRenderer-CWi8SGvx.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-B_xClOR0.js → Git-CCLgDIqs.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-CIKCDF9F.js → Governance-DUuyKrQl.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-BdRSc0oa.js → Inference-RkFcM2A0.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-DknpIQPx.js → KnowledgeGraph-C-QTauZr.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-BcCPhMaZ.js → Logs-B-7Dz5Ui.js} +2 -2
  39. package/src/assets/web-panel/assets/MarkdownRenderer-CgiHBe0A.js +1 -0
  40. package/src/assets/web-panel/assets/{Marketplace-DEMNuvwO.js → Marketplace-CK1kSFDt.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-D-tg9wfq.js → McpTools-BcaVwoY6.js} +2 -2
  42. package/src/assets/web-panel/assets/{Memory-BqCLu-X9.js → Memory-QEI4xRwF.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-bN6vwbZc.js → MobileBridge-BqD-R0Ek.js} +1 -1
  44. package/src/assets/web-panel/assets/{MobileProjects-BTM0-1MZ.js → MobileProjects-CwFoXf1M.js} +1 -1
  45. package/src/assets/web-panel/assets/{Mtc-CcGXXyEn.js → Mtc-CTZ6qICG.js} +4 -4
  46. package/src/assets/web-panel/assets/{MtcAudit-B2Z5wPnM.js → MtcAudit-Cn7y2BzO.js} +2 -2
  47. package/src/assets/web-panel/assets/{Multisig-DNW7dKam.js → Multisig-BCjsdGiN.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-Ciz-g5G3.js → NLProgramming-CupTVNtA.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-CeiEA6yF.js → Notes-C8kO3mGt.js} +3 -3
  50. package/src/assets/web-panel/assets/{NotificationSettings-DgeiEPwB.js → NotificationSettings-Cn-MJ8sQ.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-D9DjubGK.js → OrderTableRenderer-BX4PrVfN.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-CeA2EC_G.js → Organization-G_RjOL7M.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-DT40ig7t.js → Overflow-BvX644ya.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-K4H13K3M.js → P2P-yWmLgYgQ.js} +2 -2
  55. package/src/assets/web-panel/assets/PdhVaultBrowser-yYL7-rno.js +7 -0
  56. package/src/assets/web-panel/assets/{Permissions-DYQogL6r.js → Permissions-DtU8fhcZ.js} +4 -4
  57. package/src/assets/web-panel/assets/{PersonalDataHub-DXhXVHar.js → PersonalDataHub-B17Vyk-x.js} +5 -5
  58. package/src/assets/web-panel/assets/{Pipeline-DQMdn5Ij.js → Pipeline-BZUsTyhP.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-BiF1thop.js → Privacy-BswdhlPL.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-C2ptWEn7.js → ProjectInit-sJxSlY0C.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-B5WCiDZD.js → ProjectSettings-BnbpdOke.js} +2 -2
  62. package/src/assets/web-panel/assets/{Projects-BNH6LKU6.js → Projects-DUjauf-6.js} +1 -1
  63. package/src/assets/web-panel/assets/{Providers-CgRJ8ZT1.js → Providers-DhF5I-UR.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-B3tuNJ3V.js → QrScannerModal-B3PeCAGo.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-D9CO1SNI.js → QuickAsk-Cpaxrabg.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-BGmwHY_U.js → Recommend-DqXFF66-.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-CliYaolm.js → RemoteSession-DtDQ76Ox.js} +2 -2
  68. package/src/assets/web-panel/assets/{Reputation-sCiX2kmm.js → Reputation-BgLLKwu2.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-DXHx_bk0.js → Row-BuMLhd8M.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-Bg79mIxI.js → RssFeed-BizxUzBA.js} +3 -3
  71. package/src/assets/web-panel/assets/{Search-CnKDYqyS.js → Search-CYNrJAQY.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-c-0QOrC2.js → Security-CIC02soH.js} +4 -4
  73. package/src/assets/web-panel/assets/{Services-BBBTb4YA.js → Services-DD3WxXxw.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-CtL_5fJe.js → Skeleton-C-d9Mbos.js} +1 -1
  75. package/src/assets/web-panel/assets/Skills-BBkg1Eqr.js +1 -0
  76. package/src/assets/web-panel/assets/{Sla-C5LGNImz.js → Sla-DgrqUhns.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-Btx0KgwX.js → SpeechSettings-CDXFwOHX.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-DFLNSWuu.js → SyncSettings-BBio_v8M.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-Btkyo0G7.js → Tasks-QQWSk-tc.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-CIIt_k5J.js → Templates-RAPdM85o.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-Nqo1PA2a.js → Tenant-2jI745PC.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-CGwV9hW9.js → Terminal-ZCtYBMAe.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-Bu3xrXyf.js → TimelineRenderer-DfI36Yg6.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-3bC3zrYj.js → Tokens-NQ1VaO0W.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-DG84V7Xf.js → Trigger-DwFh5AMe.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-rPhNXoYJ.js → Trust-Dr0v45uH.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-CamNxeAp.js → UkeySign-i7Q1Bdqr.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-CkIuH4Gm.js → VideoEditing-CXSkk4gl.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-SD5W5uHT.js → Wallet-8_cAjou4.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn--A4Sddxn.js → WebAuthn-jn_3Gma7.js} +4 -4
  91. package/src/assets/web-panel/assets/{WorkflowEditor-Ca7qvch8.js → WorkflowEditor-BmvodVLl.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-i8OBdjCB.js → chat-DGi3bmwL.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-BeYbJKQ8.js → colors-D8OSTOU0.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-BqpF-Sya.js → compact-item-DfNygJU_.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-qXTb29t3.js → createContext-B0lT0dbj.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-BUooUkHH.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-DOfL0KSW.js → hasIn-Xtzg_EDR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-X8TXf9Bb.js → index-4s8GZJ73.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-0OxY_Nsh.js → index-B-B7DDjX.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CebShwk1.js → index-B0kDqFPU.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-czHvbhS0.js → index-B2bgL5vL.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CXXeOim8.js → index-B3ittRaJ.js} +1 -1
  103. package/src/assets/web-panel/assets/{index--TQi5102.js → index-B4-hl9Rw.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-C13IM9lj.js → index-BBR-_Pkv.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CH7mHJoh.js → index-BBegBTDb.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-vNYrAXO6.js → index-BFRkiqtr.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DIikgsI1.js → index-BJ6nxb18.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-B177TAO-.js → index-BVOyO-ZV.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Bt7Ua7EC.js → index-BbTx5wo1.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-nl9IxLfv.js → index-BhS9-r8Z.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Cy8WApMp.js → index-BhYM_Rzp.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BmzmjSGb.js → index-BhhS0xnV.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-D8c3Ctj4.js → index-BpsIkWwQ.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-C4_8KnUt.js → index-Bujix_OR.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CLrDyxeZ.js → index-Byto86PA.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-Byn_IHXR.js → index-CIbYQLD-.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DWLxMPZ_.js → index-CLRMkKeD.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-ByHZkqj5.js → index-CShl59Um.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-TAvlGp5l.js → index-ConAvib0.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BKd03Rn4.js → index-Cp-yGWti.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-rdW8KX_7.js → index-Cx_EAQEh.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-JxyF4KNw.js → index-CyVOaMS7.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BYzQaGnV.js → index-DEH5ms1R.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-zmvw3Ptl.js → index-DFkgqRqx.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BdbrE-hz.js → index-DVfE2S0f.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BOwR6mHU.js → index-DVnowoxR.js} +1 -1
  127. package/src/assets/web-panel/assets/index-DVu4QCII.js +1 -0
  128. package/src/assets/web-panel/assets/{index-Cvig0IjN.js → index-DWpRgQvO.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BD386d6M.js → index-DXNWsfbw.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BuzGZOAK.js → index-DZKM2nm2.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Dio2mTWq.js → index-De9jsBiC.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-GGEsF-NA.js → index-EV-o-rTH.js} +1 -1
  133. package/src/assets/web-panel/assets/index-XYnz-yJ_.js +1 -0
  134. package/src/assets/web-panel/assets/{index-B00rNoIx.js → index-hDo9-qDw.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-C-P0NHi4.js → index-kdyFlPZw.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-DCcXU9HN.js → index-svr-L6NS.js} +5 -5
  137. package/src/assets/web-panel/assets/{initDefaultProps-BKpYiODg.js → initDefaultProps-CPsOp_T6.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-DJ2p-V-R.js → motion-8Jakob3_.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-CmA2ejm5.js → move-DAogsEBs.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-CAIGxQzN.js → mtc-parser-CkA9zZB_.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-DJlnhA7K.js → omit-DMHNkosQ.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-CZPrJyhF.js → pickAttrs-ByIvo_lk.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-CXy74okE.js → placementArrow-CafMUHzz.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-DexkLtci.js → responsiveObserve-CTehELUQ.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-BzjBJbPV.js → slide-BQISQ1KV.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-gnHIXw2X.js → statusUtils-Drm4jUoK.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-DHBjT1Gk.js → styleChecker-DGniLRqn.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-BmMStW87.js → useFlexGapSupport-DYz_z9wn.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-BcV5VGA2.js → useFs-DRAPQMjC.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-DBxxRRY2.js → usePersonalDataHub-CpgGLb8q.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-Bt5yp9hj.js → vnode-p6925VWJ.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-CMdUkOfw.js → zoom-ClpO8REK.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/command-help-index.json +1 -1
  155. package/src/commands/evolution-deployment.js +95 -0
  156. package/src/commands/evolution.js +2 -0
  157. package/src/constants.js +2 -2
  158. package/src/data/changelog.json +191 -752
  159. package/src/gateways/ws/evolution-deployment-topic-handlers.js +53 -0
  160. package/src/lib/evolution/evolution-deployment-config.js +81 -0
  161. package/src/lib/evolution/evolution-deployment-loader.js +62 -13
  162. package/src/lib/evolution/evolution-deployment-profile.js +114 -0
  163. package/src/lib/evolution/evolution-file-identity.js +42 -0
  164. package/src/lib/evolution/evolution-ledger-file-manifest-head-store.js +242 -0
  165. package/src/lib/evolution/evolution-ledger-manifest-chain.js +74 -18
  166. package/src/lib/evolution/evolution-ledger-v2-manifest-backend.js +135 -20
  167. package/src/lib/evolution/evolution-ledger.js +353 -209
  168. package/src/lib/llm-providers.js +1 -0
  169. package/src/lib/public-ide-capability-manifest.js +2 -0
  170. package/src/lib/read-file-loop-guard.js +17 -4
  171. package/src/lib/remote-read-loop-guard.js +13 -0
  172. package/src/lib/task-model-selector.js +1 -1
  173. package/src/lib/task-progress-tracker.js +36 -1
  174. package/src/lib/text-file-search.js +11 -0
  175. package/src/runtime/agent-core.js +6 -2
  176. package/src/runtime/agent-runtime.js +2 -0
  177. package/src/assets/web-panel/assets/AppLayout-CdnpAzuo.js +0 -9
  178. package/src/assets/web-panel/assets/MarkdownRenderer-H_GkKEp-.js +0 -1
  179. package/src/assets/web-panel/assets/PdhVaultBrowser-CF7TzZmx.js +0 -7
  180. package/src/assets/web-panel/assets/Skills-DvqrC2_v.js +0 -1
  181. package/src/assets/web-panel/assets/devWarning-DATyiD_X.js +0 -1
  182. package/src/assets/web-panel/assets/index-DmzMCELP.js +0 -1
  183. package/src/assets/web-panel/assets/index-TlPg2Jz6.js +0 -1
@@ -3,7 +3,10 @@ import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { types as utilTypes } from "node:util";
5
5
  import { readBoundedDescriptor } from "./bounded-descriptor-read.js";
6
- import { withEvolutionFileIdentity } from "./evolution-file-identity.js";
6
+ import {
7
+ withEvolutionDirectoryFileIdentity,
8
+ withEvolutionFileIdentity,
9
+ } from "./evolution-file-identity.js";
7
10
  import { sameFileStatIdentity } from "../secure-file-identity.js";
8
11
  import { getHomeDir } from "../paths.js";
9
12
  import { ensurePrivateDirectory, ensurePrivateFile } from "../secure-fs.js";
@@ -24,6 +27,8 @@ export const EVOLUTION_LEDGER_ANCHOR_SCHEMA =
24
27
  "chainlesschain.evolution-ledger-head-anchor/v1";
25
28
  export const EVOLUTION_LEDGER_RECEIPT_SCHEMA =
26
29
  "chainlesschain.evolution-ledger-receipt/v2";
30
+ export const EVOLUTION_LEDGER_BATCH_RECEIPT_SCHEMA =
31
+ "chainlesschain.evolution-ledger-batch-receipt/v1";
27
32
  export const EVOLUTION_LEDGER_VERIFICATION_SCHEMA =
28
33
  "chainlesschain.evolution-ledger-verification/v2";
29
34
  export const EVOLUTION_LEDGER_QUERY_SCHEMA =
@@ -97,6 +102,7 @@ const HEAD_STAGE_FILE_PATTERN =
97
102
  const MAX_SOURCE_REFS = 256;
98
103
  const MAX_AUDIT_ARTIFACT_RECORDS = 1_000_000;
99
104
  const MAX_LEDGER_BATCH_QUERIES = 10_000;
105
+ const MAX_LEDGER_APPEND_BATCH = 1024;
100
106
  const MAX_STATE_SNAPSHOT_BYTES = 256 * 1024 * 1024;
101
107
  const STATE_QUERY_INDEXES = new WeakMap();
102
108
  const TYPED_ARRAY_PROTOTYPE = Object.getPrototypeOf(Uint8Array.prototype);
@@ -136,6 +142,7 @@ const DECISIONS = new Set([
136
142
  const REVOCATION_STATES = new Set(["not-revoked", "revoked", "tombstoned"]);
137
143
  const DURABILITY_MECHANISMS = new Set([
138
144
  "authenticated-witness-cas",
145
+ "authenticated-witness-batch-cas",
139
146
  "directory-fsync",
140
147
  "verified-existing",
141
148
  ]);
@@ -2787,8 +2794,12 @@ export class EvolutionLedger {
2787
2794
  label,
2788
2795
  allowMissing,
2789
2796
  samePathHandle,
2797
+ { expectedBytes = null, trustedParentPath = null } = {},
2790
2798
  ) {
2791
- this.#assertBoundaries();
2799
+ const heldParent =
2800
+ trustedParentPath !== null &&
2801
+ samePath(path.dirname(filePath), trustedParentPath);
2802
+ if (!heldParent) this.#assertBoundaries();
2792
2803
  let before;
2793
2804
  try {
2794
2805
  before = this.#fs.lstatSync(filePath);
@@ -2808,7 +2819,7 @@ export class EvolutionLedger {
2808
2819
  before.nlink !== 1 ||
2809
2820
  before.size < 2 ||
2810
2821
  before.size > maximum ||
2811
- !samePath(realpath(this.#fs, filePath), filePath)
2822
+ (!heldParent && !samePath(realpath(this.#fs, filePath), filePath))
2812
2823
  ) {
2813
2824
  throw ledgerError(
2814
2825
  "CC_EVOLUTION_LEDGER_CORRUPT",
@@ -2860,6 +2871,20 @@ export class EvolutionLedger {
2860
2871
  `${label} changed while it was read`,
2861
2872
  );
2862
2873
  }
2874
+ if (expectedBytes !== null) {
2875
+ if (!Buffer.isBuffer(expectedBytes) || !bytes.equals(expectedBytes)) {
2876
+ throw ledgerError(
2877
+ "CC_EVOLUTION_LEDGER_CORRUPT",
2878
+ `${label} differs from its signed snapshot bytes`,
2879
+ );
2880
+ }
2881
+ return {
2882
+ bytes,
2883
+ contentDigest: sha256(bytes),
2884
+ fingerprint: fileFingerprint(before),
2885
+ record: null,
2886
+ };
2887
+ }
2863
2888
  let text;
2864
2889
  try {
2865
2890
  text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
@@ -2902,7 +2927,7 @@ export class EvolutionLedger {
2902
2927
  };
2903
2928
  } finally {
2904
2929
  if (descriptor !== null) this.#fs.closeSync(descriptor);
2905
- this.#assertBoundaries();
2930
+ if (!heldParent) this.#assertBoundaries();
2906
2931
  }
2907
2932
  }
2908
2933
 
@@ -3620,60 +3645,82 @@ export class EvolutionLedger {
3620
3645
  );
3621
3646
  const anchorFingerprints = {};
3622
3647
  const segmentFingerprints = {};
3623
- for (let index = 0; index < anchorFiles.length; index += 1) {
3624
- const entry = anchorFiles[index];
3625
- const snapshotRecordDigest = sha256(
3626
- Buffer.from(`${canonicalJson(anchorRecords[index])}\n`, "utf8"),
3627
- );
3628
- if (entry.contentDigest !== snapshotRecordDigest) {
3629
- throw ledgerError(
3630
- "CC_EVOLUTION_LEDGER_CORRUPT",
3631
- `state snapshot anchor bytes are not bound at index ${index}`,
3632
- );
3633
- }
3634
- const file = this.#readCanonicalFile(
3635
- path.join(this.#paths.anchorDir, entry.name),
3636
- 64 * 1024,
3637
- `state snapshot anchor file ${entry.name}`,
3638
- );
3639
- if (file.contentDigest !== entry.contentDigest) {
3640
- throw ledgerError(
3641
- "CC_EVOLUTION_LEDGER_CORRUPT",
3642
- `state snapshot anchor file changed: ${entry.name}`,
3643
- );
3644
- }
3645
- anchorFingerprints[entry.name] = Object.freeze({
3646
- contentDigest: file.contentDigest,
3647
- fingerprint: file.fingerprint,
3648
- });
3649
- }
3650
- for (let index = 0; index < segmentFiles.length; index += 1) {
3651
- const entry = segmentFiles[index];
3652
- const snapshotRecordDigest = sha256(
3653
- Buffer.from(`${canonicalJson(eventRecords[index])}\n`, "utf8"),
3654
- );
3655
- if (entry.contentDigest !== snapshotRecordDigest) {
3656
- throw ledgerError(
3657
- "CC_EVOLUTION_LEDGER_CORRUPT",
3658
- `state snapshot event bytes are not bound at index ${index}`,
3659
- );
3660
- }
3661
- const file = this.#readCanonicalFile(
3662
- path.join(this.#paths.segmentDir, entry.name),
3663
- EVOLUTION_LEDGER_MAX_EVENT_BYTES,
3664
- `state snapshot segment file ${entry.name}`,
3665
- );
3666
- if (file.contentDigest !== entry.contentDigest) {
3667
- throw ledgerError(
3668
- "CC_EVOLUTION_LEDGER_CORRUPT",
3669
- `state snapshot segment file changed: ${entry.name}`,
3670
- );
3671
- }
3672
- segmentFingerprints[entry.name] = Object.freeze({
3673
- contentDigest: file.contentDigest,
3674
- fingerprint: file.fingerprint,
3675
- });
3676
- }
3648
+ withEvolutionDirectoryFileIdentity(
3649
+ this.#fs,
3650
+ this.#paths.anchorDir,
3651
+ (samePathHandle, _sameStableHandle, { parentPath }) => {
3652
+ for (let index = 0; index < anchorFiles.length; index += 1) {
3653
+ const entry = anchorFiles[index];
3654
+ const expectedBytes = Buffer.from(
3655
+ `${canonicalJson(anchorRecords[index])}\n`,
3656
+ "utf8",
3657
+ );
3658
+ const snapshotRecordDigest = sha256(expectedBytes);
3659
+ if (entry.contentDigest !== snapshotRecordDigest) {
3660
+ throw ledgerError(
3661
+ "CC_EVOLUTION_LEDGER_CORRUPT",
3662
+ `state snapshot anchor bytes are not bound at index ${index}`,
3663
+ );
3664
+ }
3665
+ const file = this.#readCanonicalFileWithIdentity(
3666
+ path.join(this.#paths.anchorDir, entry.name),
3667
+ 64 * 1024,
3668
+ `state snapshot anchor file ${entry.name}`,
3669
+ false,
3670
+ samePathHandle,
3671
+ { expectedBytes, trustedParentPath: parentPath },
3672
+ );
3673
+ if (file.contentDigest !== entry.contentDigest) {
3674
+ throw ledgerError(
3675
+ "CC_EVOLUTION_LEDGER_CORRUPT",
3676
+ `state snapshot anchor file changed: ${entry.name}`,
3677
+ );
3678
+ }
3679
+ anchorFingerprints[entry.name] = Object.freeze({
3680
+ contentDigest: file.contentDigest,
3681
+ fingerprint: file.fingerprint,
3682
+ });
3683
+ }
3684
+ },
3685
+ );
3686
+ withEvolutionDirectoryFileIdentity(
3687
+ this.#fs,
3688
+ this.#paths.segmentDir,
3689
+ (samePathHandle, _sameStableHandle, { parentPath }) => {
3690
+ for (let index = 0; index < segmentFiles.length; index += 1) {
3691
+ const entry = segmentFiles[index];
3692
+ const expectedBytes = Buffer.from(
3693
+ `${canonicalJson(eventRecords[index])}\n`,
3694
+ "utf8",
3695
+ );
3696
+ const snapshotRecordDigest = sha256(expectedBytes);
3697
+ if (entry.contentDigest !== snapshotRecordDigest) {
3698
+ throw ledgerError(
3699
+ "CC_EVOLUTION_LEDGER_CORRUPT",
3700
+ `state snapshot event bytes are not bound at index ${index}`,
3701
+ );
3702
+ }
3703
+ const file = this.#readCanonicalFileWithIdentity(
3704
+ path.join(this.#paths.segmentDir, entry.name),
3705
+ EVOLUTION_LEDGER_MAX_EVENT_BYTES,
3706
+ `state snapshot segment file ${entry.name}`,
3707
+ false,
3708
+ samePathHandle,
3709
+ { expectedBytes, trustedParentPath: parentPath },
3710
+ );
3711
+ if (file.contentDigest !== entry.contentDigest) {
3712
+ throw ledgerError(
3713
+ "CC_EVOLUTION_LEDGER_CORRUPT",
3714
+ `state snapshot segment file changed: ${entry.name}`,
3715
+ );
3716
+ }
3717
+ segmentFingerprints[entry.name] = Object.freeze({
3718
+ contentDigest: file.contentDigest,
3719
+ fingerprint: file.fingerprint,
3720
+ });
3721
+ }
3722
+ },
3723
+ );
3677
3724
 
3678
3725
  const maximumAnchor = anchors.at(-1);
3679
3726
  const maximumEvent = events.at(-1) || null;
@@ -4426,11 +4473,36 @@ export class EvolutionLedger {
4426
4473
  return this.#appendEvent(input, options, true);
4427
4474
  }
4428
4475
 
4476
+ appendBatch(inputs, options = {}) {
4477
+ return this.#appendEvents(inputs, options, false, true);
4478
+ }
4479
+
4480
+ appendDomainEventBatch(inputs, options = {}) {
4481
+ return this.#appendEvents(inputs, options, true, true);
4482
+ }
4483
+
4429
4484
  #appendEvent(input, options, domainEvent) {
4485
+ return this.#appendEvents([input], options, domainEvent, false);
4486
+ }
4487
+
4488
+ #appendEvents(inputs, options, domainEvent, batch) {
4489
+ const safeInputs = readDenseDataArray(
4490
+ inputs,
4491
+ batch ? "append batch" : "append input",
4492
+ batch ? MAX_LEDGER_APPEND_BATCH : 1,
4493
+ );
4494
+ if (safeInputs.length === 0) {
4495
+ throw ledgerError(
4496
+ "CC_EVOLUTION_LEDGER_SCHEMA_INVALID",
4497
+ "append batch must contain at least one event",
4498
+ );
4499
+ }
4430
4500
  const safeOptions = normalizeAppendOptions(options);
4431
4501
  const state = {
4432
4502
  event: null,
4503
+ events: [],
4433
4504
  receipt: null,
4505
+ receipts: [],
4434
4506
  witnessAttempted: false,
4435
4507
  witnessPublished: false,
4436
4508
  };
@@ -4467,179 +4539,240 @@ export class EvolutionLedger {
4467
4539
  },
4468
4540
  );
4469
4541
  }
4470
- const generatedTimestamp = clockTimestamp(this.#clock);
4471
- const normalized = domainEvent
4472
- ? normalizeDomainAppendInput(input, generatedTimestamp)
4473
- : normalizeAppendInput(input, generatedTimestamp);
4474
4542
  if (
4475
- current.events.some((event) => event.eventId === normalized.eventId)
4543
+ current.events.length + safeInputs.length >
4544
+ EVOLUTION_LEDGER_MAX_EVENTS
4476
4545
  ) {
4477
- throw ledgerError(
4478
- "CC_EVOLUTION_LEDGER_EVENT_CONFLICT",
4479
- `eventId already exists: ${normalized.eventId}`,
4480
- );
4481
- }
4482
- if (current.events.length >= EVOLUTION_LEDGER_MAX_EVENTS) {
4483
4546
  throw ledgerError(
4484
4547
  "CC_EVOLUTION_LEDGER_CAPACITY_EXCEEDED",
4485
4548
  "evolution ledger capacity is exhausted",
4486
4549
  );
4487
4550
  }
4488
- // Mandatory Wiki admission is inside the genuine Ledger write lock,
4489
- // after current-state authentication and before any event is signed or
4490
- // persisted. Raw domain append callers and adapters share this fence.
4491
- if (domainEvent && normalized.type === "wiki.revision.committed") {
4492
- try {
4493
- assertKnowledgeWikiSourceAdmission({
4494
- input: normalized,
4495
- events: current.events,
4496
- resolveSubject: (entry) => {
4497
- const evidence = this.#resolveArtifactEvidence(
4498
- { ...entry, sourceRefs: [] },
4499
- current.identity,
4500
- { includeBytes: true },
4501
- );
4502
- const subject = evidence.artifacts.find(
4503
- (artifact) =>
4504
- artifact.artifactRef.ref === entry.subjectRef.ref &&
4505
- artifact.artifactRef.digest === entry.subjectRef.digest,
4506
- );
4507
- if (!subject)
4508
- throw ledgerError(
4509
- WIKI_SOURCE_ADMISSION_INVALID_CODE,
4510
- "Wiki admission subject was not resolved",
4511
- );
4512
- return Buffer.from(subject.bytesBase64, "base64");
4513
- },
4514
- });
4515
- } catch (cause) {
4516
- if (cause instanceof EvolutionLedgerError) throw cause;
4551
+
4552
+ // Normalize the complete batch before any filesystem mutation. This
4553
+ // prevents a malformed later item from leaving a valid earlier prefix.
4554
+ const normalizedInputs = safeInputs.map((input) => {
4555
+ const generatedTimestamp = clockTimestamp(this.#clock);
4556
+ return domainEvent
4557
+ ? normalizeDomainAppendInput(input, generatedTimestamp)
4558
+ : normalizeAppendInput(input, generatedTimestamp);
4559
+ });
4560
+ const eventIds = new Set(current.events.map((event) => event.eventId));
4561
+ for (const normalized of normalizedInputs) {
4562
+ if (eventIds.has(normalized.eventId)) {
4517
4563
  throw ledgerError(
4518
- cause?.code === WIKI_SOURCE_REVOKED_CODE
4519
- ? WIKI_SOURCE_REVOKED_CODE
4520
- : WIKI_SOURCE_ADMISSION_INVALID_CODE,
4521
- "Wiki source admission rejected the proposed revision",
4522
- { cause },
4564
+ "CC_EVOLUTION_LEDGER_EVENT_CONFLICT",
4565
+ `eventId already exists: ${normalized.eventId}`,
4523
4566
  );
4524
4567
  }
4568
+ eventIds.add(normalized.eventId);
4525
4569
  }
4526
- const artifactValidationDigest = this.#resolveArtifacts(
4527
- normalized,
4528
- current.identity,
4529
- );
4530
- const event = domainEvent
4531
- ? this.#buildDomainEvent(
4532
- normalized,
4533
- previous,
4534
- current.identity,
4535
- artifactValidationDigest,
4536
- )
4537
- : this.#buildEvent(
4538
- normalized,
4539
- previous,
4540
- current.identity,
4541
- artifactValidationDigest,
4542
- );
4543
- state.event = event;
4544
- const segmentDigest = domainDigest(SEGMENT_DOMAIN, event);
4545
- const segmentPath = path.join(
4546
- this.#paths.segmentDir,
4547
- segmentFileName(event.sequence, segmentDigest),
4548
- );
4549
- const eventBytes = serializeRecord(
4550
- event,
4551
- EVOLUTION_LEDGER_MAX_EVENT_BYTES,
4552
- "event segment",
4553
- );
4554
- this.#writeImmutable(
4555
- segmentPath,
4556
- eventBytes,
4557
- "event segment",
4558
- (temporaryPath) => {
4559
- this.#invokeCrashHook("after-segment-link", {
4560
- eventDigest: event.eventDigest,
4561
- temporaryPath: path.basename(temporaryPath),
4562
- });
4563
- },
4564
- );
4565
- this.#invokeCrashHook("after-segment", {
4566
- eventDigest: event.eventDigest,
4567
- segmentDigest,
4568
- });
4569
4570
 
4570
- const anchor = this.#buildAnchor(
4571
- current.identity,
4572
- current.anchors.at(-1),
4573
- event,
4574
- segmentDigest,
4575
- );
4576
- const anchorPath = path.join(
4577
- this.#paths.anchorDir,
4578
- anchorFileName(anchor.sequence, anchor.anchorDigest),
4579
- );
4580
- const anchorBytes = serializeRecord(anchor, 64 * 1024, "head anchor");
4581
- this.#writeImmutable(
4582
- anchorPath,
4583
- anchorBytes,
4584
- "head anchor",
4585
- (temporaryPath) => {
4586
- this.#invokeCrashHook("after-anchor-link", {
4587
- anchorDigest: anchor.anchorDigest,
4588
- temporaryPath: path.basename(temporaryPath),
4589
- });
4590
- },
4591
- );
4592
- this.#invokeCrashHook("after-anchor", {
4593
- anchorDigest: anchor.anchorDigest,
4594
- eventDigest: event.eventDigest,
4595
- });
4596
- this.#requireDirectoryDurability([
4597
- this.#paths.segmentDir,
4598
- this.#paths.anchorDir,
4599
- ]);
4600
- state.witnessAttempted = true;
4601
- const witnessed = this.#advanceWitness(
4602
- current.witness,
4603
- current.identity,
4604
- current.storeMarker,
4605
- anchor,
4606
- event,
4607
- );
4608
- state.witnessPublished = true;
4609
- this.#invokeCrashHook("after-witness", {
4610
- anchorDigest: anchor.anchorDigest,
4611
- eventDigest: event.eventDigest,
4612
- witnessDigest: witnessed.witnessDigest,
4613
- });
4614
- this.#replaceHead(anchorBytes);
4615
- this.#invokeCrashHook("after-head", {
4616
- anchorDigest: anchor.anchorDigest,
4617
- eventDigest: event.eventDigest,
4618
- });
4571
+ // Resolve artifacts, apply Wiki admission, and sign the complete plan
4572
+ // before the first segment is linked. Later authority failures cannot
4573
+ // turn a validation error into a partially committed batch.
4574
+ const planned = [];
4575
+ const knownEvents = [...current.events];
4576
+ let previousEvent = previous;
4577
+ let previousAnchor = current.anchors.at(-1);
4578
+ for (const normalized of normalizedInputs) {
4579
+ if (domainEvent && normalized.type === "wiki.revision.committed") {
4580
+ try {
4581
+ assertKnowledgeWikiSourceAdmission({
4582
+ input: normalized,
4583
+ events: knownEvents,
4584
+ resolveSubject: (entry) => {
4585
+ const evidence = this.#resolveArtifactEvidence(
4586
+ { ...entry, sourceRefs: [] },
4587
+ current.identity,
4588
+ { includeBytes: true },
4589
+ );
4590
+ const subject = evidence.artifacts.find(
4591
+ (artifact) =>
4592
+ artifact.artifactRef.ref === entry.subjectRef.ref &&
4593
+ artifact.artifactRef.digest === entry.subjectRef.digest,
4594
+ );
4595
+ if (!subject)
4596
+ throw ledgerError(
4597
+ WIKI_SOURCE_ADMISSION_INVALID_CODE,
4598
+ "Wiki admission subject was not resolved",
4599
+ );
4600
+ return Buffer.from(subject.bytesBase64, "base64");
4601
+ },
4602
+ });
4603
+ } catch (cause) {
4604
+ if (cause instanceof EvolutionLedgerError) throw cause;
4605
+ throw ledgerError(
4606
+ cause?.code === WIKI_SOURCE_REVOKED_CODE
4607
+ ? WIKI_SOURCE_REVOKED_CODE
4608
+ : WIKI_SOURCE_ADMISSION_INVALID_CODE,
4609
+ "Wiki source admission rejected the proposed revision",
4610
+ { cause },
4611
+ );
4612
+ }
4613
+ }
4614
+ const artifactValidationDigest = this.#resolveArtifacts(
4615
+ normalized,
4616
+ current.identity,
4617
+ );
4618
+ const event = domainEvent
4619
+ ? this.#buildDomainEvent(
4620
+ normalized,
4621
+ previousEvent,
4622
+ current.identity,
4623
+ artifactValidationDigest,
4624
+ )
4625
+ : this.#buildEvent(
4626
+ normalized,
4627
+ previousEvent,
4628
+ current.identity,
4629
+ artifactValidationDigest,
4630
+ );
4631
+ const segmentDigest = domainDigest(SEGMENT_DOMAIN, event);
4632
+ const anchor = this.#buildAnchor(
4633
+ current.identity,
4634
+ previousAnchor,
4635
+ event,
4636
+ segmentDigest,
4637
+ );
4638
+ const eventBytes = serializeRecord(
4639
+ event,
4640
+ EVOLUTION_LEDGER_MAX_EVENT_BYTES,
4641
+ "event segment",
4642
+ );
4643
+ const anchorBytes = serializeRecord(anchor, 64 * 1024, "head anchor");
4644
+ planned.push({
4645
+ anchor,
4646
+ anchorBytes,
4647
+ event,
4648
+ eventBytes,
4649
+ segmentDigest,
4650
+ });
4651
+ knownEvents.push(event);
4652
+ previousEvent = event;
4653
+ previousAnchor = anchor;
4654
+ }
4655
+
4656
+ state.events = planned.map((entry) => entry.event);
4657
+ state.event = state.events.at(-1);
4658
+ const witnessedStates = [];
4659
+ let currentWitness = current.witness;
4660
+ for (const entry of planned) {
4661
+ const { anchor, anchorBytes, event, eventBytes, segmentDigest } =
4662
+ entry;
4663
+ const segmentPath = path.join(
4664
+ this.#paths.segmentDir,
4665
+ segmentFileName(event.sequence, segmentDigest),
4666
+ );
4667
+ this.#writeImmutable(
4668
+ segmentPath,
4669
+ eventBytes,
4670
+ "event segment",
4671
+ (temporaryPath) => {
4672
+ this.#invokeCrashHook("after-segment-link", {
4673
+ eventDigest: event.eventDigest,
4674
+ temporaryPath: path.basename(temporaryPath),
4675
+ });
4676
+ },
4677
+ );
4678
+ this.#invokeCrashHook("after-segment", {
4679
+ eventDigest: event.eventDigest,
4680
+ segmentDigest,
4681
+ });
4682
+ const anchorPath = path.join(
4683
+ this.#paths.anchorDir,
4684
+ anchorFileName(anchor.sequence, anchor.anchorDigest),
4685
+ );
4686
+ this.#writeImmutable(
4687
+ anchorPath,
4688
+ anchorBytes,
4689
+ "head anchor",
4690
+ (temporaryPath) => {
4691
+ this.#invokeCrashHook("after-anchor-link", {
4692
+ anchorDigest: anchor.anchorDigest,
4693
+ temporaryPath: path.basename(temporaryPath),
4694
+ });
4695
+ },
4696
+ );
4697
+ this.#invokeCrashHook("after-anchor", {
4698
+ anchorDigest: anchor.anchorDigest,
4699
+ eventDigest: event.eventDigest,
4700
+ });
4701
+ this.#requireDirectoryDurability([
4702
+ this.#paths.segmentDir,
4703
+ this.#paths.anchorDir,
4704
+ ]);
4705
+ state.witnessAttempted = true;
4706
+ currentWitness = this.#advanceWitness(
4707
+ currentWitness,
4708
+ current.identity,
4709
+ current.storeMarker,
4710
+ anchor,
4711
+ event,
4712
+ );
4713
+ witnessedStates.push(currentWitness);
4714
+ state.witnessPublished = true;
4715
+ this.#invokeCrashHook("after-witness", {
4716
+ anchorDigest: anchor.anchorDigest,
4717
+ eventDigest: event.eventDigest,
4718
+ witnessDigest: currentWitness.witnessDigest,
4719
+ });
4720
+ this.#replaceHead(anchorBytes);
4721
+ this.#invokeCrashHook("after-head", {
4722
+ anchorDigest: anchor.anchorDigest,
4723
+ eventDigest: event.eventDigest,
4724
+ });
4725
+ }
4619
4726
 
4620
4727
  const persisted = this.#loadState({
4621
4728
  allowInitialize: false,
4622
4729
  incremental: true,
4623
4730
  });
4624
- const persistedEvent = persisted.events.at(-1);
4625
- const persistedAnchor = persisted.anchors.at(-1);
4731
+ const sequenceStart = state.events[0].sequence;
4732
+ const persistedEvents = persisted.events.slice(sequenceStart - 1);
4733
+ const finalAnchor = planned.at(-1).anchor;
4626
4734
  if (
4627
- persistedEvent?.eventDigest !== event.eventDigest ||
4628
- persistedAnchor?.anchorDigest !== anchor.anchorDigest ||
4629
- persisted.head.anchorDigest !== anchor.anchorDigest
4735
+ persistedEvents.length !== state.events.length ||
4736
+ persistedEvents.some(
4737
+ (event, index) =>
4738
+ event.eventDigest !== state.events[index].eventDigest,
4739
+ ) ||
4740
+ persisted.head.anchorDigest !== finalAnchor.anchorDigest
4630
4741
  ) {
4631
4742
  throw ledgerError(
4632
4743
  "CC_EVOLUTION_LEDGER_WRITE_FAILED",
4633
- "event was not recovered under the authenticated HEAD",
4744
+ "event batch was not recovered under the authenticated HEAD",
4634
4745
  );
4635
4746
  }
4636
- state.receipt = this.#issueReceipt(
4637
- persisted,
4638
- persistedEvent,
4639
- persistedAnchor,
4640
- "authenticated-witness-cas",
4747
+ state.receipts = persistedEvents.map((event, index) =>
4748
+ this.#issueReceipt(
4749
+ { ...persisted, witness: witnessedStates[index] },
4750
+ event,
4751
+ planned[index].anchor,
4752
+ batch
4753
+ ? "authenticated-witness-batch-cas"
4754
+ : "authenticated-witness-cas",
4755
+ ),
4641
4756
  );
4642
- return state.receipt;
4757
+ state.receipt = state.receipts.at(-1);
4758
+ if (!batch) return state.receipt;
4759
+ return deepFreeze({
4760
+ anchorDigest: finalAnchor.anchorDigest,
4761
+ authenticated: true,
4762
+ committed: true,
4763
+ durable: true,
4764
+ eventCount: state.events.length,
4765
+ eventDigests: state.events.map((event) => event.eventDigest),
4766
+ eventIds: state.events.map((event) => event.eventId),
4767
+ eventReceipts: state.receipts,
4768
+ headDigest: state.event.eventDigest,
4769
+ readbackVerified: true,
4770
+ schema: EVOLUTION_LEDGER_BATCH_RECEIPT_SCHEMA,
4771
+ sequenceEnd: state.event.sequence,
4772
+ sequenceStart,
4773
+ witnessed: true,
4774
+ witnessDigest: currentWitness.witnessDigest,
4775
+ });
4643
4776
  });
4644
4777
  } catch (cause) {
4645
4778
  if (state.witnessAttempted || state.receipt) {
@@ -4650,7 +4783,16 @@ export class EvolutionLedger {
4650
4783
  cause,
4651
4784
  commitState: "unknown",
4652
4785
  eventDigest: state.event?.eventDigest || null,
4653
- eventId: state.event?.eventId || safeOwnDataValue(input, "eventId"),
4786
+ eventId:
4787
+ state.event?.eventId ||
4788
+ safeOwnDataValue(safeInputs.at(-1), "eventId"),
4789
+ ...(batch
4790
+ ? {
4791
+ eventIds: safeInputs.map((entry) =>
4792
+ safeOwnDataValue(entry, "eventId"),
4793
+ ),
4794
+ }
4795
+ : {}),
4654
4796
  witnessPublished: state.witnessPublished,
4655
4797
  },
4656
4798
  );
@@ -4665,7 +4807,9 @@ export class EvolutionLedger {
4665
4807
  {
4666
4808
  cause,
4667
4809
  commitState: "not-committed",
4668
- eventId: safeOwnDataValue(input, "eventId"),
4810
+ eventId: batch
4811
+ ? safeInputs.map((entry) => safeOwnDataValue(entry, "eventId"))[0]
4812
+ : safeOwnDataValue(safeInputs[0], "eventId"),
4669
4813
  },
4670
4814
  );
4671
4815
  }