@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.13

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 (1256) hide show
  1. package/CHANGELOG.md +5992 -82
  2. package/COMPARISON.md +168 -63
  3. package/CONTRIBUTING.md +121 -0
  4. package/MIGRATING-from-OpenSpec.md +238 -55
  5. package/QUICKSTART.md +302 -0
  6. package/README.md +653 -144
  7. package/ROADMAP.md +1035 -0
  8. package/SCHEMA.md +3916 -263
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +927 -0
  11. package/dist/cli.js +133 -21
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +204 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +309 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +74 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/closing.js +42 -0
  20. package/dist/commands/archive/closing.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
  22. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  24. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  25. package/dist/commands/archive/plan/contracts/openapi.js +193 -0
  26. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  28. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  29. package/dist/commands/archive/plan/document/head.js +151 -0
  30. package/dist/commands/archive/plan/document/head.js.map +1 -0
  31. package/dist/commands/archive/plan/document/links.js +284 -0
  32. package/dist/commands/archive/plan/document/links.js.map +1 -0
  33. package/dist/commands/archive/plan/document/run.js +136 -0
  34. package/dist/commands/archive/plan/document/run.js.map +1 -0
  35. package/dist/commands/archive/plan/gate.js +319 -0
  36. package/dist/commands/archive/plan/gate.js.map +1 -0
  37. package/dist/commands/archive/plan/landscape.js +298 -0
  38. package/dist/commands/archive/plan/landscape.js.map +1 -0
  39. package/dist/commands/archive/plan/model/extending.js +85 -0
  40. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  41. package/dist/commands/archive/plan/refusal.js +106 -0
  42. package/dist/commands/archive/plan/refusal.js.map +1 -0
  43. package/dist/commands/archive/plan/specs.js +318 -0
  44. package/dist/commands/archive/plan/specs.js.map +1 -0
  45. package/dist/commands/archive/plan/state.js +30 -0
  46. package/dist/commands/archive/plan/state.js.map +1 -0
  47. package/dist/commands/archive/run.js +355 -0
  48. package/dist/commands/archive/run.js.map +1 -0
  49. package/dist/commands/archive/shipped.js +49 -0
  50. package/dist/commands/archive/shipped.js.map +1 -0
  51. package/dist/commands/context/context.js +166 -0
  52. package/dist/commands/context/context.js.map +1 -0
  53. package/dist/commands/context/print.js +305 -0
  54. package/dist/commands/context/print.js.map +1 -0
  55. package/dist/commands/delta/delta.js +367 -0
  56. package/dist/commands/delta/delta.js.map +1 -0
  57. package/dist/commands/delta/print.js +221 -0
  58. package/dist/commands/delta/print.js.map +1 -0
  59. package/dist/commands/dependencies.js +6 -8
  60. package/dist/commands/dependencies.js.map +1 -1
  61. package/dist/commands/diff/diff.js +86 -0
  62. package/dist/commands/diff/diff.js.map +1 -0
  63. package/dist/commands/diff/print.js +38 -0
  64. package/dist/commands/diff/print.js.map +1 -0
  65. package/dist/commands/doctor.js +65 -5
  66. package/dist/commands/doctor.js.map +1 -1
  67. package/dist/commands/explain/explain.js +227 -0
  68. package/dist/commands/explain/explain.js.map +1 -0
  69. package/dist/commands/explore.js +39 -28
  70. package/dist/commands/explore.js.map +1 -1
  71. package/dist/commands/gate/gate.js +152 -0
  72. package/dist/commands/gate/gate.js.map +1 -0
  73. package/dist/commands/gate/print.js +66 -0
  74. package/dist/commands/gate/print.js.map +1 -0
  75. package/dist/commands/gherkin/commit.js +105 -0
  76. package/dist/commands/gherkin/commit.js.map +1 -0
  77. package/dist/commands/gherkin/gherkin.js +262 -0
  78. package/dist/commands/gherkin/gherkin.js.map +1 -0
  79. package/dist/commands/gherkin/reconcile.js +146 -0
  80. package/dist/commands/gherkin/reconcile.js.map +1 -0
  81. package/dist/commands/gherkin/render.js +77 -0
  82. package/dist/commands/gherkin/render.js.map +1 -0
  83. package/dist/commands/init/example.js +204 -0
  84. package/dist/commands/init/example.js.map +1 -0
  85. package/dist/commands/init/first-hour.js +72 -0
  86. package/dist/commands/init/first-hour.js.map +1 -0
  87. package/dist/commands/{init.js → init/init.js} +142 -71
  88. package/dist/commands/init/init.js.map +1 -0
  89. package/dist/commands/init/mcp.js +131 -0
  90. package/dist/commands/init/mcp.js.map +1 -0
  91. package/dist/commands/init/options.js +78 -0
  92. package/dist/commands/init/options.js.map +1 -0
  93. package/dist/commands/instructions.js +72 -14
  94. package/dist/commands/instructions.js.map +1 -1
  95. package/dist/commands/list/campaign/campaign.js +63 -0
  96. package/dist/commands/list/campaign/campaign.js.map +1 -0
  97. package/dist/commands/list/campaign/owners.js +65 -0
  98. package/dist/commands/list/campaign/owners.js.map +1 -0
  99. package/dist/commands/list/json.js +155 -0
  100. package/dist/commands/list/json.js.map +1 -0
  101. package/dist/commands/list/list.js +358 -0
  102. package/dist/commands/list/list.js.map +1 -0
  103. package/dist/commands/list/print.js +344 -0
  104. package/dist/commands/list/print.js.map +1 -0
  105. package/dist/commands/list/review.js +120 -0
  106. package/dist/commands/list/review.js.map +1 -0
  107. package/dist/commands/list/suites/suites.js +140 -0
  108. package/dist/commands/list/suites/suites.js.map +1 -0
  109. package/dist/commands/list/views.js +108 -0
  110. package/dist/commands/list/views.js.map +1 -0
  111. package/dist/commands/mcp/dispatch.js +238 -0
  112. package/dist/commands/mcp/dispatch.js.map +1 -0
  113. package/dist/commands/mcp/mcp.js +75 -0
  114. package/dist/commands/mcp/mcp.js.map +1 -0
  115. package/dist/commands/mcp/serve.js +55 -0
  116. package/dist/commands/mcp/serve.js.map +1 -0
  117. package/dist/commands/migrate-openspec/materialize/active.js +175 -0
  118. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  119. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  120. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  121. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  122. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  123. package/dist/commands/migrate-openspec/materialize/stage.js +143 -0
  124. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  125. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  126. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  127. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  128. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  129. package/dist/commands/migrate-openspec/openspec/decisions.js +86 -0
  130. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  131. package/dist/commands/migrate-openspec/openspec/error.js +18 -0
  132. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  133. package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
  134. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  135. package/dist/commands/migrate-openspec/openspec/paths.js +40 -0
  136. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  137. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  138. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  139. package/dist/commands/migrate-openspec/print.js +89 -0
  140. package/dist/commands/migrate-openspec/print.js.map +1 -0
  141. package/dist/commands/new/capability-template.js +118 -0
  142. package/dist/commands/new/capability-template.js.map +1 -0
  143. package/dist/commands/new/commit.js +62 -0
  144. package/dist/commands/new/commit.js.map +1 -0
  145. package/dist/commands/new/modifies.js +206 -0
  146. package/dist/commands/new/modifies.js.map +1 -0
  147. package/dist/commands/new/new.js +328 -0
  148. package/dist/commands/new/new.js.map +1 -0
  149. package/dist/commands/new/templates.js +279 -0
  150. package/dist/commands/new/templates.js.map +1 -0
  151. package/dist/commands/open.js +199 -0
  152. package/dist/commands/open.js.map +1 -0
  153. package/dist/commands/policy/format.js +152 -0
  154. package/dist/commands/policy/format.js.map +1 -0
  155. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +38 -11
  156. package/dist/commands/policy/gate.js.map +1 -0
  157. package/dist/commands/rebase/edit.js +106 -0
  158. package/dist/commands/rebase/edit.js.map +1 -0
  159. package/dist/commands/rebase/living.js +185 -0
  160. package/dist/commands/rebase/living.js.map +1 -0
  161. package/dist/commands/rebase/plan.js +245 -0
  162. package/dist/commands/rebase/plan.js.map +1 -0
  163. package/dist/commands/rebase/rebase.js +300 -0
  164. package/dist/commands/rebase/rebase.js.map +1 -0
  165. package/dist/commands/seed/commit.js +221 -0
  166. package/dist/commands/seed/commit.js.map +1 -0
  167. package/dist/commands/seed/plan.js +278 -0
  168. package/dist/commands/seed/plan.js.map +1 -0
  169. package/dist/commands/seed/seed.js +174 -0
  170. package/dist/commands/seed/seed.js.map +1 -0
  171. package/dist/commands/show/feature.js +182 -0
  172. package/dist/commands/show/feature.js.map +1 -0
  173. package/dist/commands/show/introduced.js +157 -0
  174. package/dist/commands/show/introduced.js.map +1 -0
  175. package/dist/commands/show/marks.js +53 -0
  176. package/dist/commands/show/marks.js.map +1 -0
  177. package/dist/commands/show/service.js +239 -0
  178. package/dist/commands/show/service.js.map +1 -0
  179. package/dist/commands/show/show.js +87 -0
  180. package/dist/commands/show/show.js.map +1 -0
  181. package/dist/commands/status/fleet-next.js +90 -0
  182. package/dist/commands/status/fleet-next.js.map +1 -0
  183. package/dist/commands/status/json.js +47 -0
  184. package/dist/commands/status/json.js.map +1 -0
  185. package/dist/commands/status/print.js +209 -0
  186. package/dist/commands/status/print.js.map +1 -0
  187. package/dist/commands/status/status.js +115 -0
  188. package/dist/commands/status/status.js.map +1 -0
  189. package/dist/commands/steps/steps.js +269 -0
  190. package/dist/commands/steps/steps.js.map +1 -0
  191. package/dist/commands/subsystem/edit.js +192 -0
  192. package/dist/commands/subsystem/edit.js.map +1 -0
  193. package/dist/commands/subsystem/move.js +325 -0
  194. package/dist/commands/subsystem/move.js.map +1 -0
  195. package/dist/commands/subsystem/query.js +113 -0
  196. package/dist/commands/subsystem/query.js.map +1 -0
  197. package/dist/commands/subsystem/subsystem.js +98 -0
  198. package/dist/commands/subsystem/subsystem.js.map +1 -0
  199. package/dist/commands/subsystem/sync.js +318 -0
  200. package/dist/commands/subsystem/sync.js.map +1 -0
  201. package/dist/commands/subsystem/txn/exclude.js +132 -0
  202. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  203. package/dist/commands/subsystem/txn/links.js +128 -0
  204. package/dist/commands/subsystem/txn/links.js.map +1 -0
  205. package/dist/commands/subsystem/txn/report.js +174 -0
  206. package/dist/commands/subsystem/txn/report.js.map +1 -0
  207. package/dist/commands/subsystem/txn/txn.js +196 -0
  208. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  209. package/dist/commands/subsystem/txn/views.js +249 -0
  210. package/dist/commands/subsystem/txn/views.js.map +1 -0
  211. package/dist/commands/tasks/actions.js +107 -0
  212. package/dist/commands/tasks/actions.js.map +1 -0
  213. package/dist/commands/tasks/render.js +253 -0
  214. package/dist/commands/tasks/render.js.map +1 -0
  215. package/dist/commands/tasks/tasks.js +119 -0
  216. package/dist/commands/tasks/tasks.js.map +1 -0
  217. package/dist/commands/unarchive/manifest.js +176 -0
  218. package/dist/commands/unarchive/manifest.js.map +1 -0
  219. package/dist/commands/unarchive/restore.js +254 -0
  220. package/dist/commands/unarchive/restore.js.map +1 -0
  221. package/dist/commands/unarchive/unarchive.js +59 -0
  222. package/dist/commands/unarchive/unarchive.js.map +1 -0
  223. package/dist/commands/validate/arch-coverage.js +245 -0
  224. package/dist/commands/validate/arch-coverage.js.map +1 -0
  225. package/dist/commands/validate/checks/fleet-shape.js +204 -0
  226. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  227. package/dist/commands/validate/checks/health-deps.js +58 -0
  228. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  229. package/dist/commands/validate/checks/introduced.js +102 -0
  230. package/dist/commands/validate/checks/introduced.js.map +1 -0
  231. package/dist/commands/validate/checks/requirements.js +264 -0
  232. package/dist/commands/validate/checks/requirements.js.map +1 -0
  233. package/dist/commands/validate/checks/sources.js +85 -0
  234. package/dist/commands/validate/checks/sources.js.map +1 -0
  235. package/dist/commands/validate/coverage/covers-after.js +105 -0
  236. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  237. package/dist/commands/validate/feature.js +222 -0
  238. package/dist/commands/validate/feature.js.map +1 -0
  239. package/dist/commands/validate/fleet/census.js +93 -0
  240. package/dist/commands/validate/fleet/census.js.map +1 -0
  241. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  242. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  243. package/dist/commands/validate/fleet/landscape.js +371 -0
  244. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  245. package/dist/commands/validate/fleet/load.js +118 -0
  246. package/dist/commands/validate/fleet/load.js.map +1 -0
  247. package/dist/commands/validate/fleet/map/attest.js +98 -0
  248. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  249. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  250. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  251. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  252. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  253. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  254. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  255. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  256. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  257. package/dist/commands/validate/fleet/obligations.js +266 -0
  258. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  259. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  260. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  261. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  262. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  263. package/dist/commands/validate/fleet/scorecard/print.js +71 -0
  264. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  265. package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
  266. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  267. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  268. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  269. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  270. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  271. package/dist/commands/validate/fleet/views/ids.js +75 -0
  272. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  273. package/dist/commands/validate/fleet/views/projects.js +278 -0
  274. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  275. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  276. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  277. package/dist/commands/validate/fleet/views/stale.js +52 -0
  278. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  279. package/dist/commands/validate/links/corpus.js +89 -0
  280. package/dist/commands/validate/links/corpus.js.map +1 -0
  281. package/dist/commands/validate/links/glossary.js +75 -0
  282. package/dist/commands/validate/links/glossary.js.map +1 -0
  283. package/dist/commands/validate/render/repeats.js +63 -0
  284. package/dist/commands/validate/render/repeats.js.map +1 -0
  285. package/dist/commands/validate/render/rollups.js +115 -0
  286. package/dist/commands/validate/render/rollups.js.map +1 -0
  287. package/dist/commands/validate/render/text.js +199 -0
  288. package/dist/commands/validate/render/text.js.map +1 -0
  289. package/dist/commands/validate/report.js +145 -0
  290. package/dist/commands/validate/report.js.map +1 -0
  291. package/dist/commands/validate/scope.js +113 -0
  292. package/dist/commands/validate/scope.js.map +1 -0
  293. package/dist/commands/validate/service/api.js +252 -0
  294. package/dist/commands/validate/service/api.js.map +1 -0
  295. package/dist/commands/validate/service/contracts/generated.js +134 -0
  296. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  297. package/dist/commands/validate/service/events/events.js +241 -0
  298. package/dist/commands/validate/service/events/events.js.map +1 -0
  299. package/dist/commands/validate/service/events/message-producers.js +77 -0
  300. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  301. package/dist/commands/validate/service/evidence-pins.js +177 -0
  302. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  303. package/dist/commands/validate/service/model/diverged.js +226 -0
  304. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  305. package/dist/commands/validate/service/model/grade.js +163 -0
  306. package/dist/commands/validate/service/model/grade.js.map +1 -0
  307. package/dist/commands/validate/service/service.js +310 -0
  308. package/dist/commands/validate/service/service.js.map +1 -0
  309. package/dist/commands/validate/service/specs.js +279 -0
  310. package/dist/commands/validate/service/specs.js.map +1 -0
  311. package/dist/commands/validate/service/spine.js +148 -0
  312. package/dist/commands/validate/service/spine.js.map +1 -0
  313. package/dist/commands/validate/service/usecases/tags.js +113 -0
  314. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  315. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  316. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  317. package/dist/commands/validate/validate.js +363 -0
  318. package/dist/commands/validate/validate.js.map +1 -0
  319. package/dist/commands/verify/cross/diff.js +178 -0
  320. package/dist/commands/verify/cross/diff.js.map +1 -0
  321. package/dist/commands/verify/evidence/contract.js +32 -0
  322. package/dist/commands/verify/evidence/contract.js.map +1 -0
  323. package/dist/commands/verify/evidence/pins.js +52 -0
  324. package/dist/commands/verify/evidence/pins.js.map +1 -0
  325. package/dist/commands/verify/evidence/read.js +81 -0
  326. package/dist/commands/verify/evidence/read.js.map +1 -0
  327. package/dist/commands/verify/frozen.js +263 -0
  328. package/dist/commands/verify/frozen.js.map +1 -0
  329. package/dist/commands/verify/record.js +278 -0
  330. package/dist/commands/verify/record.js.map +1 -0
  331. package/dist/commands/verify/report.js +206 -0
  332. package/dist/commands/verify/report.js.map +1 -0
  333. package/dist/commands/verify/results.js +328 -0
  334. package/dist/commands/verify/results.js.map +1 -0
  335. package/dist/commands/verify/verify.js +220 -0
  336. package/dist/commands/verify/verify.js.map +1 -0
  337. package/dist/commands/vouch/contract.js +11 -0
  338. package/dist/commands/vouch/contract.js.map +1 -0
  339. package/dist/commands/vouch/pack/contract.js +2 -0
  340. package/dist/commands/vouch/pack/contract.js.map +1 -0
  341. package/dist/commands/vouch/pack/pack.js +266 -0
  342. package/dist/commands/vouch/pack/pack.js.map +1 -0
  343. package/dist/commands/vouch/pack/print.js +266 -0
  344. package/dist/commands/vouch/pack/print.js.map +1 -0
  345. package/dist/commands/vouch/pack/sections.js +141 -0
  346. package/dist/commands/vouch/pack/sections.js.map +1 -0
  347. package/dist/commands/vouch/prompt/confirm.js +46 -0
  348. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  349. package/dist/commands/vouch/report.js +101 -0
  350. package/dist/commands/vouch/report.js.map +1 -0
  351. package/dist/commands/vouch/run.js +230 -0
  352. package/dist/commands/vouch/run.js.map +1 -0
  353. package/dist/commands/vouch/sample/plan.js +111 -0
  354. package/dist/commands/vouch/sample/plan.js.map +1 -0
  355. package/dist/commands/vouch/sample/print.js +109 -0
  356. package/dist/commands/vouch/sample/print.js.map +1 -0
  357. package/dist/commands/vouch/vet/verify.js +155 -0
  358. package/dist/commands/vouch/vet/verify.js.map +1 -0
  359. package/dist/commands/vouch/vouch.js +169 -0
  360. package/dist/commands/vouch/vouch.js.map +1 -0
  361. package/dist/core/agent/agents-md/command-map.js +299 -0
  362. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  363. package/dist/core/agent/agents-md/map/explain.js +46 -0
  364. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  365. package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
  366. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  367. package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
  368. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  369. package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
  370. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  371. package/dist/core/agent/agents-md/map/mcp.js +44 -0
  372. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  373. package/dist/core/agent/agents-md/map/status.js +78 -0
  374. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  375. package/dist/core/agent/agents-md/map/subsystem.js +104 -0
  376. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  377. package/dist/core/agent/agents-md/map/usecases.js +138 -0
  378. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  379. package/dist/core/agent/agents-md/refusals.js +273 -0
  380. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  381. package/dist/core/agent/agents-md.js +203 -0
  382. package/dist/core/agent/agents-md.js.map +1 -0
  383. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -0
  384. package/dist/core/agent/agents-stamp.js.map +1 -0
  385. package/dist/core/agent/contract.js +2 -0
  386. package/dist/core/agent/contract.js.map +1 -0
  387. package/dist/core/agent/protocol.js +193 -0
  388. package/dist/core/agent/protocol.js.map +1 -0
  389. package/dist/core/agent/scaffold.js +254 -0
  390. package/dist/core/agent/scaffold.js.map +1 -0
  391. package/dist/core/agent/support/report.js +144 -0
  392. package/dist/core/agent/support/report.js.map +1 -0
  393. package/dist/core/agent/tools/dialects.js +151 -0
  394. package/dist/core/agent/tools/dialects.js.map +1 -0
  395. package/dist/core/agent/tools/registry.js +193 -0
  396. package/dist/core/agent/tools/registry.js.map +1 -0
  397. package/dist/core/agent/workflows/adopt.js +280 -0
  398. package/dist/core/agent/workflows/adopt.js.map +1 -0
  399. package/dist/core/agent/workflows/check.js +373 -0
  400. package/dist/core/agent/workflows/check.js.map +1 -0
  401. package/dist/core/agent/workflows/closing.js +323 -0
  402. package/dist/core/agent/workflows/closing.js.map +1 -0
  403. package/dist/core/agent/workflows/feature.js +220 -0
  404. package/dist/core/agent/workflows/feature.js.map +1 -0
  405. package/dist/core/agent/workflows/implement.js +188 -0
  406. package/dist/core/agent/workflows/implement.js.map +1 -0
  407. package/dist/core/agent/workflows/reference/authoring.js +311 -0
  408. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  409. package/dist/core/agent/workflows/reference/codes.js +67 -0
  410. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  411. package/dist/core/agent/workflows/reference/done-check.js +210 -0
  412. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  413. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  414. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  415. package/dist/core/agent/workflows/reference/reference.js +19 -0
  416. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  417. package/dist/core/agent/workflows/reference/spine.js +338 -0
  418. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  419. package/dist/core/asyncapi/baseline/plan.js +43 -0
  420. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  421. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  422. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  423. package/dist/core/asyncapi/depth.js +164 -0
  424. package/dist/core/asyncapi/depth.js.map +1 -0
  425. package/dist/core/asyncapi/digest.js +146 -0
  426. package/dist/core/asyncapi/digest.js.map +1 -0
  427. package/dist/core/asyncapi/merge/components.js +92 -0
  428. package/dist/core/asyncapi/merge/components.js.map +1 -0
  429. package/dist/core/asyncapi/merge/error.js +38 -0
  430. package/dist/core/asyncapi/merge/error.js.map +1 -0
  431. package/dist/core/asyncapi/merge/markers.js +290 -0
  432. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  433. package/dist/core/asyncapi/merge/merge.js +195 -0
  434. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  435. package/dist/core/asyncapi/merge/pin.js +83 -0
  436. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  437. package/dist/core/asyncapi/model.js +11 -0
  438. package/dist/core/asyncapi/model.js.map +1 -0
  439. package/dist/core/asyncapi/producers.js +50 -0
  440. package/dist/core/asyncapi/producers.js.map +1 -0
  441. package/dist/core/asyncapi/read.js +263 -0
  442. package/dist/core/asyncapi/read.js.map +1 -0
  443. package/dist/core/brief/brief.js +285 -0
  444. package/dist/core/brief/brief.js.map +1 -0
  445. package/dist/core/brief/checks.js +385 -0
  446. package/dist/core/brief/checks.js.map +1 -0
  447. package/dist/core/brief/landscape.js +273 -0
  448. package/dist/core/brief/landscape.js.map +1 -0
  449. package/dist/core/brief/map/extend.js +84 -0
  450. package/dist/core/brief/map/extend.js.map +1 -0
  451. package/dist/core/brief/map/owed.js +266 -0
  452. package/dist/core/brief/map/owed.js.map +1 -0
  453. package/dist/core/brief/targets.js +304 -0
  454. package/dist/core/brief/targets.js.map +1 -0
  455. package/dist/core/brief/unchecked.js +58 -0
  456. package/dist/core/brief/unchecked.js.map +1 -0
  457. package/dist/core/c4/arch.js +190 -0
  458. package/dist/core/c4/arch.js.map +1 -0
  459. package/dist/core/c4/direction/direction.js +114 -0
  460. package/dist/core/c4/direction/direction.js.map +1 -0
  461. package/dist/core/c4/likec4.js +243 -0
  462. package/dist/core/c4/likec4.js.map +1 -0
  463. package/dist/core/c4/locate/unlocated.js +150 -0
  464. package/dist/core/c4/locate/unlocated.js.map +1 -0
  465. package/dist/core/c4/parsed/deployment.js +160 -0
  466. package/dist/core/c4/parsed/deployment.js.map +1 -0
  467. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  468. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  469. package/dist/core/c4/parsed/specification.js +78 -0
  470. package/dist/core/c4/parsed/specification.js.map +1 -0
  471. package/dist/core/c4/parsed/values.js +110 -0
  472. package/dist/core/c4/parsed/values.js.map +1 -0
  473. package/dist/core/c4/parsed/view-ids.js +113 -0
  474. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  475. package/dist/core/c4/prefetch/fleet.js +134 -0
  476. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  477. package/dist/core/c4/project/architecture.js +161 -0
  478. package/dist/core/c4/project/architecture.js.map +1 -0
  479. package/dist/core/c4/project/batch.js +140 -0
  480. package/dist/core/c4/project/batch.js.map +1 -0
  481. package/dist/core/c4/project/documents.js +89 -0
  482. package/dist/core/c4/project/documents.js.map +1 -0
  483. package/dist/core/c4/project/load.js +219 -0
  484. package/dist/core/c4/project/load.js.map +1 -0
  485. package/dist/core/c4/project/staged.js +277 -0
  486. package/dist/core/c4/project/staged.js.map +1 -0
  487. package/dist/core/c4/resolve/attested.js +0 -0
  488. package/dist/core/c4/resolve/attested.js.map +1 -0
  489. package/dist/core/c4/resolve/external.js +51 -0
  490. package/dist/core/c4/resolve/external.js.map +1 -0
  491. package/dist/core/c4/resolve/service.js +174 -0
  492. package/dist/core/c4/resolve/service.js.map +1 -0
  493. package/dist/core/c4/resolve/steps.js +290 -0
  494. package/dist/core/c4/resolve/steps.js.map +1 -0
  495. package/dist/core/c4/resolve/systems.js +154 -0
  496. package/dist/core/c4/resolve/systems.js.map +1 -0
  497. package/dist/core/c4/root-project/exclude.js +352 -0
  498. package/dist/core/c4/root-project/exclude.js.map +1 -0
  499. package/dist/core/c4/seed/fleet-file.js +201 -0
  500. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  501. package/dist/core/c4/seed/items.js +91 -0
  502. package/dist/core/c4/seed/items.js.map +1 -0
  503. package/dist/core/c4/seed/stamp.js +48 -0
  504. package/dist/core/c4/seed/stamp.js.map +1 -0
  505. package/dist/core/c4/seed/template.js +173 -0
  506. package/dist/core/c4/seed/template.js.map +1 -0
  507. package/dist/core/c4/service-model/created/models.js +96 -0
  508. package/dist/core/c4/service-model/created/models.js.map +1 -0
  509. package/dist/core/c4/service-model/documents.js +47 -0
  510. package/dist/core/c4/service-model/documents.js.map +1 -0
  511. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  512. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  513. package/dist/core/c4/service-model/load.js +165 -0
  514. package/dist/core/c4/service-model/load.js.map +1 -0
  515. package/dist/core/c4/service-model/renderer.js +128 -0
  516. package/dist/core/c4/service-model/renderer.js.map +1 -0
  517. package/dist/core/c4/service-model/shape.js +106 -0
  518. package/dist/core/c4/service-model/shape.js.map +1 -0
  519. package/dist/core/c4/service-model/slice.js +188 -0
  520. package/dist/core/c4/service-model/slice.js.map +1 -0
  521. package/dist/core/c4/source-mask.js +369 -0
  522. package/dist/core/c4/source-mask.js.map +1 -0
  523. package/dist/core/c4/source-scan.js +308 -0
  524. package/dist/core/c4/source-scan.js.map +1 -0
  525. package/dist/core/c4/splice/authored-source.js +167 -0
  526. package/dist/core/c4/splice/authored-source.js.map +1 -0
  527. package/dist/core/c4/splice/contract.js +30 -0
  528. package/dist/core/c4/splice/contract.js.map +1 -0
  529. package/dist/core/c4/splice/delta-blocks.js +126 -0
  530. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  531. package/dist/core/c4/splice/identity/declared.js +87 -0
  532. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  533. package/dist/core/c4/splice/identity/edges.js +73 -0
  534. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  535. package/dist/core/c4/splice/identity/existing.js +80 -0
  536. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  537. package/dist/core/c4/splice/identity/interior.js +80 -0
  538. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  539. package/dist/core/c4/splice/identity/owner.js +50 -0
  540. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  541. package/dist/core/c4/splice/landscape-merge.js +337 -0
  542. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  543. package/dist/core/c4/splice/model/merge.js +151 -0
  544. package/dist/core/c4/splice/model/merge.js.map +1 -0
  545. package/dist/core/c4/splice/placement.js +298 -0
  546. package/dist/core/c4/splice/placement.js.map +1 -0
  547. package/dist/core/c4/splice/text/spot.js +131 -0
  548. package/dist/core/c4/splice/text/spot.js.map +1 -0
  549. package/dist/core/c4/workspace.js +166 -0
  550. package/dist/core/c4/workspace.js.map +1 -0
  551. package/dist/core/capabilities/authoring/notes.js +141 -0
  552. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  553. package/dist/core/capabilities/capabilities.js +124 -0
  554. package/dist/core/capabilities/capabilities.js.map +1 -0
  555. package/dist/core/capabilities/delta/doc.js +47 -0
  556. package/dist/core/capabilities/delta/doc.js.map +1 -0
  557. package/dist/core/capabilities/delta/overlay.js +129 -0
  558. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  559. package/dist/core/capabilities/delta/summary.js +57 -0
  560. package/dist/core/capabilities/delta/summary.js.map +1 -0
  561. package/dist/core/capabilities/delta/tree.js +43 -0
  562. package/dist/core/capabilities/delta/tree.js.map +1 -0
  563. package/dist/core/capabilities/delta/uncovered.js +222 -0
  564. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  565. package/dist/core/capabilities/findings.js +338 -0
  566. package/dist/core/capabilities/findings.js.map +1 -0
  567. package/dist/core/capabilities/realizes/findings.js +174 -0
  568. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  569. package/dist/core/capabilities/realizes/join.js +123 -0
  570. package/dist/core/capabilities/realizes/join.js.map +1 -0
  571. package/dist/core/capabilities/rollup.js +205 -0
  572. package/dist/core/capabilities/rollup.js.map +1 -0
  573. package/dist/core/capabilities/tree.js +104 -0
  574. package/dist/core/capabilities/tree.js.map +1 -0
  575. package/dist/core/capabilities/usecase-join.js +267 -0
  576. package/dist/core/capabilities/usecase-join.js.map +1 -0
  577. package/dist/core/coherence/authoring/scaffold.js +185 -0
  578. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  579. package/dist/core/coherence/authoring/sentinels.js +75 -0
  580. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  581. package/dist/core/coherence/calls/called.js +52 -0
  582. package/dist/core/coherence/calls/called.js.map +1 -0
  583. package/dist/core/coherence/coherence.js +332 -0
  584. package/dist/core/coherence/coherence.js.map +1 -0
  585. package/dist/core/coherence/consumed/operations.js +70 -0
  586. package/dist/core/coherence/consumed/operations.js.map +1 -0
  587. package/dist/core/coherence/consumed/refusal.js +38 -0
  588. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  589. package/dist/core/coherence/covers/health.js +85 -0
  590. package/dist/core/coherence/covers/health.js.map +1 -0
  591. package/dist/core/coherence/declared.js +295 -0
  592. package/dist/core/coherence/declared.js.map +1 -0
  593. package/dist/core/coherence/events/declared.js +191 -0
  594. package/dist/core/coherence/events/declared.js.map +1 -0
  595. package/dist/core/coherence/events/events.js +335 -0
  596. package/dist/core/coherence/events/events.js.map +1 -0
  597. package/dist/core/coherence/events/grades.js +189 -0
  598. package/dist/core/coherence/events/grades.js.map +1 -0
  599. package/dist/core/coherence/events/lookups.js +63 -0
  600. package/dist/core/coherence/events/lookups.js.map +1 -0
  601. package/dist/core/coherence/events/produced.js +100 -0
  602. package/dist/core/coherence/events/produced.js.map +1 -0
  603. package/dist/core/coherence/living.js +198 -0
  604. package/dist/core/coherence/living.js.map +1 -0
  605. package/dist/core/coherence/lookups.js +95 -0
  606. package/dist/core/coherence/lookups.js.map +1 -0
  607. package/dist/core/coherence/pending.js +39 -0
  608. package/dist/core/coherence/pending.js.map +1 -0
  609. package/dist/core/coherence/retired/archived.js +285 -0
  610. package/dist/core/coherence/retired/archived.js.map +1 -0
  611. package/dist/core/coherence/retired/event-pair.js +62 -0
  612. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  613. package/dist/core/coherence/retired/merged.js +79 -0
  614. package/dist/core/coherence/retired/merged.js.map +1 -0
  615. package/dist/core/coherence/retired/retirement.js +49 -0
  616. package/dist/core/coherence/retired/retirement.js.map +1 -0
  617. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  618. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  619. package/dist/core/coherence/retired/revival/revived.js +297 -0
  620. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  621. package/dist/core/conflict-markers.js +60 -0
  622. package/dist/core/conflict-markers.js.map +1 -0
  623. package/dist/core/consumers/after.js +113 -0
  624. package/dist/core/consumers/after.js.map +1 -0
  625. package/dist/core/consumers/consumers.js +296 -0
  626. package/dist/core/consumers/consumers.js.map +1 -0
  627. package/dist/core/consumers/current.js +211 -0
  628. package/dist/core/consumers/current.js.map +1 -0
  629. package/dist/core/consumers/scan.js +46 -0
  630. package/dist/core/consumers/scan.js.map +1 -0
  631. package/dist/core/consumers/state.js +27 -0
  632. package/dist/core/consumers/state.js.map +1 -0
  633. package/dist/core/delta/claims.js +73 -0
  634. package/dist/core/delta/claims.js.map +1 -0
  635. package/dist/core/delta/delta.js +341 -0
  636. package/dist/core/delta/delta.js.map +1 -0
  637. package/dist/core/delta/document.js +177 -0
  638. package/dist/core/delta/document.js.map +1 -0
  639. package/dist/core/delta/scope.js +48 -0
  640. package/dist/core/delta/scope.js.map +1 -0
  641. package/dist/core/delta/select.js +237 -0
  642. package/dist/core/delta/select.js.map +1 -0
  643. package/dist/core/dependencies/dependencies.js +141 -0
  644. package/dist/core/dependencies/dependencies.js.map +1 -0
  645. package/dist/core/dependencies/facts.js +165 -0
  646. package/dist/core/dependencies/facts.js.map +1 -0
  647. package/dist/core/dependencies/fanin.js +88 -0
  648. package/dist/core/dependencies/fanin.js.map +1 -0
  649. package/dist/core/dependencies/graph.js +106 -0
  650. package/dist/core/dependencies/graph.js.map +1 -0
  651. package/dist/core/deployment/delta.js +191 -0
  652. package/dist/core/deployment/delta.js.map +1 -0
  653. package/dist/core/deployment/objects.js +145 -0
  654. package/dist/core/deployment/objects.js.map +1 -0
  655. package/dist/core/diff/base-git.js +230 -0
  656. package/dist/core/diff/base-git.js.map +1 -0
  657. package/dist/core/diff/base-state.js +237 -0
  658. package/dist/core/diff/base-state.js.map +1 -0
  659. package/dist/core/diff/joins.js +136 -0
  660. package/dist/core/diff/joins.js.map +1 -0
  661. package/dist/core/diff/scope/changed-paths.js +204 -0
  662. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  663. package/dist/core/diff/scope/edges.js +82 -0
  664. package/dist/core/diff/scope/edges.js.map +1 -0
  665. package/dist/core/diff/semantic.js +312 -0
  666. package/dist/core/diff/semantic.js.map +1 -0
  667. package/dist/core/docs.js +37 -85
  668. package/dist/core/docs.js.map +1 -1
  669. package/dist/core/doctor/agents.js +238 -0
  670. package/dist/core/doctor/agents.js.map +1 -0
  671. package/dist/core/doctor/config.js +139 -0
  672. package/dist/core/doctor/config.js.map +1 -0
  673. package/dist/core/doctor/doctor.js +355 -0
  674. package/dist/core/doctor/doctor.js.map +1 -0
  675. package/dist/core/doctor/report.js +13 -0
  676. package/dist/core/doctor/report.js.map +1 -0
  677. package/dist/core/doctor/reports/scan.js +242 -0
  678. package/dist/core/doctor/reports/scan.js.map +1 -0
  679. package/dist/core/doctor/residue.js +110 -0
  680. package/dist/core/doctor/residue.js.map +1 -0
  681. package/dist/core/document/apply.js +224 -0
  682. package/dist/core/document/apply.js.map +1 -0
  683. package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -2
  684. package/dist/core/document/frontmatter.js.map +1 -0
  685. package/dist/core/document/grammar/directives.js +143 -0
  686. package/dist/core/document/grammar/directives.js.map +1 -0
  687. package/dist/core/document/parse.js +286 -0
  688. package/dist/core/document/parse.js.map +1 -0
  689. package/dist/core/document/scenarios.js +238 -0
  690. package/dist/core/document/scenarios.js.map +1 -0
  691. package/dist/core/document/spec.js +234 -0
  692. package/dist/core/document/spec.js.map +1 -0
  693. package/dist/core/{config.js → envelope/config.js} +89 -18
  694. package/dist/core/envelope/config.js.map +1 -0
  695. package/dist/core/envelope/json.js +209 -0
  696. package/dist/core/envelope/json.js.map +1 -0
  697. package/dist/core/{version.js → envelope/version.js} +3 -3
  698. package/dist/core/envelope/version.js.map +1 -0
  699. package/dist/core/explain/families.js +180 -0
  700. package/dist/core/explain/families.js.map +1 -0
  701. package/dist/core/explain/fix-tables.js +178 -0
  702. package/dist/core/explain/fix-tables.js.map +1 -0
  703. package/dist/core/explain/lookup.js +194 -0
  704. package/dist/core/explain/lookup.js.map +1 -0
  705. package/dist/core/explain/refusals.js +49 -0
  706. package/dist/core/explain/refusals.js.map +1 -0
  707. package/dist/core/explain/terms/documents.js +227 -0
  708. package/dist/core/explain/terms/documents.js.map +1 -0
  709. package/dist/core/explain/terms/done-check.js +144 -0
  710. package/dist/core/explain/terms/done-check.js.map +1 -0
  711. package/dist/core/explain/terms/entry.js +14 -0
  712. package/dist/core/explain/terms/entry.js.map +1 -0
  713. package/dist/core/explain/terms/stages.js +71 -0
  714. package/dist/core/explain/terms/stages.js.map +1 -0
  715. package/dist/core/explain/terms/tasks.js +97 -0
  716. package/dist/core/explain/terms/tasks.js.map +1 -0
  717. package/dist/core/explain/terms.js +103 -0
  718. package/dist/core/explain/terms.js.map +1 -0
  719. package/dist/core/explore/describe.js +105 -0
  720. package/dist/core/explore/describe.js.map +1 -0
  721. package/dist/core/explore/explore.js +204 -0
  722. package/dist/core/explore/explore.js.map +1 -0
  723. package/dist/core/fleet-context.js +174 -146
  724. package/dist/core/fleet-context.js.map +1 -1
  725. package/dist/core/gate/checks.js +208 -0
  726. package/dist/core/gate/checks.js.map +1 -0
  727. package/dist/core/gate/partners.js +246 -0
  728. package/dist/core/gate/partners.js.map +1 -0
  729. package/dist/core/gate/report.js +47 -0
  730. package/dist/core/gate/report.js.map +1 -0
  731. package/dist/core/gate/verification.js +176 -0
  732. package/dist/core/gate/verification.js.map +1 -0
  733. package/dist/core/gherkin/digest.js +60 -0
  734. package/dist/core/gherkin/digest.js.map +1 -0
  735. package/dist/core/gherkin/emit.js +177 -0
  736. package/dist/core/gherkin/emit.js.map +1 -0
  737. package/dist/core/gherkin/read.js +76 -0
  738. package/dist/core/gherkin/read.js.map +1 -0
  739. package/dist/core/gherkin/stale.js +210 -0
  740. package/dist/core/gherkin/stale.js.map +1 -0
  741. package/dist/core/gherkin/stamp.js +77 -0
  742. package/dist/core/gherkin/stamp.js.map +1 -0
  743. package/dist/core/gherkin/steps/catalogue.js +154 -0
  744. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  745. package/dist/core/gherkin/steps/inventory.js +98 -0
  746. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  747. package/dist/core/gherkin/steps/phrase.js +72 -0
  748. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  749. package/dist/core/glossary/delta.js +109 -0
  750. package/dist/core/glossary/delta.js.map +1 -0
  751. package/dist/core/glossary/tree.js +73 -0
  752. package/dist/core/glossary/tree.js.map +1 -0
  753. package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -0
  754. package/dist/core/kernel/concurrency.js.map +1 -0
  755. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  756. package/dist/core/kernel/document-bytes.js.map +1 -0
  757. package/dist/core/kernel/fences.js +42 -0
  758. package/dist/core/kernel/fences.js.map +1 -0
  759. package/dist/core/kernel/ids/capability.js +72 -0
  760. package/dist/core/kernel/ids/capability.js.map +1 -0
  761. package/dist/core/kernel/ids/dirs.js +33 -0
  762. package/dist/core/kernel/ids/dirs.js.map +1 -0
  763. package/dist/core/kernel/ids/feature.js +75 -0
  764. package/dist/core/kernel/ids/feature.js.map +1 -0
  765. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  766. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  767. package/dist/core/kernel/ids/service.js +156 -0
  768. package/dist/core/kernel/ids/service.js.map +1 -0
  769. package/dist/core/kernel/ids/subsystem.js +63 -0
  770. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  771. package/dist/core/{path-safety.js → kernel/path-safety.js} +56 -4
  772. package/dist/core/kernel/path-safety.js.map +1 -0
  773. package/dist/core/{records.js → kernel/records.js} +11 -0
  774. package/dist/core/kernel/records.js.map +1 -0
  775. package/dist/core/links/backlinks.js +66 -0
  776. package/dist/core/links/backlinks.js.map +1 -0
  777. package/dist/core/links/case.js +74 -0
  778. package/dist/core/links/case.js.map +1 -0
  779. package/dist/core/links/corpus.js +118 -0
  780. package/dist/core/links/corpus.js.map +1 -0
  781. package/dist/core/links/findings.js +110 -0
  782. package/dist/core/links/findings.js.map +1 -0
  783. package/dist/core/links/parse.js +265 -0
  784. package/dist/core/links/parse.js.map +1 -0
  785. package/dist/core/mcp/argv.js +212 -0
  786. package/dist/core/mcp/argv.js.map +1 -0
  787. package/dist/core/mcp/author-tools.js +73 -0
  788. package/dist/core/mcp/author-tools.js.map +1 -0
  789. package/dist/core/mcp/framing.js +46 -0
  790. package/dist/core/mcp/framing.js.map +1 -0
  791. package/dist/core/mcp/protocol.js +280 -0
  792. package/dist/core/mcp/protocol.js.map +1 -0
  793. package/dist/core/mcp/tools.js +324 -0
  794. package/dist/core/mcp/tools.js.map +1 -0
  795. package/dist/core/obligations/obligations.js +106 -0
  796. package/dist/core/obligations/obligations.js.map +1 -0
  797. package/dist/core/openapi/baseline/gate.js +207 -0
  798. package/dist/core/openapi/baseline/gate.js.map +1 -0
  799. package/dist/core/openapi/baseline/plan.js +142 -0
  800. package/dist/core/openapi/baseline/plan.js.map +1 -0
  801. package/dist/core/openapi/baseline/record.js +174 -0
  802. package/dist/core/openapi/baseline/record.js.map +1 -0
  803. package/dist/core/openapi/contract-text.js +33 -0
  804. package/dist/core/openapi/contract-text.js.map +1 -0
  805. package/dist/core/openapi/contract-tree.js +301 -0
  806. package/dist/core/openapi/contract-tree.js.map +1 -0
  807. package/dist/core/openapi/depth.js +136 -0
  808. package/dist/core/openapi/depth.js.map +1 -0
  809. package/dist/core/openapi/digest.js +239 -0
  810. package/dist/core/openapi/digest.js.map +1 -0
  811. package/dist/core/{openapi.js → openapi/doc.js} +54 -108
  812. package/dist/core/openapi/doc.js.map +1 -0
  813. package/dist/core/openapi/merge/components.js +199 -0
  814. package/dist/core/openapi/merge/components.js.map +1 -0
  815. package/dist/core/openapi/merge/error.js +16 -0
  816. package/dist/core/openapi/merge/error.js.map +1 -0
  817. package/dist/core/openapi/merge/markers.js +204 -0
  818. package/dist/core/openapi/merge/markers.js.map +1 -0
  819. package/dist/core/openapi/merge/merge.js +232 -0
  820. package/dist/core/openapi/merge/merge.js.map +1 -0
  821. package/dist/core/openapi/merge/pin.js +110 -0
  822. package/dist/core/openapi/merge/pin.js.map +1 -0
  823. package/dist/core/openspec/decide/capabilities.js +244 -0
  824. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  825. package/dist/core/openspec/decide/dispositions.js +63 -0
  826. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  827. package/dist/core/openspec/decide/renames.js +179 -0
  828. package/dist/core/openspec/decide/renames.js.map +1 -0
  829. package/dist/core/openspec/decide/verdict.js +84 -0
  830. package/dist/core/openspec/decide/verdict.js.map +1 -0
  831. package/dist/core/openspec/inventory.js +220 -0
  832. package/dist/core/openspec/inventory.js.map +1 -0
  833. package/dist/core/openspec/model/mapping.js +78 -0
  834. package/dist/core/openspec/model/mapping.js.map +1 -0
  835. package/dist/core/openspec/model/model.js +70 -0
  836. package/dist/core/openspec/model/model.js.map +1 -0
  837. package/dist/core/openspec/scan/changes.js +241 -0
  838. package/dist/core/openspec/scan/changes.js.map +1 -0
  839. package/dist/core/openspec/scan/config.js +191 -0
  840. package/dist/core/openspec/scan/config.js.map +1 -0
  841. package/dist/core/openspec/scan/shape.js +304 -0
  842. package/dist/core/openspec/scan/shape.js.map +1 -0
  843. package/dist/core/openspec/scan/walk.js +116 -0
  844. package/dist/core/openspec/scan/walk.js.map +1 -0
  845. package/dist/core/openspec/scan/workspace.js +71 -0
  846. package/dist/core/openspec/scan/workspace.js.map +1 -0
  847. package/dist/core/owners/codeowners.js +141 -0
  848. package/dist/core/owners/codeowners.js.map +1 -0
  849. package/dist/core/pack/features.js +120 -0
  850. package/dist/core/pack/features.js.map +1 -0
  851. package/dist/core/pack/joins.js +112 -0
  852. package/dist/core/pack/joins.js.map +1 -0
  853. package/dist/core/pack/living.js +157 -0
  854. package/dist/core/pack/living.js.map +1 -0
  855. package/dist/core/pack/pack.js +120 -0
  856. package/dist/core/pack/pack.js.map +1 -0
  857. package/dist/core/permissions/permissions.js +87 -0
  858. package/dist/core/permissions/permissions.js.map +1 -0
  859. package/dist/core/projection/api.js +84 -0
  860. package/dist/core/projection/api.js.map +1 -0
  861. package/dist/core/projection/arch-slice.js +63 -0
  862. package/dist/core/projection/arch-slice.js.map +1 -0
  863. package/dist/core/projection/events.js +34 -0
  864. package/dist/core/projection/events.js.map +1 -0
  865. package/dist/core/projection/introduced.js +14 -0
  866. package/dist/core/projection/introduced.js.map +1 -0
  867. package/dist/core/provenance/findings.js +244 -0
  868. package/dist/core/provenance/findings.js.map +1 -0
  869. package/dist/core/provenance/git.js +201 -0
  870. package/dist/core/provenance/git.js.map +1 -0
  871. package/dist/core/provenance/gitq/moves.js +139 -0
  872. package/dist/core/provenance/gitq/moves.js.map +1 -0
  873. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  874. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  875. package/dist/core/provenance/sample/scope.js +238 -0
  876. package/dist/core/provenance/sample/scope.js.map +1 -0
  877. package/dist/core/provenance/sample/sections.js +61 -0
  878. package/dist/core/provenance/sample/sections.js.map +1 -0
  879. package/dist/core/provenance/sources.js +280 -0
  880. package/dist/core/provenance/sources.js.map +1 -0
  881. package/dist/core/provenance/stamp.js +220 -0
  882. package/dist/core/provenance/stamp.js.map +1 -0
  883. package/dist/core/provenance/walk.js +157 -0
  884. package/dist/core/provenance/walk.js.map +1 -0
  885. package/dist/core/repo/authored/paths.js +210 -0
  886. package/dist/core/repo/authored/paths.js.map +1 -0
  887. package/dist/core/repo/entries.js +126 -0
  888. package/dist/core/repo/entries.js.map +1 -0
  889. package/dist/core/repo/paths.js +322 -0
  890. package/dist/core/repo/paths.js.map +1 -0
  891. package/dist/core/repo/repo.js +308 -0
  892. package/dist/core/repo/repo.js.map +1 -0
  893. package/dist/core/repo/service-target.js +153 -0
  894. package/dist/core/repo/service-target.js.map +1 -0
  895. package/dist/core/repo/state.js +58 -0
  896. package/dist/core/repo/state.js.map +1 -0
  897. package/dist/core/repo/tree/find.js +61 -0
  898. package/dist/core/repo/tree/find.js.map +1 -0
  899. package/dist/core/repo/tree/fs.js +90 -0
  900. package/dist/core/repo/tree/fs.js.map +1 -0
  901. package/dist/core/repo/tree/marker.js +61 -0
  902. package/dist/core/repo/tree/marker.js.map +1 -0
  903. package/dist/core/repo/tree/render/body.js +258 -0
  904. package/dist/core/repo/tree/render/body.js.map +1 -0
  905. package/dist/core/repo/tree/render/projects.js +182 -0
  906. package/dist/core/repo/tree/render/projects.js.map +1 -0
  907. package/dist/core/repo/tree/render/service/header.js +125 -0
  908. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  909. package/dist/core/repo/tree/render/service/peers.js +28 -0
  910. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  911. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  912. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  913. package/dist/core/repo/tree/render/service/views.js +78 -0
  914. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  915. package/dist/core/repo/tree/render/stale.js +42 -0
  916. package/dist/core/repo/tree/render/stale.js.map +1 -0
  917. package/dist/core/repo/tree/render/text.js +84 -0
  918. package/dist/core/repo/tree/render/text.js.map +1 -0
  919. package/dist/core/repo/tree/render/views.js +293 -0
  920. package/dist/core/repo/tree/render/views.js.map +1 -0
  921. package/dist/core/repo/tree/walk.js +255 -0
  922. package/dist/core/repo/tree/walk.js.map +1 -0
  923. package/dist/core/results.js +146 -14
  924. package/dist/core/results.js.map +1 -1
  925. package/dist/core/scaffold/landscape.js +239 -0
  926. package/dist/core/scaffold/landscape.js.map +1 -0
  927. package/dist/core/scaffold/legacy.js +271 -0
  928. package/dist/core/scaffold/legacy.js.map +1 -0
  929. package/dist/core/scaffold/readme.js +84 -0
  930. package/dist/core/scaffold/readme.js.map +1 -0
  931. package/dist/core/staging/commit.js +252 -0
  932. package/dist/core/staging/commit.js.map +1 -0
  933. package/dist/core/staging/interrupted.js +96 -0
  934. package/dist/core/staging/interrupted.js.map +1 -0
  935. package/dist/core/staging/lock.js +268 -0
  936. package/dist/core/staging/lock.js.map +1 -0
  937. package/dist/core/staging/recovery/finding.js +35 -0
  938. package/dist/core/staging/recovery/finding.js.map +1 -0
  939. package/dist/core/staging/recovery/intent.js +95 -0
  940. package/dist/core/staging/recovery/intent.js.map +1 -0
  941. package/dist/core/staging/recovery/recover.js +204 -0
  942. package/dist/core/staging/recovery/recover.js.map +1 -0
  943. package/dist/core/staging/recovery/residue.js +62 -0
  944. package/dist/core/staging/recovery/residue.js.map +1 -0
  945. package/dist/core/staging/snapshot/manifest.js +188 -0
  946. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  947. package/dist/core/staging/snapshot/snapshot.js +196 -0
  948. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  949. package/dist/core/staging/txn/forward.js +181 -0
  950. package/dist/core/staging/txn/forward.js.map +1 -0
  951. package/dist/core/staging/txn/journal.js +139 -0
  952. package/dist/core/staging/txn/journal.js.map +1 -0
  953. package/dist/core/staging/txn/transaction.js +75 -0
  954. package/dist/core/staging/txn/transaction.js.map +1 -0
  955. package/dist/core/staging/writes.js +113 -0
  956. package/dist/core/staging/writes.js.map +1 -0
  957. package/dist/core/status/actions/execution.js +60 -0
  958. package/dist/core/status/actions/execution.js.map +1 -0
  959. package/dist/core/status/contracts.js +126 -0
  960. package/dist/core/status/contracts.js.map +1 -0
  961. package/dist/core/status/feature/artifacts.js +196 -0
  962. package/dist/core/status/feature/artifacts.js.map +1 -0
  963. package/dist/core/status/feature/feature.js +214 -0
  964. package/dist/core/status/feature/feature.js.map +1 -0
  965. package/dist/core/status/feature/next.js +163 -0
  966. package/dist/core/status/feature/next.js.map +1 -0
  967. package/dist/core/status/feature/state.js +21 -0
  968. package/dist/core/status/feature/state.js.map +1 -0
  969. package/dist/core/status/feature/words.js +96 -0
  970. package/dist/core/status/feature/words.js.map +1 -0
  971. package/dist/core/status/fleet/fleet.js +216 -0
  972. package/dist/core/status/fleet/fleet.js.map +1 -0
  973. package/dist/core/status/fleet/next.js +302 -0
  974. package/dist/core/status/fleet/next.js.map +1 -0
  975. package/dist/core/status/interrupted.js +97 -0
  976. package/dist/core/status/interrupted.js.map +1 -0
  977. package/dist/core/status/report.js +31 -0
  978. package/dist/core/status/report.js.map +1 -0
  979. package/dist/core/status/scan.js +41 -0
  980. package/dist/core/status/scan.js.map +1 -0
  981. package/dist/core/status/verification.js +216 -0
  982. package/dist/core/status/verification.js.map +1 -0
  983. package/dist/core/tasks/packet.js +199 -0
  984. package/dist/core/tasks/packet.js.map +1 -0
  985. package/dist/core/tasks/record.js +43 -0
  986. package/dist/core/tasks/record.js.map +1 -0
  987. package/dist/core/tasks/sources.js +181 -0
  988. package/dist/core/tasks/sources.js.map +1 -0
  989. package/dist/core/tasks/stamps.js +76 -0
  990. package/dist/core/tasks/stamps.js.map +1 -0
  991. package/dist/core/tasks/unit.js +0 -0
  992. package/dist/core/tasks/unit.js.map +1 -0
  993. package/dist/core/usecases/capability.js +166 -0
  994. package/dist/core/usecases/capability.js.map +1 -0
  995. package/dist/core/usecases/delta/claims.js +140 -0
  996. package/dist/core/usecases/delta/claims.js.map +1 -0
  997. package/dist/core/usecases/delta/flows.js +101 -0
  998. package/dist/core/usecases/delta/flows.js.map +1 -0
  999. package/dist/core/usecases/delta/modified.js +315 -0
  1000. package/dist/core/usecases/delta/modified.js.map +1 -0
  1001. package/dist/core/usecases/delta/overlay.js +76 -0
  1002. package/dist/core/usecases/delta/overlay.js.map +1 -0
  1003. package/dist/core/usecases/fleet.js +296 -0
  1004. package/dist/core/usecases/fleet.js.map +1 -0
  1005. package/dist/core/usecases/grade/capability-tag.js +93 -0
  1006. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  1007. package/dist/core/usecases/grade/feature.js +88 -0
  1008. package/dist/core/usecases/grade/feature.js.map +1 -0
  1009. package/dist/core/usecases/grade/requirement-tag.js +94 -0
  1010. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  1011. package/dist/core/usecases/grade/steps.js +266 -0
  1012. package/dist/core/usecases/grade/steps.js.map +1 -0
  1013. package/dist/core/usecases/grade/usecases.js +112 -0
  1014. package/dist/core/usecases/grade/usecases.js.map +1 -0
  1015. package/dist/core/usecases/operations.js +123 -0
  1016. package/dist/core/usecases/operations.js.map +1 -0
  1017. package/dist/core/usecases/place.js +44 -0
  1018. package/dist/core/usecases/place.js.map +1 -0
  1019. package/dist/core/usecases/service/exclude.js +119 -0
  1020. package/dist/core/usecases/service/exclude.js.map +1 -0
  1021. package/dist/core/usecases/service/flows.js +164 -0
  1022. package/dist/core/usecases/service/flows.js.map +1 -0
  1023. package/dist/core/usecases/suites/participants.js +83 -0
  1024. package/dist/core/usecases/suites/participants.js.map +1 -0
  1025. package/dist/core/usecases/suites/suites.js +45 -0
  1026. package/dist/core/usecases/suites/suites.js.map +1 -0
  1027. package/dist/core/usecases/touch.js +101 -0
  1028. package/dist/core/usecases/touch.js.map +1 -0
  1029. package/dist/core/verify/answers.js +180 -0
  1030. package/dist/core/verify/answers.js.map +1 -0
  1031. package/dist/core/verify/build.js +170 -0
  1032. package/dist/core/verify/build.js.map +1 -0
  1033. package/dist/core/verify/checklist.js +259 -0
  1034. package/dist/core/verify/checklist.js.map +1 -0
  1035. package/dist/core/verify/claims/identity.js +61 -0
  1036. package/dist/core/verify/claims/identity.js.map +1 -0
  1037. package/dist/core/verify/cross/diff.js +97 -0
  1038. package/dist/core/verify/cross/diff.js.map +1 -0
  1039. package/dist/core/verify/evidence/contract.js +169 -0
  1040. package/dist/core/verify/evidence/contract.js.map +1 -0
  1041. package/dist/core/verify/location.js +67 -0
  1042. package/dist/core/verify/location.js.map +1 -0
  1043. package/dist/core/verify/pins/lint.js +158 -0
  1044. package/dist/core/verify/pins/lint.js.map +1 -0
  1045. package/dist/core/verify/pins/pin.js +95 -0
  1046. package/dist/core/verify/pins/pin.js.map +1 -0
  1047. package/dist/core/verify/read/file.js +224 -0
  1048. package/dist/core/verify/read/file.js.map +1 -0
  1049. package/dist/core/verify/read/shape.js +169 -0
  1050. package/dist/core/verify/read/shape.js.map +1 -0
  1051. package/dist/core/verify/read/union.js +105 -0
  1052. package/dist/core/verify/read/union.js.map +1 -0
  1053. package/dist/core/verify/record.js +165 -0
  1054. package/dist/core/verify/record.js.map +1 -0
  1055. package/dist/core/verify/store/commit.js +99 -0
  1056. package/dist/core/verify/store/commit.js.map +1 -0
  1057. package/dist/core/verify/store/render.js +61 -0
  1058. package/dist/core/verify/store/render.js.map +1 -0
  1059. package/dist/core/vocabulary/health.js +91 -0
  1060. package/dist/core/vocabulary/health.js.map +1 -0
  1061. package/dist/core/vocabulary/issue.js +59 -0
  1062. package/dist/core/vocabulary/issue.js.map +1 -0
  1063. package/dist/core/vocabulary/maturity.js +216 -0
  1064. package/dist/core/vocabulary/maturity.js.map +1 -0
  1065. package/dist/core/vocabulary/report.js +90 -0
  1066. package/dist/core/vocabulary/report.js.map +1 -0
  1067. package/dist/core/vocabulary/steps.js +266 -0
  1068. package/dist/core/vocabulary/steps.js.map +1 -0
  1069. package/dist/core/workspace/discover.js +239 -0
  1070. package/dist/core/workspace/discover.js.map +1 -0
  1071. package/dist/core/workspace/render.js +52 -0
  1072. package/dist/core/workspace/render.js.map +1 -0
  1073. package/examples/README.md +232 -0
  1074. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  1075. package/examples/docs/architecture/capabilities.yaml +31 -0
  1076. package/examples/docs/architecture/landscape.likec4 +336 -0
  1077. package/examples/docs/architecture/obligations.yaml +23 -0
  1078. package/examples/docs/architecture/permissions.yaml +50 -0
  1079. package/examples/docs/architecture/services.likec4 +70 -0
  1080. package/examples/docs/architecture/subsystems.likec4 +18 -0
  1081. package/examples/docs/architecture/usecases/order-notification.likec4 +74 -0
  1082. package/examples/docs/capabilities/checkout/spec.md +55 -0
  1083. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  1084. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  1085. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  1086. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  1087. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  1088. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  1089. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +132 -0
  1090. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  1091. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  1092. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  1093. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  1094. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  1095. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +31 -0
  1096. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  1097. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  1098. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  1099. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  1100. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  1101. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  1102. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  1103. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  1104. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  1105. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  1106. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +73 -0
  1107. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  1108. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  1109. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  1110. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  1111. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  1112. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  1113. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  1114. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  1115. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  1116. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  1117. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  1118. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  1119. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  1120. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  1121. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  1122. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  1123. package/examples/docs/glossary/order.md +15 -0
  1124. package/examples/docs/glossary/payments/authorization.md +14 -0
  1125. package/examples/docs/likec4.config.json +8 -0
  1126. package/examples/docs/loam.json +3 -0
  1127. package/examples/docs/services/checkout-web/model.likec4 +92 -0
  1128. package/examples/docs/services/checkout-web/spec.md +91 -0
  1129. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  1130. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  1131. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  1132. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  1133. package/examples/docs/services/order-service/arch.spec.md +134 -0
  1134. package/examples/docs/services/order-service/asyncapi.yaml +109 -0
  1135. package/examples/docs/services/order-service/health.yaml +57 -0
  1136. package/examples/docs/services/order-service/model.likec4 +126 -0
  1137. package/examples/docs/services/order-service/openapi.yaml +257 -0
  1138. package/examples/docs/services/order-service/runbook.md +62 -0
  1139. package/examples/docs/services/order-service/spec.md +134 -0
  1140. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  1141. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  1142. package/examples/docs/services/payment-service/arch.spec.md +76 -0
  1143. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  1144. package/examples/docs/services/payment-service/health.yaml +39 -0
  1145. package/examples/docs/services/payment-service/model.likec4 +68 -0
  1146. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  1147. package/examples/docs/services/payment-service/runbook.md +37 -0
  1148. package/examples/docs/services/payment-service/spec.md +88 -0
  1149. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  1150. package/examples/docs/services/platform/identity-service/arch.spec.md +120 -0
  1151. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  1152. package/examples/docs/services/platform/identity-service/model.likec4 +81 -0
  1153. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  1154. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  1155. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  1156. package/examples/docs/services/platform/notification-service/asyncapi.yaml +200 -0
  1157. package/examples/docs/services/platform/notification-service/health.yaml +40 -0
  1158. package/examples/docs/services/platform/notification-service/model.likec4 +97 -0
  1159. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  1160. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  1161. package/examples/docs/services/platform/subsystem.yaml +2 -0
  1162. package/examples/fleet.yaml +57 -0
  1163. package/package.json +19 -6
  1164. package/dist/commands/adopt.js +0 -240
  1165. package/dist/commands/adopt.js.map +0 -1
  1166. package/dist/commands/archive.js +0 -1313
  1167. package/dist/commands/archive.js.map +0 -1
  1168. package/dist/commands/delta.js +0 -388
  1169. package/dist/commands/delta.js.map +0 -1
  1170. package/dist/commands/docs-repo-gate.js.map +0 -1
  1171. package/dist/commands/format.js +0 -17
  1172. package/dist/commands/format.js.map +0 -1
  1173. package/dist/commands/gherkin.js +0 -309
  1174. package/dist/commands/gherkin.js.map +0 -1
  1175. package/dist/commands/init.js.map +0 -1
  1176. package/dist/commands/list.js +0 -295
  1177. package/dist/commands/list.js.map +0 -1
  1178. package/dist/commands/migrate-openspec.js +0 -950
  1179. package/dist/commands/migrate-openspec.js.map +0 -1
  1180. package/dist/commands/new.js +0 -413
  1181. package/dist/commands/new.js.map +0 -1
  1182. package/dist/commands/rebase.js +0 -356
  1183. package/dist/commands/rebase.js.map +0 -1
  1184. package/dist/commands/show.js +0 -320
  1185. package/dist/commands/show.js.map +0 -1
  1186. package/dist/commands/status.js +0 -262
  1187. package/dist/commands/status.js.map +0 -1
  1188. package/dist/commands/unarchive.js +0 -317
  1189. package/dist/commands/unarchive.js.map +0 -1
  1190. package/dist/commands/validate.js +0 -1773
  1191. package/dist/commands/validate.js.map +0 -1
  1192. package/dist/commands/verify.js +0 -775
  1193. package/dist/commands/verify.js.map +0 -1
  1194. package/dist/commands/vouch.js +0 -421
  1195. package/dist/commands/vouch.js.map +0 -1
  1196. package/dist/core/agent.js +0 -2173
  1197. package/dist/core/agent.js.map +0 -1
  1198. package/dist/core/agents-stamp.js.map +0 -1
  1199. package/dist/core/arch.js +0 -130
  1200. package/dist/core/arch.js.map +0 -1
  1201. package/dist/core/asyncapi.js +0 -253
  1202. package/dist/core/asyncapi.js.map +0 -1
  1203. package/dist/core/brief.js +0 -755
  1204. package/dist/core/brief.js.map +0 -1
  1205. package/dist/core/coherence.js +0 -577
  1206. package/dist/core/coherence.js.map +0 -1
  1207. package/dist/core/concurrency.js.map +0 -1
  1208. package/dist/core/config.js.map +0 -1
  1209. package/dist/core/delta.js +0 -476
  1210. package/dist/core/delta.js.map +0 -1
  1211. package/dist/core/dependencies.js +0 -356
  1212. package/dist/core/dependencies.js.map +0 -1
  1213. package/dist/core/doctor.js +0 -596
  1214. package/dist/core/doctor.js.map +0 -1
  1215. package/dist/core/document-bytes.js.map +0 -1
  1216. package/dist/core/explore.js +0 -225
  1217. package/dist/core/explore.js.map +0 -1
  1218. package/dist/core/frontmatter.js.map +0 -1
  1219. package/dist/core/gherkin.js +0 -463
  1220. package/dist/core/gherkin.js.map +0 -1
  1221. package/dist/core/health.js +0 -67
  1222. package/dist/core/health.js.map +0 -1
  1223. package/dist/core/ids.js +0 -122
  1224. package/dist/core/ids.js.map +0 -1
  1225. package/dist/core/issue.js +0 -9
  1226. package/dist/core/issue.js.map +0 -1
  1227. package/dist/core/json.js +0 -74
  1228. package/dist/core/json.js.map +0 -1
  1229. package/dist/core/likec4.js +0 -489
  1230. package/dist/core/likec4.js.map +0 -1
  1231. package/dist/core/maturity.js +0 -66
  1232. package/dist/core/maturity.js.map +0 -1
  1233. package/dist/core/openapi-merge.js +0 -552
  1234. package/dist/core/openapi-merge.js.map +0 -1
  1235. package/dist/core/openapi.js.map +0 -1
  1236. package/dist/core/openspec-inventory.js +0 -1440
  1237. package/dist/core/openspec-inventory.js.map +0 -1
  1238. package/dist/core/path-safety.js.map +0 -1
  1239. package/dist/core/provenance.js +0 -787
  1240. package/dist/core/provenance.js.map +0 -1
  1241. package/dist/core/records.js.map +0 -1
  1242. package/dist/core/repo.js +0 -438
  1243. package/dist/core/repo.js.map +0 -1
  1244. package/dist/core/report.js +0 -47
  1245. package/dist/core/report.js.map +0 -1
  1246. package/dist/core/spec.js +0 -505
  1247. package/dist/core/spec.js.map +0 -1
  1248. package/dist/core/staging.js +0 -890
  1249. package/dist/core/staging.js.map +0 -1
  1250. package/dist/core/status.js +0 -1132
  1251. package/dist/core/status.js.map +0 -1
  1252. package/dist/core/steps.js +0 -72
  1253. package/dist/core/steps.js.map +0 -1
  1254. package/dist/core/verify.js +0 -807
  1255. package/dist/core/verify.js.map +0 -1
  1256. package/dist/core/version.js.map +0 -1
