@allocator-one/rcl 4.4.19

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 (663) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1415 -0
  3. package/dist/ci.d.ts +16 -0
  4. package/dist/ci.js +42 -0
  5. package/dist/ci.js.map +1 -0
  6. package/dist/config/data-dir.d.ts +6 -0
  7. package/dist/config/data-dir.js +12 -0
  8. package/dist/config/data-dir.js.map +1 -0
  9. package/dist/config/defaults.d.ts +82 -0
  10. package/dist/config/defaults.js +89 -0
  11. package/dist/config/defaults.js.map +1 -0
  12. package/dist/config/harness.d.ts +40 -0
  13. package/dist/config/harness.js +151 -0
  14. package/dist/config/harness.js.map +1 -0
  15. package/dist/config/loader.d.ts +13 -0
  16. package/dist/config/loader.js +131 -0
  17. package/dist/config/loader.js.map +1 -0
  18. package/dist/config/provider-concurrency.d.ts +4 -0
  19. package/dist/config/provider-concurrency.js +6 -0
  20. package/dist/config/provider-concurrency.js.map +1 -0
  21. package/dist/config/providers.d.ts +3 -0
  22. package/dist/config/providers.js +9 -0
  23. package/dist/config/providers.js.map +1 -0
  24. package/dist/config/schema.d.ts +179 -0
  25. package/dist/config/schema.js +115 -0
  26. package/dist/config/schema.js.map +1 -0
  27. package/dist/consensus/claim-contract.d.ts +9 -0
  28. package/dist/consensus/claim-contract.js +307 -0
  29. package/dist/consensus/claim-contract.js.map +1 -0
  30. package/dist/consensus/claim-identity.d.ts +5 -0
  31. package/dist/consensus/claim-identity.js +39 -0
  32. package/dist/consensus/claim-identity.js.map +1 -0
  33. package/dist/consensus/deduper.d.ts +43 -0
  34. package/dist/consensus/deduper.js +1052 -0
  35. package/dist/consensus/deduper.js.map +1 -0
  36. package/dist/consensus/finding-identity.d.ts +20 -0
  37. package/dist/consensus/finding-identity.js +49 -0
  38. package/dist/consensus/finding-identity.js.map +1 -0
  39. package/dist/consensus/gating.d.ts +215 -0
  40. package/dist/consensus/gating.js +699 -0
  41. package/dist/consensus/gating.js.map +1 -0
  42. package/dist/consensus/parser.d.ts +22 -0
  43. package/dist/consensus/parser.js +255 -0
  44. package/dist/consensus/parser.js.map +1 -0
  45. package/dist/consensus/semantic-deduper.d.ts +10 -0
  46. package/dist/consensus/semantic-deduper.js +70 -0
  47. package/dist/consensus/semantic-deduper.js.map +1 -0
  48. package/dist/consensus/types.d.ts +196 -0
  49. package/dist/consensus/types.js +2 -0
  50. package/dist/consensus/types.js.map +1 -0
  51. package/dist/consensus/verification-contract.d.ts +8 -0
  52. package/dist/consensus/verification-contract.js +95 -0
  53. package/dist/consensus/verification-contract.js.map +1 -0
  54. package/dist/consensus/voter.d.ts +29 -0
  55. package/dist/consensus/voter.js +394 -0
  56. package/dist/consensus/voter.js.map +1 -0
  57. package/dist/converge/attempt-budget.d.ts +88 -0
  58. package/dist/converge/attempt-budget.js +717 -0
  59. package/dist/converge/attempt-budget.js.map +1 -0
  60. package/dist/converge/bound-fix-recovery-source.d.ts +24 -0
  61. package/dist/converge/bound-fix-recovery-source.js +25 -0
  62. package/dist/converge/bound-fix-recovery-source.js.map +1 -0
  63. package/dist/converge/bound-fix-recovery.d.ts +15 -0
  64. package/dist/converge/bound-fix-recovery.js +65 -0
  65. package/dist/converge/bound-fix-recovery.js.map +1 -0
  66. package/dist/converge/correction-anchors.d.ts +1 -0
  67. package/dist/converge/correction-anchors.js +2 -0
  68. package/dist/converge/correction-anchors.js.map +1 -0
  69. package/dist/converge/cycle-remote.d.ts +6 -0
  70. package/dist/converge/cycle-remote.js +41 -0
  71. package/dist/converge/cycle-remote.js.map +1 -0
  72. package/dist/converge/delivery-reconciliation.d.ts +17 -0
  73. package/dist/converge/delivery-reconciliation.js +53 -0
  74. package/dist/converge/delivery-reconciliation.js.map +1 -0
  75. package/dist/converge/finding-identity.d.ts +6 -0
  76. package/dist/converge/finding-identity.js +7 -0
  77. package/dist/converge/finding-identity.js.map +1 -0
  78. package/dist/converge/fresh-review.d.ts +37 -0
  79. package/dist/converge/fresh-review.js +351 -0
  80. package/dist/converge/fresh-review.js.map +1 -0
  81. package/dist/converge/launch-guard.d.ts +55 -0
  82. package/dist/converge/launch-guard.js +363 -0
  83. package/dist/converge/launch-guard.js.map +1 -0
  84. package/dist/converge/launch-preflight.d.ts +5 -0
  85. package/dist/converge/launch-preflight.js +41 -0
  86. package/dist/converge/launch-preflight.js.map +1 -0
  87. package/dist/converge/launch-record.d.ts +136 -0
  88. package/dist/converge/launch-record.js +86 -0
  89. package/dist/converge/launch-record.js.map +1 -0
  90. package/dist/converge/legacy-launch-health.d.ts +311 -0
  91. package/dist/converge/legacy-launch-health.js +159 -0
  92. package/dist/converge/legacy-launch-health.js.map +1 -0
  93. package/dist/converge/legacy-roster.d.ts +29 -0
  94. package/dist/converge/legacy-roster.js +268 -0
  95. package/dist/converge/legacy-roster.js.map +1 -0
  96. package/dist/converge/native-lock.d.ts +18 -0
  97. package/dist/converge/native-lock.js +122 -0
  98. package/dist/converge/native-lock.js.map +1 -0
  99. package/dist/converge/ordinary-pending-export.d.ts +67 -0
  100. package/dist/converge/ordinary-pending-export.js +175 -0
  101. package/dist/converge/ordinary-pending-export.js.map +1 -0
  102. package/dist/converge/ordinary-pending-package.d.ts +28 -0
  103. package/dist/converge/ordinary-pending-package.js +36 -0
  104. package/dist/converge/ordinary-pending-package.js.map +1 -0
  105. package/dist/converge/pending-legacy-resume.d.ts +119 -0
  106. package/dist/converge/pending-legacy-resume.js +720 -0
  107. package/dist/converge/pending-legacy-resume.js.map +1 -0
  108. package/dist/converge/pending-recovery-source.d.ts +131 -0
  109. package/dist/converge/pending-recovery-source.js +71 -0
  110. package/dist/converge/pending-recovery-source.js.map +1 -0
  111. package/dist/converge/recovery-launch.d.ts +66 -0
  112. package/dist/converge/recovery-launch.js +518 -0
  113. package/dist/converge/recovery-launch.js.map +1 -0
  114. package/dist/converge/retained-report.d.ts +29 -0
  115. package/dist/converge/retained-report.js +218 -0
  116. package/dist/converge/retained-report.js.map +1 -0
  117. package/dist/converge/retry-source.d.ts +25 -0
  118. package/dist/converge/retry-source.js +13 -0
  119. package/dist/converge/retry-source.js.map +1 -0
  120. package/dist/converge/review-cycle.d.ts +49 -0
  121. package/dist/converge/review-cycle.js +26 -0
  122. package/dist/converge/review-cycle.js.map +1 -0
  123. package/dist/converge/round-gap-schema.d.ts +66 -0
  124. package/dist/converge/round-gap-schema.js +51 -0
  125. package/dist/converge/round-gap-schema.js.map +1 -0
  126. package/dist/converge/round-gap.d.ts +38 -0
  127. package/dist/converge/round-gap.js +334 -0
  128. package/dist/converge/round-gap.js.map +1 -0
  129. package/dist/converge/run-state.d.ts +224 -0
  130. package/dist/converge/run-state.js +564 -0
  131. package/dist/converge/run-state.js.map +1 -0
  132. package/dist/converge/stale-report-schema.d.ts +42 -0
  133. package/dist/converge/stale-report-schema.js +79 -0
  134. package/dist/converge/stale-report-schema.js.map +1 -0
  135. package/dist/converge/stale-report-storage.d.ts +47 -0
  136. package/dist/converge/stale-report-storage.js +172 -0
  137. package/dist/converge/stale-report-storage.js.map +1 -0
  138. package/dist/converge/stale-report.d.ts +14 -0
  139. package/dist/converge/stale-report.js +213 -0
  140. package/dist/converge/stale-report.js.map +1 -0
  141. package/dist/converge/target-ownership.d.ts +29 -0
  142. package/dist/converge/target-ownership.js +95 -0
  143. package/dist/converge/target-ownership.js.map +1 -0
  144. package/dist/converge/terminal-rejection-schema.d.ts +42 -0
  145. package/dist/converge/terminal-rejection-schema.js +39 -0
  146. package/dist/converge/terminal-rejection-schema.js.map +1 -0
  147. package/dist/converge/terminal-rejection.d.ts +13 -0
  148. package/dist/converge/terminal-rejection.js +275 -0
  149. package/dist/converge/terminal-rejection.js.map +1 -0
  150. package/dist/coordination/registry-lock.d.ts +82 -0
  151. package/dist/coordination/registry-lock.js +498 -0
  152. package/dist/coordination/registry-lock.js.map +1 -0
  153. package/dist/discuss.d.ts +53 -0
  154. package/dist/discuss.js +112 -0
  155. package/dist/discuss.js.map +1 -0
  156. package/dist/dispatch/adapter.d.ts +32 -0
  157. package/dist/dispatch/adapter.js +2 -0
  158. package/dist/dispatch/adapter.js.map +1 -0
  159. package/dist/dispatch/anthropic.d.ts +10 -0
  160. package/dist/dispatch/anthropic.js +235 -0
  161. package/dist/dispatch/anthropic.js.map +1 -0
  162. package/dist/dispatch/async-lane.d.ts +127 -0
  163. package/dist/dispatch/async-lane.js +414 -0
  164. package/dist/dispatch/async-lane.js.map +1 -0
  165. package/dist/dispatch/capture-council.d.ts +63 -0
  166. package/dist/dispatch/capture-council.js +137 -0
  167. package/dist/dispatch/capture-council.js.map +1 -0
  168. package/dist/dispatch/captured-async.d.ts +67 -0
  169. package/dist/dispatch/captured-async.js +40 -0
  170. package/dist/dispatch/captured-async.js.map +1 -0
  171. package/dist/dispatch/captured-inputs.d.ts +50 -0
  172. package/dist/dispatch/captured-inputs.js +190 -0
  173. package/dist/dispatch/captured-inputs.js.map +1 -0
  174. package/dist/dispatch/checkpoint-async-context.d.ts +27 -0
  175. package/dist/dispatch/checkpoint-async-context.js +51 -0
  176. package/dist/dispatch/checkpoint-async-context.js.map +1 -0
  177. package/dist/dispatch/checkpoint-async-execution.d.ts +22 -0
  178. package/dist/dispatch/checkpoint-async-execution.js +130 -0
  179. package/dist/dispatch/checkpoint-async-execution.js.map +1 -0
  180. package/dist/dispatch/checkpoint-async-store.d.ts +134 -0
  181. package/dist/dispatch/checkpoint-async-store.js +534 -0
  182. package/dist/dispatch/checkpoint-async-store.js.map +1 -0
  183. package/dist/dispatch/checkpoint-async-unknown.d.ts +19 -0
  184. package/dist/dispatch/checkpoint-async-unknown.js +46 -0
  185. package/dist/dispatch/checkpoint-async-unknown.js.map +1 -0
  186. package/dist/dispatch/checkpoint-async.d.ts +252 -0
  187. package/dist/dispatch/checkpoint-async.js +270 -0
  188. package/dist/dispatch/checkpoint-async.js.map +1 -0
  189. package/dist/dispatch/checkpoint-gating-execution.d.ts +26 -0
  190. package/dist/dispatch/checkpoint-gating-execution.js +84 -0
  191. package/dist/dispatch/checkpoint-gating-execution.js.map +1 -0
  192. package/dist/dispatch/checkpoint-phase-limits.d.ts +5 -0
  193. package/dist/dispatch/checkpoint-phase-limits.js +11 -0
  194. package/dist/dispatch/checkpoint-phase-limits.js.map +1 -0
  195. package/dist/dispatch/checkpoint-verification-context.d.ts +15 -0
  196. package/dist/dispatch/checkpoint-verification-context.js +48 -0
  197. package/dist/dispatch/checkpoint-verification-context.js.map +1 -0
  198. package/dist/dispatch/checkpoint-verification.d.ts +213 -0
  199. package/dist/dispatch/checkpoint-verification.js +381 -0
  200. package/dist/dispatch/checkpoint-verification.js.map +1 -0
  201. package/dist/dispatch/checkpoint.d.ts +329 -0
  202. package/dist/dispatch/checkpoint.js +1418 -0
  203. package/dist/dispatch/checkpoint.js.map +1 -0
  204. package/dist/dispatch/google.d.ts +10 -0
  205. package/dist/dispatch/google.js +158 -0
  206. package/dist/dispatch/google.js.map +1 -0
  207. package/dist/dispatch/late-audit.d.ts +23 -0
  208. package/dist/dispatch/late-audit.js +133 -0
  209. package/dist/dispatch/late-audit.js.map +1 -0
  210. package/dist/dispatch/merge.d.ts +29 -0
  211. package/dist/dispatch/merge.js +112 -0
  212. package/dist/dispatch/merge.js.map +1 -0
  213. package/dist/dispatch/openai-compat.d.ts +30 -0
  214. package/dist/dispatch/openai-compat.js +166 -0
  215. package/dist/dispatch/openai-compat.js.map +1 -0
  216. package/dist/dispatch/openai.d.ts +10 -0
  217. package/dist/dispatch/openai.js +159 -0
  218. package/dist/dispatch/openai.js.map +1 -0
  219. package/dist/dispatch/original-execution.d.ts +30 -0
  220. package/dist/dispatch/original-execution.js +91 -0
  221. package/dist/dispatch/original-execution.js.map +1 -0
  222. package/dist/dispatch/original-launch.d.ts +37 -0
  223. package/dist/dispatch/original-launch.js +117 -0
  224. package/dist/dispatch/original-launch.js.map +1 -0
  225. package/dist/dispatch/quorum.d.ts +15 -0
  226. package/dist/dispatch/quorum.js +33 -0
  227. package/dist/dispatch/quorum.js.map +1 -0
  228. package/dist/dispatch/recovery-operation.d.ts +44 -0
  229. package/dist/dispatch/recovery-operation.js +146 -0
  230. package/dist/dispatch/recovery-operation.js.map +1 -0
  231. package/dist/dispatch/recovery-policy.d.ts +54 -0
  232. package/dist/dispatch/recovery-policy.js +157 -0
  233. package/dist/dispatch/recovery-policy.js.map +1 -0
  234. package/dist/dispatch/recovery.d.ts +78 -0
  235. package/dist/dispatch/recovery.js +299 -0
  236. package/dist/dispatch/recovery.js.map +1 -0
  237. package/dist/dispatch/retained-async.d.ts +13 -0
  238. package/dist/dispatch/retained-async.js +101 -0
  239. package/dist/dispatch/retained-async.js.map +1 -0
  240. package/dist/dispatch/reviewer-identity.d.ts +10 -0
  241. package/dist/dispatch/reviewer-identity.js +19 -0
  242. package/dist/dispatch/reviewer-identity.js.map +1 -0
  243. package/dist/dispatch/runner.d.ts +76 -0
  244. package/dist/dispatch/runner.js +415 -0
  245. package/dist/dispatch/runner.js.map +1 -0
  246. package/dist/dispatch/utils.d.ts +159 -0
  247. package/dist/dispatch/utils.js +381 -0
  248. package/dist/dispatch/utils.js.map +1 -0
  249. package/dist/dispatch/verification-execution.d.ts +48 -0
  250. package/dist/dispatch/verification-execution.js +252 -0
  251. package/dist/dispatch/verification-execution.js.map +1 -0
  252. package/dist/dispatch/verification-late-audit.d.ts +17 -0
  253. package/dist/dispatch/verification-late-audit.js +117 -0
  254. package/dist/dispatch/verification-late-audit.js.map +1 -0
  255. package/dist/evidence/claim-recovery/authenticated-carrier-projection.d.ts +30 -0
  256. package/dist/evidence/claim-recovery/authenticated-carrier-projection.js +100 -0
  257. package/dist/evidence/claim-recovery/authenticated-carrier-projection.js.map +1 -0
  258. package/dist/evidence/claim-recovery/authenticated-receipts.d.ts +46 -0
  259. package/dist/evidence/claim-recovery/authenticated-receipts.js +120 -0
  260. package/dist/evidence/claim-recovery/authenticated-receipts.js.map +1 -0
  261. package/dist/evidence/claim-recovery/carrier-inventory.d.ts +49 -0
  262. package/dist/evidence/claim-recovery/carrier-inventory.js +340 -0
  263. package/dist/evidence/claim-recovery/carrier-inventory.js.map +1 -0
  264. package/dist/evidence/claim-recovery/claim-index.d.ts +12 -0
  265. package/dist/evidence/claim-recovery/claim-index.js +56 -0
  266. package/dist/evidence/claim-recovery/claim-index.js.map +1 -0
  267. package/dist/evidence/claim-recovery/confirmation.d.ts +53 -0
  268. package/dist/evidence/claim-recovery/confirmation.js +151 -0
  269. package/dist/evidence/claim-recovery/confirmation.js.map +1 -0
  270. package/dist/evidence/claim-recovery/context.d.ts +15 -0
  271. package/dist/evidence/claim-recovery/context.js +40 -0
  272. package/dist/evidence/claim-recovery/context.js.map +1 -0
  273. package/dist/evidence/claim-recovery/proof-storage.d.ts +6 -0
  274. package/dist/evidence/claim-recovery/proof-storage.js +97 -0
  275. package/dist/evidence/claim-recovery/proof-storage.js.map +1 -0
  276. package/dist/evidence/claim-recovery/validation/anchors.d.ts +20 -0
  277. package/dist/evidence/claim-recovery/validation/anchors.js +22 -0
  278. package/dist/evidence/claim-recovery/validation/anchors.js.map +1 -0
  279. package/dist/evidence/claim-recovery/validation/carrier-projection.d.ts +9 -0
  280. package/dist/evidence/claim-recovery/validation/carrier-projection.js +364 -0
  281. package/dist/evidence/claim-recovery/validation/carrier-projection.js.map +1 -0
  282. package/dist/evidence/claim-recovery/validation/carrier-types.d.ts +83 -0
  283. package/dist/evidence/claim-recovery/validation/carrier-types.js +2 -0
  284. package/dist/evidence/claim-recovery/validation/carrier-types.js.map +1 -0
  285. package/dist/evidence/claim-recovery/validation/claim-split.d.ts +57 -0
  286. package/dist/evidence/claim-recovery/validation/claim-split.js +209 -0
  287. package/dist/evidence/claim-recovery/validation/claim-split.js.map +1 -0
  288. package/dist/evidence/claim-recovery/validation/claims.d.ts +20 -0
  289. package/dist/evidence/claim-recovery/validation/claims.js +108 -0
  290. package/dist/evidence/claim-recovery/validation/claims.js.map +1 -0
  291. package/dist/evidence/claim-recovery/validation/current-projection.d.ts +36 -0
  292. package/dist/evidence/claim-recovery/validation/current-projection.js +424 -0
  293. package/dist/evidence/claim-recovery/validation/current-projection.js.map +1 -0
  294. package/dist/evidence/claim-recovery/validation/lexical.d.ts +18 -0
  295. package/dist/evidence/claim-recovery/validation/lexical.js +91 -0
  296. package/dist/evidence/claim-recovery/validation/lexical.js.map +1 -0
  297. package/dist/evidence/claim-recovery/validation/materials.d.ts +19 -0
  298. package/dist/evidence/claim-recovery/validation/materials.js +160 -0
  299. package/dist/evidence/claim-recovery/validation/materials.js.map +1 -0
  300. package/dist/evidence/claim-recovery/validation/native-material.d.ts +27 -0
  301. package/dist/evidence/claim-recovery/validation/native-material.js +35 -0
  302. package/dist/evidence/claim-recovery/validation/native-material.js.map +1 -0
  303. package/dist/evidence/claim-recovery/validation/native-occurrences.d.ts +79 -0
  304. package/dist/evidence/claim-recovery/validation/native-occurrences.js +187 -0
  305. package/dist/evidence/claim-recovery/validation/native-occurrences.js.map +1 -0
  306. package/dist/evidence/claim-recovery/validation/native-state.d.ts +45 -0
  307. package/dist/evidence/claim-recovery/validation/native-state.js +385 -0
  308. package/dist/evidence/claim-recovery/validation/native-state.js.map +1 -0
  309. package/dist/evidence/claim-recovery/validation/obligations.d.ts +15 -0
  310. package/dist/evidence/claim-recovery/validation/obligations.js +65 -0
  311. package/dist/evidence/claim-recovery/validation/obligations.js.map +1 -0
  312. package/dist/evidence/claim-recovery/validation/occurrence-source.d.ts +45 -0
  313. package/dist/evidence/claim-recovery/validation/occurrence-source.js +208 -0
  314. package/dist/evidence/claim-recovery/validation/occurrence-source.js.map +1 -0
  315. package/dist/evidence/claim-recovery/validation/occurrence-types.d.ts +101 -0
  316. package/dist/evidence/claim-recovery/validation/occurrence-types.js +2 -0
  317. package/dist/evidence/claim-recovery/validation/occurrence-types.js.map +1 -0
  318. package/dist/evidence/claim-recovery/validation/occurrence.d.ts +30 -0
  319. package/dist/evidence/claim-recovery/validation/occurrence.js +227 -0
  320. package/dist/evidence/claim-recovery/validation/occurrence.js.map +1 -0
  321. package/dist/evidence/claim-recovery/validation/primitives.d.ts +11 -0
  322. package/dist/evidence/claim-recovery/validation/primitives.js +41 -0
  323. package/dist/evidence/claim-recovery/validation/primitives.js.map +1 -0
  324. package/dist/evidence/claim-recovery/validation/receipts.d.ts +37 -0
  325. package/dist/evidence/claim-recovery/validation/receipts.js +83 -0
  326. package/dist/evidence/claim-recovery/validation/receipts.js.map +1 -0
  327. package/dist/evidence/claim-recovery/validation/recovery-json.d.ts +8 -0
  328. package/dist/evidence/claim-recovery/validation/recovery-json.js +42 -0
  329. package/dist/evidence/claim-recovery/validation/recovery-json.js.map +1 -0
  330. package/dist/evidence/claim-recovery/validation/semantic-cache.d.ts +3 -0
  331. package/dist/evidence/claim-recovery/validation/semantic-cache.js +22 -0
  332. package/dist/evidence/claim-recovery/validation/semantic-cache.js.map +1 -0
  333. package/dist/evidence/claim-recovery/validation/semantic-validation.d.ts +9 -0
  334. package/dist/evidence/claim-recovery/validation/semantic-validation.js +347 -0
  335. package/dist/evidence/claim-recovery/validation/semantic-validation.js.map +1 -0
  336. package/dist/evidence/claim-recovery/validation/sighting.d.ts +2 -0
  337. package/dist/evidence/claim-recovery/validation/sighting.js +15 -0
  338. package/dist/evidence/claim-recovery/validation/sighting.js.map +1 -0
  339. package/dist/evidence/claim-recovery/validation/sources.d.ts +15 -0
  340. package/dist/evidence/claim-recovery/validation/sources.js +2 -0
  341. package/dist/evidence/claim-recovery/validation/sources.js.map +1 -0
  342. package/dist/evidence/claim-recovery/validation/types.d.ts +126 -0
  343. package/dist/evidence/claim-recovery/validation/types.js +2 -0
  344. package/dist/evidence/claim-recovery/validation/types.js.map +1 -0
  345. package/dist/evidence/claim-split.d.ts +1 -0
  346. package/dist/evidence/claim-split.js +2 -0
  347. package/dist/evidence/claim-split.js.map +1 -0
  348. package/dist/evidence/event-receipts.d.ts +16 -0
  349. package/dist/evidence/event-receipts.js +41 -0
  350. package/dist/evidence/event-receipts.js.map +1 -0
  351. package/dist/evidence/finding-recovery.d.ts +23 -0
  352. package/dist/evidence/finding-recovery.js +74 -0
  353. package/dist/evidence/finding-recovery.js.map +1 -0
  354. package/dist/evidence/finding-retriage.d.ts +14 -0
  355. package/dist/evidence/finding-retriage.js +57 -0
  356. package/dist/evidence/finding-retriage.js.map +1 -0
  357. package/dist/evidence/format.d.ts +18 -0
  358. package/dist/evidence/format.js +152 -0
  359. package/dist/evidence/format.js.map +1 -0
  360. package/dist/evidence/original-run/decode.d.ts +30 -0
  361. package/dist/evidence/original-run/decode.js +208 -0
  362. package/dist/evidence/original-run/decode.js.map +1 -0
  363. package/dist/evidence/original-run/journal.d.ts +31 -0
  364. package/dist/evidence/original-run/journal.js +157 -0
  365. package/dist/evidence/original-run/journal.js.map +1 -0
  366. package/dist/evidence/original-run/lock-path.d.ts +17 -0
  367. package/dist/evidence/original-run/lock-path.js +116 -0
  368. package/dist/evidence/original-run/lock-path.js.map +1 -0
  369. package/dist/evidence/original-run/lock-scope.d.ts +21 -0
  370. package/dist/evidence/original-run/lock-scope.js +61 -0
  371. package/dist/evidence/original-run/lock-scope.js.map +1 -0
  372. package/dist/evidence/original-run/lock.d.ts +33 -0
  373. package/dist/evidence/original-run/lock.js +259 -0
  374. package/dist/evidence/original-run/lock.js.map +1 -0
  375. package/dist/evidence/original-run/remote.d.ts +23 -0
  376. package/dist/evidence/original-run/remote.js +110 -0
  377. package/dist/evidence/original-run/remote.js.map +1 -0
  378. package/dist/evidence/original-run/source.d.ts +61 -0
  379. package/dist/evidence/original-run/source.js +267 -0
  380. package/dist/evidence/original-run/source.js.map +1 -0
  381. package/dist/evidence/reads.d.ts +11 -0
  382. package/dist/evidence/reads.js +16 -0
  383. package/dist/evidence/reads.js.map +1 -0
  384. package/dist/evidence/recover-finding.d.ts +17 -0
  385. package/dist/evidence/recover-finding.js +65 -0
  386. package/dist/evidence/recover-finding.js.map +1 -0
  387. package/dist/evidence/recover-run.d.ts +26 -0
  388. package/dist/evidence/recover-run.js +180 -0
  389. package/dist/evidence/recover-run.js.map +1 -0
  390. package/dist/evidence/retained-time-budget.d.ts +9 -0
  391. package/dist/evidence/retained-time-budget.js +14 -0
  392. package/dist/evidence/retained-time-budget.js.map +1 -0
  393. package/dist/evidence/retriage-finding.d.ts +12 -0
  394. package/dist/evidence/retriage-finding.js +67 -0
  395. package/dist/evidence/retriage-finding.js.map +1 -0
  396. package/dist/evidence/reviewer-lineage.d.ts +35 -0
  397. package/dist/evidence/reviewer-lineage.js +293 -0
  398. package/dist/evidence/reviewer-lineage.js.map +1 -0
  399. package/dist/evidence/reviewer-original.d.ts +67 -0
  400. package/dist/evidence/reviewer-original.js +148 -0
  401. package/dist/evidence/reviewer-original.js.map +1 -0
  402. package/dist/evidence/reviewer-recovery.d.ts +74 -0
  403. package/dist/evidence/reviewer-recovery.js +179 -0
  404. package/dist/evidence/reviewer-recovery.js.map +1 -0
  405. package/dist/evidence/reviewer-status.d.ts +145 -0
  406. package/dist/evidence/reviewer-status.js +302 -0
  407. package/dist/evidence/reviewer-status.js.map +1 -0
  408. package/dist/evidence/show.d.ts +10 -0
  409. package/dist/evidence/show.js +41 -0
  410. package/dist/evidence/show.js.map +1 -0
  411. package/dist/evidence/status.d.ts +38 -0
  412. package/dist/evidence/status.js +73 -0
  413. package/dist/evidence/status.js.map +1 -0
  414. package/dist/evidence/target.d.ts +17 -0
  415. package/dist/evidence/target.js +74 -0
  416. package/dist/evidence/target.js.map +1 -0
  417. package/dist/evidence/types.d.ts +176 -0
  418. package/dist/evidence/types.js +109 -0
  419. package/dist/evidence/types.js.map +1 -0
  420. package/dist/index.d.ts +2 -0
  421. package/dist/index.js +2688 -0
  422. package/dist/index.js.map +1 -0
  423. package/dist/models/seed.d.ts +44 -0
  424. package/dist/models/seed.js +175 -0
  425. package/dist/models/seed.js.map +1 -0
  426. package/dist/models/server-stats.d.ts +80 -0
  427. package/dist/models/server-stats.js +109 -0
  428. package/dist/models/server-stats.js.map +1 -0
  429. package/dist/models/stats-store.d.ts +84 -0
  430. package/dist/models/stats-store.js +572 -0
  431. package/dist/models/stats-store.js.map +1 -0
  432. package/dist/output/artifacts.d.ts +16 -0
  433. package/dist/output/artifacts.js +29 -0
  434. package/dist/output/artifacts.js.map +1 -0
  435. package/dist/output/assembly-refusal.d.ts +8 -0
  436. package/dist/output/assembly-refusal.js +14 -0
  437. package/dist/output/assembly-refusal.js.map +1 -0
  438. package/dist/output/github.d.ts +12 -0
  439. package/dist/output/github.js +214 -0
  440. package/dist/output/github.js.map +1 -0
  441. package/dist/output/json.d.ts +3 -0
  442. package/dist/output/json.js +8 -0
  443. package/dist/output/json.js.map +1 -0
  444. package/dist/output/markdown.d.ts +3 -0
  445. package/dist/output/markdown.js +281 -0
  446. package/dist/output/markdown.js.map +1 -0
  447. package/dist/output/progress.d.ts +55 -0
  448. package/dist/output/progress.js +180 -0
  449. package/dist/output/progress.js.map +1 -0
  450. package/dist/output/sanitize.d.ts +18 -0
  451. package/dist/output/sanitize.js +46 -0
  452. package/dist/output/sanitize.js.map +1 -0
  453. package/dist/output/terminal.d.ts +2 -0
  454. package/dist/output/terminal.js +172 -0
  455. package/dist/output/terminal.js.map +1 -0
  456. package/dist/prepare/chunker.d.ts +18 -0
  457. package/dist/prepare/chunker.js +325 -0
  458. package/dist/prepare/chunker.js.map +1 -0
  459. package/dist/prepare/language.d.ts +1 -0
  460. package/dist/prepare/language.js +99 -0
  461. package/dist/prepare/language.js.map +1 -0
  462. package/dist/prepare/prompt-builder.d.ts +44 -0
  463. package/dist/prepare/prompt-builder.js +102 -0
  464. package/dist/prepare/prompt-builder.js.map +1 -0
  465. package/dist/prepare/unified-diff.d.ts +40 -0
  466. package/dist/prepare/unified-diff.js +135 -0
  467. package/dist/prepare/unified-diff.js.map +1 -0
  468. package/dist/prompts/base.d.ts +3 -0
  469. package/dist/prompts/base.js +53 -0
  470. package/dist/prompts/base.js.map +1 -0
  471. package/dist/prompts/hardening.d.ts +19 -0
  472. package/dist/prompts/hardening.js +67 -0
  473. package/dist/prompts/hardening.js.map +1 -0
  474. package/dist/prompts/languages/elixir.d.ts +1 -0
  475. package/dist/prompts/languages/elixir.js +13 -0
  476. package/dist/prompts/languages/elixir.js.map +1 -0
  477. package/dist/prompts/languages/generic.d.ts +1 -0
  478. package/dist/prompts/languages/generic.js +11 -0
  479. package/dist/prompts/languages/generic.js.map +1 -0
  480. package/dist/prompts/languages/python.d.ts +1 -0
  481. package/dist/prompts/languages/python.js +14 -0
  482. package/dist/prompts/languages/python.js.map +1 -0
  483. package/dist/prompts/languages/typescript.d.ts +1 -0
  484. package/dist/prompts/languages/typescript.js +13 -0
  485. package/dist/prompts/languages/typescript.js.map +1 -0
  486. package/dist/prompts/plan.d.ts +15 -0
  487. package/dist/prompts/plan.js +55 -0
  488. package/dist/prompts/plan.js.map +1 -0
  489. package/dist/report/aggregation-inputs.d.ts +52 -0
  490. package/dist/report/aggregation-inputs.js +114 -0
  491. package/dist/report/aggregation-inputs.js.map +1 -0
  492. package/dist/report/assembly.d.ts +43 -0
  493. package/dist/report/assembly.js +133 -0
  494. package/dist/report/assembly.js.map +1 -0
  495. package/dist/report/blocking-health.d.ts +64 -0
  496. package/dist/report/blocking-health.js +156 -0
  497. package/dist/report/blocking-health.js.map +1 -0
  498. package/dist/report/checkpoint-assembly.d.ts +10 -0
  499. package/dist/report/checkpoint-assembly.js +17 -0
  500. package/dist/report/checkpoint-assembly.js.map +1 -0
  501. package/dist/report/checkpoint-consensus.d.ts +59 -0
  502. package/dist/report/checkpoint-consensus.js +197 -0
  503. package/dist/report/checkpoint-consensus.js.map +1 -0
  504. package/dist/report/checkpoint-gating.d.ts +36 -0
  505. package/dist/report/checkpoint-gating.js +110 -0
  506. package/dist/report/checkpoint-gating.js.map +1 -0
  507. package/dist/report/checkpoint-projection.d.ts +76 -0
  508. package/dist/report/checkpoint-projection.js +122 -0
  509. package/dist/report/checkpoint-projection.js.map +1 -0
  510. package/dist/report/consensus-assembly.d.ts +37 -0
  511. package/dist/report/consensus-assembly.js +33 -0
  512. package/dist/report/consensus-assembly.js.map +1 -0
  513. package/dist/report/recovery-source.d.ts +7 -0
  514. package/dist/report/recovery-source.js +7 -0
  515. package/dist/report/recovery-source.js.map +1 -0
  516. package/dist/report/reviewer-artifact.d.ts +118 -0
  517. package/dist/report/reviewer-artifact.js +381 -0
  518. package/dist/report/reviewer-artifact.js.map +1 -0
  519. package/dist/report/reviewer-evidence-schema.d.ts +42 -0
  520. package/dist/report/reviewer-evidence-schema.js +28 -0
  521. package/dist/report/reviewer-evidence-schema.js.map +1 -0
  522. package/dist/report/reviewer-evidence.d.ts +54 -0
  523. package/dist/report/reviewer-evidence.js +229 -0
  524. package/dist/report/reviewer-evidence.js.map +1 -0
  525. package/dist/report/reviewer-health.d.ts +62 -0
  526. package/dist/report/reviewer-health.js +105 -0
  527. package/dist/report/reviewer-health.js.map +1 -0
  528. package/dist/report/run-header.d.ts +219 -0
  529. package/dist/report/run-header.js +307 -0
  530. package/dist/report/run-header.js.map +1 -0
  531. package/dist/report/supplemental-async.d.ts +19 -0
  532. package/dist/report/supplemental-async.js +85 -0
  533. package/dist/report/supplemental-async.js.map +1 -0
  534. package/dist/report/uuid.d.ts +16 -0
  535. package/dist/report/uuid.js +41 -0
  536. package/dist/report/uuid.js.map +1 -0
  537. package/dist/resolver/git.d.ts +16 -0
  538. package/dist/resolver/git.js +77 -0
  539. package/dist/resolver/git.js.map +1 -0
  540. package/dist/resolver/github-client.d.ts +82 -0
  541. package/dist/resolver/github-client.js +27 -0
  542. package/dist/resolver/github-client.js.map +1 -0
  543. package/dist/resolver/github.d.ts +29 -0
  544. package/dist/resolver/github.js +166 -0
  545. package/dist/resolver/github.js.map +1 -0
  546. package/dist/resolver/local.d.ts +3 -0
  547. package/dist/resolver/local.js +75 -0
  548. package/dist/resolver/local.js.map +1 -0
  549. package/dist/resolver/plan.d.ts +8 -0
  550. package/dist/resolver/plan.js +44 -0
  551. package/dist/resolver/plan.js.map +1 -0
  552. package/dist/resolver/target.d.ts +35 -0
  553. package/dist/resolver/target.js +112 -0
  554. package/dist/resolver/target.js.map +1 -0
  555. package/dist/resolver/types.d.ts +43 -0
  556. package/dist/resolver/types.js +2 -0
  557. package/dist/resolver/types.js.map +1 -0
  558. package/dist/roles/builtin.d.ts +4 -0
  559. package/dist/roles/builtin.js +282 -0
  560. package/dist/roles/builtin.js.map +1 -0
  561. package/dist/roles/dispatcher.d.ts +26 -0
  562. package/dist/roles/dispatcher.js +96 -0
  563. package/dist/roles/dispatcher.js.map +1 -0
  564. package/dist/roles/legacy-4.1.10.d.ts +2 -0
  565. package/dist/roles/legacy-4.1.10.js +320 -0
  566. package/dist/roles/legacy-4.1.10.js.map +1 -0
  567. package/dist/roles/legacy-4.4.9.d.ts +4 -0
  568. package/dist/roles/legacy-4.4.9.js +282 -0
  569. package/dist/roles/legacy-4.4.9.js.map +1 -0
  570. package/dist/roles/loader.d.ts +10 -0
  571. package/dist/roles/loader.js +104 -0
  572. package/dist/roles/loader.js.map +1 -0
  573. package/dist/roles/types.d.ts +13 -0
  574. package/dist/roles/types.js +2 -0
  575. package/dist/roles/types.js.map +1 -0
  576. package/dist/telemetry/abort-signal.d.ts +13 -0
  577. package/dist/telemetry/abort-signal.js +40 -0
  578. package/dist/telemetry/abort-signal.js.map +1 -0
  579. package/dist/telemetry/attest.d.ts +98 -0
  580. package/dist/telemetry/attest.js +331 -0
  581. package/dist/telemetry/attest.js.map +1 -0
  582. package/dist/telemetry/attested-retry.d.ts +79 -0
  583. package/dist/telemetry/attested-retry.js +195 -0
  584. package/dist/telemetry/attested-retry.js.map +1 -0
  585. package/dist/telemetry/attested-reviewer-delivery.d.ts +58 -0
  586. package/dist/telemetry/attested-reviewer-delivery.js +238 -0
  587. package/dist/telemetry/attested-reviewer-delivery.js.map +1 -0
  588. package/dist/telemetry/backfill.d.ts +95 -0
  589. package/dist/telemetry/backfill.js +460 -0
  590. package/dist/telemetry/backfill.js.map +1 -0
  591. package/dist/telemetry/credentials.d.ts +44 -0
  592. package/dist/telemetry/credentials.js +87 -0
  593. package/dist/telemetry/credentials.js.map +1 -0
  594. package/dist/telemetry/deliver.d.ts +152 -0
  595. package/dist/telemetry/deliver.js +662 -0
  596. package/dist/telemetry/deliver.js.map +1 -0
  597. package/dist/telemetry/envelope-validation.d.ts +13 -0
  598. package/dist/telemetry/envelope-validation.js +196 -0
  599. package/dist/telemetry/envelope-validation.js.map +1 -0
  600. package/dist/telemetry/envelope.d.ts +159 -0
  601. package/dist/telemetry/envelope.js +288 -0
  602. package/dist/telemetry/envelope.js.map +1 -0
  603. package/dist/telemetry/events.d.ts +68 -0
  604. package/dist/telemetry/events.js +79 -0
  605. package/dist/telemetry/events.js.map +1 -0
  606. package/dist/telemetry/notice.d.ts +15 -0
  607. package/dist/telemetry/notice.js +67 -0
  608. package/dist/telemetry/notice.js.map +1 -0
  609. package/dist/telemetry/outbox.d.ts +166 -0
  610. package/dist/telemetry/outbox.js +741 -0
  611. package/dist/telemetry/outbox.js.map +1 -0
  612. package/dist/telemetry/quarantine.d.ts +105 -0
  613. package/dist/telemetry/quarantine.js +224 -0
  614. package/dist/telemetry/quarantine.js.map +1 -0
  615. package/dist/telemetry/read-sink.d.ts +31 -0
  616. package/dist/telemetry/read-sink.js +25 -0
  617. package/dist/telemetry/read-sink.js.map +1 -0
  618. package/dist/telemetry/recovery/command.d.ts +16 -0
  619. package/dist/telemetry/recovery/command.js +70 -0
  620. package/dist/telemetry/recovery/command.js.map +1 -0
  621. package/dist/telemetry/recovery/discovery.d.ts +8 -0
  622. package/dist/telemetry/recovery/discovery.js +277 -0
  623. package/dist/telemetry/recovery/discovery.js.map +1 -0
  624. package/dist/telemetry/recovery/files.d.ts +20 -0
  625. package/dist/telemetry/recovery/files.js +123 -0
  626. package/dist/telemetry/recovery/files.js.map +1 -0
  627. package/dist/telemetry/recovery/plan.d.ts +10 -0
  628. package/dist/telemetry/recovery/plan.js +325 -0
  629. package/dist/telemetry/recovery/plan.js.map +1 -0
  630. package/dist/telemetry/recovery/source.d.ts +328 -0
  631. package/dist/telemetry/recovery/source.js +253 -0
  632. package/dist/telemetry/recovery/source.js.map +1 -0
  633. package/dist/telemetry/recovery/types.d.ts +100 -0
  634. package/dist/telemetry/recovery/types.js +2 -0
  635. package/dist/telemetry/recovery/types.js.map +1 -0
  636. package/dist/telemetry/recovery-request-budget.d.ts +39 -0
  637. package/dist/telemetry/recovery-request-budget.js +102 -0
  638. package/dist/telemetry/recovery-request-budget.js.map +1 -0
  639. package/dist/telemetry/report-consistency.d.ts +11 -0
  640. package/dist/telemetry/report-consistency.js +111 -0
  641. package/dist/telemetry/report-consistency.js.map +1 -0
  642. package/dist/telemetry/reviewer-delivery.d.ts +39 -0
  643. package/dist/telemetry/reviewer-delivery.js +279 -0
  644. package/dist/telemetry/reviewer-delivery.js.map +1 -0
  645. package/dist/telemetry/reviewer-preflight.d.ts +13 -0
  646. package/dist/telemetry/reviewer-preflight.js +56 -0
  647. package/dist/telemetry/reviewer-preflight.js.map +1 -0
  648. package/dist/telemetry/scrub.d.ts +53 -0
  649. package/dist/telemetry/scrub.js +205 -0
  650. package/dist/telemetry/scrub.js.map +1 -0
  651. package/dist/telemetry/sink.d.ts +212 -0
  652. package/dist/telemetry/sink.js +813 -0
  653. package/dist/telemetry/sink.js.map +1 -0
  654. package/dist/telemetry/terminal-reviewer-delivery.d.ts +18 -0
  655. package/dist/telemetry/terminal-reviewer-delivery.js +27 -0
  656. package/dist/telemetry/terminal-reviewer-delivery.js.map +1 -0
  657. package/dist/telemetry/transient-input.d.ts +2 -0
  658. package/dist/telemetry/transient-input.js +37 -0
  659. package/dist/telemetry/transient-input.js.map +1 -0
  660. package/dist/telemetry/verification.d.ts +9 -0
  661. package/dist/telemetry/verification.js +12 -0
  662. package/dist/telemetry/verification.js.map +1 -0
  663. package/package.json +73 -0
