@latysh-development/monolith 0.0.0-stage → 0.1.0-alpha.1

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 (345) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +179 -2
  3. package/dist/brief/cli.d.ts +30 -0
  4. package/dist/brief/cli.d.ts.map +1 -0
  5. package/dist/brief/cli.js +85 -0
  6. package/dist/brief/collect.d.ts +17 -0
  7. package/dist/brief/collect.d.ts.map +1 -0
  8. package/dist/brief/collect.js +342 -0
  9. package/dist/brief/config.d.ts +40 -0
  10. package/dist/brief/config.d.ts.map +1 -0
  11. package/dist/brief/config.js +85 -0
  12. package/dist/brief/constants.d.ts +12 -0
  13. package/dist/brief/constants.d.ts.map +1 -0
  14. package/dist/brief/constants.js +11 -0
  15. package/dist/brief/docs.d.ts +53 -0
  16. package/dist/brief/docs.d.ts.map +1 -0
  17. package/dist/brief/docs.js +229 -0
  18. package/dist/brief/freshness.d.ts +104 -0
  19. package/dist/brief/freshness.d.ts.map +1 -0
  20. package/dist/brief/freshness.js +263 -0
  21. package/dist/brief/git-signals.d.ts +17 -0
  22. package/dist/brief/git-signals.d.ts.map +1 -0
  23. package/dist/brief/git-signals.js +101 -0
  24. package/dist/brief/index.d.ts +11 -0
  25. package/dist/brief/index.d.ts.map +1 -0
  26. package/dist/brief/index.js +5 -0
  27. package/dist/brief/reconcile.d.ts +75 -0
  28. package/dist/brief/reconcile.d.ts.map +1 -0
  29. package/dist/brief/reconcile.js +259 -0
  30. package/dist/brief/render.d.ts +67 -0
  31. package/dist/brief/render.d.ts.map +1 -0
  32. package/dist/brief/render.js +458 -0
  33. package/dist/brief/sanitize.d.ts +38 -0
  34. package/dist/brief/sanitize.d.ts.map +1 -0
  35. package/dist/brief/sanitize.js +48 -0
  36. package/dist/brief/selectors.d.ts +36 -0
  37. package/dist/brief/selectors.d.ts.map +1 -0
  38. package/dist/brief/selectors.js +75 -0
  39. package/dist/brief/story.d.ts +18 -0
  40. package/dist/brief/story.d.ts.map +1 -0
  41. package/dist/brief/story.js +59 -0
  42. package/dist/brief/types.d.ts +126 -0
  43. package/dist/brief/types.d.ts.map +1 -0
  44. package/dist/brief/types.js +11 -0
  45. package/dist/cli/index.d.ts +3 -0
  46. package/dist/cli/index.d.ts.map +1 -0
  47. package/dist/cli/index.js +199 -0
  48. package/dist/cli/init-args.d.ts +16 -0
  49. package/dist/cli/init-args.d.ts.map +1 -0
  50. package/dist/cli/init-args.js +24 -0
  51. package/dist/cli/ui-args.d.ts +23 -0
  52. package/dist/cli/ui-args.d.ts.map +1 -0
  53. package/dist/cli/ui-args.js +66 -0
  54. package/dist/cli/ui.d.ts +40 -0
  55. package/dist/cli/ui.d.ts.map +1 -0
  56. package/dist/cli/ui.js +180 -0
  57. package/dist/coordinatorium/checkpoint.d.ts +44 -0
  58. package/dist/coordinatorium/checkpoint.d.ts.map +1 -0
  59. package/dist/coordinatorium/checkpoint.js +124 -0
  60. package/dist/coordinatorium/cli.d.ts +39 -0
  61. package/dist/coordinatorium/cli.d.ts.map +1 -0
  62. package/dist/coordinatorium/cli.js +203 -0
  63. package/dist/coordinatorium/errors.d.ts +112 -0
  64. package/dist/coordinatorium/errors.d.ts.map +1 -0
  65. package/dist/coordinatorium/errors.js +145 -0
  66. package/dist/coordinatorium/index.d.ts +11 -0
  67. package/dist/coordinatorium/index.d.ts.map +1 -0
  68. package/dist/coordinatorium/index.js +5 -0
  69. package/dist/coordinatorium/lock.d.ts +187 -0
  70. package/dist/coordinatorium/lock.d.ts.map +1 -0
  71. package/dist/coordinatorium/lock.js +659 -0
  72. package/dist/coordinatorium/mission.d.ts +32 -0
  73. package/dist/coordinatorium/mission.d.ts.map +1 -0
  74. package/dist/coordinatorium/mission.js +87 -0
  75. package/dist/coordinatorium/state-keeper.d.ts +115 -0
  76. package/dist/coordinatorium/state-keeper.d.ts.map +1 -0
  77. package/dist/coordinatorium/state-keeper.js +396 -0
  78. package/dist/coordinatorium/types.d.ts +69 -0
  79. package/dist/coordinatorium/types.d.ts.map +1 -0
  80. package/dist/coordinatorium/types.js +27 -0
  81. package/dist/discovery/compose.d.ts +28 -0
  82. package/dist/discovery/compose.d.ts.map +1 -0
  83. package/dist/discovery/compose.js +159 -0
  84. package/dist/discovery/contracts.d.ts +211 -0
  85. package/dist/discovery/contracts.d.ts.map +1 -0
  86. package/dist/discovery/contracts.js +555 -0
  87. package/dist/discovery/docs.d.ts +278 -0
  88. package/dist/discovery/docs.d.ts.map +1 -0
  89. package/dist/discovery/docs.js +1182 -0
  90. package/dist/discovery/facts.d.ts +49 -0
  91. package/dist/discovery/facts.d.ts.map +1 -0
  92. package/dist/discovery/facts.js +541 -0
  93. package/dist/discovery/index.d.ts +8 -0
  94. package/dist/discovery/index.d.ts.map +1 -0
  95. package/dist/discovery/index.js +9 -0
  96. package/dist/discovery/orchestrate.d.ts +35 -0
  97. package/dist/discovery/orchestrate.d.ts.map +1 -0
  98. package/dist/discovery/orchestrate.js +32 -0
  99. package/dist/discovery/render.d.ts +36 -0
  100. package/dist/discovery/render.d.ts.map +1 -0
  101. package/dist/discovery/render.js +278 -0
  102. package/dist/discovery/traverse.d.ts +197 -0
  103. package/dist/discovery/traverse.d.ts.map +1 -0
  104. package/dist/discovery/traverse.js +510 -0
  105. package/dist/durable/assess.d.ts +105 -0
  106. package/dist/durable/assess.d.ts.map +1 -0
  107. package/dist/durable/assess.js +239 -0
  108. package/dist/durable/canonical.d.ts +25 -0
  109. package/dist/durable/canonical.d.ts.map +1 -0
  110. package/dist/durable/canonical.js +78 -0
  111. package/dist/durable/cli.d.ts +37 -0
  112. package/dist/durable/cli.d.ts.map +1 -0
  113. package/dist/durable/cli.js +141 -0
  114. package/dist/durable/errors.d.ts +192 -0
  115. package/dist/durable/errors.d.ts.map +1 -0
  116. package/dist/durable/errors.js +323 -0
  117. package/dist/durable/fs-store.d.ts +254 -0
  118. package/dist/durable/fs-store.d.ts.map +1 -0
  119. package/dist/durable/fs-store.js +1493 -0
  120. package/dist/durable/index.d.ts +20 -0
  121. package/dist/durable/index.d.ts.map +1 -0
  122. package/dist/durable/index.js +13 -0
  123. package/dist/durable/log.d.ts +33 -0
  124. package/dist/durable/log.d.ts.map +1 -0
  125. package/dist/durable/log.js +157 -0
  126. package/dist/durable/memory-store.d.ts +51 -0
  127. package/dist/durable/memory-store.d.ts.map +1 -0
  128. package/dist/durable/memory-store.js +302 -0
  129. package/dist/durable/projection.d.ts +35 -0
  130. package/dist/durable/projection.d.ts.map +1 -0
  131. package/dist/durable/projection.js +328 -0
  132. package/dist/durable/prune-check.d.ts +34 -0
  133. package/dist/durable/prune-check.d.ts.map +1 -0
  134. package/dist/durable/prune-check.js +72 -0
  135. package/dist/durable/register.d.ts +100 -0
  136. package/dist/durable/register.d.ts.map +1 -0
  137. package/dist/durable/register.js +532 -0
  138. package/dist/durable/retention.d.ts +49 -0
  139. package/dist/durable/retention.d.ts.map +1 -0
  140. package/dist/durable/retention.js +59 -0
  141. package/dist/durable/runtime.d.ts +499 -0
  142. package/dist/durable/runtime.d.ts.map +1 -0
  143. package/dist/durable/runtime.js +1288 -0
  144. package/dist/durable/seams.d.ts +44 -0
  145. package/dist/durable/seams.d.ts.map +1 -0
  146. package/dist/durable/seams.js +21 -0
  147. package/dist/durable/testing.d.ts +11 -0
  148. package/dist/durable/testing.d.ts.map +1 -0
  149. package/dist/durable/testing.js +25 -0
  150. package/dist/durable/types.d.ts +442 -0
  151. package/dist/durable/types.d.ts.map +1 -0
  152. package/dist/durable/types.js +75 -0
  153. package/dist/graph/builder.d.ts +11 -0
  154. package/dist/graph/builder.d.ts.map +1 -0
  155. package/dist/graph/builder.js +153 -0
  156. package/dist/graph/identity.d.ts +37 -0
  157. package/dist/graph/identity.d.ts.map +1 -0
  158. package/dist/graph/identity.js +46 -0
  159. package/dist/graph/index.d.ts +7 -0
  160. package/dist/graph/index.d.ts.map +1 -0
  161. package/dist/graph/index.js +3 -0
  162. package/dist/graph/resolver.d.ts +41 -0
  163. package/dist/graph/resolver.d.ts.map +1 -0
  164. package/dist/graph/resolver.js +36 -0
  165. package/dist/graph/types.d.ts +42 -0
  166. package/dist/graph/types.d.ts.map +1 -0
  167. package/dist/graph/types.js +1 -0
  168. package/dist/http/index.d.ts +5 -0
  169. package/dist/http/index.d.ts.map +1 -0
  170. package/dist/http/index.js +2 -0
  171. package/dist/http/server.d.ts +76 -0
  172. package/dist/http/server.d.ts.map +1 -0
  173. package/dist/http/server.js +195 -0
  174. package/dist/http/ui-assets.d.ts +22 -0
  175. package/dist/http/ui-assets.d.ts.map +1 -0
  176. package/dist/http/ui-assets.js +100 -0
  177. package/dist/ideas/cli.d.ts +33 -0
  178. package/dist/ideas/cli.d.ts.map +1 -0
  179. package/dist/ideas/cli.js +158 -0
  180. package/dist/ideas/format.d.ts +38 -0
  181. package/dist/ideas/format.d.ts.map +1 -0
  182. package/dist/ideas/format.js +194 -0
  183. package/dist/ideas/index.d.ts +6 -0
  184. package/dist/ideas/index.d.ts.map +1 -0
  185. package/dist/ideas/index.js +3 -0
  186. package/dist/ideas/store.d.ts +55 -0
  187. package/dist/ideas/store.d.ts.map +1 -0
  188. package/dist/ideas/store.js +262 -0
  189. package/dist/ideas/types.d.ts +54 -0
  190. package/dist/ideas/types.d.ts.map +1 -0
  191. package/dist/ideas/types.js +26 -0
  192. package/dist/index.d.ts +32 -0
  193. package/dist/index.d.ts.map +1 -0
  194. package/dist/index.js +28 -0
  195. package/dist/init/index.d.ts +12 -0
  196. package/dist/init/index.d.ts.map +1 -0
  197. package/dist/init/index.js +90 -0
  198. package/dist/init/prompts.d.ts +3 -0
  199. package/dist/init/prompts.d.ts.map +1 -0
  200. package/dist/init/prompts.js +47 -0
  201. package/dist/init/scaffold.d.ts +29 -0
  202. package/dist/init/scaffold.d.ts.map +1 -0
  203. package/dist/init/scaffold.js +208 -0
  204. package/dist/init/types.d.ts +14 -0
  205. package/dist/init/types.d.ts.map +1 -0
  206. package/dist/init/types.js +1 -0
  207. package/dist/managed/index.d.ts +73 -0
  208. package/dist/managed/index.d.ts.map +1 -0
  209. package/dist/managed/index.js +222 -0
  210. package/dist/readmodel/dashboard.d.ts +40 -0
  211. package/dist/readmodel/dashboard.d.ts.map +1 -0
  212. package/dist/readmodel/dashboard.js +236 -0
  213. package/dist/readmodel/index.d.ts +3 -0
  214. package/dist/readmodel/index.d.ts.map +1 -0
  215. package/dist/readmodel/index.js +1 -0
  216. package/dist/readmodel/types.d.ts +104 -0
  217. package/dist/readmodel/types.d.ts.map +1 -0
  218. package/dist/readmodel/types.js +15 -0
  219. package/dist/root/index.d.ts +186 -0
  220. package/dist/root/index.d.ts.map +1 -0
  221. package/dist/root/index.js +430 -0
  222. package/dist/root/safe-write.d.ts +268 -0
  223. package/dist/root/safe-write.d.ts.map +1 -0
  224. package/dist/root/safe-write.js +966 -0
  225. package/dist/root/write-artifacts.d.ts +20 -0
  226. package/dist/root/write-artifacts.d.ts.map +1 -0
  227. package/dist/root/write-artifacts.js +42 -0
  228. package/dist/scriptorium/compile.d.ts +4 -0
  229. package/dist/scriptorium/compile.d.ts.map +1 -0
  230. package/dist/scriptorium/compile.js +185 -0
  231. package/dist/scriptorium/frontmatter.d.ts +13 -0
  232. package/dist/scriptorium/frontmatter.d.ts.map +1 -0
  233. package/dist/scriptorium/frontmatter.js +90 -0
  234. package/dist/scriptorium/index.d.ts +3 -0
  235. package/dist/scriptorium/index.d.ts.map +1 -0
  236. package/dist/scriptorium/index.js +1 -0
  237. package/dist/scriptorium/markdown.d.ts +31 -0
  238. package/dist/scriptorium/markdown.d.ts.map +1 -0
  239. package/dist/scriptorium/markdown.js +88 -0
  240. package/dist/scriptorium/types.d.ts +78 -0
  241. package/dist/scriptorium/types.d.ts.map +1 -0
  242. package/dist/scriptorium/types.js +1 -0
  243. package/dist/types/enforcement.d.ts +11 -0
  244. package/dist/types/enforcement.d.ts.map +1 -0
  245. package/dist/types/enforcement.js +1 -0
  246. package/dist/types/integrity.d.ts +33 -0
  247. package/dist/types/integrity.d.ts.map +1 -0
  248. package/dist/types/integrity.js +1 -0
  249. package/dist/types/project-definition.d.ts +30 -0
  250. package/dist/types/project-definition.d.ts.map +1 -0
  251. package/dist/types/project-definition.js +1 -0
  252. package/dist/ui/assets/cosmic-glass-bg-Dwx47zPu.webp +0 -0
  253. package/dist/ui/assets/index-C4NhMaq7.js +28 -0
  254. package/dist/ui/assets/index-DMZ7ZvZY.css +1 -0
  255. package/dist/ui/index.html +13 -0
  256. package/dist/update/cli.d.ts +8 -0
  257. package/dist/update/cli.d.ts.map +1 -0
  258. package/dist/update/cli.js +115 -0
  259. package/dist/update/index.d.ts +78 -0
  260. package/dist/update/index.d.ts.map +1 -0
  261. package/dist/update/index.js +285 -0
  262. package/dist/validate/index.d.ts +6 -0
  263. package/dist/validate/index.d.ts.map +1 -0
  264. package/dist/validate/index.js +214 -0
  265. package/dist/version.d.ts +2 -0
  266. package/dist/version.d.ts.map +1 -0
  267. package/dist/version.js +1 -0
  268. package/package.json +67 -4
  269. package/templates/.gitkeep +0 -0
  270. package/templates/default-instance/instruction/.cursorrules +59 -0
  271. package/templates/default-instance/instruction/.windsurfrules +59 -0
  272. package/templates/default-instance/instruction/CLAUDE.md +57 -0
  273. package/templates/default-instance/managed/agent.md +20 -0
  274. package/templates/default-instance/managed/bootstrap.md +7 -0
  275. package/templates/default-instance/managed/index-idea.md +5 -0
  276. package/templates/default-instance/managed/routing-idea.md +14 -0
  277. package/templates/default-instance/monolith/AGENT.md +1 -0
  278. package/templates/default-instance/monolith/context/boot/HANDOFF.md +49 -0
  279. package/templates/default-instance/monolith/context/boot/WORK_SESSION.md +30 -0
  280. package/templates/default-instance/monolith/context/execution/current-state.md +30 -0
  281. package/templates/default-instance/monolith/context/maps/dependency-map.md +38 -0
  282. package/templates/default-instance/monolith/context/maps/project-map.md +85 -0
  283. package/templates/default-instance/monolith/context/maps/roadmap-index.md +41 -0
  284. package/templates/default-instance/monolith/context/maps/routing-map.md +151 -0
  285. package/templates/default-instance/monolith/context/maps/semantic-map.md +75 -0
  286. package/templates/default-instance/monolith/context/models/model-registry.md +37 -0
  287. package/templates/default-instance/monolith/context/models/privacy-classification.md +35 -0
  288. package/templates/default-instance/monolith/context/templates/plan-template.md +56 -0
  289. package/templates/default-instance/monolith/governance/README.md +29 -0
  290. package/templates/default-instance/monolith/governance/RULE_SCHEMA.md +58 -0
  291. package/templates/default-instance/monolith/learning/INDEX.md +48 -0
  292. package/templates/default-instance/monolith/learning/injection-map.md +49 -0
  293. package/templates/default-instance/monolith/learning/taxonomy.md +30 -0
  294. package/templates/default-instance/monolith/memory/errors/README.md +26 -0
  295. package/templates/default-instance/monolith/memory/errors/SCHEMA.md +47 -0
  296. package/templates/default-instance/monolith/memory/errors/TAXONOMY.md +27 -0
  297. package/templates/default-instance/monolith/memory/long-term/architecture-principles.md +31 -0
  298. package/templates/default-instance/monolith/memory/long-term/decisions.md +36 -0
  299. package/templates/default-instance/monolith/memory/long-term/execution-history.md +20 -0
  300. package/templates/default-instance/monolith/memory/long-term/tech-debt.md +25 -0
  301. package/templates/default-instance/monolith/memory/working/active.md +41 -0
  302. package/templates/default-instance/monolith/memory/working/governance-result.md +0 -0
  303. package/templates/default-instance/monolith/memory/working/integrity-result.md +0 -0
  304. package/templates/default-instance/monolith/memory/working/story-index.md +28 -0
  305. package/templates/default-instance/monolith/protocols/boot/boot-sequence.md +59 -0
  306. package/templates/default-instance/monolith/protocols/cognition/cognitive-modes.md +90 -0
  307. package/templates/default-instance/monolith/protocols/cognition/dry-run.md +56 -0
  308. package/templates/default-instance/monolith/protocols/cognition/execution-trace-format.md +52 -0
  309. package/templates/default-instance/monolith/protocols/cognition/semantic-planning.md +51 -0
  310. package/templates/default-instance/monolith/protocols/execution/hybrid-execution.md +37 -0
  311. package/templates/default-instance/monolith/protocols/execution/local-llm-governance.md +42 -0
  312. package/templates/default-instance/monolith/protocols/governance/command-policy.md +51 -0
  313. package/templates/default-instance/monolith/protocols/governance/core-invariants.md +40 -0
  314. package/templates/default-instance/monolith/protocols/governance/memory-governance.md +54 -0
  315. package/templates/default-instance/monolith/protocols/governance/metadata-schema.md +62 -0
  316. package/templates/default-instance/monolith/protocols/governance/skills.md +53 -0
  317. package/templates/default-instance/monolith/protocols/governance/work-session.md +46 -0
  318. package/templates/default-instance/monolith/skills/INDEX.md +32 -0
  319. package/templates/default-instance/monolith/skills/current-status/SKILL.md +47 -0
  320. package/templates/default-instance/monolith/skills/finalize-story/SKILL.md +86 -0
  321. package/templates/default-instance/monolith/skills/global-status/SKILL.md +56 -0
  322. package/templates/default-instance/monolith/skills/idea-capture/SKILL.md +157 -0
  323. package/templates/default-instance/monolith/skills/self-improvement/SKILL.md +77 -0
  324. package/templates/default-instance/monolith/state.json +11 -0
  325. package/templates/default-instance/monolith/tests/INDEX.md +57 -0
  326. package/templates/default-instance/monolith/tests/scenarios/architecture-review.md +32 -0
  327. package/templates/default-instance/monolith/tests/scenarios/debug-failure.md +32 -0
  328. package/templates/default-instance/monolith/tests/scenarios/dry-run-activation.md +33 -0
  329. package/templates/default-instance/monolith/tests/scenarios/execution-trace-verification.md +31 -0
  330. package/templates/default-instance/monolith/tests/scenarios/finalize-story.md +35 -0
  331. package/templates/default-instance/monolith/tests/scenarios/implement-feature.md +36 -0
  332. package/templates/default-instance/monolith/tests/scenarios/local-llm-delegation.md +31 -0
  333. package/templates/default-instance/monolith/tests/scenarios/planning-request.md +32 -0
  334. package/templates/default-instance/monolith/tests/scenarios/sensitive-context-task.md +30 -0
  335. package/templates/default-instance/monolith/tests/scenarios/validator-verification.md +33 -0
  336. package/templates/default-instance/monolith/tests/validation/expected-behavior.md +70 -0
  337. package/templates/default-instance/monolith/tests/validators/INDEX.md +17 -0
  338. package/templates/default-instance/monolith/tests/validators/delegation-semantics.md +22 -0
  339. package/templates/default-instance/monolith/tests/validators/mode-consistency.md +25 -0
  340. package/templates/default-instance/monolith/tests/validators/privacy-routing.md +23 -0
  341. package/templates/default-instance/monolith/tests/validators/protocol-references.md +27 -0
  342. package/templates/default-instance/monolith/tests/validators/routing-integrity.md +30 -0
  343. package/templates/default-instance/projectroot/AGENTS.md +111 -0
  344. package/templates/default-instance/projectroot/monolith.config.json +32 -0
  345. package/templates/default-instance/projectroot/project.definition.mjs.template +41 -0
