@ybotok/loam 0.2.0-alpha.1 → 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 (901) hide show
  1. package/CHANGELOG.md +3448 -0
  2. package/COMPARISON.md +91 -3
  3. package/CONTRIBUTING.md +37 -0
  4. package/MIGRATING-from-OpenSpec.md +47 -23
  5. package/QUICKSTART.md +189 -12
  6. package/README.md +274 -65
  7. package/ROADMAP.md +572 -31
  8. package/SCHEMA.md +1709 -155
  9. package/WORKFLOW.md +298 -72
  10. package/dist/cli.js +26 -8
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/adopt/adopt.js +5 -10
  13. package/dist/commands/adopt/adopt.js.map +1 -1
  14. package/dist/commands/adopt/render.js +50 -9
  15. package/dist/commands/adopt/render.js.map +1 -1
  16. package/dist/commands/archive/archive.js +16 -19
  17. package/dist/commands/archive/archive.js.map +1 -1
  18. package/dist/commands/archive/closing.js +42 -0
  19. package/dist/commands/archive/closing.js.map +1 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js +36 -42
  21. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
  22. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  24. package/dist/commands/archive/plan/contracts/openapi.js +77 -43
  25. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
  26. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  28. package/dist/commands/archive/plan/document/head.js +151 -0
  29. package/dist/commands/archive/plan/document/head.js.map +1 -0
  30. package/dist/commands/archive/plan/document/links.js +284 -0
  31. package/dist/commands/archive/plan/document/links.js.map +1 -0
  32. package/dist/commands/archive/plan/document/run.js +136 -0
  33. package/dist/commands/archive/plan/document/run.js.map +1 -0
  34. package/dist/commands/archive/plan/gate.js +21 -19
  35. package/dist/commands/archive/plan/gate.js.map +1 -1
  36. package/dist/commands/archive/plan/landscape.js +167 -30
  37. package/dist/commands/archive/plan/landscape.js.map +1 -1
  38. package/dist/commands/archive/plan/model/extending.js +85 -0
  39. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  40. package/dist/commands/archive/plan/refusal.js +14 -19
  41. package/dist/commands/archive/plan/refusal.js.map +1 -1
  42. package/dist/commands/archive/plan/specs.js +137 -56
  43. package/dist/commands/archive/plan/specs.js.map +1 -1
  44. package/dist/commands/archive/plan/state.js +3 -0
  45. package/dist/commands/archive/plan/state.js.map +1 -1
  46. package/dist/commands/archive/run.js +134 -30
  47. package/dist/commands/archive/run.js.map +1 -1
  48. package/dist/commands/archive/shipped.js +49 -0
  49. package/dist/commands/archive/shipped.js.map +1 -0
  50. package/dist/commands/context/context.js +85 -18
  51. package/dist/commands/context/context.js.map +1 -1
  52. package/dist/commands/context/print.js +29 -7
  53. package/dist/commands/context/print.js.map +1 -1
  54. package/dist/commands/delta/delta.js +102 -14
  55. package/dist/commands/delta/delta.js.map +1 -1
  56. package/dist/commands/delta/print.js +17 -1
  57. package/dist/commands/delta/print.js.map +1 -1
  58. package/dist/commands/dependencies.js +3 -7
  59. package/dist/commands/dependencies.js.map +1 -1
  60. package/dist/commands/diff/diff.js +20 -27
  61. package/dist/commands/diff/diff.js.map +1 -1
  62. package/dist/commands/doctor.js +60 -1
  63. package/dist/commands/doctor.js.map +1 -1
  64. package/dist/commands/explain/explain.js +89 -13
  65. package/dist/commands/explain/explain.js.map +1 -1
  66. package/dist/commands/explore.js +16 -10
  67. package/dist/commands/explore.js.map +1 -1
  68. package/dist/commands/gate/gate.js +45 -8
  69. package/dist/commands/gate/gate.js.map +1 -1
  70. package/dist/commands/gate/print.js +15 -3
  71. package/dist/commands/gate/print.js.map +1 -1
  72. package/dist/commands/gherkin/commit.js +13 -54
  73. package/dist/commands/gherkin/commit.js.map +1 -1
  74. package/dist/commands/gherkin/gherkin.js +36 -20
  75. package/dist/commands/gherkin/gherkin.js.map +1 -1
  76. package/dist/commands/gherkin/reconcile.js +10 -13
  77. package/dist/commands/gherkin/reconcile.js.map +1 -1
  78. package/dist/commands/init/first-hour.js +44 -0
  79. package/dist/commands/init/first-hour.js.map +1 -1
  80. package/dist/commands/init/init.js +18 -22
  81. package/dist/commands/init/init.js.map +1 -1
  82. package/dist/commands/list/campaign/campaign.js +4 -6
  83. package/dist/commands/list/campaign/campaign.js.map +1 -1
  84. package/dist/commands/list/json.js +5 -7
  85. package/dist/commands/list/json.js.map +1 -1
  86. package/dist/commands/list/list.js +44 -29
  87. package/dist/commands/list/list.js.map +1 -1
  88. package/dist/commands/list/print.js +52 -9
  89. package/dist/commands/list/print.js.map +1 -1
  90. package/dist/commands/list/suites/suites.js +140 -0
  91. package/dist/commands/list/suites/suites.js.map +1 -0
  92. package/dist/commands/list/views.js +37 -34
  93. package/dist/commands/list/views.js.map +1 -1
  94. package/dist/commands/mcp/dispatch.js +91 -36
  95. package/dist/commands/mcp/dispatch.js.map +1 -1
  96. package/dist/commands/mcp/mcp.js +56 -15
  97. package/dist/commands/mcp/mcp.js.map +1 -1
  98. package/dist/commands/mcp/serve.js.map +1 -1
  99. package/dist/commands/migrate-openspec/materialize/active.js +27 -22
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
  101. package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
  102. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
  103. package/dist/commands/migrate-openspec/materialize/target.js +2 -2
  104. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
  105. package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
  106. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
  107. package/dist/commands/migrate-openspec/openspec/error.js +7 -8
  108. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
  109. package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
  110. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
  111. package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
  112. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
  113. package/dist/commands/new/capability-template.js +118 -0
  114. package/dist/commands/new/capability-template.js.map +1 -0
  115. package/dist/commands/new/commit.js +8 -22
  116. package/dist/commands/new/commit.js.map +1 -1
  117. package/dist/commands/new/modifies.js +206 -0
  118. package/dist/commands/new/modifies.js.map +1 -0
  119. package/dist/commands/new/new.js +59 -14
  120. package/dist/commands/new/new.js.map +1 -1
  121. package/dist/commands/new/templates.js +48 -124
  122. package/dist/commands/new/templates.js.map +1 -1
  123. package/dist/commands/open.js +3 -7
  124. package/dist/commands/open.js.map +1 -1
  125. package/dist/commands/policy/gate.js +27 -0
  126. package/dist/commands/policy/gate.js.map +1 -1
  127. package/dist/commands/rebase/plan.js +2 -2
  128. package/dist/commands/rebase/plan.js.map +1 -1
  129. package/dist/commands/rebase/rebase.js +60 -35
  130. package/dist/commands/rebase/rebase.js.map +1 -1
  131. package/dist/commands/seed/commit.js +55 -26
  132. package/dist/commands/seed/commit.js.map +1 -1
  133. package/dist/commands/seed/plan.js +158 -13
  134. package/dist/commands/seed/plan.js.map +1 -1
  135. package/dist/commands/seed/seed.js +13 -11
  136. package/dist/commands/seed/seed.js.map +1 -1
  137. package/dist/commands/show/feature.js +9 -5
  138. package/dist/commands/show/feature.js.map +1 -1
  139. package/dist/commands/show/introduced.js +157 -0
  140. package/dist/commands/show/introduced.js.map +1 -0
  141. package/dist/commands/show/marks.js +35 -6
  142. package/dist/commands/show/marks.js.map +1 -1
  143. package/dist/commands/show/service.js +41 -33
  144. package/dist/commands/show/service.js.map +1 -1
  145. package/dist/commands/show/show.js +17 -7
  146. package/dist/commands/show/show.js.map +1 -1
  147. package/dist/commands/status/fleet-next.js +90 -0
  148. package/dist/commands/status/fleet-next.js.map +1 -0
  149. package/dist/commands/status/json.js +2 -0
  150. package/dist/commands/status/json.js.map +1 -1
  151. package/dist/commands/status/print.js +89 -37
  152. package/dist/commands/status/print.js.map +1 -1
  153. package/dist/commands/status/status.js +3 -7
  154. package/dist/commands/status/status.js.map +1 -1
  155. package/dist/commands/steps/steps.js +103 -23
  156. package/dist/commands/steps/steps.js.map +1 -1
  157. package/dist/commands/subsystem/edit.js +7 -7
  158. package/dist/commands/subsystem/edit.js.map +1 -1
  159. package/dist/commands/subsystem/move.js +106 -46
  160. package/dist/commands/subsystem/move.js.map +1 -1
  161. package/dist/commands/subsystem/query.js +2 -4
  162. package/dist/commands/subsystem/query.js.map +1 -1
  163. package/dist/commands/subsystem/subsystem.js +4 -7
  164. package/dist/commands/subsystem/subsystem.js.map +1 -1
  165. package/dist/commands/subsystem/sync.js +289 -74
  166. package/dist/commands/subsystem/sync.js.map +1 -1
  167. package/dist/commands/subsystem/txn/exclude.js +132 -0
  168. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  169. package/dist/commands/subsystem/txn/links.js +128 -0
  170. package/dist/commands/subsystem/txn/links.js.map +1 -0
  171. package/dist/commands/subsystem/txn/report.js +174 -0
  172. package/dist/commands/subsystem/txn/report.js.map +1 -0
  173. package/dist/commands/subsystem/txn/txn.js +147 -45
  174. package/dist/commands/subsystem/txn/txn.js.map +1 -1
  175. package/dist/commands/subsystem/txn/views.js +200 -21
  176. package/dist/commands/subsystem/txn/views.js.map +1 -1
  177. package/dist/commands/tasks/actions.js +107 -0
  178. package/dist/commands/tasks/actions.js.map +1 -0
  179. package/dist/commands/tasks/render.js +253 -0
  180. package/dist/commands/tasks/render.js.map +1 -0
  181. package/dist/commands/tasks/tasks.js +119 -0
  182. package/dist/commands/tasks/tasks.js.map +1 -0
  183. package/dist/commands/unarchive/manifest.js +42 -26
  184. package/dist/commands/unarchive/manifest.js.map +1 -1
  185. package/dist/commands/unarchive/restore.js +83 -33
  186. package/dist/commands/unarchive/restore.js.map +1 -1
  187. package/dist/commands/unarchive/unarchive.js +22 -30
  188. package/dist/commands/unarchive/unarchive.js.map +1 -1
  189. package/dist/commands/validate/arch-coverage.js +78 -27
  190. package/dist/commands/validate/arch-coverage.js.map +1 -1
  191. package/dist/commands/validate/checks/fleet-shape.js +34 -126
  192. package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
  193. package/dist/commands/validate/checks/health-deps.js +9 -6
  194. package/dist/commands/validate/checks/health-deps.js.map +1 -1
  195. package/dist/commands/validate/checks/introduced.js +102 -0
  196. package/dist/commands/validate/checks/introduced.js.map +1 -0
  197. package/dist/commands/validate/checks/requirements.js +18 -8
  198. package/dist/commands/validate/checks/requirements.js.map +1 -1
  199. package/dist/commands/validate/checks/sources.js +11 -2
  200. package/dist/commands/validate/checks/sources.js.map +1 -1
  201. package/dist/commands/validate/coverage/covers-after.js +105 -0
  202. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  203. package/dist/commands/validate/feature.js +26 -20
  204. package/dist/commands/validate/feature.js.map +1 -1
  205. package/dist/commands/validate/fleet/census.js +37 -13
  206. package/dist/commands/validate/fleet/census.js.map +1 -1
  207. package/dist/commands/validate/fleet/landscape.js +144 -126
  208. package/dist/commands/validate/fleet/landscape.js.map +1 -1
  209. package/dist/commands/validate/fleet/load.js +66 -0
  210. package/dist/commands/validate/fleet/load.js.map +1 -1
  211. package/dist/commands/validate/fleet/map/attest.js +98 -0
  212. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  213. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  214. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  215. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  216. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  217. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  218. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  219. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  220. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  221. package/dist/commands/validate/fleet/obligations.js +44 -14
  222. package/dist/commands/validate/fleet/obligations.js.map +1 -1
  223. package/dist/commands/validate/fleet/scorecard/print.js +10 -2
  224. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
  225. package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
  226. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
  227. package/dist/commands/validate/fleet/usecases/place.js.map +1 -1
  228. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  229. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  230. package/dist/commands/validate/fleet/views/ids.js +50 -15
  231. package/dist/commands/validate/fleet/views/ids.js.map +1 -1
  232. package/dist/commands/validate/fleet/views/projects.js +278 -0
  233. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  234. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  235. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  236. package/dist/commands/validate/fleet/views/stale.js +40 -47
  237. package/dist/commands/validate/fleet/views/stale.js.map +1 -1
  238. package/dist/commands/validate/links/corpus.js +1 -4
  239. package/dist/commands/validate/links/corpus.js.map +1 -1
  240. package/dist/commands/validate/links/glossary.js.map +1 -1
  241. package/dist/commands/validate/render/repeats.js +63 -0
  242. package/dist/commands/validate/render/repeats.js.map +1 -0
  243. package/dist/commands/validate/render/rollups.js +115 -0
  244. package/dist/commands/validate/render/rollups.js.map +1 -0
  245. package/dist/commands/validate/render/text.js +199 -0
  246. package/dist/commands/validate/render/text.js.map +1 -0
  247. package/dist/commands/validate/report.js +36 -160
  248. package/dist/commands/validate/report.js.map +1 -1
  249. package/dist/commands/validate/scope.js +113 -0
  250. package/dist/commands/validate/scope.js.map +1 -0
  251. package/dist/commands/validate/service/api.js +21 -107
  252. package/dist/commands/validate/service/api.js.map +1 -1
  253. package/dist/commands/validate/service/contracts/generated.js +134 -0
  254. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  255. package/dist/commands/validate/service/events/events.js +36 -14
  256. package/dist/commands/validate/service/events/events.js.map +1 -1
  257. package/dist/commands/validate/service/events/message-producers.js +1 -1
  258. package/dist/commands/validate/service/events/message-producers.js.map +1 -1
  259. package/dist/commands/validate/service/evidence-pins.js +56 -10
  260. package/dist/commands/validate/service/evidence-pins.js.map +1 -1
  261. package/dist/commands/validate/service/model/diverged.js +226 -0
  262. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  263. package/dist/commands/validate/service/model/grade.js +163 -0
  264. package/dist/commands/validate/service/model/grade.js.map +1 -0
  265. package/dist/commands/validate/service/service.js +121 -61
  266. package/dist/commands/validate/service/service.js.map +1 -1
  267. package/dist/commands/validate/service/specs.js +88 -28
  268. package/dist/commands/validate/service/specs.js.map +1 -1
  269. package/dist/commands/validate/service/spine.js +38 -3
  270. package/dist/commands/validate/service/spine.js.map +1 -1
  271. package/dist/commands/validate/service/usecases/tags.js +113 -0
  272. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  273. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  274. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  275. package/dist/commands/validate/validate.js +85 -60
  276. package/dist/commands/validate/validate.js.map +1 -1
  277. package/dist/commands/verify/cross/diff.js +2 -6
  278. package/dist/commands/verify/cross/diff.js.map +1 -1
  279. package/dist/commands/verify/evidence/contract.js +1 -1
  280. package/dist/commands/verify/evidence/contract.js.map +1 -1
  281. package/dist/commands/verify/evidence/read.js +12 -3
  282. package/dist/commands/verify/evidence/read.js.map +1 -1
  283. package/dist/commands/verify/frozen.js +45 -23
  284. package/dist/commands/verify/frozen.js.map +1 -1
  285. package/dist/commands/verify/record.js +69 -17
  286. package/dist/commands/verify/record.js.map +1 -1
  287. package/dist/commands/verify/report.js +27 -44
  288. package/dist/commands/verify/report.js.map +1 -1
  289. package/dist/commands/verify/results.js +112 -30
  290. package/dist/commands/verify/results.js.map +1 -1
  291. package/dist/commands/verify/verify.js +55 -52
  292. package/dist/commands/verify/verify.js.map +1 -1
  293. package/dist/commands/vouch/pack/pack.js +2 -2
  294. package/dist/commands/vouch/pack/pack.js.map +1 -1
  295. package/dist/commands/vouch/pack/print.js +1 -6
  296. package/dist/commands/vouch/pack/print.js.map +1 -1
  297. package/dist/commands/vouch/pack/sections.js +1 -2
  298. package/dist/commands/vouch/pack/sections.js.map +1 -1
  299. package/dist/commands/vouch/run.js +26 -81
  300. package/dist/commands/vouch/run.js.map +1 -1
  301. package/dist/commands/vouch/sample/plan.js +20 -34
  302. package/dist/commands/vouch/sample/plan.js.map +1 -1
  303. package/dist/commands/vouch/vet/verify.js +39 -7
  304. package/dist/commands/vouch/vet/verify.js.map +1 -1
  305. package/dist/commands/vouch/vouch.js +10 -17
  306. package/dist/commands/vouch/vouch.js.map +1 -1
  307. package/dist/core/agent/agents-md/command-map.js +81 -106
  308. package/dist/core/agent/agents-md/command-map.js.map +1 -1
  309. package/dist/core/agent/agents-md/map/explain.js +21 -9
  310. package/dist/core/agent/agents-md/map/explain.js.map +1 -1
  311. package/dist/core/agent/agents-md/map/lenses/context.js +17 -8
  312. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
  313. package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
  314. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
  315. package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
  316. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
  317. package/dist/core/agent/agents-md/map/mcp.js +10 -7
  318. package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
  319. package/dist/core/agent/agents-md/map/status.js +24 -8
  320. package/dist/core/agent/agents-md/map/status.js.map +1 -1
  321. package/dist/core/agent/agents-md/map/subsystem.js +80 -8
  322. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
  323. package/dist/core/agent/agents-md/map/usecases.js +88 -10
  324. package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
  325. package/dist/core/agent/agents-md/refusals.js +49 -22
  326. package/dist/core/agent/agents-md/refusals.js.map +1 -1
  327. package/dist/core/agent/agents-md.js +39 -6
  328. package/dist/core/agent/agents-md.js.map +1 -1
  329. package/dist/core/agent/agents-stamp.js +10 -0
  330. package/dist/core/agent/agents-stamp.js.map +1 -1
  331. package/dist/core/agent/protocol.js +1 -1
  332. package/dist/core/agent/protocol.js.map +1 -1
  333. package/dist/core/agent/scaffold.js +10 -15
  334. package/dist/core/agent/scaffold.js.map +1 -1
  335. package/dist/core/agent/support/report.js +46 -5
  336. package/dist/core/agent/support/report.js.map +1 -1
  337. package/dist/core/agent/tools/dialects.js +1 -0
  338. package/dist/core/agent/tools/dialects.js.map +1 -1
  339. package/dist/core/agent/tools/registry.js +41 -76
  340. package/dist/core/agent/tools/registry.js.map +1 -1
  341. package/dist/core/agent/workflows/adopt.js +158 -11
  342. package/dist/core/agent/workflows/adopt.js.map +1 -1
  343. package/dist/core/agent/workflows/check.js +78 -39
  344. package/dist/core/agent/workflows/check.js.map +1 -1
  345. package/dist/core/agent/workflows/closing.js +88 -27
  346. package/dist/core/agent/workflows/closing.js.map +1 -1
  347. package/dist/core/agent/workflows/feature.js +128 -13
  348. package/dist/core/agent/workflows/feature.js.map +1 -1
  349. package/dist/core/agent/workflows/implement.js +96 -13
  350. package/dist/core/agent/workflows/implement.js.map +1 -1
  351. package/dist/core/agent/workflows/reference/authoring.js +106 -4
  352. package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
  353. package/dist/core/agent/workflows/reference/codes.js +8 -6
  354. package/dist/core/agent/workflows/reference/codes.js.map +1 -1
  355. package/dist/core/agent/workflows/reference/done-check.js +37 -15
  356. package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
  357. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  358. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  359. package/dist/core/agent/workflows/reference/reference.js +6 -3
  360. package/dist/core/agent/workflows/reference/reference.js.map +1 -1
  361. package/dist/core/agent/workflows/reference/spine.js +68 -27
  362. package/dist/core/agent/workflows/reference/spine.js.map +1 -1
  363. package/dist/core/asyncapi/baseline/plan.js +14 -81
  364. package/dist/core/asyncapi/baseline/plan.js.map +1 -1
  365. package/dist/core/asyncapi/digest.js +30 -25
  366. package/dist/core/asyncapi/digest.js.map +1 -1
  367. package/dist/core/asyncapi/merge/components.js +5 -4
  368. package/dist/core/asyncapi/merge/components.js.map +1 -1
  369. package/dist/core/asyncapi/merge/error.js +7 -2
  370. package/dist/core/asyncapi/merge/error.js.map +1 -1
  371. package/dist/core/asyncapi/merge/markers.js +32 -50
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -1
  373. package/dist/core/asyncapi/merge/merge.js +33 -53
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -1
  375. package/dist/core/asyncapi/merge/pin.js +12 -36
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -1
  377. package/dist/core/asyncapi/model.js.map +1 -1
  378. package/dist/core/asyncapi/read.js +36 -12
  379. package/dist/core/asyncapi/read.js.map +1 -1
  380. package/dist/core/brief/brief.js +96 -36
  381. package/dist/core/brief/brief.js.map +1 -1
  382. package/dist/core/brief/checks.js +138 -3
  383. package/dist/core/brief/checks.js.map +1 -1
  384. package/dist/core/brief/landscape.js +209 -130
  385. package/dist/core/brief/landscape.js.map +1 -1
  386. package/dist/core/brief/map/extend.js +84 -0
  387. package/dist/core/brief/map/extend.js.map +1 -0
  388. package/dist/core/brief/map/owed.js +266 -0
  389. package/dist/core/brief/map/owed.js.map +1 -0
  390. package/dist/core/brief/targets.js +109 -31
  391. package/dist/core/brief/targets.js.map +1 -1
  392. package/dist/core/brief/unchecked.js +14 -3
  393. package/dist/core/brief/unchecked.js.map +1 -1
  394. package/dist/core/c4/arch.js +90 -182
  395. package/dist/core/c4/arch.js.map +1 -1
  396. package/dist/core/c4/direction/direction.js +114 -0
  397. package/dist/core/c4/direction/direction.js.map +1 -0
  398. package/dist/core/c4/likec4.js +169 -14
  399. package/dist/core/c4/likec4.js.map +1 -1
  400. package/dist/core/c4/locate/unlocated.js +150 -0
  401. package/dist/core/c4/locate/unlocated.js.map +1 -0
  402. package/dist/core/c4/parsed/deployment.js +160 -0
  403. package/dist/core/c4/parsed/deployment.js.map +1 -0
  404. package/dist/core/c4/parsed/dynamic-views.js.map +1 -1
  405. package/dist/core/c4/parsed/values.js +54 -1
  406. package/dist/core/c4/parsed/values.js.map +1 -1
  407. package/dist/core/c4/parsed/view-ids.js +39 -1
  408. package/dist/core/c4/parsed/view-ids.js.map +1 -1
  409. package/dist/core/c4/prefetch/fleet.js +134 -0
  410. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  411. package/dist/core/c4/project/architecture.js +123 -7
  412. package/dist/core/c4/project/architecture.js.map +1 -1
  413. package/dist/core/c4/project/batch.js +140 -0
  414. package/dist/core/c4/project/batch.js.map +1 -0
  415. package/dist/core/c4/project/documents.js +43 -12
  416. package/dist/core/c4/project/documents.js.map +1 -1
  417. package/dist/core/c4/project/load.js +79 -43
  418. package/dist/core/c4/project/load.js.map +1 -1
  419. package/dist/core/c4/project/staged.js +277 -0
  420. package/dist/core/c4/project/staged.js.map +1 -0
  421. package/dist/core/c4/resolve/attested.js +0 -0
  422. package/dist/core/c4/resolve/attested.js.map +1 -0
  423. package/dist/core/c4/resolve/external.js +51 -0
  424. package/dist/core/c4/resolve/external.js.map +1 -0
  425. package/dist/core/c4/resolve/service.js +78 -17
  426. package/dist/core/c4/resolve/service.js.map +1 -1
  427. package/dist/core/c4/resolve/steps.js +290 -0
  428. package/dist/core/c4/resolve/steps.js.map +1 -0
  429. package/dist/core/c4/resolve/systems.js +154 -0
  430. package/dist/core/c4/resolve/systems.js.map +1 -0
  431. package/dist/core/c4/root-project/exclude.js +352 -0
  432. package/dist/core/c4/root-project/exclude.js.map +1 -0
  433. package/dist/core/c4/seed/template.js +65 -1
  434. package/dist/core/c4/seed/template.js.map +1 -1
  435. package/dist/core/c4/service-model/created/models.js +96 -0
  436. package/dist/core/c4/service-model/created/models.js.map +1 -0
  437. package/dist/core/c4/service-model/documents.js +47 -0
  438. package/dist/core/c4/service-model/documents.js.map +1 -0
  439. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  440. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  441. package/dist/core/c4/service-model/load.js +165 -0
  442. package/dist/core/c4/service-model/load.js.map +1 -0
  443. package/dist/core/c4/service-model/renderer.js +128 -0
  444. package/dist/core/c4/service-model/renderer.js.map +1 -0
  445. package/dist/core/c4/service-model/shape.js +106 -0
  446. package/dist/core/c4/service-model/shape.js.map +1 -0
  447. package/dist/core/c4/service-model/slice.js +188 -0
  448. package/dist/core/c4/service-model/slice.js.map +1 -0
  449. package/dist/core/c4/source-mask.js +297 -10
  450. package/dist/core/c4/source-mask.js.map +1 -1
  451. package/dist/core/c4/source-scan.js +222 -141
  452. package/dist/core/c4/source-scan.js.map +1 -1
  453. package/dist/core/c4/splice/authored-source.js +79 -13
  454. package/dist/core/c4/splice/authored-source.js.map +1 -1
  455. package/dist/core/c4/splice/contract.js +20 -0
  456. package/dist/core/c4/splice/contract.js.map +1 -1
  457. package/dist/core/c4/splice/delta-blocks.js +20 -20
  458. package/dist/core/c4/splice/delta-blocks.js.map +1 -1
  459. package/dist/core/c4/splice/identity/declared.js +87 -0
  460. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  461. package/dist/core/c4/splice/identity/edges.js +37 -0
  462. package/dist/core/c4/splice/identity/edges.js.map +1 -1
  463. package/dist/core/c4/splice/identity/existing.js +80 -0
  464. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  465. package/dist/core/c4/splice/identity/interior.js +80 -0
  466. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  467. package/dist/core/c4/splice/identity/owner.js +50 -0
  468. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  469. package/dist/core/c4/splice/landscape-merge.js +182 -114
  470. package/dist/core/c4/splice/landscape-merge.js.map +1 -1
  471. package/dist/core/c4/splice/model/merge.js +151 -0
  472. package/dist/core/c4/splice/model/merge.js.map +1 -0
  473. package/dist/core/c4/splice/placement.js +160 -56
  474. package/dist/core/c4/splice/placement.js.map +1 -1
  475. package/dist/core/c4/splice/text/spot.js +131 -0
  476. package/dist/core/c4/splice/text/spot.js.map +1 -0
  477. package/dist/core/c4/workspace.js +13 -19
  478. package/dist/core/c4/workspace.js.map +1 -1
  479. package/dist/core/capabilities/capabilities.js +6 -6
  480. package/dist/core/capabilities/capabilities.js.map +1 -1
  481. package/dist/core/capabilities/delta/doc.js +7 -10
  482. package/dist/core/capabilities/delta/doc.js.map +1 -1
  483. package/dist/core/capabilities/delta/uncovered.js +2 -2
  484. package/dist/core/capabilities/delta/uncovered.js.map +1 -1
  485. package/dist/core/capabilities/findings.js +18 -22
  486. package/dist/core/capabilities/findings.js.map +1 -1
  487. package/dist/core/capabilities/realizes/findings.js +12 -19
  488. package/dist/core/capabilities/realizes/findings.js.map +1 -1
  489. package/dist/core/capabilities/realizes/join.js +0 -20
  490. package/dist/core/capabilities/realizes/join.js.map +1 -1
  491. package/dist/core/capabilities/rollup.js +6 -0
  492. package/dist/core/capabilities/rollup.js.map +1 -1
  493. package/dist/core/capabilities/tree.js +6 -28
  494. package/dist/core/capabilities/tree.js.map +1 -1
  495. package/dist/core/capabilities/usecase-join.js +3 -13
  496. package/dist/core/capabilities/usecase-join.js.map +1 -1
  497. package/dist/core/coherence/authoring/scaffold.js +11 -3
  498. package/dist/core/coherence/authoring/scaffold.js.map +1 -1
  499. package/dist/core/coherence/authoring/sentinels.js +2 -1
  500. package/dist/core/coherence/authoring/sentinels.js.map +1 -1
  501. package/dist/core/coherence/calls/called.js +52 -0
  502. package/dist/core/coherence/calls/called.js.map +1 -0
  503. package/dist/core/coherence/coherence.js +103 -22
  504. package/dist/core/coherence/coherence.js.map +1 -1
  505. package/dist/core/coherence/consumed/operations.js +70 -0
  506. package/dist/core/coherence/consumed/operations.js.map +1 -0
  507. package/dist/core/coherence/consumed/refusal.js +38 -0
  508. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  509. package/dist/core/coherence/covers/health.js +85 -0
  510. package/dist/core/coherence/covers/health.js.map +1 -0
  511. package/dist/core/coherence/declared.js +60 -34
  512. package/dist/core/coherence/declared.js.map +1 -1
  513. package/dist/core/coherence/events/declared.js +44 -59
  514. package/dist/core/coherence/events/declared.js.map +1 -1
  515. package/dist/core/coherence/events/events.js +147 -16
  516. package/dist/core/coherence/events/events.js.map +1 -1
  517. package/dist/core/coherence/events/grades.js +31 -8
  518. package/dist/core/coherence/events/grades.js.map +1 -1
  519. package/dist/core/coherence/events/lookups.js +28 -87
  520. package/dist/core/coherence/events/lookups.js.map +1 -1
  521. package/dist/core/coherence/events/produced.js +100 -0
  522. package/dist/core/coherence/events/produced.js.map +1 -0
  523. package/dist/core/coherence/lookups.js +18 -78
  524. package/dist/core/coherence/lookups.js.map +1 -1
  525. package/dist/core/coherence/retired/archived.js +285 -0
  526. package/dist/core/coherence/retired/archived.js.map +1 -0
  527. package/dist/core/coherence/retired/event-pair.js +62 -0
  528. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  529. package/dist/core/coherence/retired/merged.js +79 -0
  530. package/dist/core/coherence/retired/merged.js.map +1 -0
  531. package/dist/core/coherence/retired/retirement.js +49 -0
  532. package/dist/core/coherence/retired/retirement.js.map +1 -0
  533. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  534. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  535. package/dist/core/coherence/retired/revival/revived.js +297 -0
  536. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  537. package/dist/core/consumers/after.js +113 -0
  538. package/dist/core/consumers/after.js.map +1 -0
  539. package/dist/core/consumers/consumers.js +296 -0
  540. package/dist/core/consumers/consumers.js.map +1 -0
  541. package/dist/core/consumers/current.js +211 -0
  542. package/dist/core/consumers/current.js.map +1 -0
  543. package/dist/core/consumers/scan.js +46 -0
  544. package/dist/core/consumers/scan.js.map +1 -0
  545. package/dist/core/consumers/state.js +27 -0
  546. package/dist/core/consumers/state.js.map +1 -0
  547. package/dist/core/delta/delta.js +51 -6
  548. package/dist/core/delta/delta.js.map +1 -1
  549. package/dist/core/dependencies/fanin.js +2 -2
  550. package/dist/core/dependencies/fanin.js.map +1 -1
  551. package/dist/core/deployment/delta.js +191 -0
  552. package/dist/core/deployment/delta.js.map +1 -0
  553. package/dist/core/deployment/objects.js +145 -0
  554. package/dist/core/deployment/objects.js.map +1 -0
  555. package/dist/core/diff/base-git.js +94 -12
  556. package/dist/core/diff/base-git.js.map +1 -1
  557. package/dist/core/diff/base-state.js +49 -21
  558. package/dist/core/diff/base-state.js.map +1 -1
  559. package/dist/core/diff/joins.js +136 -0
  560. package/dist/core/diff/joins.js.map +1 -0
  561. package/dist/core/diff/scope/changed-paths.js +22 -6
  562. package/dist/core/diff/scope/changed-paths.js.map +1 -1
  563. package/dist/core/diff/scope/edges.js +82 -0
  564. package/dist/core/diff/scope/edges.js.map +1 -0
  565. package/dist/core/diff/semantic.js +100 -31
  566. package/dist/core/diff/semantic.js.map +1 -1
  567. package/dist/core/docs.js +31 -22
  568. package/dist/core/docs.js.map +1 -1
  569. package/dist/core/doctor/agents.js +34 -18
  570. package/dist/core/doctor/agents.js.map +1 -1
  571. package/dist/core/doctor/config.js +7 -3
  572. package/dist/core/doctor/config.js.map +1 -1
  573. package/dist/core/doctor/doctor.js +91 -11
  574. package/dist/core/doctor/doctor.js.map +1 -1
  575. package/dist/core/doctor/report.js.map +1 -1
  576. package/dist/core/doctor/reports/scan.js +242 -0
  577. package/dist/core/doctor/reports/scan.js.map +1 -0
  578. package/dist/core/document/apply.js +158 -11
  579. package/dist/core/document/apply.js.map +1 -1
  580. package/dist/core/document/frontmatter.js +55 -0
  581. package/dist/core/document/frontmatter.js.map +1 -1
  582. package/dist/core/document/parse.js +29 -6
  583. package/dist/core/document/parse.js.map +1 -1
  584. package/dist/core/document/scenarios.js +17 -0
  585. package/dist/core/document/scenarios.js.map +1 -1
  586. package/dist/core/document/spec.js +4 -11
  587. package/dist/core/document/spec.js.map +1 -1
  588. package/dist/core/envelope/config.js +10 -0
  589. package/dist/core/envelope/config.js.map +1 -1
  590. package/dist/core/envelope/json.js +34 -0
  591. package/dist/core/envelope/json.js.map +1 -1
  592. package/dist/core/explain/families.js +26 -21
  593. package/dist/core/explain/families.js.map +1 -1
  594. package/dist/core/explain/lookup.js +14 -1
  595. package/dist/core/explain/lookup.js.map +1 -1
  596. package/dist/core/explain/refusals.js +5 -5
  597. package/dist/core/explain/refusals.js.map +1 -1
  598. package/dist/core/explain/terms/documents.js +227 -0
  599. package/dist/core/explain/terms/documents.js.map +1 -0
  600. package/dist/core/explain/terms/done-check.js +144 -0
  601. package/dist/core/explain/terms/done-check.js.map +1 -0
  602. package/dist/core/explain/terms/entry.js +14 -0
  603. package/dist/core/explain/terms/entry.js.map +1 -0
  604. package/dist/core/explain/terms/stages.js +71 -0
  605. package/dist/core/explain/terms/stages.js.map +1 -0
  606. package/dist/core/explain/terms/tasks.js +97 -0
  607. package/dist/core/explain/terms/tasks.js.map +1 -0
  608. package/dist/core/explain/terms.js +68 -109
  609. package/dist/core/explain/terms.js.map +1 -1
  610. package/dist/core/explore/explore.js +40 -10
  611. package/dist/core/explore/explore.js.map +1 -1
  612. package/dist/core/fleet-context.js +81 -95
  613. package/dist/core/fleet-context.js.map +1 -1
  614. package/dist/core/gate/checks.js +11 -4
  615. package/dist/core/gate/checks.js.map +1 -1
  616. package/dist/core/gate/partners.js +69 -28
  617. package/dist/core/gate/partners.js.map +1 -1
  618. package/dist/core/gate/report.js.map +1 -1
  619. package/dist/core/gate/verification.js +75 -12
  620. package/dist/core/gate/verification.js.map +1 -1
  621. package/dist/core/gherkin/stale.js +13 -37
  622. package/dist/core/gherkin/stale.js.map +1 -1
  623. package/dist/core/glossary/delta.js +10 -7
  624. package/dist/core/glossary/delta.js.map +1 -1
  625. package/dist/core/glossary/tree.js +6 -19
  626. package/dist/core/glossary/tree.js.map +1 -1
  627. package/dist/core/kernel/concurrency.js +19 -0
  628. package/dist/core/kernel/concurrency.js.map +1 -1
  629. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  630. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  631. package/dist/core/kernel/path-safety.js +38 -0
  632. package/dist/core/kernel/path-safety.js.map +1 -1
  633. package/dist/core/kernel/records.js +11 -0
  634. package/dist/core/kernel/records.js.map +1 -1
  635. package/dist/core/links/backlinks.js +1 -3
  636. package/dist/core/links/backlinks.js.map +1 -1
  637. package/dist/core/links/corpus.js +51 -37
  638. package/dist/core/links/corpus.js.map +1 -1
  639. package/dist/core/links/findings.js.map +1 -1
  640. package/dist/core/links/parse.js +38 -9
  641. package/dist/core/links/parse.js.map +1 -1
  642. package/dist/core/mcp/argv.js +101 -0
  643. package/dist/core/mcp/argv.js.map +1 -1
  644. package/dist/core/mcp/author-tools.js +2 -1
  645. package/dist/core/mcp/author-tools.js.map +1 -1
  646. package/dist/core/mcp/protocol.js +2 -2
  647. package/dist/core/mcp/protocol.js.map +1 -1
  648. package/dist/core/mcp/tools.js +43 -33
  649. package/dist/core/mcp/tools.js.map +1 -1
  650. package/dist/core/openapi/baseline/gate.js +53 -12
  651. package/dist/core/openapi/baseline/gate.js.map +1 -1
  652. package/dist/core/openapi/baseline/plan.js +40 -10
  653. package/dist/core/openapi/baseline/plan.js.map +1 -1
  654. package/dist/core/openapi/baseline/record.js +0 -1
  655. package/dist/core/openapi/baseline/record.js.map +1 -1
  656. package/dist/core/openapi/contract-text.js +33 -0
  657. package/dist/core/openapi/contract-text.js.map +1 -0
  658. package/dist/core/openapi/contract-tree.js +301 -0
  659. package/dist/core/openapi/contract-tree.js.map +1 -0
  660. package/dist/core/openapi/depth.js +38 -24
  661. package/dist/core/openapi/depth.js.map +1 -1
  662. package/dist/core/openapi/digest.js +52 -2
  663. package/dist/core/openapi/digest.js.map +1 -1
  664. package/dist/core/openapi/doc.js +12 -4
  665. package/dist/core/openapi/doc.js.map +1 -1
  666. package/dist/core/openapi/merge/components.js +25 -60
  667. package/dist/core/openapi/merge/components.js.map +1 -1
  668. package/dist/core/openapi/merge/error.js +3 -13
  669. package/dist/core/openapi/merge/error.js.map +1 -1
  670. package/dist/core/openapi/merge/markers.js +26 -30
  671. package/dist/core/openapi/merge/markers.js.map +1 -1
  672. package/dist/core/openapi/merge/merge.js +28 -52
  673. package/dist/core/openapi/merge/merge.js.map +1 -1
  674. package/dist/core/openapi/merge/pin.js +17 -35
  675. package/dist/core/openapi/merge/pin.js.map +1 -1
  676. package/dist/core/openspec/decide/verdict.js.map +1 -1
  677. package/dist/core/openspec/inventory.js +4 -5
  678. package/dist/core/openspec/inventory.js.map +1 -1
  679. package/dist/core/openspec/model/mapping.js +30 -28
  680. package/dist/core/openspec/model/mapping.js.map +1 -1
  681. package/dist/core/openspec/model/model.js +12 -7
  682. package/dist/core/openspec/model/model.js.map +1 -1
  683. package/dist/core/openspec/scan/changes.js +10 -4
  684. package/dist/core/openspec/scan/changes.js.map +1 -1
  685. package/dist/core/openspec/scan/config.js +7 -16
  686. package/dist/core/openspec/scan/config.js.map +1 -1
  687. package/dist/core/openspec/scan/shape.js +63 -19
  688. package/dist/core/openspec/scan/shape.js.map +1 -1
  689. package/dist/core/openspec/scan/walk.js +21 -38
  690. package/dist/core/openspec/scan/walk.js.map +1 -1
  691. package/dist/core/pack/living.js +43 -4
  692. package/dist/core/pack/living.js.map +1 -1
  693. package/dist/core/pack/pack.js +50 -6
  694. package/dist/core/pack/pack.js.map +1 -1
  695. package/dist/core/projection/arch-slice.js +2 -2
  696. package/dist/core/projection/arch-slice.js.map +1 -1
  697. package/dist/core/projection/introduced.js +14 -0
  698. package/dist/core/projection/introduced.js.map +1 -0
  699. package/dist/core/provenance/findings.js +48 -12
  700. package/dist/core/provenance/findings.js.map +1 -1
  701. package/dist/core/provenance/git.js +33 -57
  702. package/dist/core/provenance/git.js.map +1 -1
  703. package/dist/core/provenance/gitq/moves.js +71 -114
  704. package/dist/core/provenance/gitq/moves.js.map +1 -1
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
  707. package/dist/core/provenance/sources.js +23 -6
  708. package/dist/core/provenance/sources.js.map +1 -1
  709. package/dist/core/provenance/stamp.js +5 -17
  710. package/dist/core/provenance/stamp.js.map +1 -1
  711. package/dist/core/repo/authored/paths.js +18 -0
  712. package/dist/core/repo/authored/paths.js.map +1 -1
  713. package/dist/core/repo/entries.js.map +1 -1
  714. package/dist/core/repo/paths.js +92 -6
  715. package/dist/core/repo/paths.js.map +1 -1
  716. package/dist/core/repo/repo.js +74 -14
  717. package/dist/core/repo/repo.js.map +1 -1
  718. package/dist/core/repo/tree/find.js +12 -3
  719. package/dist/core/repo/tree/find.js.map +1 -1
  720. package/dist/core/repo/tree/fs.js +27 -1
  721. package/dist/core/repo/tree/fs.js.map +1 -1
  722. package/dist/core/repo/tree/render/body.js +258 -0
  723. package/dist/core/repo/tree/render/body.js.map +1 -0
  724. package/dist/core/repo/tree/render/projects.js +182 -0
  725. package/dist/core/repo/tree/render/projects.js.map +1 -0
  726. package/dist/core/repo/tree/render/service/header.js +125 -0
  727. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  728. package/dist/core/repo/tree/render/service/peers.js +28 -0
  729. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  730. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  731. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  732. package/dist/core/repo/tree/render/service/views.js +78 -0
  733. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  734. package/dist/core/repo/tree/render/stale.js +42 -0
  735. package/dist/core/repo/tree/render/stale.js.map +1 -0
  736. package/dist/core/repo/tree/render/text.js +84 -0
  737. package/dist/core/repo/tree/render/text.js.map +1 -0
  738. package/dist/core/repo/tree/render/views.js +293 -0
  739. package/dist/core/repo/tree/render/views.js.map +1 -0
  740. package/dist/core/repo/tree/walk.js +53 -32
  741. package/dist/core/repo/tree/walk.js.map +1 -1
  742. package/dist/core/results.js +47 -12
  743. package/dist/core/results.js.map +1 -1
  744. package/dist/core/scaffold/landscape.js +121 -13
  745. package/dist/core/scaffold/landscape.js.map +1 -1
  746. package/dist/core/scaffold/legacy.js +271 -0
  747. package/dist/core/scaffold/legacy.js.map +1 -0
  748. package/dist/core/staging/commit.js +26 -15
  749. package/dist/core/staging/commit.js.map +1 -1
  750. package/dist/core/staging/lock.js +74 -12
  751. package/dist/core/staging/lock.js.map +1 -1
  752. package/dist/core/staging/recovery/intent.js +2 -5
  753. package/dist/core/staging/recovery/intent.js.map +1 -1
  754. package/dist/core/staging/recovery/recover.js +84 -6
  755. package/dist/core/staging/recovery/recover.js.map +1 -1
  756. package/dist/core/staging/snapshot/manifest.js +188 -0
  757. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  758. package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +39 -45
  759. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  760. package/dist/core/staging/txn/forward.js +24 -14
  761. package/dist/core/staging/txn/forward.js.map +1 -1
  762. package/dist/core/staging/writes.js.map +1 -1
  763. package/dist/core/status/actions/execution.js +11 -0
  764. package/dist/core/status/actions/execution.js.map +1 -1
  765. package/dist/core/status/contracts.js +39 -15
  766. package/dist/core/status/contracts.js.map +1 -1
  767. package/dist/core/status/feature/artifacts.js +33 -8
  768. package/dist/core/status/feature/artifacts.js.map +1 -1
  769. package/dist/core/status/feature/feature.js +24 -17
  770. package/dist/core/status/feature/feature.js.map +1 -1
  771. package/dist/core/status/feature/next.js +20 -7
  772. package/dist/core/status/feature/next.js.map +1 -1
  773. package/dist/core/status/feature/words.js +96 -0
  774. package/dist/core/status/feature/words.js.map +1 -0
  775. package/dist/core/status/fleet/fleet.js +43 -14
  776. package/dist/core/status/fleet/fleet.js.map +1 -1
  777. package/dist/core/status/fleet/next.js +153 -58
  778. package/dist/core/status/fleet/next.js.map +1 -1
  779. package/dist/core/status/report.js.map +1 -1
  780. package/dist/core/status/scan.js.map +1 -1
  781. package/dist/core/status/verification.js +30 -15
  782. package/dist/core/status/verification.js.map +1 -1
  783. package/dist/core/tasks/packet.js +199 -0
  784. package/dist/core/tasks/packet.js.map +1 -0
  785. package/dist/core/tasks/record.js +43 -0
  786. package/dist/core/tasks/record.js.map +1 -0
  787. package/dist/core/tasks/sources.js +181 -0
  788. package/dist/core/tasks/sources.js.map +1 -0
  789. package/dist/core/tasks/stamps.js +76 -0
  790. package/dist/core/tasks/stamps.js.map +1 -0
  791. package/dist/core/tasks/unit.js +0 -0
  792. package/dist/core/tasks/unit.js.map +1 -0
  793. package/dist/core/usecases/capability.js +11 -14
  794. package/dist/core/usecases/capability.js.map +1 -1
  795. package/dist/core/usecases/delta/claims.js +31 -7
  796. package/dist/core/usecases/delta/claims.js.map +1 -1
  797. package/dist/core/usecases/delta/flows.js +5 -7
  798. package/dist/core/usecases/delta/flows.js.map +1 -1
  799. package/dist/core/usecases/delta/modified.js +315 -0
  800. package/dist/core/usecases/delta/modified.js.map +1 -0
  801. package/dist/core/usecases/delta/overlay.js +32 -191
  802. package/dist/core/usecases/delta/overlay.js.map +1 -1
  803. package/dist/core/usecases/fleet.js +195 -36
  804. package/dist/core/usecases/fleet.js.map +1 -1
  805. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/capability-tag.js +8 -9
  806. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  807. package/dist/core/usecases/grade/feature.js +88 -0
  808. package/dist/core/usecases/grade/feature.js.map +1 -0
  809. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/requirement-tag.js +3 -4
  810. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  811. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/steps.js +102 -33
  812. package/dist/core/usecases/grade/steps.js.map +1 -0
  813. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/usecases.js +23 -10
  814. package/dist/core/usecases/grade/usecases.js.map +1 -0
  815. package/dist/core/usecases/operations.js +26 -14
  816. package/dist/core/usecases/operations.js.map +1 -1
  817. package/dist/core/usecases/place.js.map +1 -1
  818. package/dist/core/usecases/service/exclude.js +119 -0
  819. package/dist/core/usecases/service/exclude.js.map +1 -0
  820. package/dist/core/usecases/service/flows.js +164 -0
  821. package/dist/core/usecases/service/flows.js.map +1 -0
  822. package/dist/core/usecases/suites/participants.js +83 -0
  823. package/dist/core/usecases/suites/participants.js.map +1 -0
  824. package/dist/core/usecases/suites/suites.js +45 -0
  825. package/dist/core/usecases/suites/suites.js.map +1 -0
  826. package/dist/core/verify/answers.js +12 -5
  827. package/dist/core/verify/answers.js.map +1 -1
  828. package/dist/core/verify/build.js +102 -82
  829. package/dist/core/verify/build.js.map +1 -1
  830. package/dist/core/verify/checklist.js +70 -12
  831. package/dist/core/verify/checklist.js.map +1 -1
  832. package/dist/core/verify/location.js +67 -0
  833. package/dist/core/verify/location.js.map +1 -0
  834. package/dist/core/verify/pins/lint.js +3 -2
  835. package/dist/core/verify/pins/lint.js.map +1 -1
  836. package/dist/core/verify/pins/pin.js +1 -1
  837. package/dist/core/verify/pins/pin.js.map +1 -1
  838. package/dist/core/verify/read/file.js +224 -0
  839. package/dist/core/verify/read/file.js.map +1 -0
  840. package/dist/core/verify/{file.js → read/shape.js} +16 -104
  841. package/dist/core/verify/read/shape.js.map +1 -0
  842. package/dist/core/verify/read/union.js +105 -0
  843. package/dist/core/verify/read/union.js.map +1 -0
  844. package/dist/core/verify/record.js +35 -12
  845. package/dist/core/verify/record.js.map +1 -1
  846. package/dist/core/verify/store/commit.js +40 -30
  847. package/dist/core/verify/store/commit.js.map +1 -1
  848. package/dist/core/verify/store/render.js +8 -4
  849. package/dist/core/verify/store/render.js.map +1 -1
  850. package/dist/core/vocabulary/issue.js +4 -0
  851. package/dist/core/vocabulary/issue.js.map +1 -1
  852. package/dist/core/vocabulary/maturity.js +75 -4
  853. package/dist/core/vocabulary/maturity.js.map +1 -1
  854. package/dist/core/vocabulary/report.js +16 -1
  855. package/dist/core/vocabulary/report.js.map +1 -1
  856. package/examples/README.md +54 -11
  857. package/examples/docs/architecture/landscape.likec4 +62 -6
  858. package/examples/docs/architecture/services.likec4 +70 -0
  859. package/examples/docs/architecture/subsystems.likec4 +7 -0
  860. package/examples/docs/architecture/usecases/order-notification.likec4 +16 -7
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
  863. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +4 -1
  864. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
  865. package/examples/docs/likec4.config.json +0 -1
  866. package/examples/docs/services/checkout-web/model.likec4 +39 -56
  867. package/examples/docs/services/order-service/arch.spec.md +13 -6
  868. package/examples/docs/services/order-service/asyncapi.yaml +3 -2
  869. package/examples/docs/services/order-service/model.likec4 +58 -70
  870. package/examples/docs/services/payment-service/arch.spec.md +7 -4
  871. package/examples/docs/services/payment-service/model.likec4 +38 -37
  872. package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
  873. package/examples/docs/services/platform/identity-service/model.likec4 +35 -37
  874. package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
  875. package/examples/docs/services/platform/notification-service/health.yaml +8 -3
  876. package/examples/docs/services/platform/notification-service/model.likec4 +43 -64
  877. package/package.json +1 -1
  878. package/dist/commands/validate/checks/vocabulary.js +0 -31
  879. package/dist/commands/validate/checks/vocabulary.js.map +0 -1
  880. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +0 -1
  881. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +0 -1
  882. package/dist/commands/validate/fleet/usecases/steps.js.map +0 -1
  883. package/dist/commands/validate/fleet/usecases/usecases.js.map +0 -1
  884. package/dist/core/agent/agents-md/artifacts.js +0 -220
  885. package/dist/core/agent/agents-md/artifacts.js.map +0 -1
  886. package/dist/core/agent/agents-md/cycle.js +0 -165
  887. package/dist/core/agent/agents-md/cycle.js.map +0 -1
  888. package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
  889. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
  890. package/dist/core/agent/agents-md/spine.js +0 -40
  891. package/dist/core/agent/agents-md/spine.js.map +0 -1
  892. package/dist/core/coherence/events/merged.js +0 -40
  893. package/dist/core/coherence/events/merged.js.map +0 -1
  894. package/dist/core/diff/current-state.js +0 -96
  895. package/dist/core/diff/current-state.js.map +0 -1
  896. package/dist/core/diff/victims.js +0 -247
  897. package/dist/core/diff/victims.js.map +0 -1
  898. package/dist/core/repo/tree/views.js +0 -172
  899. package/dist/core/repo/tree/views.js.map +0 -1
  900. package/dist/core/staging/snapshot.js.map +0 -1
  901. package/dist/core/verify/file.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extending.js","sourceRoot":"","sources":["../../../../../src/commands/archive/plan/model/extending.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Whether the model this merge would leave behind is one LikeC4 can read.\n *\n * It is here because this is the seam that HAS the other document: an extending\n * model is never parsed alone, it is parsed beside the `architecture/` project,\n * and the project the merge must be proven against is the one this very archive\n * would leave behind — the merged map, not the living one. `core/c4/splice` is\n * a pure text-to-text computation — texts in, texts out — so proving the result\n * stays with the command that decides to write.\n *\n * READING the fleet's extending models used to be here too, as the other half\n * of one seam. It moved to `core/c4/service-model/fleet/extending.ts` when the\n * archive stopped being the only reader: `core/c4/project/staged.ts` previews\n * the same merge for every feature-side gate, and `core/` may not import\n * `commands/`. That module's header carries the fail-open the move closes.\n */\nimport { copyFile, mkdir, mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { errorText } from \"../../../../core/c4/likec4.js\";\nimport { architectureProjectDocuments } from \"../../../../core/c4/project/architecture.js\";\nimport { asLoadedDoc, loadProject } from \"../../../../core/c4/project/load.js\";\nimport type { DocsDir } from \"../../../../core/kernel/ids/dirs.js\";\nimport { repoPath } from \"../../../../core/envelope/json.js\";\nimport { landscapePath } from \"../../../../core/repo/paths.js\";\n\nexport interface ModelProof {\n docsDir: DocsDir;\n /** The merged landscape, or null when this archive leaves the map as it is. */\n landscape: string | null;\n /** The merged model: repo-relative path, and the text the archive would write. */\n model: { path: string; content: string };\n}\n\n/**\n * What LikeC4 says about the model this merge would leave, read the way the\n * per-service grade reads it — the `architecture/` project plus this one file.\n *\n * Empty means clean. Anything else refuses the archive at plan time, with\n * nothing written, for the reason the landscape's own parse net exists:\n * splicing is text surgery, and a document that does not parse takes a whole\n * service's grade down (`c4.invalid`) the moment it lands.\n *\n * Errors carry the path the author wrote rather than the staged copy's, and a\n * staging failure is reported as an error rather than swallowed: a merge that\n * could not be proven is not one that passed.\n */\nexport async function modelMergeErrors(proof: ModelProof): Promise<string[]> {\n const { docsDir, landscape, model } = proof;\n let root: string | undefined;\n try {\n root = await mkdtemp(join(tmpdir(), \"loam-model-merge-\"));\n const map = resolve(landscapePath(docsDir));\n const authored = new Map<string, string>();\n const staged: string[] = [];\n for (const path of await architectureProjectDocuments(docsDir)) {\n const rel = repoPath(docsDir, path);\n const at =\n landscape !== null && resolve(path) === map\n ? await write(root, rel, landscape)\n : await copy(root, rel, path);\n authored.set(at, rel);\n staged.push(at);\n }\n const at = await write(root, model.path, model.content);\n authored.set(at, model.path);\n staged.push(at);\n const doc = asLoadedDoc(await loadProject(root, staged));\n return doc.errors.map((e) => {\n const where = e.sourceFsPath === undefined ? undefined : authored.get(resolve(e.sourceFsPath));\n return where === undefined ? errorText(e) : `${where} ${errorText(e)}`;\n });\n } catch (err) {\n return [err instanceof Error ? err.message : String(err)];\n } finally {\n if (root !== undefined) await rm(root, { recursive: true, force: true });\n }\n}\n\n/** Mirror one authored document into the staged tree at its docs-relative path. */\nasync function copy(root: string, rel: string, path: string): Promise<string> {\n const dest = join(root, ...rel.split(\"/\"));\n await mkdir(dirname(dest), { recursive: true });\n await copyFile(path, dest);\n return resolve(dest);\n}\n\n/** The same for bytes loam holds rather than a file — the merge previews. */\nasync function write(root: string, rel: string, content: string): Promise<string> {\n const dest = join(root, ...rel.split(\"/\"));\n await mkdir(dirname(dest), { recursive: true });\n await writeFile(dest, content, \"utf8\");\n return resolve(dest);\n}\n"]}