@@ -0,0 +1,717 @@
1
+ import { retrySourceSchema } from './retry-source.js';
2
+ import { boundFixRecoverySourceSchema } from './bound-fix-recovery-source.js';
3
+ import { pendingRecoverySourceSchema } from './pending-recovery-source.js';
4
+ import { execFile } from 'node:child_process';
5
+ import { createHash, randomUUID } from 'node:crypto';
6
+ import { link, lstat, mkdir, open, readFile, realpath, rename, rm, unlink, writeFile, } from 'node:fs/promises';
7
+ import { dirname, isAbsolute, join, resolve } from 'node:path';
8
+ import { promisify } from 'node:util';
9
+ import { withNativeTarget, withOwnedNativeOperation } from './target-ownership.js';
10
+ import { validCycleVersion } from './review-cycle.js';
11
+ import { RegistryCleanupError } from '../coordination/registry-lock.js';
12
+ export const DEFAULT_CONVERGE_ATTEMPT_CAP = 20;
13
+ const STATE_VERSION = 2;
14
+ const STATE_DIR = 'rcl-converge-attempts';
15
+ // The native target reservation now also bridges historical recovery clients
16
+ // for the whole critical section. A burst of normal starters may therefore
17
+ // wait behind valid work longer than the accounting lock's 5s retry bound.
18
+ const DEFAULT_TARGET_LOCK_TIMEOUT_MS = 30_000;
19
+ const DEFAULT_LOCK_TIMEOUT_MS = 5_000;
20
+ const DEFAULT_LOCK_RETRY_MS = 10;
21
+ const execFileAsync = promisify(execFile);
22
+ export class ConvergeAttemptBudgetExceededError extends Error {
23
+ target;
24
+ attemptsUsed;
25
+ cap;
26
+ code = 'RCL_CONVERGE_ATTEMPT_CAP';
27
+ constructor(target, attemptsUsed, cap) {
28
+ super(`Convergence attempt budget exhausted for ${target}: ${attemptsUsed}/${cap} attempts used. ` +
29
+ 'No provider calls were started. Ask the user whether to continue; only after explicit ' +
30
+ 'approval, retry with a higher --max-attempts value.');
31
+ this.target = target;
32
+ this.attemptsUsed = attemptsUsed;
33
+ this.cap = cap;
34
+ this.name = 'ConvergeAttemptBudgetExceededError';
35
+ }
36
+ }
37
+ /** A post-claim delivery failed after the attempt was durably consumed. */
38
+ export class ConvergeAttemptPostClaimError extends Error {
39
+ claim;
40
+ constructor(claim, cause) {
41
+ super(`Attempt ${claim.attempt}/${claim.cap} is durably recorded, but post-claim delivery failed: ` +
42
+ `${cause instanceof Error ? cause.message : String(cause)}. Do not retry this claim.`, { cause });
43
+ this.claim = claim;
44
+ this.name = 'ConvergeAttemptPostClaimError';
45
+ }
46
+ }
47
+ export class ConvergeAttemptStateError extends Error {
48
+ code = 'RCL_CONVERGE_ATTEMPT_STATE';
49
+ constructor(message, options) {
50
+ super(message, options);
51
+ this.name = 'ConvergeAttemptStateError';
52
+ }
53
+ }
54
+ export function convergeAttemptErrorExitCode(err) {
55
+ return err instanceof ConvergeAttemptBudgetExceededError ? 2 : 3;
56
+ }
57
+ function validateTarget(target) {
58
+ const trimmed = target.trim();
59
+ if (!trimmed) {
60
+ throw new ConvergeAttemptStateError('Convergence target must not be empty.');
61
+ }
62
+ return trimmed;
63
+ }
64
+ export function validateAttemptCap(maxAttempts) {
65
+ if (!Number.isSafeInteger(maxAttempts) || maxAttempts < 1) {
66
+ throw new ConvergeAttemptStateError('maxAttempts (--max-attempts) must be a positive safe integer.');
67
+ }
68
+ return maxAttempts;
69
+ }
70
+ function stateBaseName(target) {
71
+ const slug = target.replace(/[^A-Za-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 48);
72
+ const digest = createHash('sha256').update(target).digest('hex').slice(0, 16);
73
+ return `${slug || 'target'}-${digest}`;
74
+ }
75
+ export function convergeAttemptStatePath(gitCommonDir, target) {
76
+ return join(resolve(gitCommonDir), STATE_DIR, `${stateBaseName(validateTarget(target))}.json`);
77
+ }
78
+ function isNodeError(err, code) {
79
+ return err instanceof Error && err.code === code;
80
+ }
81
+ export function validateConvergeAttemptState(value, expectedTarget, stateFile) {
82
+ if (typeof value !== 'object' || value === null) {
83
+ throw new ConvergeAttemptStateError(`Invalid convergence attempt state: ${stateFile}`);
84
+ }
85
+ const state = value;
86
+ const attempts = state.attempts;
87
+ if (!validCycleVersion(state, STATE_VERSION) ||
88
+ state.target !== expectedTarget ||
89
+ !Number.isSafeInteger(state.cap) ||
90
+ (state.cap ?? 0) < 1 ||
91
+ !Number.isSafeInteger(state.migratedAttempts) ||
92
+ (state.migratedAttempts ?? -1) < 0 ||
93
+ !Number.isSafeInteger(state.attemptsUsed) ||
94
+ (state.attemptsUsed ?? -1) < 0 ||
95
+ !Array.isArray(attempts) ||
96
+ attempts.length + (state.migratedAttempts ?? 0) !== state.attemptsUsed ||
97
+ typeof state.updatedAt !== 'string' ||
98
+ attempts.some((record, index) => typeof record !== 'object' ||
99
+ record === null ||
100
+ record.attempt !== (state.migratedAttempts ?? 0) + index + 1 ||
101
+ typeof record.claimedAt !== 'string' ||
102
+ !Number.isInteger(record.pid) ||
103
+ record.source !== 'claim' ||
104
+ (record.retrySource !== undefined && (!retrySourceSchema.safeParse(record.retrySource).success ||
105
+ record.retrySource.attempt !== record.attempt - 1)) ||
106
+ (record.boundFixRecoverySource !== undefined &&
107
+ (!boundFixRecoverySourceSchema.safeParse(record.boundFixRecoverySource).success ||
108
+ record.boundFixRecoverySource.attempt !== record.attempt - 1 ||
109
+ record.boundFixRecoverySource.target !== expectedTarget || record.retrySource !== undefined ||
110
+ record.pendingRecoverySource !== undefined)) ||
111
+ (record.pendingRecoverySource !== undefined &&
112
+ (!pendingRecoverySourceSchema.safeParse(record.pendingRecoverySource).success ||
113
+ record.pendingRecoverySource.pendingAttempt !== record.attempt - 1 ||
114
+ record.pendingRecoverySource.target !== expectedTarget ||
115
+ record.retrySource !== undefined || record.boundFixRecoverySource !== undefined)))) {
116
+ throw new ConvergeAttemptStateError(`Invalid convergence attempt state in ${stateFile}; refusing to reset the safety budget.`);
117
+ }
118
+ return state;
119
+ }
120
+ async function stateFromExistingLedger(gitCommonDir, target, timestamp) {
121
+ // The skill already restricts TARGET to this alphabet. For a direct CLI
122
+ // caller with another shape, skip migration rather than deriving a path
123
+ // from untrusted input; the hashed machine-state path remains safe.
124
+ if (!/^[A-Za-z0-9._-]+$/.test(target))
125
+ return undefined;
126
+ const ledgerFile = join(resolve(gitCommonDir), `rcl-converge-${target}-ledger.md`);
127
+ let ledger;
128
+ try {
129
+ ledger = await readFile(ledgerFile, 'utf8');
130
+ }
131
+ catch (err) {
132
+ if (isNodeError(err, 'ENOENT'))
133
+ return undefined;
134
+ throw new ConvergeAttemptStateError(`Could not read existing convergence ledger: ${ledgerFile}`, {
135
+ cause: err,
136
+ });
137
+ }
138
+ let attemptsUsed = 0;
139
+ for (const match of ledger.matchAll(/^## Round\s+(\d+)\b/gm)) {
140
+ const round = Number(match[1]);
141
+ if (!Number.isSafeInteger(round) || round < 1) {
142
+ throw new ConvergeAttemptStateError(`Invalid round number in existing convergence ledger: ${ledgerFile}`);
143
+ }
144
+ attemptsUsed = Math.max(attemptsUsed, round);
145
+ }
146
+ if (attemptsUsed === 0)
147
+ return undefined;
148
+ return {
149
+ version: STATE_VERSION,
150
+ target,
151
+ cap: DEFAULT_CONVERGE_ATTEMPT_CAP,
152
+ migratedAttempts: attemptsUsed,
153
+ attemptsUsed,
154
+ attempts: [],
155
+ updatedAt: timestamp,
156
+ };
157
+ }
158
+ async function readState(stateFile, target) {
159
+ let raw;
160
+ try {
161
+ raw = await readFile(stateFile, 'utf8');
162
+ }
163
+ catch (err) {
164
+ if (isNodeError(err, 'ENOENT'))
165
+ return undefined;
166
+ throw new ConvergeAttemptStateError(`Could not read convergence attempt state: ${stateFile}`, {
167
+ cause: err,
168
+ });
169
+ }
170
+ try {
171
+ return validateConvergeAttemptState(JSON.parse(raw), target, stateFile);
172
+ }
173
+ catch (err) {
174
+ if (err instanceof ConvergeAttemptStateError)
175
+ throw err;
176
+ throw new ConvergeAttemptStateError(`Invalid JSON in ${stateFile}; refusing to reset the safety budget.`, { cause: err });
177
+ }
178
+ }
179
+ function delay(ms) {
180
+ return new Promise((resolveDelay) => setTimeout(resolveDelay, ms));
181
+ }
182
+ function processIsAlive(pid) {
183
+ try {
184
+ process.kill(pid, 0);
185
+ return true;
186
+ }
187
+ catch (err) {
188
+ if (isNodeError(err, 'ESRCH'))
189
+ return false;
190
+ if (isNodeError(err, 'EPERM'))
191
+ return true;
192
+ throw err;
193
+ }
194
+ }
195
+ function parseLockOwner(raw) {
196
+ try {
197
+ const parsed = JSON.parse(raw);
198
+ if (parsed !== null &&
199
+ typeof parsed === 'object' &&
200
+ Number.isInteger(parsed.pid) &&
201
+ (parsed.pid ?? 0) > 0 &&
202
+ typeof parsed.claimedAt === 'string' &&
203
+ typeof parsed.token === 'string' &&
204
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(parsed.token)) {
205
+ return parsed;
206
+ }
207
+ }
208
+ catch (err) {
209
+ if (!(err instanceof SyntaxError))
210
+ throw err;
211
+ }
212
+ return undefined;
213
+ }
214
+ async function readLockSnapshot(lockFile) {
215
+ let handle;
216
+ try {
217
+ handle = await open(lockFile, 'r');
218
+ }
219
+ catch (err) {
220
+ if (isNodeError(err, 'ENOENT') ||
221
+ isNodeError(err, 'EISDIR') ||
222
+ isNodeError(err, 'EPERM')) {
223
+ return undefined;
224
+ }
225
+ throw err;
226
+ }
227
+ let raw;
228
+ let stats;
229
+ let primaryError;
230
+ try {
231
+ raw = await handle.readFile('utf8');
232
+ stats = await handle.stat({ bigint: true });
233
+ }
234
+ catch (err) {
235
+ primaryError = err;
236
+ if (isNodeError(err, 'EISDIR') || isNodeError(err, 'ENOTDIR'))
237
+ return undefined;
238
+ throw err;
239
+ }
240
+ finally {
241
+ try {
242
+ await handle.close();
243
+ }
244
+ catch (closeError) {
245
+ if (primaryError === undefined)
246
+ throw closeError;
247
+ }
248
+ }
249
+ const owner = parseLockOwner(raw);
250
+ return owner ? { owner, dev: stats.dev, ino: stats.ino } : undefined;
251
+ }
252
+ async function lockPathExists(lockFile) {
253
+ try {
254
+ await lstat(lockFile);
255
+ return true;
256
+ }
257
+ catch (err) {
258
+ if (isNodeError(err, 'ENOENT'))
259
+ return false;
260
+ throw err;
261
+ }
262
+ }
263
+ async function isPublicationContention(err, destination) {
264
+ if (isNodeError(err, 'EEXIST') || isNodeError(err, 'ENOTEMPTY'))
265
+ return true;
266
+ // Windows can report an existing destination as EPERM or EACCES. Treat
267
+ // those as contention only when the destination now exists;
268
+ // a genuine permission failure on an absent path remains infrastructure
269
+ // failure and must fail closed.
270
+ return ((isNodeError(err, 'EPERM') || isNodeError(err, 'EACCES')) &&
271
+ (await lockPathExists(destination)));
272
+ }
273
+ async function tryAcquireOwnedLock(lockFile, owner) {
274
+ // Fully write a private regular file, then atomically hard-link it into the
275
+ // canonical path. link(2) never replaces an existing file *or directory*,
276
+ // so this remains safe while an older mkdir-based client is in flight.
277
+ const claimFile = `${lockFile}.claim.${process.pid}.${randomUUID()}`;
278
+ let primaryError;
279
+ let published = false;
280
+ try {
281
+ await writeFile(claimFile, `${JSON.stringify(owner)}\n`, {
282
+ encoding: 'utf8',
283
+ flag: 'wx',
284
+ mode: 0o600,
285
+ });
286
+ try {
287
+ await link(claimFile, lockFile);
288
+ }
289
+ catch (err) {
290
+ if (await isPublicationContention(err, lockFile))
291
+ return false;
292
+ throw err;
293
+ }
294
+ published = true;
295
+ return true;
296
+ }
297
+ catch (err) {
298
+ primaryError = err;
299
+ throw err;
300
+ }
301
+ finally {
302
+ try {
303
+ await rm(claimFile, { force: true });
304
+ }
305
+ catch (cleanupError) {
306
+ // Once linked, the canonical inode is complete and authoritative; an
307
+ // orphaned private hard link is harmless and must not negate success.
308
+ if (!published && primaryError === undefined)
309
+ throw cleanupError;
310
+ }
311
+ }
312
+ }
313
+ async function pathMatchesSnapshot(path, snapshot) {
314
+ try {
315
+ const stats = await lstat(path, { bigint: true });
316
+ return stats.dev === snapshot.dev && stats.ino === snapshot.ino;
317
+ }
318
+ catch (err) {
319
+ if (isNodeError(err, 'ENOENT'))
320
+ return false;
321
+ throw err;
322
+ }
323
+ }
324
+ async function reclaimStaleLock(lockFile, staleSnapshot) {
325
+ const current = await readLockSnapshot(lockFile);
326
+ if (!current ||
327
+ current.owner.token !== staleSnapshot.owner.token ||
328
+ current.dev !== staleSnapshot.dev ||
329
+ current.ino !== staleSnapshot.ino ||
330
+ processIsAlive(current.owner.pid)) {
331
+ return false;
332
+ }
333
+ // Exactly one reclaimer can create this generation's hard-link tombstone.
334
+ // Every delayed peer sees EEXIST and is forbidden from unlinking canonical,
335
+ // so it can never remove a newer generation that appeared later.
336
+ const staleFile = `${lockFile}.stale.${current.owner.token}`;
337
+ try {
338
+ await link(lockFile, staleFile);
339
+ }
340
+ catch (err) {
341
+ if (isNodeError(err, 'ENOENT') || (await isPublicationContention(err, staleFile)))
342
+ return false;
343
+ throw err;
344
+ }
345
+ const stillCanonical = await pathMatchesSnapshot(lockFile, current);
346
+ const ownsTombstone = await pathMatchesSnapshot(staleFile, current);
347
+ if (!stillCanonical || !ownsTombstone || processIsAlive(current.owner.pid)) {
348
+ await rm(staleFile, { force: true });
349
+ return !stillCanonical;
350
+ }
351
+ try {
352
+ await unlink(lockFile);
353
+ }
354
+ catch (err) {
355
+ if (!isNodeError(err, 'ENOENT'))
356
+ throw err;
357
+ }
358
+ // Inode comparison makes even an arbitrarily delayed reclaimer safe after
359
+ // this point, so the tombstone can be removed without reopening the race.
360
+ try {
361
+ await rm(staleFile, { force: true });
362
+ }
363
+ catch {
364
+ // A leftover hard link is harmless and generation-scoped.
365
+ }
366
+ return true;
367
+ }
368
+ async function acquireOwnedLock(lockFile, timeoutMs, retryMs, owner) {
369
+ const deadline = Date.now() + timeoutMs;
370
+ let waitMs = Math.max(1, retryMs);
371
+ while (true) {
372
+ // These reads choose between acquire, reclaim, and fail-closed waiting;
373
+ // they do not provide mutual exclusion. Exclusive hard-link publication
374
+ // and the generation tombstone are the serialization primitives.
375
+ const current = await readLockSnapshot(lockFile);
376
+ if (current && !processIsAlive(current.owner.pid)) {
377
+ if (await reclaimStaleLock(lockFile, current)) {
378
+ continue;
379
+ }
380
+ }
381
+ else if (!current && !(await lockPathExists(lockFile))) {
382
+ if (await tryAcquireOwnedLock(lockFile, owner))
383
+ return;
384
+ }
385
+ if (Date.now() >= deadline) {
386
+ throw new ConvergeAttemptStateError(`Timed out waiting for convergence attempt lock: ${lockFile}. ` +
387
+ 'Refusing to start provider calls while accounting is uncertain. ' +
388
+ 'If no live converge-attempt process owns it, move or remove that lock path and retry.');
389
+ }
390
+ await delay(Math.min(waitMs, Math.max(1, deadline - Date.now())));
391
+ waitMs = Math.min(waitMs * 2, 250);
392
+ }
393
+ }
394
+ async function syncDirectory(path) {
395
+ // Windows does not expose directory handles that Node can fsync. The state
396
+ // file itself is still flushed before the atomic rename; POSIX platforms
397
+ // additionally flush the directory entry here.
398
+ if (process.platform === 'win32')
399
+ return;
400
+ const directory = await open(path, 'r');
401
+ let primaryError;
402
+ try {
403
+ await directory.sync();
404
+ }
405
+ catch (err) {
406
+ primaryError = err;
407
+ throw err;
408
+ }
409
+ finally {
410
+ try {
411
+ await directory.close();
412
+ }
413
+ catch (closeError) {
414
+ if (primaryError === undefined)
415
+ throw closeError;
416
+ }
417
+ }
418
+ }
419
+ async function writeStateAtomically(stateFile, state) {
420
+ const tempFile = `${stateFile}.${process.pid}.${randomUUID()}.tmp`;
421
+ let primaryError;
422
+ let renamed = false;
423
+ try {
424
+ const tempHandle = await open(tempFile, 'wx', 0o600);
425
+ let tempHandleError;
426
+ try {
427
+ await tempHandle.writeFile(`${JSON.stringify(state, null, 2)}\n`, 'utf8');
428
+ await tempHandle.sync();
429
+ }
430
+ catch (err) {
431
+ tempHandleError = err;
432
+ throw err;
433
+ }
434
+ finally {
435
+ try {
436
+ await tempHandle.close();
437
+ }
438
+ catch (closeError) {
439
+ if (tempHandleError === undefined)
440
+ throw closeError;
441
+ }
442
+ }
443
+ await rename(tempFile, stateFile);
444
+ renamed = true;
445
+ // fsyncing the file before rename makes its contents durable; syncing the
446
+ // parent directory makes the atomic name replacement durable too.
447
+ await syncDirectory(dirname(stateFile));
448
+ }
449
+ catch (err) {
450
+ primaryError =
451
+ renamed && !(err instanceof ConvergeAttemptStateError)
452
+ ? new ConvergeAttemptStateError(`Attempt state was replaced but its directory durability sync failed: ${stateFile}. ` +
453
+ 'Treat the attempt as spent and do not retry automatically.', { cause: err })
454
+ : err;
455
+ throw primaryError;
456
+ }
457
+ finally {
458
+ try {
459
+ await rm(tempFile, { force: true });
460
+ }
461
+ catch (cleanupError) {
462
+ if (primaryError === undefined)
463
+ throw cleanupError;
464
+ }
465
+ }
466
+ }
467
+ async function releaseOwnedLock(lockFile, owner) {
468
+ const current = await readLockSnapshot(lockFile);
469
+ if (!current || current.owner.token !== owner.token) {
470
+ throw new ConvergeAttemptStateError(`Convergence attempt lock ownership changed unexpectedly: ${lockFile}. ` +
471
+ 'Refusing to remove a lock that may belong to another process.');
472
+ }
473
+ const releasedFile = `${lockFile}.released.${owner.token}`;
474
+ await rename(lockFile, releasedFile);
475
+ // The canonical lock is already gone. A cleanup failure leaves only a
476
+ // harmless generation-scoped artifact and must not turn a recorded claim
477
+ // into a reported failure that an agent might retry.
478
+ try {
479
+ await rm(releasedFile, { force: true });
480
+ }
481
+ catch {
482
+ // Intentionally retained for later manual cleanup.
483
+ }
484
+ }
485
+ /**
486
+ * Atomically consume one convergence attempt before a council process starts.
487
+ * The claim is intentionally outcome-blind: once returned, a failed launch,
488
+ * timeout, kill, missing report, or inconclusive review has still spent the
489
+ * attempt. This makes the cost ceiling independent of agent bookkeeping.
490
+ */
491
+ export async function claimConvergeAttempt(options) {
492
+ // Callers can retain and mutate their options object while this invocation
493
+ // waits for target ownership. Capture every input before that first await so
494
+ // the state claim cannot escape the lock selected for this operation.
495
+ const claimOptions = {
496
+ gitCommonDir: options.gitCommonDir,
497
+ target: validateTarget(options.target),
498
+ maxAttempts: options.maxAttempts,
499
+ now: options.now,
500
+ recordPid: options.recordPid,
501
+ lockTimeoutMs: options.lockTimeoutMs,
502
+ lockRetryMs: options.lockRetryMs,
503
+ targetLockTimeoutMs: options.targetLockTimeoutMs,
504
+ targetLockRetryMs: options.targetLockRetryMs,
505
+ beforeClaim: options.beforeClaim,
506
+ afterClaim: options.afterClaim,
507
+ ownership: options.ownership,
508
+ freshReviewOperation: options.freshReviewOperation,
509
+ pendingRecoverySource: options.pendingRecoverySource,
510
+ };
511
+ if (claimOptions.freshReviewOperation && !claimOptions.ownership)
512
+ throw new Error('fresh_review_owner_required');
513
+ // Use one canonical directory for both target ownership and state paths.
514
+ // The caller's textual symlink must not be resolved once for a lock and
515
+ // later again for a state write after it has been retargeted.
516
+ claimOptions.gitCommonDir = await realpath(resolve(claimOptions.gitCommonDir));
517
+ const { gitCommonDir, target } = claimOptions;
518
+ if (claimOptions.maxAttempts !== undefined)
519
+ validateAttemptCap(claimOptions.maxAttempts);
520
+ let committed;
521
+ try {
522
+ const work = async (ownership) => {
523
+ const source = await claimOptions.beforeClaim?.(ownership);
524
+ if (source?.retrySource !== undefined)
525
+ claimOptions.retrySource = retrySourceSchema.parse(source.retrySource);
526
+ if (source?.boundFixRecoverySource !== undefined) {
527
+ claimOptions.boundFixRecoverySource = boundFixRecoverySourceSchema.parse(source.boundFixRecoverySource);
528
+ }
529
+ if (source?.pendingRecoverySource !== undefined) {
530
+ claimOptions.pendingRecoverySource = pendingRecoverySourceSchema.parse(source.pendingRecoverySource);
531
+ }
532
+ const { assertFreshReviewClaim } = await import('./fresh-review.js');
533
+ await assertFreshReviewClaim(gitCommonDir, target, claimOptions.freshReviewOperation);
534
+ committed = await claimConvergeAttemptOwned(claimOptions);
535
+ try {
536
+ await claimOptions.afterClaim?.(committed, ownership);
537
+ }
538
+ catch (error) {
539
+ throw new ConvergeAttemptPostClaimError(committed, error);
540
+ }
541
+ return committed;
542
+ };
543
+ return claimOptions.ownership
544
+ ? await withOwnedNativeOperation(claimOptions.ownership, gitCommonDir, target, work)
545
+ : await withNativeTarget(gitCommonDir, target, work, {
546
+ lockTimeoutMs: claimOptions.targetLockTimeoutMs ?? DEFAULT_TARGET_LOCK_TIMEOUT_MS,
547
+ lockRetryMs: claimOptions.targetLockRetryMs,
548
+ });
549
+ }
550
+ catch (error) {
551
+ const postClaim = findPostClaimError(error);
552
+ if (postClaim)
553
+ throw postClaim;
554
+ if (!(error instanceof RegistryCleanupError) || !committed || error.result !== committed)
555
+ throw error;
556
+ committed.warning = [committed.warning,
557
+ `Attempt ${committed.attempt}/${committed.cap} is durably recorded, but target lock cleanup failed: ${error.message}. ` +
558
+ 'Do not retry this claim. Inspect target coordination before further target mutations.'].filter(Boolean).join(' ');
559
+ return committed;
560
+ }
561
+ }
562
+ function findPostClaimError(error) {
563
+ if (error instanceof ConvergeAttemptPostClaimError)
564
+ return error;
565
+ if (error instanceof AggregateError) {
566
+ for (const nested of error.errors) {
567
+ const found = findPostClaimError(nested);
568
+ if (found)
569
+ return found;
570
+ }
571
+ }
572
+ return undefined;
573
+ }
574
+ async function claimConvergeAttemptOwned(options) {
575
+ const target = validateTarget(options.target);
576
+ const requestedCap = options.maxAttempts === undefined ? undefined : validateAttemptCap(options.maxAttempts);
577
+ const stateFile = convergeAttemptStatePath(options.gitCommonDir, target);
578
+ const stateDir = join(resolve(options.gitCommonDir), STATE_DIR);
579
+ const lockFile = `${stateFile}.lock`;
580
+ const now = options.now ?? (() => new Date());
581
+ const recordPid = options.recordPid ?? process.pid;
582
+ const lockOwner = {
583
+ pid: process.pid,
584
+ claimedAt: now().toISOString(),
585
+ token: randomUUID(),
586
+ };
587
+ await mkdir(stateDir, { recursive: true, mode: 0o700 });
588
+ // Persist a newly created directory entry before relying on state files
589
+ // inside it. Repeating the sync is intentional: if a prior sync failed,
590
+ // the next invocation must not silently skip the durability barrier merely
591
+ // because mkdir now observes the directory.
592
+ await syncDirectory(dirname(stateDir));
593
+ await acquireOwnedLock(lockFile, options.lockTimeoutMs ?? DEFAULT_LOCK_TIMEOUT_MS, options.lockRetryMs ?? DEFAULT_LOCK_RETRY_MS, lockOwner);
594
+ let claim;
595
+ let claimError;
596
+ try {
597
+ const timestamp = now().toISOString();
598
+ const stored = await readState(stateFile, target);
599
+ const { assertReviewCyclePair } = await import('./fresh-review.js');
600
+ await assertReviewCyclePair(options.gitCommonDir, target, stored?.cycle);
601
+ const previous = stored ?? (await stateFromExistingLedger(options.gitCommonDir, target, timestamp));
602
+ const attemptsUsed = previous?.attemptsUsed ?? 0;
603
+ // Omitting --max-attempts preserves an existing target's configured cap.
604
+ // Supplying it is an explicit invocation-time override: it can raise or
605
+ // lower the persisted boundary after the workflow has obtained approval.
606
+ const effectiveCap = requestedCap ?? previous?.cap ?? DEFAULT_CONVERGE_ATTEMPT_CAP;
607
+ if (attemptsUsed >= effectiveCap) {
608
+ // Persist a migrated ledger even when it already exhausts the cap, so
609
+ // later processes do not depend on reparsing mutable prose. Also
610
+ // persist a newly tightened cap even when the claim itself is refused.
611
+ if (previous && (!stored || previous.cap !== effectiveCap)) {
612
+ await writeStateAtomically(stateFile, {
613
+ ...previous,
614
+ cap: effectiveCap,
615
+ updatedAt: timestamp,
616
+ });
617
+ }
618
+ throw new ConvergeAttemptBudgetExceededError(target, attemptsUsed, effectiveCap);
619
+ }
620
+ const attempt = attemptsUsed + 1;
621
+ if (options.retrySource && options.retrySource.attempt !== attemptsUsed) {
622
+ throw new ConvergeAttemptStateError('Retry source does not bind the previous spent claim.');
623
+ }
624
+ if (options.boundFixRecoverySource && (options.boundFixRecoverySource.attempt !== attemptsUsed ||
625
+ options.boundFixRecoverySource.target !== target || options.retrySource !== undefined)) {
626
+ throw new ConvergeAttemptStateError('Bound fix recovery source does not bind this target and the previous spent claim.');
627
+ }
628
+ if (options.pendingRecoverySource && (options.pendingRecoverySource.pendingAttempt !== attemptsUsed ||
629
+ options.pendingRecoverySource.target !== target || options.retrySource !== undefined ||
630
+ options.boundFixRecoverySource !== undefined)) {
631
+ throw new ConvergeAttemptStateError('Pending recovery source does not bind this target and the previous spent claim.');
632
+ }
633
+ const state = {
634
+ version: previous?.version ?? STATE_VERSION,
635
+ ...(previous?.cycle ? { cycle: previous.cycle } : {}),
636
+ target,
637
+ cap: effectiveCap,
638
+ migratedAttempts: previous?.migratedAttempts ?? 0,
639
+ attemptsUsed: attempt,
640
+ attempts: [
641
+ ...(previous?.attempts ?? []),
642
+ { attempt, claimedAt: timestamp, pid: recordPid, source: 'claim',
643
+ ...(options.retrySource ? { retrySource: options.retrySource } : {}),
644
+ ...(options.boundFixRecoverySource ? { boundFixRecoverySource: options.boundFixRecoverySource } : {}),
645
+ ...(options.pendingRecoverySource ? { pendingRecoverySource: options.pendingRecoverySource } : {}) },
646
+ ],
647
+ updatedAt: timestamp,
648
+ };
649
+ await writeStateAtomically(stateFile, state);
650
+ claim = { target, attempt, attemptsUsed: attempt, cap: effectiveCap, stateFile,
651
+ ...(state.cycle ? { cycle: state.cycle } : {}) };
652
+ }
653
+ catch (err) {
654
+ claimError = err;
655
+ }
656
+ let releaseError;
657
+ try {
658
+ await releaseOwnedLock(lockFile, lockOwner);
659
+ }
660
+ catch (err) {
661
+ releaseError = err;
662
+ }
663
+ if (claimError !== undefined) {
664
+ if (releaseError !== undefined) {
665
+ const claimMessage = claimError instanceof Error ? claimError.message : String(claimError);
666
+ const releaseMessage = releaseError instanceof Error ? releaseError.message : String(releaseError);
667
+ // A cap refusal alone is exit 2, but a simultaneous release failure
668
+ // means the accounting lock is unhealthy. Classify the combined outcome
669
+ // as infrastructure failure so raising the cap is never suggested as a
670
+ // remedy for a stranded lock.
671
+ throw new ConvergeAttemptStateError(`${claimMessage} Lock release also failed: ${releaseMessage}`, { cause: releaseError });
672
+ }
673
+ throw claimError;
674
+ }
675
+ if (!claim) {
676
+ throw new ConvergeAttemptStateError('Attempt accounting ended without a claim or error.');
677
+ }
678
+ if (releaseError !== undefined) {
679
+ const releaseMessage = releaseError instanceof Error ? releaseError.message : String(releaseError);
680
+ claim.warning =
681
+ `Attempt ${claim.attempt}/${claim.cap} is durably recorded, but lock release failed: ` +
682
+ `${releaseMessage} Do not retry this claim; the review may proceed.`;
683
+ }
684
+ return claim;
685
+ }
686
+ export async function loadConvergeAttemptState(gitCommonDir, target) {
687
+ return readState(convergeAttemptStatePath(gitCommonDir, target), validateTarget(target));
688
+ }
689
+ export async function previewConvergeAttemptState(gitCommonDir, target) {
690
+ const validatedTarget = validateTarget(target);
691
+ return await loadConvergeAttemptState(gitCommonDir, validatedTarget) ??
692
+ await stateFromExistingLedger(gitCommonDir, validatedTarget, new Date().toISOString());
693
+ }
694
+ export async function resolveGitCommonDir(cwd = process.cwd()) {
695
+ let stdout;
696
+ try {
697
+ const result = await execFileAsync('git', ['rev-parse', '--git-common-dir'], {
698
+ cwd,
699
+ encoding: 'utf8',
700
+ });
701
+ stdout = result.stdout;
702
+ }
703
+ catch (err) {
704
+ throw new ConvergeAttemptStateError('Could not resolve the repository common Git directory.', {
705
+ cause: err,
706
+ });
707
+ }
708
+ const value = stdout.trim();
709
+ if (!value) {
710
+ throw new ConvergeAttemptStateError('Git returned an empty common-directory path.');
711
+ }
712
+ // Worktrees may spell the same directory through a symlinked system path
713
+ // (macOS commonly returns /var from one checkout and /private/var from
714
+ // another). Canonicalize it so one repository cannot acquire two budgets.
715
+ return realpath(isAbsolute(value) ? value : resolve(cwd, value));
716
+ }
717
+ //# sourceMappingURL=attempt-budget.js.map