@@ -0,0 +1,242 @@
1
+ /**
2
+ * The problem reports a repository has collected: how many there are, what
3
+ * state each one is in, and which ordinal the next one takes.
4
+ *
5
+ * A sub-package because `doctor/` is at its five-file limit, and a scan of its
6
+ * own because this is the one directory loam reads that loam never writes. The
7
+ * `loam-report` protocol has always asked a repository to accumulate a corpus
8
+ * under `loam-reports/` and then never looked at it — eleven reports landed in
9
+ * this repository in two days, three of them already closed, and every bit of
10
+ * that state lived outside the files, in whoever remembered. The directory is
11
+ * loam's own convention and its contents are loam's own format, so counting
12
+ * them is a fact loam can read as cheaply as it reads `agentFiles`. Reading is
13
+ * the whole of it: nothing here transmits anything, which is the constraint the
14
+ * protocol is built around.
15
+ *
16
+ * Everything below is best-effort on purpose. A report is a hand-written
17
+ * Markdown file, so an absent directory, an unreadable one, a name written
18
+ * before the numbering existed and a file with no `Status:` line are all
19
+ * ordinary states of a healthy repository. None of them is a finding, and
20
+ * `doctor`'s `healthy` does not move for anything in here — a repo with eleven
21
+ * open reports is not broken, it is one that has been paying attention.
22
+ */
23
+ import { readdir, readFile } from "node:fs/promises";
24
+ import { join } from "node:path";
25
+ import {} from "../report.js";
26
+ /**
27
+ * The conventional NAME of the directory the `loam-report` protocol asks a
28
+ * repository to accumulate, spelled once — the segment `scanReports` joins onto
29
+ * the resolved root to reach it.
30
+ *
31
+ * A name rather than a path, because two readers want different things out of
32
+ * it and both are right: `ProblemReports.dir` carries the joined ABSOLUTE
33
+ * location, because the protocol tells an agent to write there and a relative
34
+ * spelling leaves it guessing which repository "relative" meant (`../report.ts`
35
+ * records that), while `commands/doctor.ts`'s human row prints this constant, so
36
+ * a person standing in the repository reads `loam-reports/` — what the protocol,
37
+ * the reports themselves and every page that mentions them say.
38
+ */
39
+ export const REPORTS_DIR = "loam-reports";
40
+ /**
41
+ * The leading ordinal of `012-2026-09-03-slug.md`. Three digits or more, so the
42
+ * thousandth report widens the field instead of losing its number.
43
+ */
44
+ const ORDINAL = /^(\d{3,})-/;
45
+ /**
46
+ * A name written before the numbering existed: `2026-09-03-slug.md`, the shape
47
+ * eleven reports in this repository already carry.
48
+ *
49
+ * Checked FIRST, and this is the whole reason it exists as its own pattern: a
50
+ * four-digit year satisfies `ORDINAL` perfectly, so a legacy name read as an
51
+ * ordinal is report number 2026 — and the next report loam hands out is then
52
+ * 2027, in a directory whose highest real ordinal is 3. A legacy name is still
53
+ * a report; it just has no number, and contributes none.
54
+ */
55
+ const LEGACY_DATE_NAME = /^\d{4}-\d{2}-\d{2}-/;
56
+ /** The ordinal a report's file name claims, or null when the name predates numbering. */
57
+ function ordinalOf(file) {
58
+ if (LEGACY_DATE_NAME.test(file))
59
+ return null;
60
+ return ORDINAL.exec(file)?.[1] ?? null;
61
+ }
62
+ /**
63
+ * The template's `- Status:` line, matched in the header FIELD BLOCK alone (see
64
+ * `headerFields`). Only the first word is captured: the vocabulary's two
65
+ * composite values carry prose after it (`fixed in 0.2.0-alpha.5`,
66
+ * `superseded by 010`) that an author writes for a reader, and parsing further
67
+ * would make loam an authority on a sentence it does not own.
68
+ */
69
+ const STATUS_LINE = /^[ \t]*-[ \t]*Status:[ \t]*(\S+)/m;
70
+ /** A fenced block's delimiter line, either spelling. */
71
+ const FENCE = /^[ \t]*(`{3,}|~{3,})/;
72
+ /**
73
+ * An indented code block's line — the OTHER way markdown quotes code, and the
74
+ * way `loam instructions loam-report` prints its own template (the four-space
75
+ * block in ../../agent/support/report.ts). A fence-only reader counted such a
76
+ * report open off the template's `- Status: open`.
77
+ */
78
+ const INDENTED = /^(?: {4}|\t)/;
79
+ /** A section heading — the line that ends the header field block. */
80
+ const SECTION = /^##[ \t]/;
81
+ /**
82
+ * The report's header field block: every line above the first `## ` heading,
83
+ * with quoted code — fenced or indented — dropped.
84
+ *
85
+ * Matched anywhere in the file, `- Status:` convicted the wrong reports twice
86
+ * over. A report that QUOTES the protocol template — which several do, because
87
+ * an agent reporting that the protocol is wrong pastes the protocol — carries a
88
+ * `- Status: open` inside a fence and was counted open however its own header
89
+ * read; and a report whose body discusses a status line later on was read the
90
+ * same way. The status a report claims is a header FIELD, written beside
91
+ * `- Classification:` above the first section, so that is the only place it is
92
+ * read from. An unterminated fence swallows the rest of the file rather than
93
+ * flipping back — the safe direction, since the alternative is reading code as
94
+ * a field.
95
+ *
96
+ * Two shapes defeated the first version of that, and both are the same quoting
97
+ * case: a NESTED fence, where the outer ```` opens and the inner ``` was taken
98
+ * for its close, leaving the quoted block read as fields; and an INDENTED
99
+ * block, which the protocol itself uses and whose indented `## Summary` never
100
+ * ends the header either. So a fence is closed only by a run of the same
101
+ * character at least as long as the one that opened it, and an indented block
102
+ * (four spaces after a blank line, through the blank lines inside it) is
103
+ * dropped whole.
104
+ */
105
+ function headerFields(text) {
106
+ const kept = [];
107
+ let fence = null;
108
+ let indented = false;
109
+ let afterBlank = true;
110
+ for (const line of text.split(/\r?\n/)) {
111
+ if (fence !== null) {
112
+ const close = FENCE.exec(line)?.[1];
113
+ if (close !== undefined && close[0] === fence[0] && close.length >= fence.length)
114
+ fence = null;
115
+ continue;
116
+ }
117
+ const blank = line.trim() === "";
118
+ if (indented) {
119
+ if (blank || INDENTED.test(line))
120
+ continue;
121
+ indented = false;
122
+ }
123
+ const open = FENCE.exec(line)?.[1];
124
+ if (open !== undefined) {
125
+ fence = open;
126
+ afterBlank = false;
127
+ continue;
128
+ }
129
+ if (afterBlank && INDENTED.test(line)) {
130
+ indented = true;
131
+ continue;
132
+ }
133
+ if (SECTION.test(line))
134
+ break;
135
+ kept.push(line);
136
+ afterBlank = blank;
137
+ }
138
+ return kept.join("\n");
139
+ }
140
+ /** The words a `Status:` line may say that loam can count. */
141
+ const STATED = ["open", "sent", "fixed", "superseded"];
142
+ /**
143
+ * The ordinal the next report takes: one past the highest present, never one
144
+ * past the count.
145
+ *
146
+ * Those two differ exactly when the directory has a gap or a legacy name in it
147
+ * — which this directory does, since the numbering arrived after eleven
148
+ * reports had already been written — and counting instead of maximising is how
149
+ * a next ordinal starts handing out numbers that are already taken.
150
+ */
151
+ function nextOrdinal(entries) {
152
+ let highest = 0;
153
+ for (const entry of entries) {
154
+ if (entry.ordinal === null)
155
+ continue;
156
+ const value = Number.parseInt(entry.ordinal, 10);
157
+ if (value > highest)
158
+ highest = value;
159
+ }
160
+ return String(highest + 1).padStart(3, "0");
161
+ }
162
+ /**
163
+ * What one report's own `Status:` line says, or `unstated`.
164
+ *
165
+ * Unreadable reads as unstated rather than throwing: a report saved as UTF-16,
166
+ * a file the process cannot open, or a directory somebody named `notes.md` are
167
+ * all things a diagnostic must survive. `doctor` is the command that has to be
168
+ * able to describe a broken repository without becoming the next thing that
169
+ * breaks in it.
170
+ */
171
+ async function statusOf(path) {
172
+ let text;
173
+ try {
174
+ text = await readFile(path, "utf8");
175
+ }
176
+ catch {
177
+ // Unreadable is not a state the file claims — it is a state of the read.
178
+ return "unstated";
179
+ }
180
+ const word = STATUS_LINE.exec(headerFields(text))?.[1]?.toLowerCase();
181
+ return STATED.find((known) => known === word) ?? "unstated";
182
+ }
183
+ /**
184
+ * Read `<root>/loam-reports/`, where `root` is the directory holding the
185
+ * `loam.json` that resolved — the repository the reports were written at the
186
+ * root of — falling back, when nothing parsed, to the directory of the
187
+ * `loam.json` loam FOUND (`doctor.ts` says why that and not the cwd), and to the
188
+ * run directory only when there is no config file anywhere above it.
189
+ *
190
+ * Every `*.md` in the directory is an entry, including a hand-written index
191
+ * page: which files in there are "really" reports is a second naming
192
+ * convention, and inventing one would make loam disagree with a directory
193
+ * listing about what the directory holds. An unnumbered entry contributes
194
+ * nothing to `next`, so an index costs the corpus nothing either.
195
+ */
196
+ export async function scanReports(root) {
197
+ const dir = join(root, REPORTS_DIR);
198
+ let names;
199
+ try {
200
+ names = (await readdir(dir)).filter((name) => name.toLowerCase().endsWith(".md"));
201
+ }
202
+ catch (error) {
203
+ // Absent is the state of every repository that has never had to write a
204
+ // report, and it is the common one — `present: false`, nothing to say. Any
205
+ // other errno means the directory IS there and this process could not list
206
+ // it, which is a different sentence: the corpus exists and loam cannot see
207
+ // into it, so `present` stays true and the counts stay honestly empty.
208
+ const code = error.code;
209
+ const present = code !== "ENOENT" && code !== "ENOTDIR";
210
+ return { dir, present, total: 0, next: "001", entries: [] };
211
+ }
212
+ // Sorted here rather than left in readdir order, which is the filesystem's and
213
+ // differs between one machine and another — and sorted by the ORDINAL the name
214
+ // claims, numerically, because report order is what a reader scanning the list
215
+ // expects and byte order stops being it at exactly the point the widening rule
216
+ // was written for: `1000-…` sorts before `998-…`, so a directory that has
217
+ // passed its thousandth report reads 1000, 1001, 998, 999 (verification
218
+ // 2026-09-04, second pass). Unnumbered names — the shape reports carried before
219
+ // the numbering existed — contribute no ordinal, so they sort last among
220
+ // themselves by name, where a reader looking for "the next one" is not looking.
221
+ const rank = (file) => {
222
+ const ordinal = ordinalOf(file);
223
+ return ordinal === null ? Number.POSITIVE_INFINITY : Number.parseInt(ordinal, 10);
224
+ };
225
+ names.sort((a, b) => rank(a) - rank(b) || (a < b ? -1 : a > b ? 1 : 0));
226
+ // Read together, like `staleAgentFiles` does: a report corpus is a flat
227
+ // directory of small hand-written files, so there is nothing here worth a
228
+ // concurrency cap, and `Promise.all` preserves the order just established.
229
+ const entries = await Promise.all(names.map(async (file) => ({
230
+ file,
231
+ ordinal: ordinalOf(file),
232
+ status: await statusOf(join(dir, file)),
233
+ })));
234
+ return {
235
+ dir,
236
+ present: true,
237
+ total: entries.length,
238
+ next: nextOrdinal(entries),
239
+ entries,
240
+ };
241
+ }
242
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../../src/core/doctor/reports/scan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The problem reports a repository has collected: how many there are, what\n * state each one is in, and which ordinal the next one takes.\n *\n * A sub-package because `doctor/` is at its five-file limit, and a scan of its\n * own because this is the one directory loam reads that loam never writes. The\n * `loam-report` protocol has always asked a repository to accumulate a corpus\n * under `loam-reports/` and then never looked at it — eleven reports landed in\n * this repository in two days, three of them already closed, and every bit of\n * that state lived outside the files, in whoever remembered. The directory is\n * loam's own convention and its contents are loam's own format, so counting\n * them is a fact loam can read as cheaply as it reads `agentFiles`. Reading is\n * the whole of it: nothing here transmits anything, which is the constraint the\n * protocol is built around.\n *\n * Everything below is best-effort on purpose. A report is a hand-written\n * Markdown file, so an absent directory, an unreadable one, a name written\n * before the numbering existed and a file with no `Status:` line are all\n * ordinary states of a healthy repository. None of them is a finding, and\n * `doctor`'s `healthy` does not move for anything in here — a repo with eleven\n * open reports is not broken, it is one that has been paying attention.\n */\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n type ProblemReportEntry,\n type ProblemReports,\n type ProblemReportStatus,\n} from \"../report.js\";\n\n/**\n * The conventional NAME of the directory the `loam-report` protocol asks a\n * repository to accumulate, spelled once — the segment `scanReports` joins onto\n * the resolved root to reach it.\n *\n * A name rather than a path, because two readers want different things out of\n * it and both are right: `ProblemReports.dir` carries the joined ABSOLUTE\n * location, because the protocol tells an agent to write there and a relative\n * spelling leaves it guessing which repository \"relative\" meant (`../report.ts`\n * records that), while `commands/doctor.ts`'s human row prints this constant, so\n * a person standing in the repository reads `loam-reports/` — what the protocol,\n * the reports themselves and every page that mentions them say.\n */\nexport const REPORTS_DIR = \"loam-reports\";\n\n/**\n * The leading ordinal of `012-2026-09-03-slug.md`. Three digits or more, so the\n * thousandth report widens the field instead of losing its number.\n */\nconst ORDINAL = /^(\\d{3,})-/;\n\n/**\n * A name written before the numbering existed: `2026-09-03-slug.md`, the shape\n * eleven reports in this repository already carry.\n *\n * Checked FIRST, and this is the whole reason it exists as its own pattern: a\n * four-digit year satisfies `ORDINAL` perfectly, so a legacy name read as an\n * ordinal is report number 2026 — and the next report loam hands out is then\n * 2027, in a directory whose highest real ordinal is 3. A legacy name is still\n * a report; it just has no number, and contributes none.\n */\nconst LEGACY_DATE_NAME = /^\\d{4}-\\d{2}-\\d{2}-/;\n\n/** The ordinal a report's file name claims, or null when the name predates numbering. */\nfunction ordinalOf(file: string): string | null {\n if (LEGACY_DATE_NAME.test(file)) return null;\n return ORDINAL.exec(file)?.[1] ?? null;\n}\n\n/**\n * The template's `- Status:` line, matched in the header FIELD BLOCK alone (see\n * `headerFields`). Only the first word is captured: the vocabulary's two\n * composite values carry prose after it (`fixed in 0.2.0-alpha.5`,\n * `superseded by 010`) that an author writes for a reader, and parsing further\n * would make loam an authority on a sentence it does not own.\n */\nconst STATUS_LINE = /^[ \\t]*-[ \\t]*Status:[ \\t]*(\\S+)/m;\n\n/** A fenced block's delimiter line, either spelling. */\nconst FENCE = /^[ \\t]*(`{3,}|~{3,})/;\n\n/**\n * An indented code block's line — the OTHER way markdown quotes code, and the\n * way `loam instructions loam-report` prints its own template (the four-space\n * block in ../../agent/support/report.ts). A fence-only reader counted such a\n * report open off the template's `- Status: open`.\n */\nconst INDENTED = /^(?: {4}|\\t)/;\n\n/** A section heading — the line that ends the header field block. */\nconst SECTION = /^##[ \\t]/;\n\n/**\n * The report's header field block: every line above the first `## ` heading,\n * with quoted code — fenced or indented — dropped.\n *\n * Matched anywhere in the file, `- Status:` convicted the wrong reports twice\n * over. A report that QUOTES the protocol template — which several do, because\n * an agent reporting that the protocol is wrong pastes the protocol — carries a\n * `- Status: open` inside a fence and was counted open however its own header\n * read; and a report whose body discusses a status line later on was read the\n * same way. The status a report claims is a header FIELD, written beside\n * `- Classification:` above the first section, so that is the only place it is\n * read from. An unterminated fence swallows the rest of the file rather than\n * flipping back — the safe direction, since the alternative is reading code as\n * a field.\n *\n * Two shapes defeated the first version of that, and both are the same quoting\n * case: a NESTED fence, where the outer ```` opens and the inner ``` was taken\n * for its close, leaving the quoted block read as fields; and an INDENTED\n * block, which the protocol itself uses and whose indented `## Summary` never\n * ends the header either. So a fence is closed only by a run of the same\n * character at least as long as the one that opened it, and an indented block\n * (four spaces after a blank line, through the blank lines inside it) is\n * dropped whole.\n */\nfunction headerFields(text: string): string {\n const kept: string[] = [];\n let fence: string | null = null;\n let indented = false;\n let afterBlank = true;\n for (const line of text.split(/\\r?\\n/)) {\n if (fence !== null) {\n const close = FENCE.exec(line)?.[1];\n if (close !== undefined && close[0] === fence[0] && close.length >= fence.length) fence = null;\n continue;\n }\n const blank = line.trim() === \"\";\n if (indented) {\n if (blank || INDENTED.test(line)) continue;\n indented = false;\n }\n const open = FENCE.exec(line)?.[1];\n if (open !== undefined) {\n fence = open;\n afterBlank = false;\n continue;\n }\n if (afterBlank && INDENTED.test(line)) {\n indented = true;\n continue;\n }\n if (SECTION.test(line)) break;\n kept.push(line);\n afterBlank = blank;\n }\n return kept.join(\"\\n\");\n}\n\n/** The words a `Status:` line may say that loam can count. */\nconst STATED: readonly ProblemReportStatus[] = [\"open\", \"sent\", \"fixed\", \"superseded\"];\n\n/**\n * The ordinal the next report takes: one past the highest present, never one\n * past the count.\n *\n * Those two differ exactly when the directory has a gap or a legacy name in it\n * — which this directory does, since the numbering arrived after eleven\n * reports had already been written — and counting instead of maximising is how\n * a next ordinal starts handing out numbers that are already taken.\n */\nfunction nextOrdinal(entries: readonly ProblemReportEntry[]): string {\n let highest = 0;\n for (const entry of entries) {\n if (entry.ordinal === null) continue;\n const value = Number.parseInt(entry.ordinal, 10);\n if (value > highest) highest = value;\n }\n return String(highest + 1).padStart(3, \"0\");\n}\n\n/**\n * What one report's own `Status:` line says, or `unstated`.\n *\n * Unreadable reads as unstated rather than throwing: a report saved as UTF-16,\n * a file the process cannot open, or a directory somebody named `notes.md` are\n * all things a diagnostic must survive. `doctor` is the command that has to be\n * able to describe a broken repository without becoming the next thing that\n * breaks in it.\n */\nasync function statusOf(path: string): Promise<ProblemReportStatus> {\n let text: string;\n try {\n text = await readFile(path, \"utf8\");\n } catch {\n // Unreadable is not a state the file claims — it is a state of the read.\n return \"unstated\";\n }\n const word = STATUS_LINE.exec(headerFields(text))?.[1]?.toLowerCase();\n return STATED.find((known) => known === word) ?? \"unstated\";\n}\n\n/**\n * Read `<root>/loam-reports/`, where `root` is the directory holding the\n * `loam.json` that resolved — the repository the reports were written at the\n * root of — falling back, when nothing parsed, to the directory of the\n * `loam.json` loam FOUND (`doctor.ts` says why that and not the cwd), and to the\n * run directory only when there is no config file anywhere above it.\n *\n * Every `*.md` in the directory is an entry, including a hand-written index\n * page: which files in there are \"really\" reports is a second naming\n * convention, and inventing one would make loam disagree with a directory\n * listing about what the directory holds. An unnumbered entry contributes\n * nothing to `next`, so an index costs the corpus nothing either.\n */\nexport async function scanReports(root: string): Promise<ProblemReports> {\n const dir = join(root, REPORTS_DIR);\n let names: string[];\n try {\n names = (await readdir(dir)).filter((name) => name.toLowerCase().endsWith(\".md\"));\n } catch (error) {\n // Absent is the state of every repository that has never had to write a\n // report, and it is the common one — `present: false`, nothing to say. Any\n // other errno means the directory IS there and this process could not list\n // it, which is a different sentence: the corpus exists and loam cannot see\n // into it, so `present` stays true and the counts stay honestly empty.\n const code = (error as NodeJS.ErrnoException).code;\n const present = code !== \"ENOENT\" && code !== \"ENOTDIR\";\n return { dir, present, total: 0, next: \"001\", entries: [] };\n }\n\n // Sorted here rather than left in readdir order, which is the filesystem's and\n // differs between one machine and another — and sorted by the ORDINAL the name\n // claims, numerically, because report order is what a reader scanning the list\n // expects and byte order stops being it at exactly the point the widening rule\n // was written for: `1000-…` sorts before `998-…`, so a directory that has\n // passed its thousandth report reads 1000, 1001, 998, 999 (verification\n // 2026-09-04, second pass). Unnumbered names — the shape reports carried before\n // the numbering existed — contribute no ordinal, so they sort last among\n // themselves by name, where a reader looking for \"the next one\" is not looking.\n const rank = (file: string): number => {\n const ordinal = ordinalOf(file);\n return ordinal === null ? Number.POSITIVE_INFINITY : Number.parseInt(ordinal, 10);\n };\n names.sort((a, b) => rank(a) - rank(b) || (a < b ? -1 : a > b ? 1 : 0));\n // Read together, like `staleAgentFiles` does: a report corpus is a flat\n // directory of small hand-written files, so there is nothing here worth a\n // concurrency cap, and `Promise.all` preserves the order just established.\n const entries = await Promise.all(names.map(async (file): Promise<ProblemReportEntry> => ({\n file,\n ordinal: ordinalOf(file),\n status: await statusOf(join(dir, file)),\n })));\n\n return {\n dir,\n present: true,\n total: entries.length,\n next: nextOrdinal(entries),\n entries,\n };\n}\n"]}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * What an unfinished write means for the health of the repo.
3
+ *
4
+ * `core/staging/recovery/residue.ts` reports what is on disk; this decides how
5
+ * bad it is. A held lock and an interrupted commit are blockers because the docs
6
+ * are, or may be, half-merged: a SIGKILL between two of archive's renames once
7
+ * left `doctor: healthy: true` over a merged spec.md and an unmerged landscape,
8
+ * and the next `loam archive` reported loam's own half-merge as the author's
9
+ * bug. Temp files are the exception — a `.loam-*.tmp` was never linked into
10
+ * place, so nothing reads it. Litter, not damage.
11
+ */
12
+ import { join } from "node:path";
13
+ import {} from "../staging/recovery/residue.js";
14
+ import {} from "./report.js";
15
+ export function gradeWritePathResidue(docsDir, residue, findings) {
16
+ if (residue.lock !== null) {
17
+ const lockFile = join(docsDir, residue.lock.path);
18
+ // Three grades of one file. Held by a live process is a fact about right
19
+ // now — wait and re-run. Held by a dead process is damage: nothing will
20
+ // ever release it. And a lock that cannot NAME a holder — empty bytes from
21
+ // a crash between create and flush, or JSON nothing understands — is the
22
+ // same damage wearing a live lock's face: `breakStaleLock` rightly refuses
23
+ // to guess about it, so "wait" is advice that can never work, while every
24
+ // writer (archive, unarchive, rebase, verify --record) refuses `docs-busy`
25
+ // forever.
26
+ const unbreakable = residue.lock.stale || residue.lock.unreadable;
27
+ findings.push({
28
+ severity: unbreakable ? "blocker" : "warning",
29
+ code: "doctor.docs-locked",
30
+ message: residue.lock.unreadable
31
+ ? `${residue.lock.path} exists but cannot be read as a lock record — no process can be identified as its holder, so nothing is ever going to release it, and every writing command refuses with \`docs-busy\` while it is there.`
32
+ : residue.lock.stale
33
+ ? `${residue.lock.path} is held by ${residue.lock.holder}, a process that no longer exists on this host — every command that writes through this root will refuse with \`docs-busy\` until it is gone.`
34
+ : `${residue.lock.path} is held by ${residue.lock.holder}; another loam command is writing through this root.`,
35
+ fix: unbreakable
36
+ ? `Delete ${lockFile} — ${residue.lock.unreadable ? "it names no holder, so nothing is going to release it" : "its holder is dead, so nothing is going to release it"}. Check \`loam doctor\` again afterwards for an interrupted commit.`
37
+ : "Wait for it to finish and re-run; nothing is read or written while it is held.",
38
+ });
39
+ }
40
+ if (residue.intentUnreadable) {
41
+ findings.push({
42
+ severity: "blocker",
43
+ code: "doctor.commit-unreadable",
44
+ message: `${docsDir} holds a .loam-commit that cannot be read — a commit was interrupted and the one record of which files it had already written is unreadable.`,
45
+ fix: "Hand this to a human: compare this root's files against version control before running any loam command that writes here. Every journaled writer refuses with `commit-interrupted` while it is there.",
46
+ });
47
+ }
48
+ else if (residue.intent !== null && "rerun" in residue.intent) {
49
+ // Version 2 — the smaller journaled transaction (rebase, vouch, new,
50
+ // gherkin, and any writer after them). Its stored `rerun` IS the repair:
51
+ // that command recovers first, rolling the staged bytes forward. The
52
+ // string is journal data, so agent-commands-runnable cannot parse it here;
53
+ // test/staging-txn.test.ts parses every writer's rerun template against
54
+ // the real program instead.
55
+ const i = residue.intent;
56
+ // Both halves of the journal are named, because a version-3 record can be
57
+ // rename-only (`subsystem move` where the views bytes did not change): a
58
+ // blocker that said "0 file(s) may be half-written" and named nothing sent
59
+ // the operator hunting for files while the pending damage was directories.
60
+ const halves = [
61
+ ...(i.files.length > 0 ? [`${i.files.length} file(s) may be half-written: ${i.files.map((f) => f.path).join(", ")}`] : []),
62
+ ...(i.moves.length > 0
63
+ ? [`${i.moves.length} directory move(s) pending: ${i.moves.map((m) => `${m.from} -> ${m.to}`).join(", ")}`]
64
+ : []),
65
+ ];
66
+ findings.push({
67
+ severity: "blocker",
68
+ code: "doctor.commit-interrupted",
69
+ message: `A \`${i.rerun}\` was killed mid-commit (${i.host}, pid ${i.pid}, ${i.at}) — `
70
+ + (halves.length > 0 ? halves.join("; ") : "its journal records no pending file or directory"),
71
+ fix: `Re-run \`${i.rerun}\` — it recovers first, rolling the staged bytes forward, and refuses with \`commit-interrupted\` rather than guessing if a file has been edited since.`,
72
+ });
73
+ }
74
+ else if (residue.intent !== null) {
75
+ const i = residue.intent;
76
+ // The command is spelled out per branch rather than interpolated into one
77
+ // sentence: `loam ${i.command} ${i.feature}` reads fine to a person and is
78
+ // opaque to test/agent-commands-runnable.test.ts, which parses the commands
79
+ // loam prints against the real program. Same discipline as spelling `code:`
80
+ // literally — be visible to your own guard.
81
+ const repair = i.command === "archive"
82
+ ? `\`loam archive ${i.feature}\` — it recovers first, under the lock, putting the half-written files back from the snapshot`
83
+ : `\`loam unarchive ${i.feature}\` — it recovers first, under the lock, finishing the restore (an interrupted restore is FINISHED, never undone: the merged text it was replacing is written down nowhere)`;
84
+ findings.push({
85
+ severity: "blocker",
86
+ code: "doctor.commit-interrupted",
87
+ message: `A ${i.command === "archive" ? `\`loam archive ${i.feature}\`` : `\`loam unarchive ${i.feature}\``} `
88
+ + `was killed mid-commit (${i.host}, pid ${i.pid}, ${i.at}) — `
89
+ + `${i.files.length} file(s) may be half-written: ${i.files.map((f) => f.path).join(", ")}`,
90
+ fix: `Re-run ${repair}, and refuses with \`commit-interrupted\` rather than guessing if a file has been edited since.`,
91
+ });
92
+ }
93
+ // A version-2 journal's recorded temps are NOT litter: they are the only
94
+ // durable copy of the after-bytes its roll-forward recovery renames in.
95
+ // Advising their deletion beside a blocker that says "re-run to recover"
96
+ // converted a one-command repair into a manual VCS restore.
97
+ const journalTemps = new Set(residue.intent !== null && "rerun" in residue.intent
98
+ ? residue.intent.files.flatMap((f) => (f.tmp === null ? [] : [f.tmp]))
99
+ : []);
100
+ const litter = residue.temps.filter((t) => !journalTemps.has(t));
101
+ if (litter.length > 0) {
102
+ findings.push({
103
+ severity: "warning",
104
+ code: "doctor.staging-temps",
105
+ message: `${litter.length} orphaned staging file(s) under ${docsDir}: ${litter.join(", ")} — a killed writer's scratch, never linked into place.`,
106
+ fix: "The next journaled writer through this root removes its own; delete any that remain. Nothing reads them, so they cost disk and nothing else.",
107
+ });
108
+ }
109
+ }
110
+ //# sourceMappingURL=residue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"residue.js","sourceRoot":"","sources":["../../../src/core/doctor/residue.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What an unfinished write means for the health of the repo.\n *\n * `core/staging/recovery/residue.ts` reports what is on disk; this decides how\n * bad it is. A held lock and an interrupted commit are blockers because the docs\n * are, or may be, half-merged: a SIGKILL between two of archive's renames once\n * left `doctor: healthy: true` over a merged spec.md and an unmerged landscape,\n * and the next `loam archive` reported loam's own half-merge as the author's\n * bug. Temp files are the exception — a `.loam-*.tmp` was never linked into\n * place, so nothing reads it. Litter, not damage.\n */\nimport { join } from \"node:path\";\nimport { type WritePathResidue } from \"../staging/recovery/residue.js\";\nimport { type DoctorFinding } from \"./report.js\";\n\nexport function gradeWritePathResidue(\n docsDir: string,\n residue: WritePathResidue,\n findings: DoctorFinding[],\n): void {\n if (residue.lock !== null) {\n const lockFile = join(docsDir, residue.lock.path);\n // Three grades of one file. Held by a live process is a fact about right\n // now — wait and re-run. Held by a dead process is damage: nothing will\n // ever release it. And a lock that cannot NAME a holder — empty bytes from\n // a crash between create and flush, or JSON nothing understands — is the\n // same damage wearing a live lock's face: `breakStaleLock` rightly refuses\n // to guess about it, so \"wait\" is advice that can never work, while every\n // writer (archive, unarchive, rebase, verify --record) refuses `docs-busy`\n // forever.\n const unbreakable = residue.lock.stale || residue.lock.unreadable;\n findings.push({\n severity: unbreakable ? \"blocker\" : \"warning\",\n code: \"doctor.docs-locked\",\n message: residue.lock.unreadable\n ? `${residue.lock.path} exists but cannot be read as a lock record — no process can be identified as its holder, so nothing is ever going to release it, and every writing command refuses with \\`docs-busy\\` while it is there.`\n : residue.lock.stale\n ? `${residue.lock.path} is held by ${residue.lock.holder}, a process that no longer exists on this host — every command that writes through this root will refuse with \\`docs-busy\\` until it is gone.`\n : `${residue.lock.path} is held by ${residue.lock.holder}; another loam command is writing through this root.`,\n fix: unbreakable\n ? `Delete ${lockFile} — ${residue.lock.unreadable ? \"it names no holder, so nothing is going to release it\" : \"its holder is dead, so nothing is going to release it\"}. Check \\`loam doctor\\` again afterwards for an interrupted commit.`\n : \"Wait for it to finish and re-run; nothing is read or written while it is held.\",\n });\n }\n\n if (residue.intentUnreadable) {\n findings.push({\n severity: \"blocker\",\n code: \"doctor.commit-unreadable\",\n message: `${docsDir} holds a .loam-commit that cannot be read — a commit was interrupted and the one record of which files it had already written is unreadable.`,\n fix: \"Hand this to a human: compare this root's files against version control before running any loam command that writes here. Every journaled writer refuses with `commit-interrupted` while it is there.\",\n });\n } else if (residue.intent !== null && \"rerun\" in residue.intent) {\n // Version 2 — the smaller journaled transaction (rebase, vouch, new,\n // gherkin, and any writer after them). Its stored `rerun` IS the repair:\n // that command recovers first, rolling the staged bytes forward. The\n // string is journal data, so agent-commands-runnable cannot parse it here;\n // test/staging-txn.test.ts parses every writer's rerun template against\n // the real program instead.\n const i = residue.intent;\n // Both halves of the journal are named, because a version-3 record can be\n // rename-only (`subsystem move` where the views bytes did not change): a\n // blocker that said \"0 file(s) may be half-written\" and named nothing sent\n // the operator hunting for files while the pending damage was directories.\n const halves = [\n ...(i.files.length > 0 ? [`${i.files.length} file(s) may be half-written: ${i.files.map((f) => f.path).join(\", \")}`] : []),\n ...(i.moves.length > 0\n ? [`${i.moves.length} directory move(s) pending: ${i.moves.map((m) => `${m.from} -> ${m.to}`).join(\", \")}`]\n : []),\n ];\n findings.push({\n severity: \"blocker\",\n code: \"doctor.commit-interrupted\",\n message:\n `A \\`${i.rerun}\\` was killed mid-commit (${i.host}, pid ${i.pid}, ${i.at}) — `\n + (halves.length > 0 ? halves.join(\"; \") : \"its journal records no pending file or directory\"),\n fix: `Re-run \\`${i.rerun}\\` — it recovers first, rolling the staged bytes forward, and refuses with \\`commit-interrupted\\` rather than guessing if a file has been edited since.`,\n });\n } else if (residue.intent !== null) {\n const i = residue.intent;\n // The command is spelled out per branch rather than interpolated into one\n // sentence: `loam ${i.command} ${i.feature}` reads fine to a person and is\n // opaque to test/agent-commands-runnable.test.ts, which parses the commands\n // loam prints against the real program. Same discipline as spelling `code:`\n // literally — be visible to your own guard.\n const repair = i.command === \"archive\"\n ? `\\`loam archive ${i.feature}\\` — it recovers first, under the lock, putting the half-written files back from the snapshot`\n : `\\`loam unarchive ${i.feature}\\` — it recovers first, under the lock, finishing the restore (an interrupted restore is FINISHED, never undone: the merged text it was replacing is written down nowhere)`;\n findings.push({\n severity: \"blocker\",\n code: \"doctor.commit-interrupted\",\n message:\n `A ${i.command === \"archive\" ? `\\`loam archive ${i.feature}\\`` : `\\`loam unarchive ${i.feature}\\``} `\n + `was killed mid-commit (${i.host}, pid ${i.pid}, ${i.at}) — `\n + `${i.files.length} file(s) may be half-written: ${i.files.map((f) => f.path).join(\", \")}`,\n fix: `Re-run ${repair}, and refuses with \\`commit-interrupted\\` rather than guessing if a file has been edited since.`,\n });\n }\n\n // A version-2 journal's recorded temps are NOT litter: they are the only\n // durable copy of the after-bytes its roll-forward recovery renames in.\n // Advising their deletion beside a blocker that says \"re-run to recover\"\n // converted a one-command repair into a manual VCS restore.\n const journalTemps = new Set(\n residue.intent !== null && \"rerun\" in residue.intent\n ? residue.intent.files.flatMap((f) => (f.tmp === null ? [] : [f.tmp]))\n : [],\n );\n const litter = residue.temps.filter((t) => !journalTemps.has(t));\n if (litter.length > 0) {\n findings.push({\n severity: \"warning\",\n code: \"doctor.staging-temps\",\n message: `${litter.length} orphaned staging file(s) under ${docsDir}: ${litter.join(\", \")} — a killed writer's scratch, never linked into place.`,\n fix: \"The next journaled writer through this root removes its own; delete any that remain. Nothing reads them, so they cost disk and nothing else.\",\n });\n }\n}\n"]}
@@ -0,0 +1,224 @@
1
+ /**
2
+ * A feature's ADDED/MODIFIED/REMOVED requirements folded onto a living set.
3
+ *
4
+ * The one thing `loam archive` does to a spec, and a module of its own because
5
+ * it is where a requirement stops being a delta: `asLiving` drops the
6
+ * `Based-On:` pin, which is a claim about which living version this was written
7
+ * against — meaningless once it IS the living version, and poison for the next
8
+ * feature's baseline, which would otherwise hash the previous feature's pin.
9
+ *
10
+ * It is also where the merge says what it TAKES AWAY (`replacementsOf`,
11
+ * `droppedParts`), because only the algebra knows which living requirement a
12
+ * delta requirement selects: a MODIFIED carries its full new text and replaces
13
+ * the living requirement whole, so every scenario and every join line it does
14
+ * not restate is gone after the archive — and a second reading of "which one
15
+ * does this select" anywhere else would be a second answer free to disagree.
16
+ */
17
+ import { requirementIdProblems, splitRealizesPin, withoutBaseline } from "./spec.js";
18
+ /**
19
+ * A delta requirement as it lands in the living document, with the bookkeeping
20
+ * that belongs to the DELTA left behind: the `Based-On:` pin (a claim about
21
+ * which living version this was written against — meaningless once it IS the
22
+ * living version, and poison for the next feature's baseline, which would then
23
+ * hash the previous feature's pin) and the line it was parsed from.
24
+ */
25
+ function asLiving(d) {
26
+ const { line: _dropped, ...rest } = withoutBaseline(d);
27
+ return { ...rest, kind: "BASE" };
28
+ }
29
+ /**
30
+ * Apply a feature's ADDED/MODIFIED/REMOVED requirements onto a living requirement set.
31
+ *
32
+ * A living requirement the delta does not touch comes back as the SAME object
33
+ * it went in as (a living spec's requirements are already BASE), and that
34
+ * identity is load-bearing: archive keys each requirement's raw bytes on it, so
35
+ * an untouched requirement is written back exactly as its author wrote it and
36
+ * only the ones this function replaced or added are serialized.
37
+ */
38
+ export function applyRequirementDelta(living, delta) {
39
+ return foldDelta(living, delta).merged;
40
+ }
41
+ /**
42
+ * Every living requirement the delta replaces or removes, in delta order — the
43
+ * walk `applyRequirementDelta` takes, so the two cannot disagree about which
44
+ * requirement a MODIFIED selected. Throws exactly when the merge would.
45
+ */
46
+ export function replacementsOf(living, delta) {
47
+ return foldDelta(living, delta).replaced;
48
+ }
49
+ function foldDelta(living, delta) {
50
+ const malformed = [...requirementIdProblems(living), ...requirementIdProblems(delta)];
51
+ if (malformed.length > 0) {
52
+ throw new Error("cannot merge requirements with invalid, repeated, or duplicate Requirement-ID declarations");
53
+ }
54
+ let result = living.map((r) => (r.kind === "BASE" ? r : { ...r, kind: "BASE" }));
55
+ const replaced = [];
56
+ // What each requirement the fold has PRODUCED stands for: the replacement
57
+ // record it belongs to, or null for one this delta added. A delta may select
58
+ // one requirement twice (nothing refuses a repeated heading in a delta), and
59
+ // without this the second step reported the first step's text as "living" —
60
+ // a drop the merge never makes. With it every record stays pre-merge to
61
+ // post-merge, so what `droppedParts` reads is the net change.
62
+ const born = new Map();
63
+ const record = (kind, previous, merged) => {
64
+ const earlier = born.get(previous);
65
+ if (earlier === undefined) {
66
+ const entry = { kind, living: previous, merged };
67
+ replaced.push(entry);
68
+ if (merged !== null)
69
+ born.set(merged, entry);
70
+ }
71
+ else if (earlier === null) {
72
+ // Added by this delta, so nothing living is replaced by rewriting it.
73
+ if (merged !== null)
74
+ born.set(merged, null);
75
+ }
76
+ else {
77
+ earlier.merged = merged;
78
+ if (merged === null)
79
+ earlier.kind = "REMOVED";
80
+ else
81
+ born.set(merged, earlier);
82
+ }
83
+ };
84
+ const add = (merged) => {
85
+ born.set(merged, null);
86
+ result.push(merged);
87
+ };
88
+ for (const d of delta) {
89
+ // BASE is not a delta kind — a requirement outside an ADDED/MODIFIED/REMOVED
90
+ // section (e.g. quoted under ## Notes) is documentation, not a change.
91
+ if (d.kind === "BASE")
92
+ continue;
93
+ const kind = d.kind;
94
+ if (d.id !== undefined) {
95
+ const idMatches = result
96
+ .map((r, i) => (r.id === d.id ? i : -1))
97
+ .filter((i) => i >= 0);
98
+ const nameMatches = result
99
+ .map((r, i) => (r.name === d.name ? i : -1))
100
+ .filter((i) => i >= 0);
101
+ const otherNameMatches = nameMatches.filter((i) => !idMatches.includes(i));
102
+ if (idMatches.length > 1 || otherNameMatches.length > 0) {
103
+ throw new Error(`ambiguous requirement identity for '${d.name}' (${d.id}): Requirement-ID and heading select different living requirements`);
104
+ }
105
+ if (d.kind === "REMOVED") {
106
+ const selected = new Set(idMatches);
107
+ for (const i of idMatches)
108
+ record(kind, result[i], null);
109
+ result = result.filter((_, i) => !selected.has(i));
110
+ }
111
+ else {
112
+ const merged = asLiving(d);
113
+ const at = idMatches[0];
114
+ if (at === undefined)
115
+ add(merged);
116
+ else {
117
+ record(kind, result[at], merged);
118
+ result[at] = merged;
119
+ }
120
+ }
121
+ }
122
+ else if (d.kind === "REMOVED") {
123
+ for (const r of result)
124
+ if (r.name === d.name)
125
+ record(kind, r, null);
126
+ result = result.filter((r) => r.name !== d.name);
127
+ }
128
+ else {
129
+ const i = result.findIndex((r) => r.name === d.name);
130
+ // A legacy delta may still modify an ID-bearing living requirement by
131
+ // its exact heading. Keep the identity while the repository migrates.
132
+ const inheritedId = i >= 0 ? result[i].id : undefined;
133
+ const merged = {
134
+ ...asLiving(d),
135
+ ...(inheritedId === undefined ? {} : { id: inheritedId }),
136
+ };
137
+ if (i < 0)
138
+ add(merged);
139
+ else {
140
+ record(kind, result[i], merged);
141
+ result[i] = merged;
142
+ }
143
+ }
144
+ }
145
+ return { merged: result, replaced };
146
+ }
147
+ /**
148
+ * The join lines a requirement carries, keyed by `Requirement` field and
149
+ * spelled as the body line writes them — every list the parser reads out of a
150
+ * requirement's text, in one order, so the archive plan, `loam delta` and their
151
+ * `--json` rows name a dropped entry the same way.
152
+ */
153
+ export const DIRECTIVE_LINES = {
154
+ operations: "Operations",
155
+ covers: "Covers",
156
+ requires: "Requires",
157
+ capabilities: "Capability",
158
+ realizes: "Realizes",
159
+ publishes: "Publishes",
160
+ consumes: "Consumes",
161
+ };
162
+ /**
163
+ * What a replacement drops: the living scenarios its new text does not carry,
164
+ * by name, and each join-line entry it does not restate, verbatim.
165
+ *
166
+ * VERBATIM AND BY NAME, and that is a reading, not a judgement — with one
167
+ * exception for bookkeeping: a `Realizes:` entry is compared, and reported, by
168
+ * the target it names, its `@<digest>` pin set aside. A scenario
169
+ * renamed is reported dropped, and a `Covers:` entry respelled from an element
170
+ * id to the service name is reported dropped too, though either may mean the
171
+ * same thing — this lists what the living text says that the merged text does
172
+ * not, and the author decides. What it must never be again is the old answer,
173
+ * which was nothing: a MODIFIED that restated one of two scenarios merged, and
174
+ * the second vanished under the archive's exit 0.
175
+ */
176
+ export function droppedParts(replacement) {
177
+ const { living, merged } = replacement;
178
+ const keptScenarios = new Set((merged?.scenarios ?? []).map((s) => s.name));
179
+ const directives = {};
180
+ for (const key of Object.keys(DIRECTIVE_LINES)) {
181
+ // A `Realizes:` entry is compared by the target it names: the `@<digest>`
182
+ // pin `loam rebase --living` writes is bookkeeping, and a replacement that
183
+ // restates the target unpinned has kept the join, not dropped it.
184
+ const spell = key === "realizes" ? (entry) => splitRealizesPin(entry).target : (entry) => entry;
185
+ const kept = new Set((merged?.[key] ?? []).map(spell));
186
+ const gone = [...new Set(living[key].map(spell))].filter((entry) => !kept.has(entry));
187
+ if (gone.length > 0)
188
+ directives[key] = gone;
189
+ }
190
+ return { scenarios: living.scenarios.map((s) => s.name).filter((name) => !keptScenarios.has(name)), directives };
191
+ }
192
+ /** Does this replacement take anything away at all? */
193
+ export function dropsAnything(parts) {
194
+ return parts.scenarios.length > 0 || Object.keys(parts.directives).length > 0;
195
+ }
196
+ /**
197
+ * Every replacement that takes something away: a removal always (the
198
+ * requirement itself is what goes), a MODIFIED or a landing ADDED whenever its
199
+ * new text restates less than the living one held.
200
+ */
201
+ export function droppedBy(living, delta) {
202
+ return replacementsOf(living, delta).flatMap((replacement) => {
203
+ const parts = droppedParts(replacement);
204
+ if (replacement.kind !== "REMOVED" && !dropsAnything(parts))
205
+ return [];
206
+ const { name, id } = replacement.living;
207
+ return [{ kind: replacement.kind, requirement: name, ...(id === undefined ? {} : { id }), ...parts }];
208
+ });
209
+ }
210
+ /** One dropped row in words — the line the archive plan and `loam delta` both print. */
211
+ export function droppedSentence(row) {
212
+ const who = row.id === undefined ? `'${row.requirement}'` : `${row.id} '${row.requirement}'`;
213
+ const lost = [
214
+ ...(row.scenarios.length === 0 ? [] : [`scenario ${row.scenarios.map((s) => `'${s}'`).join(", ")}`]),
215
+ ...Object.keys(DIRECTIVE_LINES).flatMap((key) => {
216
+ const gone = row.directives[key];
217
+ return gone === undefined ? [] : [`${DIRECTIVE_LINES[key]}: ${gone.join(", ")}`];
218
+ }),
219
+ ];
220
+ if (row.kind === "REMOVED")
221
+ return lost.length === 0 ? `${who} is removed` : `${who} is removed, and with it ${lost.join("; ")}`;
222
+ return `${who} is replaced whole, and its new text does not carry ${lost.join("; ")}`;
223
+ }
224
+ //# sourceMappingURL=apply.js.map