@@ -0,0 +1,328 @@
1
+ /**
2
+ * Projection — the pure fold from events to `TaskState`.
3
+ *
4
+ * Deterministic and total over valid logs: the same events always give the
5
+ * same state, with no clock, randomness or I/O. It is also *strict*: an event
6
+ * that violates the task's own rules (a second claim with the wrong epoch, a
7
+ * delivery to an unknown await, an event after a terminal one) is a corrupt
8
+ * log, not something to be skipped. Writers run every new event through
9
+ * `applyEvent` before publishing it, so a log that was written by this code
10
+ * always folds.
11
+ */
12
+ import { LogCorruptError } from './errors.js';
13
+ import { GENESIS_HASH } from './types.js';
14
+ /** Idempotency keys are scoped to the await they were delivered to ('awaitId' never contains ':'). */
15
+ export function deliveryKey(awaitId, idempotencyKey) {
16
+ return `${awaitId}:${idempotencyKey}`;
17
+ }
18
+ /**
19
+ * A string-keyed dictionary that does not inherit from `Object.prototype`.
20
+ *
21
+ * Keys of these dictionaries are application data (assumption keys, effect keys, await ids, labels).
22
+ * On a plain object `d['__proto__'] = x` replaces the prototype instead of storing an entry, and
23
+ * `d['constructor']` / `d['toString']` read an inherited function for a key that was never written.
24
+ * A null-prototype object has neither problem; it serializes exactly like a plain one (JSON, canonical
25
+ * form, `Object.keys/values/entries`), so stored events and the public `Record<string, T>` types are unchanged.
26
+ */
27
+ export function newDict(from) {
28
+ const out = Object.create(null);
29
+ if (from) {
30
+ // defineProperty, not assignment: an own "__proto__" key of `from` must stay an entry.
31
+ for (const k of Object.keys(from))
32
+ Object.defineProperty(out, k, { value: from[k], enumerable: true, writable: true, configurable: true });
33
+ }
34
+ return out;
35
+ }
36
+ function corrupt(taskId, seq, reason) {
37
+ throw new LogCorruptError(taskId, seq, reason);
38
+ }
39
+ /** Validates a plan declaration; returns the first problem or `null`. Shared by the runtime (nice errors) and the fold (strictness). */
40
+ export function planProblem(steps) {
41
+ const ids = new Set();
42
+ for (const s of steps) {
43
+ if (ids.has(s.id))
44
+ return `duplicate step id "${s.id}"`;
45
+ ids.add(s.id);
46
+ }
47
+ for (const s of steps) {
48
+ for (const d of s.dependsOn) {
49
+ if (!ids.has(d))
50
+ return `step "${s.id}" depends on unknown step "${d}"`;
51
+ if (d === s.id)
52
+ return `step "${s.id}" depends on itself`;
53
+ }
54
+ }
55
+ // cycle detection (Kahn)
56
+ const indeg = new Map(steps.map((s) => [s.id, s.dependsOn.length]));
57
+ const queue = steps.filter((s) => s.dependsOn.length === 0).map((s) => s.id);
58
+ let visited = 0;
59
+ while (queue.length > 0) {
60
+ const id = queue.pop();
61
+ visited++;
62
+ for (const s of steps) {
63
+ if (s.dependsOn.includes(id)) {
64
+ const n = indeg.get(s.id) - 1;
65
+ indeg.set(s.id, n);
66
+ if (n === 0)
67
+ queue.push(s.id);
68
+ }
69
+ }
70
+ }
71
+ return visited === steps.length ? null : 'the plan has a dependency cycle';
72
+ }
73
+ export function applyEvent(prevState, e) {
74
+ const t = e.taskId;
75
+ if (prevState === null) {
76
+ if (e.seq !== 1 || e.type !== 'task.created')
77
+ corrupt(t, e.seq, 'a log must start with task.created at seq 1');
78
+ const d = e.data;
79
+ return {
80
+ taskId: t,
81
+ kind: d.kind,
82
+ goal: d.goal,
83
+ input: d.input,
84
+ parentTaskId: d.parentTaskId,
85
+ dependsOn: [...d.dependsOn],
86
+ labels: newDict(d.labels),
87
+ status: 'active',
88
+ createdAt: e.at,
89
+ updatedAt: e.at,
90
+ closedAt: null,
91
+ result: null,
92
+ error: null,
93
+ headSeq: 1,
94
+ headHash: e.hash,
95
+ epoch: 0,
96
+ lease: null,
97
+ plan: null,
98
+ decisions: [],
99
+ assumptions: newDict(),
100
+ observations: newDict(),
101
+ effects: newDict(),
102
+ awaits: newDict(),
103
+ deliveryKeys: newDict(),
104
+ eventCount: 1,
105
+ };
106
+ }
107
+ const s = prevState;
108
+ if (e.seq !== s.headSeq + 1)
109
+ corrupt(t, e.seq, `sequence gap (expected ${s.headSeq + 1})`);
110
+ if (s.status !== 'active')
111
+ corrupt(t, e.seq, `event after the terminal state (${s.status})`);
112
+ switch (e.type) {
113
+ case 'task.created':
114
+ return corrupt(t, e.seq, 'task.created after seq 1');
115
+ case 'run.claimed': {
116
+ const d = e.data;
117
+ if (d.epoch !== s.epoch + 1)
118
+ corrupt(t, e.seq, `claim epoch ${d.epoch} is not ${s.epoch + 1}`);
119
+ s.epoch = d.epoch;
120
+ s.lease = { owner: d.owner, epoch: d.epoch, leaseUntil: d.leaseUntil, released: false };
121
+ break;
122
+ }
123
+ case 'run.heartbeat': {
124
+ const d = e.data;
125
+ if (!s.lease || s.lease.released || s.lease.epoch !== d.epoch || s.lease.owner !== d.owner) {
126
+ corrupt(t, e.seq, 'heartbeat from a non-current lease holder');
127
+ }
128
+ s.lease.leaseUntil = d.leaseUntil;
129
+ break;
130
+ }
131
+ case 'run.released': {
132
+ const d = e.data;
133
+ if (!s.lease || s.lease.released || s.lease.epoch !== d.epoch || s.lease.owner !== d.owner) {
134
+ corrupt(t, e.seq, 'release from a non-current lease holder');
135
+ }
136
+ s.lease.released = true;
137
+ break;
138
+ }
139
+ case 'plan.declared': {
140
+ const problem = planProblem(e.data.steps);
141
+ if (problem)
142
+ corrupt(t, e.seq, `invalid plan: ${problem}`);
143
+ const previous = new Map((s.plan ?? []).map((p) => [p.id, p]));
144
+ s.plan = e.data.steps.map((decl) => {
145
+ const old = previous.get(decl.id);
146
+ // A re-plan never reopens work that is already closed.
147
+ if (old && old.status !== 'pending')
148
+ return { ...old, title: decl.title, dependsOn: [...decl.dependsOn] };
149
+ return { id: decl.id, title: decl.title, dependsOn: [...decl.dependsOn], status: 'pending', result: null, skipReason: null, closedAtSeq: null };
150
+ });
151
+ break;
152
+ }
153
+ case 'plan.step_done':
154
+ case 'plan.step_skipped': {
155
+ const step = s.plan?.find((p) => p.id === e.data.stepId);
156
+ if (!step)
157
+ corrupt(t, e.seq, `unknown plan step "${e.data.stepId}"`);
158
+ if (step.status !== 'pending')
159
+ corrupt(t, e.seq, `plan step "${step.id}" is already ${step.status}`);
160
+ if (e.type === 'plan.step_done') {
161
+ step.status = 'done';
162
+ step.result = e.data.result;
163
+ }
164
+ else {
165
+ step.status = 'skipped';
166
+ step.skipReason = e.data.reason;
167
+ }
168
+ step.closedAtSeq = e.seq;
169
+ break;
170
+ }
171
+ case 'decision.recorded': {
172
+ if (s.decisions.some((x) => x.id === e.data.id))
173
+ corrupt(t, e.seq, `duplicate decision id "${e.data.id}"`);
174
+ s.decisions.push({ id: e.data.id, seq: e.seq, at: e.at, summary: e.data.summary, rationale: e.data.rationale, basedOn: [...e.data.basedOn] });
175
+ break;
176
+ }
177
+ case 'assumption.recorded': {
178
+ const d = e.data;
179
+ s.assumptions[d.key] = {
180
+ key: d.key, statement: d.statement, criticality: d.criticality, fingerprint: d.fingerprint, value: d.value,
181
+ evidence: d.evidence.map((x) => ({ ...x })), status: 'active', recordedAtSeq: e.seq, retractedReason: null,
182
+ };
183
+ break;
184
+ }
185
+ case 'assumption.retracted': {
186
+ const a = s.assumptions[e.data.key];
187
+ if (!a || a.status !== 'active')
188
+ corrupt(t, e.seq, `no active assumption "${e.data.key}"`);
189
+ a.status = 'retracted';
190
+ a.retractedReason = e.data.reason;
191
+ break;
192
+ }
193
+ case 'fact.observed': {
194
+ const d = e.data;
195
+ s.observations[d.key] = { key: d.key, fingerprint: d.fingerprint, value: d.value, source: d.source, seq: e.seq, at: e.at };
196
+ break;
197
+ }
198
+ case 'effect.intended': {
199
+ const d = e.data;
200
+ const old = s.effects[d.key];
201
+ if (old && old.status === 'completed')
202
+ corrupt(t, e.seq, `effect "${d.key}" is already completed`);
203
+ s.effects[d.key] = {
204
+ key: d.key, description: d.description, params: d.params, status: 'intended', intendedAtSeq: e.seq,
205
+ intendedEpoch: d.epoch, result: null, error: null, retryable: true, uncertain: false,
206
+ };
207
+ break;
208
+ }
209
+ case 'effect.completed': {
210
+ const x = s.effects[e.data.key];
211
+ if (!x || x.status === 'completed')
212
+ corrupt(t, e.seq, `effect "${e.data.key}" cannot be completed from ${x ? x.status : 'nothing'}`);
213
+ x.status = 'completed';
214
+ x.result = e.data.result;
215
+ x.error = null;
216
+ x.uncertain = false;
217
+ break;
218
+ }
219
+ case 'effect.failed': {
220
+ const x = s.effects[e.data.key];
221
+ if (!x || x.status !== 'intended')
222
+ corrupt(t, e.seq, `effect "${e.data.key}" cannot fail from ${x ? x.status : 'nothing'}`);
223
+ x.status = 'failed';
224
+ x.error = e.data.error;
225
+ x.retryable = e.data.retryable;
226
+ x.uncertain = e.data.uncertain === true;
227
+ break;
228
+ }
229
+ case 'await.registered': {
230
+ const d = e.data;
231
+ if (s.awaits[d.awaitId])
232
+ corrupt(t, e.seq, `duplicate await id "${d.awaitId}"`);
233
+ if (Object.values(s.awaits).some((a) => a.token === d.token))
234
+ corrupt(t, e.seq, 'duplicate await token');
235
+ s.awaits[d.awaitId] = {
236
+ awaitId: d.awaitId, token: d.token, purpose: d.purpose, stepId: d.stepId, request: d.request, deadlineAt: d.deadlineAt,
237
+ basisSeq: d.basisSeq, registeredAtSeq: e.seq, status: 'pending', resolvedAtSeq: null, payload: null, idempotencyKey: null,
238
+ source: null, late: false, rejectedDeliveries: 0,
239
+ };
240
+ break;
241
+ }
242
+ case 'await.resolved': {
243
+ const d = e.data;
244
+ const a = s.awaits[d.awaitId];
245
+ if (!a)
246
+ corrupt(t, e.seq, `delivery to unknown await "${d.awaitId}"`);
247
+ if (a.status === 'resolved')
248
+ corrupt(t, e.seq, `await "${a.awaitId}" is already resolved`);
249
+ if (a.status === 'expired' && !d.late)
250
+ corrupt(t, e.seq, 'delivery after expiry must be marked late');
251
+ const dk = deliveryKey(d.awaitId, d.idempotencyKey);
252
+ if (dk in s.deliveryKeys)
253
+ corrupt(t, e.seq, 'idempotency key reused');
254
+ a.status = 'resolved';
255
+ a.resolvedAtSeq = e.seq;
256
+ a.payload = d.payload;
257
+ a.idempotencyKey = d.idempotencyKey;
258
+ a.source = d.source;
259
+ a.late = d.late;
260
+ s.deliveryKeys[dk] = e.seq;
261
+ break;
262
+ }
263
+ case 'await.delivery_rejected': {
264
+ const d = e.data;
265
+ const a = s.awaits[d.awaitId];
266
+ if (!a || a.status !== 'resolved')
267
+ corrupt(t, e.seq, 'rejected delivery for an await that is not resolved');
268
+ const dk = deliveryKey(d.awaitId, d.idempotencyKey);
269
+ if (dk in s.deliveryKeys)
270
+ corrupt(t, e.seq, 'idempotency key reused');
271
+ a.rejectedDeliveries++;
272
+ s.deliveryKeys[dk] = e.seq;
273
+ break;
274
+ }
275
+ case 'await.expired': {
276
+ const a = s.awaits[e.data.awaitId];
277
+ if (!a || a.status !== 'pending')
278
+ corrupt(t, e.seq, `await "${e.data.awaitId}" cannot expire`);
279
+ a.status = 'expired';
280
+ break;
281
+ }
282
+ case 'task.completed':
283
+ s.status = 'completed';
284
+ s.result = e.data.result;
285
+ s.closedAt = e.at;
286
+ break;
287
+ case 'task.failed':
288
+ s.status = 'failed';
289
+ s.error = e.data.error;
290
+ s.closedAt = e.at;
291
+ break;
292
+ case 'task.cancelled':
293
+ s.status = 'cancelled';
294
+ s.error = e.data.reason;
295
+ s.closedAt = e.at;
296
+ break;
297
+ }
298
+ s.headSeq = e.seq;
299
+ s.headHash = e.hash;
300
+ s.updatedAt = e.at;
301
+ s.eventCount++;
302
+ return s;
303
+ }
304
+ /** Folds a verified, contiguous list of events (starting at seq 1, or continuing `from`). */
305
+ export function foldEvents(events, from = null) {
306
+ let state = from;
307
+ for (const e of events)
308
+ state = applyEvent(state, e);
309
+ if (state === null)
310
+ throw new LogCorruptError('?', null, 'empty log');
311
+ return state;
312
+ }
313
+ /** The state as it was when the log had `seq` events — "what did the task look like when this was sent". */
314
+ export function foldUntil(events, seq) {
315
+ return foldEvents(events.filter((e) => e.seq <= seq));
316
+ }
317
+ /** Deep copy. `structuredClone` alone would turn the null-prototype dictionaries back into plain objects. */
318
+ export function cloneState(s) {
319
+ const c = structuredClone(s);
320
+ c.labels = newDict(c.labels);
321
+ c.assumptions = newDict(c.assumptions);
322
+ c.observations = newDict(c.observations);
323
+ c.effects = newDict(c.effects);
324
+ c.awaits = newDict(c.awaits);
325
+ c.deliveryKeys = newDict(c.deliveryKeys);
326
+ return c;
327
+ }
328
+ export { GENESIS_HASH };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Preconditions of an irreversible prune, checked against the task's own log. A pure function over verified events: the
3
+ * stores call it AFTER the prune attempt is visible in the register, so that any append that lands later closes the
4
+ * attempt through G2 (ADR-019) instead of being missed by a check-then-act gap.
5
+ */
6
+ import { type TaskEvent, type TaskState, type Tombstone } from './types.js';
7
+ /** sha256 of the canonical final result/error: what the tombstone keeps instead of the data. */
8
+ export declare function outcomeDigestOf(state: TaskState): string;
9
+ /** The tombstone of a finished task: what remains of it once its data is removed. */
10
+ export declare function tombstoneFor(state: TaskState, prunedAt: string): Tombstone;
11
+ /**
12
+ * Why `tombstone` may not be used to remove the task whose log is `events`, or `null` when it may. Throws
13
+ * `LogCorruptError` when the log itself does not verify (a corrupt task is never pruned). `prunedAt` is the pruner's own
14
+ * clock and is not compared.
15
+ */
16
+ export declare function tombstoneProblem(taskId: string, events: readonly TaskEvent[], t: Tombstone): string | null;
17
+ /**
18
+ * Why a COMMITTED prune must not be rolled forward over the data that is still on disk, or `null` when it may.
19
+ * `events` are the surviving events with `seq <= t.headSeq`, each verified on its own (`parseEvent`), at most one per seq.
20
+ * Events beyond the committed head are stragglers of appends that lost against the commit (G2 reports them as pruned but
21
+ * leaves the file): they are deleted with the rest and are not evidence either way.
22
+ *
23
+ * What the data can prove depends on whether the roll-forward has begun. It publishes `tombstone.json` BEFORE its first
24
+ * unlink, so a log with a part missing and no `tombstone.json` was not removed by a roll-forward:
25
+ * - `deletionStarted` is false: nothing may be missing. The whole prefix `1..headSeq` must be there and is judged exactly
26
+ * like a prepare (`tombstoneProblem`: a finished task with the tombstone's head). A register forged for an active task,
27
+ * or one that names a head the log does not have, is caught here, before the first unlink;
28
+ * - `deletionStarted` is true: a roll-forward deletes in directory order, so any part of the log may be gone and no check
29
+ * may demand the whole of it. The head slot, if it survives, must be the head the commit names; a complete prefix is
30
+ * judged as above; a partial one has nothing that contradicts the commit, and a part cannot prove the rest.
31
+ * Throws `LogCorruptError` when a complete prefix does not verify.
32
+ */
33
+ export declare function committedProblem(taskId: string, events: readonly TaskEvent[], t: Tombstone, deletionStarted: boolean): string | null;
34
+ //# sourceMappingURL=prune-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prune-check.d.ts","sourceRoot":"","sources":["../../src/durable/prune-check.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAExF,gGAAgG;AAChG,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAGxD;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAK1E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAW1G;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAOpI"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Preconditions of an irreversible prune, checked against the task's own log. A pure function over verified events: the
3
+ * stores call it AFTER the prune attempt is visible in the register, so that any append that lands later closes the
4
+ * attempt through G2 (ADR-019) instead of being missed by a check-then-act gap.
5
+ */
6
+ import { canonicalize, sha256Hex } from './canonical.js';
7
+ import { GENESIS_HASH, verifyChain } from './log.js';
8
+ import { foldEvents } from './projection.js';
9
+ import { isTerminal } from './types.js';
10
+ /** sha256 of the canonical final result/error: what the tombstone keeps instead of the data. */
11
+ export function outcomeDigestOf(state) {
12
+ const outcome = state.status === 'completed' ? state.result : { error: state.error };
13
+ return sha256Hex(canonicalize((outcome ?? null)));
14
+ }
15
+ /** The tombstone of a finished task: what remains of it once its data is removed. */
16
+ export function tombstoneFor(state, prunedAt) {
17
+ return {
18
+ v: 1, taskId: state.taskId, kind: state.kind, finalStatus: state.status, createdAt: state.createdAt, closedAt: state.closedAt,
19
+ prunedAt, headSeq: state.headSeq, headHash: state.headHash, outcomeDigest: outcomeDigestOf(state),
20
+ };
21
+ }
22
+ /**
23
+ * Why `tombstone` may not be used to remove the task whose log is `events`, or `null` when it may. Throws
24
+ * `LogCorruptError` when the log itself does not verify (a corrupt task is never pruned). `prunedAt` is the pruner's own
25
+ * clock and is not compared.
26
+ */
27
+ export function tombstoneProblem(taskId, events, t) {
28
+ if (events.length === 0)
29
+ return 'its log has no readable events';
30
+ verifyChain(taskId, events, 0, GENESIS_HASH);
31
+ const s = foldEvents(events);
32
+ if (!isTerminal(s.status))
33
+ return `the task is ${s.status}, not finished`;
34
+ if (t.headSeq !== s.headSeq)
35
+ return `the tombstone names head ${t.headSeq}, the log ends at ${s.headSeq}`;
36
+ if (t.headHash !== s.headHash)
37
+ return 'the tombstone head hash is not the hash of the last event of the log';
38
+ if (t.finalStatus !== s.status)
39
+ return `the tombstone says "${t.finalStatus}", the task ended "${s.status}"`;
40
+ if (t.kind !== s.kind || t.createdAt !== s.createdAt || t.closedAt !== s.closedAt)
41
+ return 'the tombstone does not describe this task';
42
+ if (t.outcomeDigest !== outcomeDigestOf(s))
43
+ return 'the tombstone outcome digest is not the digest of the final outcome';
44
+ return null;
45
+ }
46
+ /**
47
+ * Why a COMMITTED prune must not be rolled forward over the data that is still on disk, or `null` when it may.
48
+ * `events` are the surviving events with `seq <= t.headSeq`, each verified on its own (`parseEvent`), at most one per seq.
49
+ * Events beyond the committed head are stragglers of appends that lost against the commit (G2 reports them as pruned but
50
+ * leaves the file): they are deleted with the rest and are not evidence either way.
51
+ *
52
+ * What the data can prove depends on whether the roll-forward has begun. It publishes `tombstone.json` BEFORE its first
53
+ * unlink, so a log with a part missing and no `tombstone.json` was not removed by a roll-forward:
54
+ * - `deletionStarted` is false: nothing may be missing. The whole prefix `1..headSeq` must be there and is judged exactly
55
+ * like a prepare (`tombstoneProblem`: a finished task with the tombstone's head). A register forged for an active task,
56
+ * or one that names a head the log does not have, is caught here, before the first unlink;
57
+ * - `deletionStarted` is true: a roll-forward deletes in directory order, so any part of the log may be gone and no check
58
+ * may demand the whole of it. The head slot, if it survives, must be the head the commit names; a complete prefix is
59
+ * judged as above; a partial one has nothing that contradicts the commit, and a part cannot prove the rest.
60
+ * Throws `LogCorruptError` when a complete prefix does not verify.
61
+ */
62
+ export function committedProblem(taskId, events, t, deletionStarted) {
63
+ if (events.length === 0)
64
+ return deletionStarted ? null : 'the log has no readable events, yet no removal was started';
65
+ const head = events.find((e) => e.seq === t.headSeq);
66
+ if (head && head.hash !== t.headHash)
67
+ return `the surviving event ${t.headSeq} is not the head hash the commit names`;
68
+ const whole = events.length === t.headSeq && events.every((e, i) => e.seq === i + 1);
69
+ if (!whole)
70
+ return deletionStarted ? null : `events of the log are missing (${events.length} of ${t.headSeq} found), yet no removal was started`;
71
+ return tombstoneProblem(taskId, events, t);
72
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * The persisted prune decision register: record formats and the pure derivation of the prune state.
3
+ *
4
+ * Design A (docs/architecture/DURABLE-PRUNE-PROTOCOL-DESIGN-004.md, sections 5, 19, 20, 32, 37, 41; ADR-019).
5
+ * This module does no I/O of its own. `derivePruneState` is a function of the names in the task directory and of what
6
+ * `RegisterIO` returns for them, so its decisions can be tested with injected partial listings and I/O errors
7
+ * without a filesystem. It never writes, never deletes and never repairs.
8
+ *
9
+ * Every verdict is fail-closed: `corrupt`, `unreadable`, `missing` and `legacy` never grant an irreversible action,
10
+ * and a missing name is never read as permission to delete anything (section 37, "absence of information is not
11
+ * permission").
12
+ */
13
+ import { MAX_PRUNE_ATTEMPTS, type DecisionBy, type PruneOutcome, type PruneState, type Tombstone } from './types.js';
14
+ export { MAX_PRUNE_ATTEMPTS };
15
+ /** Re-checks of the register by a writer that has published a file (Design A, section 24.2). */
16
+ export declare const MAX_WRITE_RESOLVE = 3;
17
+ /** A register record is tiny; anything larger is refused before it is read. */
18
+ export declare const MAX_REGISTER_BYTES: number;
19
+ export declare const REGISTER_FORMAT_VERSION = 2;
20
+ /**
21
+ * Staging files of the write primitive: `<name>.tmp.<pid>.<hex16>`. The ONE definition: the filesystem store uses it
22
+ * for its own temp names too (Design A, section 20.2, N1), so the register can never mistake a staging file for a record.
23
+ */
24
+ export declare const STAGING_RE: RegExp;
25
+ export declare const TOMBSTONE_FILE = "tombstone.json";
26
+ export declare const PROTOCOL_MARKER_FILE = "durable-protocol.json";
27
+ export declare const prepareFile: (n: number) => string;
28
+ export declare const decisionFile: (n: number) => string;
29
+ export interface PrepareRecord {
30
+ v: 2;
31
+ attempt: number;
32
+ tombstone: Tombstone;
33
+ check: string;
34
+ }
35
+ export type DecisionRecord = {
36
+ v: 2;
37
+ attempt: number;
38
+ outcome: 'abort';
39
+ by?: DecisionBy;
40
+ check: string;
41
+ } | {
42
+ v: 2;
43
+ attempt: number;
44
+ outcome: 'commit';
45
+ tombstone: Tombstone;
46
+ migrated?: true;
47
+ legacySha256?: string;
48
+ check: string;
49
+ };
50
+ /** SHA-256 of the canonical serialization of every other field: a guard against accidental damage, not against an adversary. */
51
+ export declare function checkOf(record: object): string;
52
+ export declare function encodePrepare(attempt: number, tombstone: Tombstone): string;
53
+ export declare function encodeDecision(attempt: number, outcome: PruneOutcome, tombstone: Tombstone | undefined, by: DecisionBy | undefined): string;
54
+ /** The `tombstone.json` file published from a commit. Same content, any reader of the v1 format understands it. */
55
+ export declare function encodeTombstone(tombstone: Tombstone): string;
56
+ /** Closed schema of a v1 tombstone. `null` when it is anything else. */
57
+ export declare function asTombstone(v: unknown, taskId: string): Tombstone | null;
58
+ /** Same tombstone, whatever the key order. */
59
+ export declare const sameTombstone: (a: Tombstone, b: Tombstone) => boolean;
60
+ /**
61
+ * What reading one file gave. `bad` is a PRESENT file that is not a valid record (damage, an unknown schema, a symlink,
62
+ * a special file) — evidence. `ioerr` is "the value is unknown" (EIO, EACCES, EMFILE): never evidence of anything.
63
+ */
64
+ export type Obs<T> = {
65
+ k: 'ok';
66
+ v: T;
67
+ } | {
68
+ k: 'absent';
69
+ } | {
70
+ k: 'bad';
71
+ reason: string;
72
+ } | {
73
+ k: 'ioerr';
74
+ reason: string;
75
+ };
76
+ export declare function parsePrepare(text: string, n: number, taskId: string): Obs<PrepareRecord>;
77
+ export declare function parseDecision(text: string, n: number, taskId: string): Obs<DecisionRecord>;
78
+ /** `tombstone.json` is the v1 format and is written by older code with its own key order: parse leniently, validate strictly. */
79
+ export declare function parseTombstoneFile(text: string, taskId: string): Obs<Tombstone>;
80
+ /**
81
+ * Reads for `derivePruneState`. Each returns an observation of ONE name in the task directory; a name that is not there
82
+ * is `absent`. The caller maps its filesystem errors to `ioerr` (never to `absent`) and a refused file (symlink, special
83
+ * file, wrong size) to `bad`.
84
+ */
85
+ export interface RegisterIO {
86
+ prepare(n: number): Obs<PrepareRecord>;
87
+ decision(n: number): Obs<DecisionRecord>;
88
+ tombstone(): Obs<Tombstone>;
89
+ }
90
+ /**
91
+ * The state of a task's register.
92
+ *
93
+ * `names` is ONE directory listing of `tasks/<id>/` (not an atomic snapshot: a name created during the listing may be
94
+ * missing from it). `io` reads individual files. A verdict that rests only on names that were NOT in the listing is
95
+ * not given without looking those names up (section 32.3); if the lookup finds the names the verdict is recomputed, if
96
+ * every one is confirmed absent it stands with `basis: 'lookup'`, and if anything cannot be confirmed the answer is
97
+ * `unreadable` — never a guess.
98
+ */
99
+ export declare function derivePruneState(names: readonly string[], io: RegisterIO, maxAttempts?: number): PruneState;
100
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/durable/register.ts"],"names":[],"mappings":"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"}