@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,741 @@
1
+ import { mkdir, open, readdir, readFile, rename, rm, rmdir, stat, writeFile } from 'fs/promises';
2
+ import { join, resolve, sep } from 'path';
3
+ import { resolveDataDir } from '../config/data-dir.js';
4
+ import { sha256Hex } from './envelope.js';
5
+ import { MAX_ARTIFACT_BYTES, validateRunEnvelope } from './envelope-validation.js';
6
+ import { buildEvent } from './events.js';
7
+ import { verifiedConsensusReportProblem } from './report-consistency.js';
8
+ /**
9
+ * Failed deliveries wait here (epic IO-12475, section 8.4): one directory
10
+ * per run under `<data dir>/outbox/`, holding the envelope, the artifacts
11
+ * and any events that could not be sent. Flushed at the start of every rcl
12
+ * command (bounded) and by `rcl telemetry flush` (to completion). Retried
13
+ * deliveries carry `delivery: {mode: retried, spooled_at}` and keep their
14
+ * original ids, so the server dedupes them.
15
+ *
16
+ * Nothing is evicted silently. Above the size cap the outbox stops spooling
17
+ * artifacts — envelopes and events are small and always kept — and records
18
+ * each affected run as a `loss` event of its own (stable id), reported on
19
+ * the next flush that reaches the server. A file that cannot be read is
20
+ * never treated as delivered: a torn file marks its entry failed, a
21
+ * transient read error leaves it for the next flush.
22
+ *
23
+ * Concurrency: two rcl processes may touch the outbox at once (a review
24
+ * finishing while another command flushes). Files are written atomically
25
+ * (temp + rename) and re-read before use; a flush removes only the files it
26
+ * delivered and never a directory that gained content meanwhile; an entry
27
+ * another process removed first counts as delivered by that process. The
28
+ * size cap is best-effort across processes, which is what a client-side
29
+ * courtesy cap needs to be. An entry whose spool was interrupted (no
30
+ * `meta.json` after a grace period) is listed as failed, never hidden.
31
+ */
32
+ export const OUTBOX_DIR = 'outbox';
33
+ export const DEFAULT_OUTBOX_CAP_BYTES = 1024 * 1024 * 1024;
34
+ const META_FILE = 'meta.json';
35
+ const ENVELOPE_FILE = 'envelope.json';
36
+ const EVENTS_FILE = 'events.json';
37
+ const ARTIFACTS_DIR = 'artifacts';
38
+ const LOSS_DIR = 'loss';
39
+ const FAILED_MARKER = 'failed.json';
40
+ /** A loss report the server refused stays on disk under this suffix; it is never retried or counted as reported. */
41
+ const LOSS_REFUSED_SUFFIX = '.refused';
42
+ /** Loss reports go out in batches this size, well under the server's event cap. */
43
+ const LOSS_BATCH = 100;
44
+ const LOSS_FILE = /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.json$/i;
45
+ /** A directory without `meta.json` older than this is an interrupted spool, not one in progress. */
46
+ export const INTERRUPTED_SPOOL_MS = 10 * 60 * 1000;
47
+ const ARTIFACT_FILES = { report_json: 'report_json.json', report_md: 'report_md.md' };
48
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
49
+ const ENTRY_ID = /^(?:events-)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
50
+ /** 4.4.5 is the first release with the original-report check and this queued replay guard. */
51
+ function hasGuardedProducer(version) {
52
+ if (typeof version !== 'string')
53
+ return false;
54
+ const match = /^(\d+)\.(\d+)\.(\d+)(?:\+[\w.-]+)?$/.exec(version);
55
+ if (!match)
56
+ return false;
57
+ const [major, minor, patch] = match.slice(1).map(Number);
58
+ if (![major, minor, patch].every(Number.isSafeInteger))
59
+ return false;
60
+ return major > 4 || (major === 4 && (minor > 4 || (minor === 4 && patch >= 5)));
61
+ }
62
+ export class OutboxError extends Error {
63
+ constructor(message) {
64
+ super(message);
65
+ this.name = 'OutboxError';
66
+ }
67
+ }
68
+ /** The entry vanished under us: another process delivered or dropped it. */
69
+ class EntryGone extends Error {
70
+ constructor() {
71
+ super('outbox entry removed concurrently');
72
+ this.name = 'EntryGone';
73
+ }
74
+ }
75
+ async function readJson(path) {
76
+ let raw;
77
+ try {
78
+ raw = await readFile(path, 'utf8');
79
+ }
80
+ catch (err) {
81
+ if (err.code === 'ENOENT')
82
+ return { kind: 'missing' };
83
+ return { kind: 'error', reason: err instanceof Error ? err.message : String(err) };
84
+ }
85
+ try {
86
+ return { kind: 'ok', value: JSON.parse(raw), raw };
87
+ }
88
+ catch {
89
+ return { kind: 'malformed' };
90
+ }
91
+ }
92
+ /** Read no more than the declared artifact bytes, including if a file grows after stat. */
93
+ async function readBoundedJson(path, limit) {
94
+ let file;
95
+ try {
96
+ file = await open(path, 'r');
97
+ if ((await file.stat()).size > limit)
98
+ return { kind: 'oversized' };
99
+ const chunks = [];
100
+ let size = 0;
101
+ while (true) {
102
+ const chunk = Buffer.allocUnsafe(Math.min(64 * 1024, limit - size + 1));
103
+ const { bytesRead } = await file.read(chunk, 0, chunk.length, null);
104
+ if (bytesRead === 0)
105
+ break;
106
+ size += bytesRead;
107
+ if (size > limit)
108
+ return { kind: 'oversized' };
109
+ chunks.push(chunk.subarray(0, bytesRead));
110
+ }
111
+ const raw = Buffer.concat(chunks, size).toString('utf8');
112
+ try {
113
+ return { kind: 'ok', value: JSON.parse(raw), raw };
114
+ }
115
+ catch {
116
+ return { kind: 'malformed' };
117
+ }
118
+ }
119
+ catch (err) {
120
+ if (err.code === 'ENOENT')
121
+ return { kind: 'missing' };
122
+ return { kind: 'error', reason: err instanceof Error ? err.message : String(err) };
123
+ }
124
+ finally {
125
+ await file?.close().catch(() => undefined);
126
+ }
127
+ }
128
+ /**
129
+ * The events file after a successful POST: gone when it still holds exactly
130
+ * what was sent; otherwise (another process queued more meanwhile) only the
131
+ * delivered ids leave it and the rest waits for the next flush.
132
+ */
133
+ async function dropDeliveredEvents(path, raw, delivered) {
134
+ let current;
135
+ try {
136
+ current = await readFile(path, 'utf8');
137
+ }
138
+ catch {
139
+ return;
140
+ }
141
+ if (current === raw) {
142
+ await rm(path, { force: true });
143
+ return;
144
+ }
145
+ let parsed;
146
+ try {
147
+ parsed = JSON.parse(current);
148
+ }
149
+ catch {
150
+ return; // Mid-write or torn: leave it for the next flush to judge.
151
+ }
152
+ if (!validEvents(parsed))
153
+ return;
154
+ const sent = new Set(delivered.map((e) => e.id));
155
+ const remaining = parsed.filter((e) => !sent.has(e.id));
156
+ if (remaining.length === 0)
157
+ await rm(path, { force: true });
158
+ else
159
+ await writeJsonAtomic(path, remaining);
160
+ }
161
+ function isEnoent(err) {
162
+ return err.code === 'ENOENT';
163
+ }
164
+ async function readOptionalJson(path) {
165
+ const result = await readJson(path);
166
+ return result.kind === 'ok' ? result.value : undefined;
167
+ }
168
+ /** Write via a temp file and rename, so a reader never sees a torn file. */
169
+ async function writeJsonAtomic(path, value) {
170
+ const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
171
+ await writeFile(tmp, JSON.stringify(value, null, 2), { encoding: 'utf8', mode: 0o600 });
172
+ await rename(tmp, path);
173
+ }
174
+ async function writeTextAtomic(path, text) {
175
+ const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
176
+ await writeFile(tmp, text, { encoding: 'utf8', mode: 0o600 });
177
+ await rename(tmp, path);
178
+ }
179
+ /**
180
+ * Bytes under `dir`, walked one entry at a time (never one `stat` per file in
181
+ * flight — a large outbox must not exhaust descriptors). A file that vanishes
182
+ * mid-walk (a concurrent rename) counts as zero; the cap is a courtesy.
183
+ */
184
+ async function directorySize(dir) {
185
+ let names;
186
+ try {
187
+ names = await readdir(dir);
188
+ }
189
+ catch {
190
+ return 0;
191
+ }
192
+ let total = 0;
193
+ for (const name of names) {
194
+ const path = join(dir, name);
195
+ const info = await stat(path).catch(() => undefined);
196
+ if (!info)
197
+ continue;
198
+ total += info.isDirectory() ? await directorySize(path) : info.size;
199
+ }
200
+ return total;
201
+ }
202
+ function isRecord(value) {
203
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
204
+ }
205
+ function validEvents(value) {
206
+ return Array.isArray(value) && value.every((e) => isRecord(e) && typeof e['id'] === 'string' && typeof e['kind'] === 'string');
207
+ }
208
+ export class Outbox {
209
+ dir;
210
+ capBytes;
211
+ now;
212
+ constructor(dir = join(resolveDataDir(), OUTBOX_DIR), options = {}) {
213
+ this.dir = resolve(dir);
214
+ this.capBytes = options.capBytes ?? DEFAULT_OUTBOX_CAP_BYTES;
215
+ this.now = options.now ?? Date.now;
216
+ }
217
+ async totalBytes() {
218
+ return directorySize(this.dir);
219
+ }
220
+ /**
221
+ * Entry ids are run UUIDs or `events-<uuid>`, lower-cased so one id spelt
222
+ * two ways is one entry; nothing else becomes a path.
223
+ */
224
+ entryDir(id) {
225
+ if (!ENTRY_ID.test(id))
226
+ throw new OutboxError(`Not an outbox entry id: ${JSON.stringify(id)}`);
227
+ const dir = resolve(this.dir, id.toLowerCase());
228
+ if (!dir.startsWith(`${this.dir}${sep}`))
229
+ throw new OutboxError(`Entry escapes the outbox: ${id}`);
230
+ return dir;
231
+ }
232
+ /** Spool a run whose delivery failed (or whose artifacts could not be uploaded). */
233
+ async spoolRun(input) {
234
+ if (!UUID.test(input.runId))
235
+ throw new OutboxError(`Not a run id: ${JSON.stringify(input.runId)}`);
236
+ if (input.envelope.run?.id?.toLowerCase() !== input.runId.toLowerCase()) {
237
+ throw new OutboxError(`Envelope run id ${JSON.stringify(input.envelope.run?.id)} does not match the entry id ${input.runId}.`);
238
+ }
239
+ const dir = this.entryDir(input.runId);
240
+ await mkdir(join(dir, ARTIFACTS_DIR), { recursive: true, mode: 0o700 });
241
+ const existing = await readOptionalJson(join(dir, META_FILE));
242
+ const meta = {
243
+ kind: 'run',
244
+ spooled_at: existing?.spooled_at ?? new Date().toISOString(),
245
+ attempts: existing?.attempts ?? 0,
246
+ ...(input.envelopeDelivered || existing?.envelope_delivered ? { envelope_delivered: true } : {}),
247
+ ...(input.runUrl !== undefined ? { run_url: input.runUrl } : existing?.run_url ? { run_url: existing.run_url } : {}),
248
+ };
249
+ await writeJsonAtomic(join(dir, ENVELOPE_FILE), input.envelope);
250
+ // Events queued earlier for this run are kept; a re-spool merges by id.
251
+ if (input.events && input.events.length > 0) {
252
+ const previous = await readOptionalJson(join(dir, EVENTS_FILE));
253
+ const merged = new Map();
254
+ for (const event of validEvents(previous) ? previous : [])
255
+ merged.set(event.id, event);
256
+ for (const event of input.events)
257
+ merged.set(event.id, event);
258
+ await writeJsonAtomic(join(dir, EVENTS_FILE), [...merged.values()]);
259
+ }
260
+ const artifactsDropped = [];
261
+ if (input.artifacts) {
262
+ const wanted = new Set(Object.keys(input.artifacts));
263
+ // Kinds no longer pending were delivered; their stale copies go.
264
+ for (const [kind, file] of Object.entries(ARTIFACT_FILES)) {
265
+ if (!wanted.has(kind))
266
+ await rm(join(dir, ARTIFACTS_DIR, file), { force: true });
267
+ }
268
+ // The cap counts everything else in the outbox plus what this entry will hold.
269
+ let used = (await this.totalBytes()) - (await directorySize(join(dir, ARTIFACTS_DIR)));
270
+ for (const [kind, bytes] of Object.entries(input.artifacts)) {
271
+ if (bytes === undefined)
272
+ continue;
273
+ const size = Buffer.byteLength(bytes, 'utf8');
274
+ if (used + size > this.capBytes) {
275
+ artifactsDropped.push(kind);
276
+ await rm(join(dir, ARTIFACTS_DIR, ARTIFACT_FILES[kind]), { force: true });
277
+ continue;
278
+ }
279
+ await writeTextAtomic(join(dir, ARTIFACTS_DIR, ARTIFACT_FILES[kind]), bytes);
280
+ used += size;
281
+ }
282
+ }
283
+ if (artifactsDropped.length > 0)
284
+ await this.recordLoss(input.runId, artifactsDropped);
285
+ await writeJsonAtomic(join(dir, META_FILE), meta);
286
+ return { spooled: true, artifactsDropped };
287
+ }
288
+ /** Spool events that belong to no run delivery of their own (converge commands). */
289
+ async spoolEvents(events) {
290
+ const first = events[0];
291
+ if (!first || !UUID.test(first.id))
292
+ throw new OutboxError('Events to spool must carry UUID ids.');
293
+ const id = `events-${first.id.toLowerCase()}`;
294
+ const dir = this.entryDir(id);
295
+ await mkdir(dir, { recursive: true, mode: 0o700 });
296
+ // A batch spooled again lands on the same entry: merge by event id so
297
+ // nothing already waiting is lost, and keep the entry's own history.
298
+ const existing = await readOptionalJson(join(dir, META_FILE));
299
+ const previous = await readOptionalJson(join(dir, EVENTS_FILE));
300
+ const merged = new Map();
301
+ for (const event of validEvents(previous) ? previous : [])
302
+ merged.set(event.id, event);
303
+ for (const event of events)
304
+ merged.set(event.id, event);
305
+ await writeJsonAtomic(join(dir, EVENTS_FILE), [...merged.values()]);
306
+ await writeJsonAtomic(join(dir, META_FILE), {
307
+ kind: 'events',
308
+ spooled_at: existing?.spooled_at ?? new Date().toISOString(),
309
+ attempts: existing?.attempts ?? 0,
310
+ });
311
+ return id;
312
+ }
313
+ /** One file per loss, holding the event that will report it (stable id, no read-modify-write). */
314
+ async recordLoss(runId, kinds) {
315
+ const event = buildEvent({ kind: 'loss', payload: { reason: 'outbox_over_cap', run_id: runId, kinds } });
316
+ await mkdir(join(this.dir, LOSS_DIR), { recursive: true, mode: 0o700 });
317
+ await writeJsonAtomic(join(this.dir, LOSS_DIR, `${event.id}.json`), event);
318
+ }
319
+ /** The loss events still to report. */
320
+ async pendingLoss() {
321
+ return (await this.pendingLossFiles()).map((f) => f.event);
322
+ }
323
+ /** Loss reports the server refused for good, kept on disk (`<id>.json.refused`) and never retried. */
324
+ async refusedLoss() {
325
+ try {
326
+ return (await readdir(join(this.dir, LOSS_DIR))).filter((n) => n.endsWith(`.json${LOSS_REFUSED_SUFFIX}`)).sort();
327
+ }
328
+ catch {
329
+ return [];
330
+ }
331
+ }
332
+ /**
333
+ * Loss files whose name is `<uuid>.json` and whose event carries that very
334
+ * id — only such a file ever becomes a path again. Anything else in the
335
+ * directory is ignored, never reported and never touched.
336
+ */
337
+ async pendingLossFiles() {
338
+ let names;
339
+ try {
340
+ names = (await readdir(join(this.dir, LOSS_DIR))).sort();
341
+ }
342
+ catch {
343
+ return [];
344
+ }
345
+ const files = [];
346
+ for (const name of names) {
347
+ const match = LOSS_FILE.exec(name);
348
+ if (!match)
349
+ continue;
350
+ const read = await readJson(join(this.dir, LOSS_DIR, name));
351
+ if (read.kind !== 'ok' || !isRecord(read.value))
352
+ continue;
353
+ const id = read.value['id'];
354
+ if (typeof id !== 'string' || id.toLowerCase() !== match[1].toLowerCase())
355
+ continue;
356
+ files.push({ name, event: read.value });
357
+ }
358
+ return files;
359
+ }
360
+ /**
361
+ * Every entry, or — given `only` — that one entry when it exists (a targeted
362
+ * flush reads nothing else). Sizes are walked only when asked for: a flush
363
+ * never reads them, `rcl telemetry status` does.
364
+ */
365
+ async list(only, options = {}) {
366
+ let names;
367
+ if (only !== undefined) {
368
+ const dir = this.entryDir(only);
369
+ const exists = await stat(dir).then((info) => info.isDirectory()).catch(() => false);
370
+ names = exists ? [only] : [];
371
+ }
372
+ else {
373
+ try {
374
+ names = (await readdir(this.dir, { withFileTypes: true }))
375
+ .filter((d) => d.isDirectory() && ENTRY_ID.test(d.name))
376
+ .map((d) => d.name);
377
+ }
378
+ catch {
379
+ return [];
380
+ }
381
+ }
382
+ const entries = [];
383
+ for (const id of names.sort()) {
384
+ const dir = this.entryDir(id);
385
+ let meta = await readOptionalJson(join(dir, META_FILE));
386
+ let failed = await readOptionalJson(join(dir, FAILED_MARKER));
387
+ if (!meta) {
388
+ // `meta.json` is written last: a young directory is a spool in
389
+ // progress; an old one was interrupted and is shown, not hidden.
390
+ const info = await stat(dir).catch(() => undefined);
391
+ if (!info || this.now() - info.mtimeMs < INTERRUPTED_SPOOL_MS)
392
+ continue;
393
+ meta = { kind: id.startsWith('events-') ? 'events' : 'run', spooled_at: info.mtime.toISOString(), attempts: 0 };
394
+ failed = { at: new Date(this.now()).toISOString(), reason: 'spool interrupted before meta.json was written' };
395
+ }
396
+ const files = new Set(await readdir(join(dir, ARTIFACTS_DIR)).catch(() => []));
397
+ const events = await readOptionalJson(join(dir, EVENTS_FILE));
398
+ entries.push({
399
+ id,
400
+ meta,
401
+ bytes: options.sizes === false ? 0 : await directorySize(dir),
402
+ artifacts: Object.entries(ARTIFACT_FILES)
403
+ .filter(([, file]) => files.has(file))
404
+ .map(([kind]) => kind),
405
+ events: validEvents(events) ? events.length : 0,
406
+ ...(failed ? { failed } : {}),
407
+ });
408
+ }
409
+ return entries;
410
+ }
411
+ /**
412
+ * Deliver what waits. Stops at the first unreachable response (the server
413
+ * is down; hammering it helps nobody) or when the deadline passes. Entries
414
+ * the server refuses for good are marked and skipped afterwards. Pending
415
+ * loss reports go out on every flush that reached the server.
416
+ */
417
+ async flush(sink, options = {}) {
418
+ const now = options.now ?? this.now;
419
+ const started = now();
420
+ const pastDeadline = () => options.deadlineMs !== undefined && now() - started >= options.deadlineMs;
421
+ // Every request is bounded by what remains of the deadline, so a flush
422
+ // given five seconds cannot sit in one ten-second request.
423
+ const request = () => options.deadlineMs === undefined ? {} : { timeoutMs: Math.max(1, options.deadlineMs - (now() - started)) };
424
+ const summary = { delivered: [], remaining: [], failed: [], dropped: [] };
425
+ const entries = await this.list(options.runId, { sizes: false });
426
+ for (const entry of entries) {
427
+ if (entry.failed) {
428
+ summary.failed.push({ id: entry.id, reason: entry.failed.reason });
429
+ continue;
430
+ }
431
+ if (summary.stopped) {
432
+ summary.remaining.push(entry.id);
433
+ continue;
434
+ }
435
+ if (pastDeadline()) {
436
+ summary.stopped = 'deadline';
437
+ summary.remaining.push(entry.id);
438
+ continue;
439
+ }
440
+ const result = await this.flushEntry(sink, entry, pastDeadline, request).catch((err) => {
441
+ if (err instanceof EntryGone)
442
+ return { kind: 'delivered' };
443
+ throw err;
444
+ });
445
+ switch (result.kind) {
446
+ case 'delivered':
447
+ summary.delivered.push(entry.id);
448
+ break;
449
+ case 'failed':
450
+ summary.failed.push({ id: entry.id, reason: result.reason });
451
+ break;
452
+ case 'dropped':
453
+ summary.dropped.push({ id: entry.id, reason: result.reason });
454
+ break;
455
+ case 'retry':
456
+ summary.remaining.push(entry.id);
457
+ break;
458
+ case 'unavailable':
459
+ summary.stopped = 'unavailable';
460
+ summary.remaining.push(entry.id);
461
+ break;
462
+ case 'deadline':
463
+ summary.stopped = 'deadline';
464
+ summary.remaining.push(entry.id);
465
+ break;
466
+ }
467
+ }
468
+ if (summary.stopped !== 'unavailable' && options.runId === undefined) {
469
+ const loss = await this.reportLoss(sink, pastDeadline, request);
470
+ if (loss.kind === 'done' && loss.reported > 0)
471
+ summary.lossReported = loss.reported;
472
+ if (loss.kind !== 'done' && !summary.stopped)
473
+ summary.stopped = loss.kind;
474
+ const pending = (await this.pendingLossFiles()).length;
475
+ if (pending > 0)
476
+ summary.lossPending = pending;
477
+ }
478
+ return summary;
479
+ }
480
+ async flushEntry(sink, entry, pastDeadline, request) {
481
+ const dir = this.entryDir(entry.id);
482
+ if (entry.meta.kind !== 'run' && entry.meta.kind !== 'events') {
483
+ return this.markFailed(dir, `meta.json: unknown entry kind ${JSON.stringify(entry.meta.kind)}`);
484
+ }
485
+ const meta = { ...entry.meta, attempts: entry.meta.attempts + 1 };
486
+ const remember = async (error) => {
487
+ if (error !== undefined)
488
+ meta.last_error = error;
489
+ try {
490
+ await writeJsonAtomic(join(dir, META_FILE), meta);
491
+ }
492
+ catch (err) {
493
+ if (isEnoent(err))
494
+ throw new EntryGone();
495
+ throw err;
496
+ }
497
+ };
498
+ await remember();
499
+ if (meta.kind === 'run' && !meta.envelope_delivered) {
500
+ const read = await readJson(join(dir, ENVELOPE_FILE));
501
+ if (read.kind === 'error') {
502
+ await remember(`envelope unreadable: ${read.reason}`);
503
+ return { kind: 'retry' };
504
+ }
505
+ if (read.kind !== 'ok' || !isRecord(read.value) || !isRecord(read.value['run'])) {
506
+ return this.markFailed(dir, 'envelope.json missing or malformed');
507
+ }
508
+ const envelope = read.value;
509
+ envelope.delivery = { mode: 'retried', spooled_at: meta.spooled_at };
510
+ if (envelope.run.gating?.mode === 'verified-consensus') {
511
+ const invalid = validateRunEnvelope(envelope);
512
+ if (invalid.length > 0)
513
+ return this.markFailed(dir, `queued verified-consensus envelope invalid: ${invalid[0].path}`);
514
+ const declared = envelope.artifacts_declared.find(artifact => artifact.kind === 'report_json');
515
+ const report = await readBoundedJson(join(dir, ARTIFACTS_DIR, ARTIFACT_FILES.report_json), Math.min(declared.bytes, MAX_ARTIFACT_BYTES));
516
+ if (report.kind === 'error') {
517
+ await remember(`report_json unreadable: ${report.reason}`);
518
+ return { kind: 'retry' };
519
+ }
520
+ if (report.kind === 'oversized')
521
+ return this.markFailed(dir, 'report_json exceeds declared or maximum artifact bytes');
522
+ if (report.kind === 'malformed')
523
+ return this.markFailed(dir, 'report_json malformed; verified-consensus source cannot be checked');
524
+ if (report.kind === 'ok') {
525
+ if (declared.sha256 !== sha256Hex(report.raw) || declared.bytes !== Buffer.byteLength(report.raw, 'utf8')) {
526
+ return this.markFailed(dir, 'report_json digest or size differs from the queued envelope');
527
+ }
528
+ const problem = verifiedConsensusReportProblem(report.value, envelope, report.raw);
529
+ if (problem)
530
+ return this.markFailed(dir, problem);
531
+ }
532
+ else if (!hasGuardedProducer(envelope.run.rcl_version)) {
533
+ return this.markFailed(dir, 'report_json unavailable; queued verified-consensus producer or envelope cannot prove original gating labels');
534
+ }
535
+ }
536
+ if (pastDeadline())
537
+ return { kind: 'deadline' };
538
+ const outcome = await sink.postRun(envelope, request());
539
+ switch (outcome.kind) {
540
+ case 'ok':
541
+ meta.envelope_delivered = true;
542
+ meta.run_url = outcome.value.url;
543
+ await remember();
544
+ break;
545
+ case 'unavailable':
546
+ await remember(outcome.reason);
547
+ return { kind: 'unavailable' };
548
+ case 'disabled':
549
+ // The organization switched evidence off; there is nothing to keep waiting for.
550
+ await this.drop(dir);
551
+ return { kind: 'dropped', reason: outcome.message || outcome.reason };
552
+ case 'conflict':
553
+ // The server holds this run id with a different report. The events
554
+ // queued here name that run id too, so they must not be attached to
555
+ // whatever the server has; the whole entry stays for inspection.
556
+ return this.markFailed(dir, `conflict: ${outcome.message}`);
557
+ case 'rejected':
558
+ return this.markFailed(dir, `HTTP ${outcome.httpStatus} ${outcome.error} ${outcome.message}`.trim());
559
+ }
560
+ }
561
+ if (meta.kind === 'run') {
562
+ for (const kind of entry.artifacts) {
563
+ if (pastDeadline())
564
+ return { kind: 'deadline' };
565
+ const path = join(dir, ARTIFACTS_DIR, ARTIFACT_FILES[kind]);
566
+ let bytes;
567
+ try {
568
+ bytes = await readFile(path, 'utf8');
569
+ }
570
+ catch (err) {
571
+ if (err.code === 'ENOENT')
572
+ continue; // delivered by a concurrent flush
573
+ await remember(`artifact ${kind} unreadable: ${err instanceof Error ? err.message : String(err)}`);
574
+ return { kind: 'retry' };
575
+ }
576
+ const outcome = await sink.putArtifact(entry.id, kind, bytes, request());
577
+ switch (outcome.kind) {
578
+ case 'ok': {
579
+ // Remove exactly the bytes that were uploaded; a re-spool meanwhile stays.
580
+ const current = await readFile(path, 'utf8').catch(() => undefined);
581
+ if (current === bytes)
582
+ await rm(path, { force: true });
583
+ break;
584
+ }
585
+ case 'disabled':
586
+ if (outcome.reason === 'reviews_disabled') {
587
+ await this.drop(dir);
588
+ return { kind: 'dropped', reason: outcome.message || outcome.reason };
589
+ }
590
+ // Artifacts are capped for the org; the envelope stands.
591
+ await rm(path, { force: true });
592
+ break;
593
+ case 'unavailable':
594
+ await remember(outcome.reason);
595
+ return { kind: 'unavailable' };
596
+ case 'conflict':
597
+ case 'rejected':
598
+ return this.markFailed(dir, `artifact ${kind}: ${outcome.kind === 'conflict' ? outcome.message : `HTTP ${outcome.httpStatus} ${outcome.error}`}`);
599
+ }
600
+ }
601
+ }
602
+ const events = await readJson(join(dir, EVENTS_FILE));
603
+ if (events.kind === 'error') {
604
+ await remember(`events unreadable: ${events.reason}`);
605
+ return { kind: 'retry' };
606
+ }
607
+ if (events.kind === 'malformed' || (events.kind === 'ok' && !validEvents(events.value))) {
608
+ return this.markFailed(dir, 'events.json malformed');
609
+ }
610
+ if (events.kind === 'missing' && meta.kind === 'events') {
611
+ // events.json is written before meta.json, so a missing file means an
612
+ // earlier pass delivered and dropped it and only the directory stayed
613
+ // (something else was in it at the time): finish, do not fail it.
614
+ return (await this.finish(dir, meta)) ? { kind: 'delivered' } : { kind: 'retry' };
615
+ }
616
+ if (events.kind === 'ok' && validEvents(events.value) && events.value.length > 0) {
617
+ if (pastDeadline())
618
+ return { kind: 'deadline' };
619
+ const outcome = await sink.postEvents(events.value, request());
620
+ switch (outcome.kind) {
621
+ case 'ok':
622
+ await dropDeliveredEvents(join(dir, EVENTS_FILE), events.raw, events.value);
623
+ break;
624
+ case 'unavailable':
625
+ await remember(outcome.reason);
626
+ return { kind: 'unavailable' };
627
+ case 'disabled':
628
+ await this.drop(dir);
629
+ return { kind: 'dropped', reason: outcome.message || outcome.reason };
630
+ case 'conflict':
631
+ case 'rejected':
632
+ return this.markFailed(dir, `events: ${outcome.kind === 'conflict' ? outcome.message : `HTTP ${outcome.httpStatus} ${outcome.error} ${outcome.message}`.trim()}`);
633
+ }
634
+ }
635
+ if (events.kind === 'ok' && Array.isArray(events.value) && events.value.length === 0) {
636
+ await dropDeliveredEvents(join(dir, EVENTS_FILE), events.raw, []);
637
+ }
638
+ // Whatever arrived while flushing stays for the next flush; the entry
639
+ // is only "delivered" once nothing of it remains.
640
+ return (await this.finish(dir, meta)) ? { kind: 'delivered' } : { kind: 'retry' };
641
+ }
642
+ /**
643
+ * Everything this flush read has been delivered: remove exactly those
644
+ * files, then the directory — which stays, listed, if another process
645
+ * put something new into it meanwhile. Returns whether the directory went.
646
+ */
647
+ async finish(dir, meta) {
648
+ await rm(join(dir, ENVELOPE_FILE), { force: true });
649
+ await rm(join(dir, FAILED_MARKER), { force: true });
650
+ await this.sweepTempFiles(dir);
651
+ await rmdir(join(dir, ARTIFACTS_DIR)).catch(() => undefined);
652
+ await rm(join(dir, META_FILE), { force: true });
653
+ try {
654
+ await rmdir(dir);
655
+ return true;
656
+ }
657
+ catch (err) {
658
+ if (isEnoent(err))
659
+ return true;
660
+ if (err.code !== 'ENOTEMPTY')
661
+ throw err;
662
+ // Something arrived while flushing: keep the entry visible for the next flush.
663
+ await writeJsonAtomic(join(dir, META_FILE), { ...meta, envelope_delivered: true }).catch(() => undefined);
664
+ return false;
665
+ }
666
+ }
667
+ /** Temp files a crashed writer left behind (a live writer's are younger than the grace period). */
668
+ async sweepTempFiles(dir) {
669
+ for (const sub of [dir, join(dir, ARTIFACTS_DIR)]) {
670
+ const names = await readdir(sub).catch(() => []);
671
+ for (const name of names.filter((n) => n.endsWith('.tmp'))) {
672
+ const path = join(sub, name);
673
+ const info = await stat(path).catch(() => undefined);
674
+ if (info && this.now() - info.mtimeMs >= INTERRUPTED_SPOOL_MS)
675
+ await rm(path, { force: true });
676
+ }
677
+ }
678
+ }
679
+ /** The organization switched evidence off: nothing in this entry will ever be wanted. */
680
+ async drop(dir) {
681
+ await rm(dir, { recursive: true, force: true });
682
+ }
683
+ async markFailed(dir, reason) {
684
+ try {
685
+ await writeJsonAtomic(join(dir, FAILED_MARKER), { at: new Date().toISOString(), reason });
686
+ }
687
+ catch (err) {
688
+ if (isEnoent(err))
689
+ throw new EntryGone();
690
+ throw err;
691
+ }
692
+ return { kind: 'failed', reason };
693
+ }
694
+ /**
695
+ * Report pending losses with their stable ids, in bounded batches. A batch's
696
+ * files go once the server has taken every event in it (inserted or
697
+ * already known), or when the organization has switched evidence off
698
+ * (there is nobody to report to). A batch the server refuses is kept under
699
+ * a `.refused` suffix — visible on disk and in `rcl telemetry status`,
700
+ * never retried, never counted. An unreachable server or an expired
701
+ * deadline ends the pass with the rest still pending.
702
+ */
703
+ async reportLoss(sink, pastDeadline, request) {
704
+ const files = await this.pendingLossFiles();
705
+ let reported = 0;
706
+ for (let i = 0; i < files.length; i += LOSS_BATCH) {
707
+ if (pastDeadline())
708
+ return { kind: 'deadline' };
709
+ const batch = files.slice(i, i + LOSS_BATCH);
710
+ const outcome = await sink.postEvents(batch.map((f) => f.event), request());
711
+ switch (outcome.kind) {
712
+ case 'ok':
713
+ // The sink only reads `ok` when the receipt accounts for every event
714
+ // sent (inserted or already known), so the whole batch is done.
715
+ for (const f of batch)
716
+ await rm(join(this.dir, LOSS_DIR, f.name), { force: true }).catch(() => undefined);
717
+ reported += batch.length;
718
+ break;
719
+ case 'disabled':
720
+ for (const f of batch)
721
+ await rm(join(this.dir, LOSS_DIR, f.name), { force: true }).catch(() => undefined);
722
+ break;
723
+ case 'conflict':
724
+ case 'rejected':
725
+ for (const f of batch) {
726
+ const path = join(this.dir, LOSS_DIR, f.name);
727
+ await rename(path, `${path}${LOSS_REFUSED_SUFFIX}`).catch(() => undefined);
728
+ }
729
+ break;
730
+ case 'unavailable':
731
+ return { kind: 'unavailable' };
732
+ }
733
+ }
734
+ return { kind: 'done', reported };
735
+ }
736
+ /** Remove one entry by id (validated like every other id). */
737
+ async remove(id) {
738
+ await rm(this.entryDir(id), { recursive: true, force: true });
739
+ }
740
+ }
741
+ //# sourceMappingURL=outbox.js.map