@@ -3,10 +3,11 @@
3
3
  *
4
4
  * Every arm here keeps one property: a refusal means nothing was written. The
5
5
  * `--json` shapes carry the issues that caused it so an agent can act on the
6
- * list rather than on the sentence, and `ArchiveFailure` exists so a merge that
7
- * could not be computed reports as a merge failure rather than as `internal` —
8
- * a read-only directory or an unreadable pre-image is not a bug in loam, and
9
- * saying so sends the reader looking for one.
6
+ * list rather than on the sentence, and a refusal thrown from below is a
7
+ * `CodedFailure` (core/envelope/json.ts) so a merge that could not be computed
8
+ * reports as a merge failure rather than as `internal` — a read-only directory
9
+ * or an unreadable pre-image is not a bug in loam, and saying so sends the
10
+ * reader looking for one.
10
11
  */
11
12
  import { existsSync } from "node:fs";
12
13
  import { emitJsonError, repoPath } from "../../../core/envelope/json.js";
@@ -15,20 +16,9 @@ import {} from "../../../core/staging/interrupted.js";
15
16
  import {} from "../../../core/staging/writes.js";
16
17
  import { findingJson } from "../../../core/vocabulary/report.js";
17
18
  /**
18
- * A refusal or failure with its stable `--json` code attached. Thrown from the
19
- * plan phase (nothing written yet) and from the commit's rollback path (whose
20
- * message says whether the rollback held). Anything ELSE that escapes runArchive
21
- * is a bug, and the action handler reports it as `internal`.
22
- */
23
- export class ArchiveFailure extends Error {
24
- code;
25
- constructor(code, msg) {
26
- super(msg);
27
- this.code = code;
28
- }
29
- }
30
- /**
31
- * An Issue as the `--json` envelope spells it — the Finding shape, minus details.
19
+ * An Issue as the `--json` envelope spells it — the whole Finding shape, `details`
20
+ * included (`[]` when the issue carries none; the overwrite warnings list their
21
+ * current consumers there), plus `overridable`.
32
22
  * `gates` and `overridable` are always present and already resolved: a consumer
33
23
  * must not have to re-implement the severity default to know what blocks
34
24
  * archive, nor keep a code list to know what `--approve` can move.
@@ -99,13 +89,18 @@ export function sayRecovery(r) {
99
89
  console.log("");
100
90
  }
101
91
  /** The full plan, as files: what a dry run shows instead of doing. */
102
- export function printPlan(docsDir, writes, dirName) {
92
+ export function printPlan(docsDir, writes, dirName, owed) {
103
93
  console.log(`\n plan — ${writes.length} file(s):`);
104
94
  for (const w of writes) {
105
95
  const verb = existsSync(w.path) ? "update" : "create";
106
96
  console.log(` ${verb} ${repoPath(docsDir, w.path)}`);
107
97
  }
108
98
  console.log(` move features/${dirName} → features/archive/${dirName}`);
99
+ // What the real run would print in place of "complete + current" (../closing.ts).
100
+ if (owed.length > 0)
101
+ console.log("");
102
+ for (const line of owed)
103
+ console.log(line);
109
104
  console.log("\n dry run — nothing was written.");
110
105
  }
111
106
  //# sourceMappingURL=refusal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"refusal.js","sourceRoot":"","sources":["../../../../src/commands/archive/plan/refusal.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * How `loam archive` refuses, and what a refusal prints.\n *\n * Every arm here keeps one property: a refusal means nothing was written. The\n * `--json` shapes carry the issues that caused it so an agent can act on the\n * list rather than on the sentence, and `ArchiveFailure` exists so a merge that\n * could not be computed reports as a merge failure rather than as `internal` —\n * a read-only directory or an unreadable pre-image is not a bug in loam, and\n * saying so sends the reader looking for one.\n */\nimport { existsSync } from \"node:fs\";\nimport { emitJsonError, repoPath, type ErrorCode } from \"../../../core/envelope/json.js\";\nimport {\n approveOverrides,\n issueFinding,\n type Issue,\n} from \"../../../core/vocabulary/issue.js\";\nimport { type CommitRecovery } from \"../../../core/staging/interrupted.js\";\nimport { type PlannedWrite } from \"../../../core/staging/writes.js\";\nimport { findingJson, type Finding } from \"../../../core/vocabulary/report.js\";\n\nexport interface ArchiveOptions {\n approve?: boolean;\n dryRun?: boolean;\n json?: boolean;\n}\n\n\n/**\n * A refusal or failure with its stable `--json` code attached. Thrown from the\n * plan phase (nothing written yet) and from the commit's rollback path (whose\n * message says whether the rollback held). Anything ELSE that escapes runArchive\n * is a bug, and the action handler reports it as `internal`.\n */\nexport class ArchiveFailure extends Error {\n constructor(\n readonly code: ErrorCode,\n msg: string,\n ) {\n super(msg);\n }\n}\n\n/**\n * An Issue as the `--json` envelope spells it — the Finding shape, minus details.\n * `gates` and `overridable` are always present and already resolved: a consumer\n * must not have to re-implement the severity default to know what blocks\n * archive, nor keep a code list to know what `--approve` can move.\n */\nexport function issueJson(i: Issue, scope?: string): Record<string, unknown> {\n return {\n ...findingJson(\n issueFinding(i),\n scope === undefined ? undefined : { path: scope, role: \"scope\" },\n ),\n overridable: approveOverrides(i),\n };\n}\n\n/** The failure envelope plus the issues that caused it, so a caller need not re-run validate. */\nexport function refuseJson(code: ErrorCode, msg: string, issues: Issue[], scope?: string): void {\n emitJsonError(code, msg, { issues: issues.map((issue) => issueJson(issue, scope)) });\n}\n\n/**\n * The same envelope for a refusal computed from `Finding`s rather than\n * `Issue`s — the plan-time checks whose codes are not coherence's (they belong\n * to the LIVING documents, not to the feature) and so are not `IssueCode`s.\n *\n * `gates: true` is asserted rather than derived: every finding listed in a\n * refusal is a reason archive stopped, which is what the field means. Nothing\n * advisory reaches here.\n */\nexport function refuseFindings(\n code: ErrorCode,\n msg: string,\n findings: Finding[],\n scope?: string,\n): void {\n emitJsonError(code, msg, {\n issues: findings.map((finding) => ({\n ...findingJson(\n finding,\n scope === undefined ? undefined : { path: scope, role: \"scope\" },\n ),\n gates: true,\n })),\n });\n}\n\n/**\n * Take the docs repo's advisory lock for the WHOLE plan+commit window, then\n * archive.\n *\n * The window is the point. Two archives that overlap do not fight over a\n * rename: they each read the living landscape, each splice their additions into\n * the bytes they read, and the second write replaces the first — both exit 0,\n * and `validate` stays green over a landscape that is missing one feature's\n * architecture, because a document with fewer elements is not an invalid one.\n * That is the only silent-loss path in loam that a later command cannot even\n * detect, so it is closed at the coarsest possible granularity: one writer per\n * docs repo, refusing rather than queueing, because a CLI that blocks for an\n * unknown time is worse for an agent than one that says `docs-busy`.\n */\n\n/**\n * What the recovery did, before this command's own output — a docs repo that\n * changed under the caller is the first thing they have to be told, not a\n * footnote. Shared by archive and unarchive through the same CommitRecovery.\n */\nexport function sayRecovery(r: CommitRecovery): void {\n const what = `an interrupted \\`loam ${r.command} ${r.feature}\\``;\n if (r.outcome === \"completed\") {\n console.log(`⚠ ${what} had in fact finished — cleared its commit record.\\n`);\n return;\n }\n if (r.outcome === \"consistent\") {\n console.log(`⚠ ${what} was rolled back before it wrote anything — cleared its commit record.\\n`);\n return;\n }\n // An interrupted archive is UNDONE and an interrupted unarchive is FINISHED —\n // the merged text a restore was replacing is written down nowhere, so there is\n // nothing to go back to. Say which happened; the paths are the same either way.\n const what_ = r.command === \"archive\" ? \"put them back from\" : \"finished them from\";\n console.log(`⚠ ${what} left ${r.repaired.length} file(s) half-written; ${what_} its snapshot:`);\n for (const p of r.repaired) console.log(` ↩ ${p}`);\n console.log(\"\");\n}\n\n/** The full plan, as files: what a dry run shows instead of doing. */\nexport function printPlan(docsDir: string, writes: PlannedWrite[], dirName: string): void {\n console.log(`\\n plan — ${writes.length} file(s):`);\n for (const w of writes) {\n const verb = existsSync(w.path) ? \"update\" : \"create\";\n console.log(` ${verb} ${repoPath(docsDir, w.path)}`);\n }\n console.log(` move features/${dirName} → features/archive/${dirName}`);\n console.log(\"\\n dry run — nothing was written.\");\n}\n"]}
1
+ {"version":3,"file":"refusal.js","sourceRoot":"","sources":["../../../../src/commands/archive/plan/refusal.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * How `loam archive` refuses, and what a refusal prints.\n *\n * Every arm here keeps one property: a refusal means nothing was written. The\n * `--json` shapes carry the issues that caused it so an agent can act on the\n * list rather than on the sentence, and a refusal thrown from below is a\n * `CodedFailure` (core/envelope/json.ts) so a merge that could not be computed\n * reports as a merge failure rather than as `internal` — a read-only directory\n * or an unreadable pre-image is not a bug in loam, and saying so sends the\n * reader looking for one.\n */\nimport { existsSync } from \"node:fs\";\nimport { emitJsonError, repoPath, type ErrorCode } from \"../../../core/envelope/json.js\";\nimport {\n approveOverrides,\n issueFinding,\n type Issue,\n} from \"../../../core/vocabulary/issue.js\";\nimport { type CommitRecovery } from \"../../../core/staging/interrupted.js\";\nimport { type PlannedWrite } from \"../../../core/staging/writes.js\";\nimport { findingJson, type Finding } from \"../../../core/vocabulary/report.js\";\n\nexport interface ArchiveOptions {\n approve?: boolean;\n dryRun?: boolean;\n json?: boolean;\n}\n\n/**\n * An Issue as the `--json` envelope spells it — the whole Finding shape, `details`\n * included (`[]` when the issue carries none; the overwrite warnings list their\n * current consumers there), plus `overridable`.\n * `gates` and `overridable` are always present and already resolved: a consumer\n * must not have to re-implement the severity default to know what blocks\n * archive, nor keep a code list to know what `--approve` can move.\n */\nexport function issueJson(i: Issue, scope?: string): Record<string, unknown> {\n return {\n ...findingJson(\n issueFinding(i),\n scope === undefined ? undefined : { path: scope, role: \"scope\" },\n ),\n overridable: approveOverrides(i),\n };\n}\n\n/** The failure envelope plus the issues that caused it, so a caller need not re-run validate. */\nexport function refuseJson(code: ErrorCode, msg: string, issues: Issue[], scope?: string): void {\n emitJsonError(code, msg, { issues: issues.map((issue) => issueJson(issue, scope)) });\n}\n\n/**\n * The same envelope for a refusal computed from `Finding`s rather than\n * `Issue`s — the plan-time checks whose codes are not coherence's (they belong\n * to the LIVING documents, not to the feature) and so are not `IssueCode`s.\n *\n * `gates: true` is asserted rather than derived: every finding listed in a\n * refusal is a reason archive stopped, which is what the field means. Nothing\n * advisory reaches here.\n */\nexport function refuseFindings(\n code: ErrorCode,\n msg: string,\n findings: Finding[],\n scope?: string,\n): void {\n emitJsonError(code, msg, {\n issues: findings.map((finding) => ({\n ...findingJson(\n finding,\n scope === undefined ? undefined : { path: scope, role: \"scope\" },\n ),\n gates: true,\n })),\n });\n}\n\n/**\n * Take the docs repo's advisory lock for the WHOLE plan+commit window, then\n * archive.\n *\n * The window is the point. Two archives that overlap do not fight over a\n * rename: they each read the living landscape, each splice their additions into\n * the bytes they read, and the second write replaces the first — both exit 0,\n * and `validate` stays green over a landscape that is missing one feature's\n * architecture, because a document with fewer elements is not an invalid one.\n * That is the only silent-loss path in loam that a later command cannot even\n * detect, so it is closed at the coarsest possible granularity: one writer per\n * docs repo, refusing rather than queueing, because a CLI that blocks for an\n * unknown time is worse for an agent than one that says `docs-busy`.\n */\n\n/**\n * What the recovery did, before this command's own output — a docs repo that\n * changed under the caller is the first thing they have to be told, not a\n * footnote. Shared by archive and unarchive through the same CommitRecovery.\n */\nexport function sayRecovery(r: CommitRecovery): void {\n const what = `an interrupted \\`loam ${r.command} ${r.feature}\\``;\n if (r.outcome === \"completed\") {\n console.log(`⚠ ${what} had in fact finished — cleared its commit record.\\n`);\n return;\n }\n if (r.outcome === \"consistent\") {\n console.log(`⚠ ${what} was rolled back before it wrote anything — cleared its commit record.\\n`);\n return;\n }\n // An interrupted archive is UNDONE and an interrupted unarchive is FINISHED —\n // the merged text a restore was replacing is written down nowhere, so there is\n // nothing to go back to. Say which happened; the paths are the same either way.\n const what_ = r.command === \"archive\" ? \"put them back from\" : \"finished them from\";\n console.log(`⚠ ${what} left ${r.repaired.length} file(s) half-written; ${what_} its snapshot:`);\n for (const p of r.repaired) console.log(` ↩ ${p}`);\n console.log(\"\");\n}\n\n/** The full plan, as files: what a dry run shows instead of doing. */\nexport function printPlan(docsDir: string, writes: PlannedWrite[], dirName: string, owed: readonly string[]): void {\n console.log(`\\n plan — ${writes.length} file(s):`);\n for (const w of writes) {\n const verb = existsSync(w.path) ? \"update\" : \"create\";\n console.log(` ${verb} ${repoPath(docsDir, w.path)}`);\n }\n console.log(` move features/${dirName} → features/archive/${dirName}`);\n // What the real run would print in place of \"complete + current\" (../closing.ts).\n if (owed.length > 0) console.log(\"\");\n for (const line of owed) console.log(line);\n console.log(\"\\n dry run — nothing was written.\");\n}\n"]}
@@ -2,7 +2,10 @@
2
2
  * The requirements merge: the feature's ADDED/MODIFIED/REMOVED requirements
3
3
  * applied into each living service spec. The contract merges live beside it in
4
4
  * `./contracts/` — one file per axis, split out when the OpenAPI half made
5
- * this one carry two merges.
5
+ * this one carry two merges. What happens to the TEXT of one document lives in
6
+ * `./document/`: the in-place rewrite of an existing requirements run, the
7
+ * head of a document this merge creates, and where a merged link points once
8
+ * the feature has moved.
6
9
  *
7
10
  * ONE code path for the pair of requirement-carrying files — the business
8
11
  * spec.md and the architecture arch.spec.md ride the same delta algebra, the
@@ -19,16 +22,29 @@ import { planWrite, readUtf8 } from "../../../core/staging/writes.js";
19
22
  import { featureSpecPaths, SPEC_AXES } from "../../../core/repo/paths.js";
20
23
  import { capabilityDocsDir, glossaryDir, livingCapabilityPaths } from "../../../core/repo/authored/paths.js";
21
24
  import { featureGlossary, livingTermPath } from "../../../core/glossary/delta.js";
22
- import { locateServicePaths } from "../../../core/repo/service-target.js";
23
- import { isRequirementsHeading, parseRequirements, sectionHeadings, splitRequirementsSection, } from "../../../core/document/parse.js";
24
- import { applyRequirementDelta } from "../../../core/document/apply.js";
25
- import { serializeRequirements } from "../../../core/document/spec.js";
25
+ import { enumeratedServiceIds, locateServicePaths } from "../../../core/repo/service-target.js";
26
+ import { introducedServices } from "../../../core/projection/arch-slice.js";
27
+ import { isRequirementsHeading, parseRequirements, sectionHeadings } from "../../../core/document/parse.js";
28
+ import { applyRequirementDelta, droppedBy, droppedSentence } from "../../../core/document/apply.js";
26
29
  import {} from "../../../core/document/spec.js";
27
- import { ArchiveFailure } from "./refusal.js";
30
+ import { movedUnderVouch, parseFrontmatter, stringField } from "../../../core/document/frontmatter.js";
31
+ import { CodedFailure } from "../../../core/envelope/json.js";
28
32
  import {} from "./state.js";
33
+ import { featureRetarget } from "./document/links.js";
34
+ import { createdDocument, hasPurpose } from "./document/head.js";
35
+ import { rewriteRequirementsRun } from "./document/run.js";
29
36
  export async function planSpecs(config, gated, plan, say) {
30
37
  const { featureDir, deltaServices } = gated;
31
38
  const { writes } = plan;
39
+ // Where every file of the feature will be once this archive lands — the
40
+ // glossary terms it copies out, everything else under features/archive/.
41
+ const retarget = await featureRetarget(config.docsDir, gated);
42
+ // Who the fleet already has, asked BEFORE any of this archive's writes, and
43
+ // which of them this feature's own C4 delta introduces: a first spec.md for a
44
+ // service that existed and was never adopted is the feature's slice, not the
45
+ // service, and the create branch below says so in its frontmatter.
46
+ const existing = new Set(await enumeratedServiceIds(config.docsDir, config.fleet));
47
+ const introduced = new Set(introducedServices(gated.deltaDoc ?? null, gated.id));
32
48
  // Requirements merge — apply ADDED/MODIFIED/REMOVED into each living service
33
49
  // spec. ONE code path for the pair of requirement-carrying files: the business
34
50
  // spec.md and the architecture arch.spec.md ride the same delta algebra, the
@@ -48,19 +64,43 @@ export async function planSpecs(config, gated, plan, say) {
48
64
  // `core/links/parse.ts`'s `rebaseLinks` states the defect; the ordering
49
65
  // here is what lets the fix see both ends of the move, including a
50
66
  // service filed under a subsystem, whose living directory is deeper still.
51
- const deltaReqs = parseRequirements(rebaseLinks(await readUtf8(deltaPath), { from: dirname(deltaPath), to: dirname(livingPath) }));
67
+ // `retarget` is the other half: a link INTO the feature points at a file
68
+ // this same archive moves (`./document/links.ts`).
69
+ const delta = rebaseLinks(await readUtf8(deltaPath), { from: dirname(deltaPath), to: dirname(livingPath), retarget });
70
+ const deltaReqs = parseRequirements(delta);
52
71
  if (!existsSync(livingPath)) {
53
72
  // New service (or first arch spec) — create the living file from the
54
- // ADDED/MODIFIED requirements.
73
+ // ADDED/MODIFIED requirements, under the head `./document/head.ts` writes:
74
+ // what the delta marked as the document's own, and a link to the rest.
55
75
  const created = applyRequirementDelta([], deltaReqs);
56
76
  if (created.length === 0) {
57
77
  say(` ${axis.label}: ${svc} — nothing to merge (delta leaves no requirements), no living ${axis.file} created`);
58
78
  continue;
59
79
  }
60
- const heading = axis.key === "spec" ? svc : `${svc} — architecture`;
61
- const frontmatter = `---\nservice: ${svc}\nstatus: draft\n---\n\n# ${heading}\n\n`;
62
- writes.push(planWrite(livingPath, `${frontmatter}## Requirements\n\n${serializeRequirements(created)}`));
80
+ // The business spec only: it is the document the maturity ladder and
81
+ // `next.adopt` read as "this service is written down" (SCHEMA.md,
82
+ // `adoption`). A service the feature introduces IS its slice — there was
83
+ // nothing before it to adopt — so it is never marked.
84
+ const unadopted = axis.key === "spec" && existing.has(svc) && !introduced.has(svc);
85
+ const doc = createdDocument({
86
+ docsDir: config.docsDir,
87
+ featureId: gated.id,
88
+ deltaPath,
89
+ delta,
90
+ livingPath,
91
+ retarget,
92
+ fallbackTitle: axis.key === "spec" ? svc : `${svc} — architecture`,
93
+ service: svc,
94
+ ...(unadopted ? { adoption: "partial" } : {}),
95
+ requirements: created,
96
+ });
97
+ writes.push(planWrite(livingPath, doc.text));
63
98
  say(` ${axis.label}: ${svc} — created living ${axis.file} (${created.length} requirement(s))`);
99
+ say(` ${doc.note}`);
100
+ if (unadopted) {
101
+ say(` ${svc} existed before ${gated.id} and was never adopted — this spec.md holds only the feature's slice, so it is ` +
102
+ `written \`adoption: partial\` and ${svc} stays owed its adoption: \`loam adopt --service ${svc}\`, then delete the line`);
103
+ }
64
104
  continue;
65
105
  }
66
106
  const livingText = await readUtf8(livingPath);
@@ -71,23 +111,47 @@ export async function planSpecs(config, gated, plan, say) {
71
111
  // Mechanical, like a model-less landscape, so merge-failed, not --approve.
72
112
  const reqHeadings = sectionHeadings(livingText).filter((h) => isRequirementsHeading(h.text));
73
113
  if (reqHeadings.length > 1) {
74
- throw new ArchiveFailure("merge-failed", `living ${axis.file} for ${svc} has ${reqHeadings.length} '## Requirements' headings (lines ${reqHeadings.map((h) => h.line).join(", ")}) — the merge rewrites ONE requirements section and cannot choose; merge them into one, then re-run`);
114
+ throw new CodedFailure("merge-failed", `living ${axis.file} for ${svc} has ${reqHeadings.length} '## Requirements' headings (lines ${reqHeadings.map((h) => h.line).join(", ")}) — the merge rewrites ONE requirements section and cannot choose; merge them into one, then re-run`);
115
+ }
116
+ const livingReqs = parseRequirements(livingText);
117
+ const merged = applyRequirementDelta(livingReqs, deltaReqs);
118
+ const next = rewriteRequirementsRun(livingText, livingReqs, merged);
119
+ writes.push(planWrite(livingPath, next));
120
+ // A merge is an edit to the document's body like any other, so a vouched
121
+ // spec it moves goes `content.stale` — and honestly: the merged text is
122
+ // words no person has yet read against the code. Archive does not soften
123
+ // that. It names the document and its owner, so the re-vouch is known to
124
+ // be owed while the merge is still a PR rather than discovered later as a
125
+ // red `--strict` gate. Asked of the bytes about to be written, through the
126
+ // one definition validate grades with.
127
+ const fm = parseFrontmatter(next);
128
+ if (movedUnderVouch(fm, next)) {
129
+ plan.revouchOwed.push({ service: svc, path: livingPath, owner: stringField(fm, "owner") ?? null });
75
130
  }
76
- const merged = applyRequirementDelta(parseRequirements(livingText), deltaReqs);
77
- writes.push(planWrite(livingPath, rewriteRequirementsRun(livingText, merged)));
78
131
  const c = summarize(deltaReqs);
79
132
  say(` ${axis.label}: ${svc} ← +${c.ADDED} ~${c.MODIFIED} -${c.REMOVED} (now ${merged.length} total)`);
133
+ sayDropped(plan, say, livingPath, droppedBy(livingReqs, deltaReqs));
134
+ if (hasPurpose(delta))
135
+ say(` ${PURPOSE_NOT_MERGED}`);
80
136
  }
81
137
  }
82
138
  }
139
+ /**
140
+ * A `## Purpose` in a delta against a document that already exists merges as
141
+ * nothing — the living narrative is edited in place, never replaced by a merge
142
+ * — and the author who wrote one expected it to land. Said, not refused: the
143
+ * requirements are still exactly what they meant.
144
+ */
145
+ const PURPOSE_NOT_MERGED = "the delta's ## Purpose was not merged — the living document keeps its own narrative; edit it there in this change";
83
146
  /**
84
147
  * The BUSINESS corpus's merge: a feature's `capabilities/<id>/spec.md` deltas
85
148
  * applied into the living `capabilities/<id>/spec.md`.
86
149
  *
87
150
  * Here rather than in a sixth file in this package because this module already
88
- * owns "requirements merged into a living document" — it owns
89
- * `rewriteRequirementsRun`, the two-headings refusal and the `applyRequirementDelta`
90
- * call, and the business corpus needs all three unchanged. What differs from
151
+ * owns "requirements merged into a living document" — it owns the two-headings
152
+ * refusal and the `applyRequirementDelta` call, and calls the same
153
+ * `./document/` rewrite and head, and the business corpus needs all of them
154
+ * unchanged. What differs from
91
155
  * `planSpecs` above is only where the living document lives and what a CREATED
92
156
  * one says at the top.
93
157
  *
@@ -118,25 +182,42 @@ export async function planCapabilities(config, gated, plan, say) {
118
182
  // run whose every capability delta merged into a document already there.
119
183
  const adopting = !existsSync(capabilityDocsDir(config.docsDir));
120
184
  let creating = false;
185
+ const retarget = await featureRetarget(config.docsDir, gated);
121
186
  for (const doc of gated.capabilityDeltas) {
122
187
  const livingPath = livingCapabilityPaths(config.docsDir, doc.id).spec;
123
188
  // Same move, same rewrite: `features/<FEAT>/capabilities/<id>/` is two
124
189
  // directories deeper than `capabilities/<id>/`, so a citation of a glossary
125
- // term or an ADR would land pointing above the repository.
126
- const deltaReqs = parseRequirements(rebaseLinks(await readUtf8(doc.spec), { from: dirname(doc.spec), to: dirname(livingPath) }));
190
+ // term or an ADR would land pointing above the repository — or, aimed into
191
+ // the feature itself, at a file this archive moves.
192
+ const delta = rebaseLinks(await readUtf8(doc.spec), { from: dirname(doc.spec), to: dirname(livingPath), retarget });
193
+ const deltaReqs = parseRequirements(delta);
127
194
  if (!existsSync(livingPath)) {
128
195
  const created = applyRequirementDelta([], deltaReqs);
129
196
  if (created.length === 0) {
130
197
  say(` capability: ${doc.id} — nothing to merge (delta leaves no requirements), no living spec.md created`);
131
198
  continue;
132
199
  }
133
- // The heading is the id and nothing else. loam merges requirements and
134
- // never prose, so it must not fabricate the narrative that is the whole
135
- // point of the document — the line below tells the author it is theirs.
136
- writes.push(planWrite(livingPath, `# ${doc.id}\n\n## Requirements\n\n${serializeRequirements(created)}`));
200
+ // The heading is the id unless the delta titled the capability, and the
201
+ // narrative is the delta's `## Purpose` or nothing: loam merges
202
+ // requirements and never prose, so it must not fabricate the narrative
203
+ // that is the whole point of the document — it carries only what the
204
+ // author marked as the document's own (`./document/head.ts`), and the note
205
+ // below tells them where the rest is.
206
+ const living = createdDocument({
207
+ docsDir: config.docsDir,
208
+ featureId: gated.id,
209
+ deltaPath: doc.spec,
210
+ delta,
211
+ livingPath,
212
+ retarget,
213
+ fallbackTitle: doc.id,
214
+ service: null,
215
+ requirements: created,
216
+ });
217
+ writes.push(planWrite(livingPath, living.text));
137
218
  creating = true;
138
219
  say(` capability: ${doc.id} — created capabilities/${doc.id}/spec.md (${created.length} requirement(s))`);
139
- say(` write the narrative above '## Requirements' — loam merges requirements, not prose`);
220
+ say(` ${living.note}`);
140
221
  continue;
141
222
  }
142
223
  const livingText = await readUtf8(livingPath);
@@ -144,44 +225,35 @@ export async function planCapabilities(config, gated, plan, say) {
144
225
  // reason it cannot be guessed at.
145
226
  const reqHeadings = sectionHeadings(livingText).filter((h) => isRequirementsHeading(h.text));
146
227
  if (reqHeadings.length > 1) {
147
- throw new ArchiveFailure("merge-failed", `living capabilities/${doc.id}/spec.md has ${reqHeadings.length} '## Requirements' headings (lines ${reqHeadings.map((h) => h.line).join(", ")}) — the merge rewrites ONE requirements section and cannot choose; merge them into one, then re-run`);
228
+ throw new CodedFailure("merge-failed", `living capabilities/${doc.id}/spec.md has ${reqHeadings.length} '## Requirements' headings (lines ${reqHeadings.map((h) => h.line).join(", ")}) — the merge rewrites ONE requirements section and cannot choose; merge them into one, then re-run`);
148
229
  }
149
- const merged = applyRequirementDelta(parseRequirements(livingText), deltaReqs);
150
- writes.push(planWrite(livingPath, rewriteRequirementsRun(livingText, merged)));
230
+ const livingReqs = parseRequirements(livingText);
231
+ const merged = applyRequirementDelta(livingReqs, deltaReqs);
232
+ writes.push(planWrite(livingPath, rewriteRequirementsRun(livingText, livingReqs, merged)));
151
233
  const c = summarize(deltaReqs);
152
234
  say(` capability: ${doc.id} ← +${c.ADDED} ~${c.MODIFIED} -${c.REMOVED} (now ${merged.length} total)`);
235
+ sayDropped(plan, say, livingPath, droppedBy(livingReqs, deltaReqs));
236
+ if (hasPurpose(delta))
237
+ say(` ${PURPOSE_NOT_MERGED}`);
153
238
  }
154
239
  if (adopting && creating) {
155
240
  say(` capabilities/ did not exist — this archive opts the fleet into the business axis, and \`loam validate --all\` grades it from now on`);
156
241
  }
157
242
  }
158
243
  /**
159
- * Rewrite ONLY the requirements run of a living spec. Byte-for-byte preserved:
160
- * everything before the first requirement inside `## Requirements` (the intro,
161
- * the heading line, prose under the heading) and everything from the section's
162
- * end onward (the next `## ` heading to EOF) — the old cut was a substring
163
- * `indexOf("\n## Requirements")`, a prefix match that also hit
164
- * `## Requirements Extra` and silently destroyed every section after the
165
- * requirements. Prose BETWEEN requirements is body text of whatever is open
166
- * above it (parseRequirements attributes it to the previous requirement's last
167
- * scenario, or its text) and survives inside the re-serialized run, framing
168
- * normalized. `merged` must contain every living requirement — runArchive's
169
- * stray guard refuses any document whose requirements sit outside the section,
170
- * using the same heading definition, before this output is ever written.
244
+ * What each replacement takes out of the living document, named under the
245
+ * count line and carried as `--json` `dropped`. The counts alone were the whole
246
+ * report — `~1` — while a MODIFIED that restated one of two scenarios, or wrote
247
+ * `Covers:` without the `sli:` entries the living text had, merged at exit 0
248
+ * and the rest was gone (`core/document/apply.ts` says why it is read verbatim
249
+ * and by name). Said, never gated: rewriting a requirement smaller is a
250
+ * legitimate change, and what was missing was only that nobody was told.
171
251
  */
172
- function rewriteRequirementsRun(text, merged) {
173
- const s = splitRequirementsSection(text);
174
- // No `## Requirements` at all: the stray guard has already refused any doc
175
- // whose requirements live elsewhere, so this one has none — open the section.
176
- if (s === null)
177
- return `${text.trimEnd()}\n\n## Requirements\n\n${serializeRequirements(merged)}`;
178
- const body = serializeRequirements(merged);
179
- // head/tail are raw slices; only the run's own framing is normalized. When
180
- // the section held no requirements yet, the glue supplies the blank line the
181
- // author never had reason to write.
182
- const headGlue = s.run !== "" || s.head.endsWith("\n\n") ? "" : s.head.endsWith("\n") ? "\n" : "\n\n";
183
- const tailGlue = s.tail === "" ? "" : "\n";
184
- return s.head + headGlue + body + tailGlue + s.tail;
252
+ function sayDropped(plan, say, path, rows) {
253
+ for (const row of rows) {
254
+ plan.dropped.push({ path, ...row });
255
+ say(` ${row.kind === "REMOVED" ? "-" : "~"} ${droppedSentence(row)}`);
256
+ }
185
257
  }
186
258
  function summarize(reqs) {
187
259
  const c = { ADDED: 0, MODIFIED: 0, REMOVED: 0 };
@@ -203,9 +275,15 @@ function summarize(reqs) {
203
275
  * is folded into a living document by the requirement algebra because the two
204
276
  * documents share identified parts; a term document has one part, and merging
205
277
  * two definitions of one word is not something a machine may attempt. So the
206
- * definition the author wrote in the feature IS the definition that lands,
207
- * verbatim — loam re-encodes it as UTF-8 through `readUtf8` and changes nothing
208
- * else, not even the trailing newline.
278
+ * definition the author wrote in the feature IS the definition that lands —
279
+ * loam re-encodes it as UTF-8 through `readUtf8` and changes nothing else, not
280
+ * even the trailing newline, but the ROUTE of each relative link. That one
281
+ * exception is the requirement merge's, for the requirement merge's reason: the
282
+ * term moves from `features/<FEAT>/glossary/` to `glossary/`, two directories
283
+ * up, so a definition citing a service spec or the feature's own ADR landed
284
+ * pointing at nothing (`link.unresolved` on the very next `validate --all`,
285
+ * against a document graded at fleet scope). Same `rebaseLinks`, same
286
+ * `retarget`: the target is unchanged, only the way there.
209
287
  *
210
288
  * CREATE-ONLY, which is why this loop has no other branch. A term the living
211
289
  * glossary already defines was refused at the gate (`glossary.term-exists`,
@@ -226,8 +304,11 @@ export async function planGlossary(config, gated, plan, say) {
226
304
  return;
227
305
  // Asked BEFORE the loop, because the loop is what would create it.
228
306
  const adopting = !existsSync(glossaryDir(config.docsDir));
307
+ const retarget = await featureRetarget(config.docsDir, gated);
229
308
  for (const term of glossary.terms) {
230
- plan.writes.push(planWrite(livingTermPath(config.docsDir, term.id), await readUtf8(term.path)));
309
+ const livingPath = livingTermPath(config.docsDir, term.id);
310
+ const text = rebaseLinks(await readUtf8(term.path), { from: dirname(term.path), to: dirname(livingPath), retarget });
311
+ plan.writes.push(planWrite(livingPath, text));
231
312
  say(` glossary: ${term.id} — created glossary/${term.id}.md`);
232
313
  }
233
314
  if (adopting) {
@@ -1 +1 @@
1
- {"version":3,"file":"specs.js","sourceRoot":"","sources":["../../../../src/commands/archive/plan/specs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The requirements merge: the feature's ADDED/MODIFIED/REMOVED requirements\n * applied into each living service spec. The contract merges live beside it in\n * `./contracts/` — one file per axis, split out when the OpenAPI half made\n * this one carry two merges.\n *\n * ONE code path for the pair of requirement-carrying files — the business\n * spec.md and the architecture arch.spec.md ride the same delta algebra, the\n * same prose-preserving rewrite and the same guards, parameterized by filename.\n * A fork here would be two places the merge could disagree.\n *\n * Nothing is written. Everything lands in the `Plan`, so a failure on any axis\n * leaves the living docs exactly as they were.\n */\nimport { existsSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { rebaseLinks } from \"../../../core/links/parse.js\";\nimport { planWrite, readUtf8 } from \"../../../core/staging/writes.js\";\nimport { featureSpecPaths, SPEC_AXES } from \"../../../core/repo/paths.js\";\nimport { capabilityDocsDir, glossaryDir, livingCapabilityPaths } from \"../../../core/repo/authored/paths.js\";\nimport { featureGlossary, livingTermPath } from \"../../../core/glossary/delta.js\";\nimport { locateServicePaths } from \"../../../core/repo/service-target.js\";\nimport {\n isRequirementsHeading,\n parseRequirements,\n sectionHeadings,\n splitRequirementsSection,\n} from \"../../../core/document/parse.js\";\nimport { applyRequirementDelta } from \"../../../core/document/apply.js\";\nimport { serializeRequirements } from \"../../../core/document/spec.js\";\nimport { type Requirement } from \"../../../core/document/spec.js\";\nimport { ArchiveFailure } from \"./refusal.js\";\nimport { type Gated, type Plan } from \"./state.js\";\nimport type { DocsDir } from \"../../../core/kernel/ids/dirs.js\";\nimport type { FleetContext } from \"../../../core/fleet-context.js\";\n\nexport async function planSpecs(\n config: { docsDir: DocsDir; fleet?: FleetContext },\n gated: Gated,\n plan: Plan,\n say: (line?: string) => void,\n): Promise<void> {\n const { featureDir, deltaServices } = gated;\n const { writes } = plan;\n // Requirements merge — apply ADDED/MODIFIED/REMOVED into each living service\n // spec. ONE code path for the pair of requirement-carrying files: the business\n // spec.md and the architecture arch.spec.md ride the same delta algebra, the\n // same prose-preserving rewrite and the same guards, parameterized by filename\n // (SPEC_AXES) — a fork here would be two places the merge could disagree.\n for (const svc of deltaServices) {\n for (const axis of SPEC_AXES) {\n const deltaPath = featureSpecPaths(featureDir, svc)[axis.key];\n if (!existsSync(deltaPath)) continue;\n\n // The shared context: this is a deltaServices × SPEC_AXES loop, and a\n // context-less locate is a full fleet walk per iteration.\n const livingPath = (await locateServicePaths(config.docsDir, svc, config.fleet))[axis.key];\n // Resolved BEFORE the delta is parsed, because the parse now depends on\n // it: a requirement's markdown links are relative to the file they were\n // written in, and this merge moves the text two directories up the tree.\n // `core/links/parse.ts`'s `rebaseLinks` states the defect; the ordering\n // here is what lets the fix see both ends of the move, including a\n // service filed under a subsystem, whose living directory is deeper still.\n const deltaReqs = parseRequirements(\n rebaseLinks(await readUtf8(deltaPath), { from: dirname(deltaPath), to: dirname(livingPath) }),\n );\n if (!existsSync(livingPath)) {\n // New service (or first arch spec) — create the living file from the\n // ADDED/MODIFIED requirements.\n const created = applyRequirementDelta([], deltaReqs);\n if (created.length === 0) {\n say(` ${axis.label}: ${svc} — nothing to merge (delta leaves no requirements), no living ${axis.file} created`);\n continue;\n }\n const heading = axis.key === \"spec\" ? svc : `${svc} — architecture`;\n const frontmatter = `---\\nservice: ${svc}\\nstatus: draft\\n---\\n\\n# ${heading}\\n\\n`;\n writes.push(planWrite(livingPath, `${frontmatter}## Requirements\\n\\n${serializeRequirements(created)}`));\n say(` ${axis.label}: ${svc} — created living ${axis.file} (${created.length} requirement(s))`);\n continue;\n }\n const livingText = await readUtf8(livingPath);\n // TWO `## Requirements` headings would put the rewrite's one-section\n // invariant to a choice it must not make: the run of the first would be\n // rewritten while the second survived verbatim in the tail — and its\n // requirements, collected by parseRequirements, would land in the run TOO.\n // Mechanical, like a model-less landscape, so merge-failed, not --approve.\n const reqHeadings = sectionHeadings(livingText).filter((h) => isRequirementsHeading(h.text));\n if (reqHeadings.length > 1) {\n throw new ArchiveFailure(\n \"merge-failed\",\n `living ${axis.file} for ${svc} has ${reqHeadings.length} '## Requirements' headings (lines ${reqHeadings.map((h) => h.line).join(\", \")}) — the merge rewrites ONE requirements section and cannot choose; merge them into one, then re-run`,\n );\n }\n const merged = applyRequirementDelta(parseRequirements(livingText), deltaReqs);\n writes.push(planWrite(livingPath, rewriteRequirementsRun(livingText, merged)));\n\n const c = summarize(deltaReqs);\n say(` ${axis.label}: ${svc} ← +${c.ADDED} ~${c.MODIFIED} -${c.REMOVED} (now ${merged.length} total)`);\n }\n }\n}\n\n/**\n * The BUSINESS corpus's merge: a feature's `capabilities/<id>/spec.md` deltas\n * applied into the living `capabilities/<id>/spec.md`.\n *\n * Here rather than in a sixth file in this package because this module already\n * owns \"requirements merged into a living document\" — it owns\n * `rewriteRequirementsRun`, the two-headings refusal and the `applyRequirementDelta`\n * call, and the business corpus needs all three unchanged. What differs from\n * `planSpecs` above is only where the living document lives and what a CREATED\n * one says at the top.\n *\n * ARCHIVE CREATES THE LIVING DOCUMENT, by exact analogy with the new-service\n * branch above. The directory IS the list on this axis (`core/capabilities/tree.ts`),\n * so an archive that merged into a file it refused to create would make the\n * whole delta merge nothing — which is the `delta.no-delta-sections` failure\n * class, arriving through the merge instead of through the grammar.\n *\n * NO FRONTMATTER on a created capability document, and that is a decision\n * rather than an omission. Nothing reads a capability document's frontmatter:\n * `readCapabilityTree` classifies by the file's PRESENCE and\n * `readCapabilityVocabulary` takes `description`/`owner` from the YAML side. A\n * `status:` field invented here would be the \"second list nothing keeps\n * current\" this axis was designed against.\n *\n * AND IT SAYS SO OUT LOUD. Creating the first `capabilities/<id>/spec.md`\n * creates `capabilities/`, which is one of the two ways a fleet opts INTO the\n * capability axis — from the next command on, `loam validate --all` grades a\n * corpus that did not exist before. A merge that changes what the whole fleet\n * is graded on must not do it silently.\n */\nexport async function planCapabilities(\n config: { docsDir: DocsDir; fleet?: FleetContext },\n gated: Gated,\n plan: Plan,\n say: (line?: string) => void,\n): Promise<void> {\n const { writes } = plan;\n // Whether `capabilities/` exists is asked BEFORE the loop, because the loop\n // is what would create it; `creating` records whether this run actually\n // materialises a document, so the adoption line below is not printed by a\n // run whose every capability delta merged into a document already there.\n const adopting = !existsSync(capabilityDocsDir(config.docsDir));\n let creating = false;\n for (const doc of gated.capabilityDeltas) {\n const livingPath = livingCapabilityPaths(config.docsDir, doc.id).spec;\n // Same move, same rewrite: `features/<FEAT>/capabilities/<id>/` is two\n // directories deeper than `capabilities/<id>/`, so a citation of a glossary\n // term or an ADR would land pointing above the repository.\n const deltaReqs = parseRequirements(\n rebaseLinks(await readUtf8(doc.spec), { from: dirname(doc.spec), to: dirname(livingPath) }),\n );\n if (!existsSync(livingPath)) {\n const created = applyRequirementDelta([], deltaReqs);\n if (created.length === 0) {\n say(` capability: ${doc.id} — nothing to merge (delta leaves no requirements), no living spec.md created`);\n continue;\n }\n // The heading is the id and nothing else. loam merges requirements and\n // never prose, so it must not fabricate the narrative that is the whole\n // point of the document — the line below tells the author it is theirs.\n writes.push(planWrite(livingPath, `# ${doc.id}\\n\\n## Requirements\\n\\n${serializeRequirements(created)}`));\n creating = true;\n say(` capability: ${doc.id} — created capabilities/${doc.id}/spec.md (${created.length} requirement(s))`);\n say(` write the narrative above '## Requirements' — loam merges requirements, not prose`);\n continue;\n }\n const livingText = await readUtf8(livingPath);\n // The same one-section invariant as the service axis above, and the same\n // reason it cannot be guessed at.\n const reqHeadings = sectionHeadings(livingText).filter((h) => isRequirementsHeading(h.text));\n if (reqHeadings.length > 1) {\n throw new ArchiveFailure(\n \"merge-failed\",\n `living capabilities/${doc.id}/spec.md has ${reqHeadings.length} '## Requirements' headings (lines ${reqHeadings.map((h) => h.line).join(\", \")}) — the merge rewrites ONE requirements section and cannot choose; merge them into one, then re-run`,\n );\n }\n const merged = applyRequirementDelta(parseRequirements(livingText), deltaReqs);\n writes.push(planWrite(livingPath, rewriteRequirementsRun(livingText, merged)));\n const c = summarize(deltaReqs);\n say(` capability: ${doc.id} ← +${c.ADDED} ~${c.MODIFIED} -${c.REMOVED} (now ${merged.length} total)`);\n }\n if (adopting && creating) {\n say(` capabilities/ did not exist — this archive opts the fleet into the business axis, and \\`loam validate --all\\` grades it from now on`);\n }\n}\n\n/**\n * Rewrite ONLY the requirements run of a living spec. Byte-for-byte preserved:\n * everything before the first requirement inside `## Requirements` (the intro,\n * the heading line, prose under the heading) and everything from the section's\n * end onward (the next `## ` heading to EOF) — the old cut was a substring\n * `indexOf(\"\\n## Requirements\")`, a prefix match that also hit\n * `## Requirements Extra` and silently destroyed every section after the\n * requirements. Prose BETWEEN requirements is body text of whatever is open\n * above it (parseRequirements attributes it to the previous requirement's last\n * scenario, or its text) and survives inside the re-serialized run, framing\n * normalized. `merged` must contain every living requirement — runArchive's\n * stray guard refuses any document whose requirements sit outside the section,\n * using the same heading definition, before this output is ever written.\n */\nfunction rewriteRequirementsRun(text: string, merged: Requirement[]): string {\n const s = splitRequirementsSection(text);\n // No `## Requirements` at all: the stray guard has already refused any doc\n // whose requirements live elsewhere, so this one has none — open the section.\n if (s === null) return `${text.trimEnd()}\\n\\n## Requirements\\n\\n${serializeRequirements(merged)}`;\n const body = serializeRequirements(merged);\n // head/tail are raw slices; only the run's own framing is normalized. When\n // the section held no requirements yet, the glue supplies the blank line the\n // author never had reason to write.\n const headGlue = s.run !== \"\" || s.head.endsWith(\"\\n\\n\") ? \"\" : s.head.endsWith(\"\\n\") ? \"\\n\" : \"\\n\\n\";\n const tailGlue = s.tail === \"\" ? \"\" : \"\\n\";\n return s.head + headGlue + body + tailGlue + s.tail;\n}\n\nfunction summarize(reqs: Requirement[]): { ADDED: number; MODIFIED: number; REMOVED: number } {\n const c = { ADDED: 0, MODIFIED: 0, REMOVED: 0 };\n for (const r of reqs) {\n if (r.kind === \"ADDED\") c.ADDED += 1;\n else if (r.kind === \"MODIFIED\") c.MODIFIED += 1;\n else if (r.kind === \"REMOVED\") c.REMOVED += 1;\n }\n return c;\n}\n\n/**\n * The vocabulary merge: each `features/<FEAT>/glossary/<term>.md` copied to\n * `glossary/<term>.md`.\n *\n * A WHOLE-FILE COPY, and there is nothing else it could be. A capability delta\n * is folded into a living document by the requirement algebra because the two\n * documents share identified parts; a term document has one part, and merging\n * two definitions of one word is not something a machine may attempt. So the\n * definition the author wrote in the feature IS the definition that lands,\n * verbatim — loam re-encodes it as UTF-8 through `readUtf8` and changes nothing\n * else, not even the trailing newline.\n *\n * CREATE-ONLY, which is why this loop has no other branch. A term the living\n * glossary already defines was refused at the gate (`glossary.term-exists`,\n * `core/glossary/delta.ts` has the reasoning), so by the time the plan runs\n * every path here is a file that does not exist. `planWrite` marks it\n * `exclusive`, so a race that created it between the gate and the commit fails\n * the write rather than overwriting somebody.\n *\n * AND IT SAYS SO OUT LOUD when it creates `glossary/`, exactly as\n * `planCapabilities` does for `capabilities/`: the directory's existence is the\n * axis's opt-in, so this merge changes what `loam validate --all` grades from\n * the next command on, and a merge that widens the fleet's own gate must not do\n * it silently.\n */\nexport async function planGlossary(\n config: { docsDir: DocsDir },\n gated: Gated,\n plan: Plan,\n say: (line?: string) => void,\n): Promise<void> {\n const glossary = await featureGlossary(gated.featureDir);\n if (!glossary.present || glossary.terms.length === 0) return;\n // Asked BEFORE the loop, because the loop is what would create it.\n const adopting = !existsSync(glossaryDir(config.docsDir));\n for (const term of glossary.terms) {\n plan.writes.push(planWrite(livingTermPath(config.docsDir, term.id), await readUtf8(term.path)));\n say(` glossary: ${term.id} — created glossary/${term.id}.md`);\n }\n if (adopting) {\n say(` glossary/ did not exist — this archive opts the fleet into the domain vocabulary, and \\`loam validate --all\\` grades it from now on`);\n }\n}\n"]}
1
+ {"version":3,"file":"specs.js","sourceRoot":"","sources":["../../../../src/commands/archive/plan/specs.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The requirements merge: the feature's ADDED/MODIFIED/REMOVED requirements\n * applied into each living service spec. The contract merges live beside it in\n * `./contracts/` — one file per axis, split out when the OpenAPI half made\n * this one carry two merges. What happens to the TEXT of one document lives in\n * `./document/`: the in-place rewrite of an existing requirements run, the\n * head of a document this merge creates, and where a merged link points once\n * the feature has moved.\n *\n * ONE code path for the pair of requirement-carrying files — the business\n * spec.md and the architecture arch.spec.md ride the same delta algebra, the\n * same prose-preserving rewrite and the same guards, parameterized by filename.\n * A fork here would be two places the merge could disagree.\n *\n * Nothing is written. Everything lands in the `Plan`, so a failure on any axis\n * leaves the living docs exactly as they were.\n */\nimport { existsSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { rebaseLinks } from \"../../../core/links/parse.js\";\nimport { planWrite, readUtf8 } from \"../../../core/staging/writes.js\";\nimport { featureSpecPaths, SPEC_AXES } from \"../../../core/repo/paths.js\";\nimport { capabilityDocsDir, glossaryDir, livingCapabilityPaths } from \"../../../core/repo/authored/paths.js\";\nimport { featureGlossary, livingTermPath } from \"../../../core/glossary/delta.js\";\nimport { enumeratedServiceIds, locateServicePaths } from \"../../../core/repo/service-target.js\";\nimport { introducedServices } from \"../../../core/projection/arch-slice.js\";\nimport { isRequirementsHeading, parseRequirements, sectionHeadings } from \"../../../core/document/parse.js\";\nimport { applyRequirementDelta, droppedBy, droppedSentence, type DroppedRow } from \"../../../core/document/apply.js\";\nimport { type Requirement } from \"../../../core/document/spec.js\";\nimport { movedUnderVouch, parseFrontmatter, stringField } from \"../../../core/document/frontmatter.js\";\nimport { CodedFailure } from \"../../../core/envelope/json.js\";\nimport { type Gated, type Plan } from \"./state.js\";\nimport { featureRetarget } from \"./document/links.js\";\nimport { createdDocument, hasPurpose } from \"./document/head.js\";\nimport { rewriteRequirementsRun } from \"./document/run.js\";\nimport type { DocsDir } from \"../../../core/kernel/ids/dirs.js\";\nimport type { FleetContext } from \"../../../core/fleet-context.js\";\n\nexport async function planSpecs(\n config: { docsDir: DocsDir; fleet: FleetContext },\n gated: Gated,\n plan: Plan,\n say: (line?: string) => void,\n): Promise<void> {\n const { featureDir, deltaServices } = gated;\n const { writes } = plan;\n // Where every file of the feature will be once this archive lands — the\n // glossary terms it copies out, everything else under features/archive/.\n const retarget = await featureRetarget(config.docsDir, gated);\n // Who the fleet already has, asked BEFORE any of this archive's writes, and\n // which of them this feature's own C4 delta introduces: a first spec.md for a\n // service that existed and was never adopted is the feature's slice, not the\n // service, and the create branch below says so in its frontmatter.\n const existing = new Set<string>(await enumeratedServiceIds(config.docsDir, config.fleet));\n const introduced = new Set(introducedServices(gated.deltaDoc ?? null, gated.id));\n // Requirements merge — apply ADDED/MODIFIED/REMOVED into each living service\n // spec. ONE code path for the pair of requirement-carrying files: the business\n // spec.md and the architecture arch.spec.md ride the same delta algebra, the\n // same prose-preserving rewrite and the same guards, parameterized by filename\n // (SPEC_AXES) — a fork here would be two places the merge could disagree.\n for (const svc of deltaServices) {\n for (const axis of SPEC_AXES) {\n const deltaPath = featureSpecPaths(featureDir, svc)[axis.key];\n if (!existsSync(deltaPath)) continue;\n\n // The shared context: this is a deltaServices × SPEC_AXES loop, and a\n // context-less locate is a full fleet walk per iteration.\n const livingPath = (await locateServicePaths(config.docsDir, svc, config.fleet))[axis.key];\n // Resolved BEFORE the delta is parsed, because the parse now depends on\n // it: a requirement's markdown links are relative to the file they were\n // written in, and this merge moves the text two directories up the tree.\n // `core/links/parse.ts`'s `rebaseLinks` states the defect; the ordering\n // here is what lets the fix see both ends of the move, including a\n // service filed under a subsystem, whose living directory is deeper still.\n // `retarget` is the other half: a link INTO the feature points at a file\n // this same archive moves (`./document/links.ts`).\n const delta = rebaseLinks(await readUtf8(deltaPath), { from: dirname(deltaPath), to: dirname(livingPath), retarget });\n const deltaReqs = parseRequirements(delta);\n if (!existsSync(livingPath)) {\n // New service (or first arch spec) — create the living file from the\n // ADDED/MODIFIED requirements, under the head `./document/head.ts` writes:\n // what the delta marked as the document's own, and a link to the rest.\n const created = applyRequirementDelta([], deltaReqs);\n if (created.length === 0) {\n say(` ${axis.label}: ${svc} — nothing to merge (delta leaves no requirements), no living ${axis.file} created`);\n continue;\n }\n // The business spec only: it is the document the maturity ladder and\n // `next.adopt` read as \"this service is written down\" (SCHEMA.md,\n // `adoption`). A service the feature introduces IS its slice — there was\n // nothing before it to adopt — so it is never marked.\n const unadopted = axis.key === \"spec\" && existing.has(svc) && !introduced.has(svc);\n const doc = createdDocument({\n docsDir: config.docsDir,\n featureId: gated.id,\n deltaPath,\n delta,\n livingPath,\n retarget,\n fallbackTitle: axis.key === \"spec\" ? svc : `${svc} — architecture`,\n service: svc,\n ...(unadopted ? { adoption: \"partial\" as const } : {}),\n requirements: created,\n });\n writes.push(planWrite(livingPath, doc.text));\n say(` ${axis.label}: ${svc} — created living ${axis.file} (${created.length} requirement(s))`);\n say(` ${doc.note}`);\n if (unadopted) {\n say(\n ` ${svc} existed before ${gated.id} and was never adopted — this spec.md holds only the feature's slice, so it is ` +\n `written \\`adoption: partial\\` and ${svc} stays owed its adoption: \\`loam adopt --service ${svc}\\`, then delete the line`,\n );\n }\n continue;\n }\n const livingText = await readUtf8(livingPath);\n // TWO `## Requirements` headings would put the rewrite's one-section\n // invariant to a choice it must not make: the run of the first would be\n // rewritten while the second survived verbatim in the tail — and its\n // requirements, collected by parseRequirements, would land in the run TOO.\n // Mechanical, like a model-less landscape, so merge-failed, not --approve.\n const reqHeadings = sectionHeadings(livingText).filter((h) => isRequirementsHeading(h.text));\n if (reqHeadings.length > 1) {\n throw new CodedFailure(\n \"merge-failed\",\n `living ${axis.file} for ${svc} has ${reqHeadings.length} '## Requirements' headings (lines ${reqHeadings.map((h) => h.line).join(\", \")}) — the merge rewrites ONE requirements section and cannot choose; merge them into one, then re-run`,\n );\n }\n const livingReqs = parseRequirements(livingText);\n const merged = applyRequirementDelta(livingReqs, deltaReqs);\n const next = rewriteRequirementsRun(livingText, livingReqs, merged);\n writes.push(planWrite(livingPath, next));\n // A merge is an edit to the document's body like any other, so a vouched\n // spec it moves goes `content.stale` — and honestly: the merged text is\n // words no person has yet read against the code. Archive does not soften\n // that. It names the document and its owner, so the re-vouch is known to\n // be owed while the merge is still a PR rather than discovered later as a\n // red `--strict` gate. Asked of the bytes about to be written, through the\n // one definition validate grades with.\n const fm = parseFrontmatter(next);\n if (movedUnderVouch(fm, next)) {\n plan.revouchOwed.push({ service: svc, path: livingPath, owner: stringField(fm, \"owner\") ?? null });\n }\n\n const c = summarize(deltaReqs);\n say(` ${axis.label}: ${svc} ← +${c.ADDED} ~${c.MODIFIED} -${c.REMOVED} (now ${merged.length} total)`);\n sayDropped(plan, say, livingPath, droppedBy(livingReqs, deltaReqs));\n if (hasPurpose(delta)) say(` ${PURPOSE_NOT_MERGED}`);\n }\n }\n}\n\n/**\n * A `## Purpose` in a delta against a document that already exists merges as\n * nothing — the living narrative is edited in place, never replaced by a merge\n * — and the author who wrote one expected it to land. Said, not refused: the\n * requirements are still exactly what they meant.\n */\nconst PURPOSE_NOT_MERGED =\n \"the delta's ## Purpose was not merged — the living document keeps its own narrative; edit it there in this change\";\n\n/**\n * The BUSINESS corpus's merge: a feature's `capabilities/<id>/spec.md` deltas\n * applied into the living `capabilities/<id>/spec.md`.\n *\n * Here rather than in a sixth file in this package because this module already\n * owns \"requirements merged into a living document\" — it owns the two-headings\n * refusal and the `applyRequirementDelta` call, and calls the same\n * `./document/` rewrite and head, and the business corpus needs all of them\n * unchanged. What differs from\n * `planSpecs` above is only where the living document lives and what a CREATED\n * one says at the top.\n *\n * ARCHIVE CREATES THE LIVING DOCUMENT, by exact analogy with the new-service\n * branch above. The directory IS the list on this axis (`core/capabilities/tree.ts`),\n * so an archive that merged into a file it refused to create would make the\n * whole delta merge nothing — which is the `delta.no-delta-sections` failure\n * class, arriving through the merge instead of through the grammar.\n *\n * NO FRONTMATTER on a created capability document, and that is a decision\n * rather than an omission. Nothing reads a capability document's frontmatter:\n * `readCapabilityTree` classifies by the file's PRESENCE and\n * `readCapabilityVocabulary` takes `description`/`owner` from the YAML side. A\n * `status:` field invented here would be the \"second list nothing keeps\n * current\" this axis was designed against.\n *\n * AND IT SAYS SO OUT LOUD. Creating the first `capabilities/<id>/spec.md`\n * creates `capabilities/`, which is one of the two ways a fleet opts INTO the\n * capability axis — from the next command on, `loam validate --all` grades a\n * corpus that did not exist before. A merge that changes what the whole fleet\n * is graded on must not do it silently.\n */\nexport async function planCapabilities(\n config: { docsDir: DocsDir; fleet: FleetContext },\n gated: Gated,\n plan: Plan,\n say: (line?: string) => void,\n): Promise<void> {\n const { writes } = plan;\n // Whether `capabilities/` exists is asked BEFORE the loop, because the loop\n // is what would create it; `creating` records whether this run actually\n // materialises a document, so the adoption line below is not printed by a\n // run whose every capability delta merged into a document already there.\n const adopting = !existsSync(capabilityDocsDir(config.docsDir));\n let creating = false;\n const retarget = await featureRetarget(config.docsDir, gated);\n for (const doc of gated.capabilityDeltas) {\n const livingPath = livingCapabilityPaths(config.docsDir, doc.id).spec;\n // Same move, same rewrite: `features/<FEAT>/capabilities/<id>/` is two\n // directories deeper than `capabilities/<id>/`, so a citation of a glossary\n // term or an ADR would land pointing above the repository — or, aimed into\n // the feature itself, at a file this archive moves.\n const delta = rebaseLinks(await readUtf8(doc.spec), { from: dirname(doc.spec), to: dirname(livingPath), retarget });\n const deltaReqs = parseRequirements(delta);\n if (!existsSync(livingPath)) {\n const created = applyRequirementDelta([], deltaReqs);\n if (created.length === 0) {\n say(` capability: ${doc.id} — nothing to merge (delta leaves no requirements), no living spec.md created`);\n continue;\n }\n // The heading is the id unless the delta titled the capability, and the\n // narrative is the delta's `## Purpose` or nothing: loam merges\n // requirements and never prose, so it must not fabricate the narrative\n // that is the whole point of the document — it carries only what the\n // author marked as the document's own (`./document/head.ts`), and the note\n // below tells them where the rest is.\n const living = createdDocument({\n docsDir: config.docsDir,\n featureId: gated.id,\n deltaPath: doc.spec,\n delta,\n livingPath,\n retarget,\n fallbackTitle: doc.id,\n service: null,\n requirements: created,\n });\n writes.push(planWrite(livingPath, living.text));\n creating = true;\n say(` capability: ${doc.id} — created capabilities/${doc.id}/spec.md (${created.length} requirement(s))`);\n say(` ${living.note}`);\n continue;\n }\n const livingText = await readUtf8(livingPath);\n // The same one-section invariant as the service axis above, and the same\n // reason it cannot be guessed at.\n const reqHeadings = sectionHeadings(livingText).filter((h) => isRequirementsHeading(h.text));\n if (reqHeadings.length > 1) {\n throw new CodedFailure(\n \"merge-failed\",\n `living capabilities/${doc.id}/spec.md has ${reqHeadings.length} '## Requirements' headings (lines ${reqHeadings.map((h) => h.line).join(\", \")}) — the merge rewrites ONE requirements section and cannot choose; merge them into one, then re-run`,\n );\n }\n const livingReqs = parseRequirements(livingText);\n const merged = applyRequirementDelta(livingReqs, deltaReqs);\n writes.push(planWrite(livingPath, rewriteRequirementsRun(livingText, livingReqs, merged)));\n const c = summarize(deltaReqs);\n say(` capability: ${doc.id} ← +${c.ADDED} ~${c.MODIFIED} -${c.REMOVED} (now ${merged.length} total)`);\n sayDropped(plan, say, livingPath, droppedBy(livingReqs, deltaReqs));\n if (hasPurpose(delta)) say(` ${PURPOSE_NOT_MERGED}`);\n }\n if (adopting && creating) {\n say(` capabilities/ did not exist — this archive opts the fleet into the business axis, and \\`loam validate --all\\` grades it from now on`);\n }\n}\n\n/**\n * What each replacement takes out of the living document, named under the\n * count line and carried as `--json` `dropped`. The counts alone were the whole\n * report — `~1` — while a MODIFIED that restated one of two scenarios, or wrote\n * `Covers:` without the `sli:` entries the living text had, merged at exit 0\n * and the rest was gone (`core/document/apply.ts` says why it is read verbatim\n * and by name). Said, never gated: rewriting a requirement smaller is a\n * legitimate change, and what was missing was only that nobody was told.\n */\nfunction sayDropped(plan: Plan, say: (line?: string) => void, path: string, rows: DroppedRow[]): void {\n for (const row of rows) {\n plan.dropped.push({ path, ...row });\n say(` ${row.kind === \"REMOVED\" ? \"-\" : \"~\"} ${droppedSentence(row)}`);\n }\n}\n\nfunction summarize(reqs: Requirement[]): { ADDED: number; MODIFIED: number; REMOVED: number } {\n const c = { ADDED: 0, MODIFIED: 0, REMOVED: 0 };\n for (const r of reqs) {\n if (r.kind === \"ADDED\") c.ADDED += 1;\n else if (r.kind === \"MODIFIED\") c.MODIFIED += 1;\n else if (r.kind === \"REMOVED\") c.REMOVED += 1;\n }\n return c;\n}\n\n/**\n * The vocabulary merge: each `features/<FEAT>/glossary/<term>.md` copied to\n * `glossary/<term>.md`.\n *\n * A WHOLE-FILE COPY, and there is nothing else it could be. A capability delta\n * is folded into a living document by the requirement algebra because the two\n * documents share identified parts; a term document has one part, and merging\n * two definitions of one word is not something a machine may attempt. So the\n * definition the author wrote in the feature IS the definition that lands —\n * loam re-encodes it as UTF-8 through `readUtf8` and changes nothing else, not\n * even the trailing newline, but the ROUTE of each relative link. That one\n * exception is the requirement merge's, for the requirement merge's reason: the\n * term moves from `features/<FEAT>/glossary/` to `glossary/`, two directories\n * up, so a definition citing a service spec or the feature's own ADR landed\n * pointing at nothing (`link.unresolved` on the very next `validate --all`,\n * against a document graded at fleet scope). Same `rebaseLinks`, same\n * `retarget`: the target is unchanged, only the way there.\n *\n * CREATE-ONLY, which is why this loop has no other branch. A term the living\n * glossary already defines was refused at the gate (`glossary.term-exists`,\n * `core/glossary/delta.ts` has the reasoning), so by the time the plan runs\n * every path here is a file that does not exist. `planWrite` marks it\n * `exclusive`, so a race that created it between the gate and the commit fails\n * the write rather than overwriting somebody.\n *\n * AND IT SAYS SO OUT LOUD when it creates `glossary/`, exactly as\n * `planCapabilities` does for `capabilities/`: the directory's existence is the\n * axis's opt-in, so this merge changes what `loam validate --all` grades from\n * the next command on, and a merge that widens the fleet's own gate must not do\n * it silently.\n */\nexport async function planGlossary(\n config: { docsDir: DocsDir },\n gated: Gated,\n plan: Plan,\n say: (line?: string) => void,\n): Promise<void> {\n const glossary = await featureGlossary(gated.featureDir);\n if (!glossary.present || glossary.terms.length === 0) return;\n // Asked BEFORE the loop, because the loop is what would create it.\n const adopting = !existsSync(glossaryDir(config.docsDir));\n const retarget = await featureRetarget(config.docsDir, gated);\n for (const term of glossary.terms) {\n const livingPath = livingTermPath(config.docsDir, term.id);\n const text = rebaseLinks(await readUtf8(term.path), { from: dirname(term.path), to: dirname(livingPath), retarget });\n plan.writes.push(planWrite(livingPath, text));\n say(` glossary: ${term.id} — created glossary/${term.id}.md`);\n }\n if (adopting) {\n say(` glossary/ did not exist — this archive opts the fleet into the domain vocabulary, and \\`loam validate --all\\` grades it from now on`);\n }\n}\n"]}
@@ -14,6 +14,7 @@ import {} from "../../../core/kernel/ids/service.js";
14
14
  import {} from "../../../core/c4/likec4.js";
15
15
  import {} from "../../../core/capabilities/tree.js";
16
16
  import {} from "../../../core/staging/interrupted.js";
17
+ import {} from "../../../core/document/apply.js";
17
18
  export function emptyPlan() {
18
19
  return {
19
20
  writes: [],
@@ -22,6 +23,8 @@ export function emptyPlan() {
22
23
  openapiRemovals: [],
23
24
  asyncapiRemovals: [],
24
25
  architectureServices: new Set(),
26
+ revouchOwed: [],
27
+ dropped: [],
25
28
  };
26
29
  }
27
30
  //# sourceMappingURL=state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../../src/commands/archive/plan/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAc,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAAqB,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAmB,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAwB,MAAM,qCAAqC,CAAC;AAC3E,OAAO,EAAkB,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAsB,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAuB,MAAM,sCAAsC,CAAC;AA6C3E,MAAM,UAAU,SAAS;IACvB,OAAO;QACL,MAAM,EAAE,EAAE;QACV,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,EAAE;QACb,eAAe,EAAE,EAAE;QACnB,gBAAgB,EAAE,EAAE;QACpB,oBAAoB,EAAE,IAAI,GAAG,EAAmB;KACjD,CAAC;AACJ,CAAC","sourcesContent":["/**\n * What one phase of an archive hands the next.\n *\n * `Gated` is everything the refusals resolved on the way through — the\n * canonical id, the delta document parsed once, the issue lists. `Plan` is what\n * the merges accumulate. Neither is a bag of conveniences: a value is in here\n * exactly when two phases have to agree about it, and the alternative was\n * fifteen parameters threaded through three functions in the same order.\n */\nimport { type Issue } from \"../../../core/vocabulary/issue.js\";\nimport { type PlannedWrite } from \"../../../core/staging/writes.js\";\nimport { type FeatureDir } from \"../../../core/kernel/ids/dirs.js\";\nimport { type PathableService } from \"../../../core/kernel/ids/service.js\";\nimport { type LoadedDoc } from \"../../../core/c4/likec4.js\";\nimport { type CapabilityDoc } from \"../../../core/capabilities/tree.js\";\nimport { type CommitRecovery } from \"../../../core/staging/interrupted.js\";\n\nexport interface Gated {\n /** The canonical feature id. The raw argument does not survive the gate. */\n id: string;\n dirName: string;\n featureDir: FeatureDir;\n /** Parsed ONCE for the whole run — loading it spins up a fresh Langium workspace. */\n deltaDoc: LoadedDoc | undefined;\n deltaServices: PathableService[];\n /**\n * The capability documents this feature's delta carries, walked ONCE in the\n * gate. Three phases downstream ask about them — the conflict-marker scan,\n * the strayed-requirement scan and the merge — and a second walk is a second\n * chance to disagree about which capabilities the merge touches.\n */\n capabilityDeltas: CapabilityDoc[];\n gating: Issue[];\n advisory: Issue[];\n archiveDir: string;\n archiveDest: string;\n /** The interrupted commit this run repaired, if any — `--json` reports it. */\n recovered: CommitRecovery | null;\n /** Every coherence issue the gate read, gating and advisory together. */\n issues: Issue[];\n}\n\nexport interface Plan {\n writes: PlannedWrite[];\n /**\n * Warnings born in the plan itself (openapi.op-modified,\n * openapi.component-modified, the asyncapi.*-modified trio) — printed with\n * the plan and carried into the `--json` envelope beside the coherence\n * warnings.\n */\n planWarns: Issue[];\n /** Gating issues born in the plan itself (openapi.ref-unresolved, asyncapi.ref-unresolved). */\n planGates: Issue[];\n openapiRemovals: Array<{ service: string; operations: string[] }>;\n /** Living asyncapi slots the plan deletes on removal markers, by their labels. */\n asyncapiRemovals: Array<{ service: string; slots: string[] }>;\n /** Services this feature introduces on the architecture axis alone. */\n architectureServices: Set<PathableService>;\n}\n\nexport function emptyPlan(): Plan {\n return {\n writes: [],\n planWarns: [],\n planGates: [],\n openapiRemovals: [],\n asyncapiRemovals: [],\n architectureServices: new Set<PathableService>(),\n };\n}\n"]}
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../../src/commands/archive/plan/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAc,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAAqB,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAmB,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAwB,MAAM,qCAAqC,CAAC;AAC3E,OAAO,EAAkB,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAsB,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAuB,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAmB,MAAM,iCAAiC,CAAC;AA+DlE,MAAM,UAAU,SAAS;IACvB,OAAO;QACL,MAAM,EAAE,EAAE;QACV,SAAS,EAAE,EAAE;QACb,SAAS,EAAE,EAAE;QACb,eAAe,EAAE,EAAE;QACnB,gBAAgB,EAAE,EAAE;QACpB,oBAAoB,EAAE,IAAI,GAAG,EAAmB;QAChD,WAAW,EAAE,EAAE;QACf,OAAO,EAAE,EAAE;KACZ,CAAC;AACJ,CAAC","sourcesContent":["/**\n * What one phase of an archive hands the next.\n *\n * `Gated` is everything the refusals resolved on the way through — the\n * canonical id, the delta document parsed once, the issue lists. `Plan` is what\n * the merges accumulate. Neither is a bag of conveniences: a value is in here\n * exactly when two phases have to agree about it, and the alternative was\n * fifteen parameters threaded through three functions in the same order.\n */\nimport { type Issue } from \"../../../core/vocabulary/issue.js\";\nimport { type PlannedWrite } from \"../../../core/staging/writes.js\";\nimport { type FeatureDir } from \"../../../core/kernel/ids/dirs.js\";\nimport { type PathableService } from \"../../../core/kernel/ids/service.js\";\nimport { type LoadedDoc } from \"../../../core/c4/likec4.js\";\nimport { type CapabilityDoc } from \"../../../core/capabilities/tree.js\";\nimport { type CommitRecovery } from \"../../../core/staging/interrupted.js\";\nimport { type DroppedRow } from \"../../../core/document/apply.js\";\n\nexport interface Gated {\n /** The canonical feature id. The raw argument does not survive the gate. */\n id: string;\n dirName: string;\n featureDir: FeatureDir;\n /** Parsed ONCE for the whole run — loading it spins up a fresh Langium workspace. */\n deltaDoc: LoadedDoc | undefined;\n deltaServices: PathableService[];\n /**\n * The capability documents this feature's delta carries, walked ONCE in the\n * gate. Three phases downstream ask about them — the conflict-marker scan,\n * the strayed-requirement scan and the merge — and a second walk is a second\n * chance to disagree about which capabilities the merge touches.\n */\n capabilityDeltas: CapabilityDoc[];\n gating: Issue[];\n advisory: Issue[];\n archiveDir: string;\n archiveDest: string;\n /** The interrupted commit this run repaired, if any — `--json` reports it. */\n recovered: CommitRecovery | null;\n /** Every coherence issue the gate read, gating and advisory together. */\n issues: Issue[];\n}\n\nexport interface Plan {\n writes: PlannedWrite[];\n /**\n * Warnings born in the plan itself (openapi.op-modified,\n * openapi.component-modified, the asyncapi.*-modified trio) — printed with\n * the plan and carried into the `--json` envelope beside the coherence\n * warnings. Every one of them is NON-GATING, which is not the same as being a\n * warning: `service.no-model` rides here at error severity with `gates: false`,\n * the grade validate gives the directory it names (../closing.ts prints it in\n * place of the closing line).\n */\n planWarns: Issue[];\n /** Gating issues born in the plan itself (openapi.ref-unresolved, asyncapi.ref-unresolved). */\n planGates: Issue[];\n openapiRemovals: Array<{ service: string; operations: string[] }>;\n /** Living asyncapi slots the plan deletes on removal markers, by their labels. */\n asyncapiRemovals: Array<{ service: string; slots: string[] }>;\n /** Services this feature introduces on the architecture axis alone. */\n architectureServices: Set<PathableService>;\n /**\n * Every vouched living spec this merge leaves out of step with its vouch\n * stamp — `content.stale` follows on each until its owner re-vouches.\n * `path` is absolute, like every planned write's, and made docs-relative\n * where it is printed; `owner` is the frontmatter's, or null when the\n * document names none. The `--json` payload carries it as `revouchOwed`.\n */\n revouchOwed: Array<{ service: string; path: string; owner: string | null }>;\n /**\n * What each requirement replacement takes out of a living document — the\n * scenarios and join-line entries a MODIFIED does not restate, and every\n * removal. `path` is absolute like `revouchOwed`'s, made docs-relative where\n * it is printed; the `--json` payload carries it as `dropped`.\n */\n dropped: Array<DroppedRow & { path: string }>;\n}\n\nexport function emptyPlan(): Plan {\n return {\n writes: [],\n planWarns: [],\n planGates: [],\n openapiRemovals: [],\n asyncapiRemovals: [],\n architectureServices: new Set<PathableService>(),\n revouchOwed: [],\n dropped: [],\n };\n}\n"]}