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

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 (1036) hide show
  1. package/CHANGELOG.md +2635 -86
  2. package/COMPARISON.md +80 -63
  3. package/CONTRIBUTING.md +84 -0
  4. package/MIGRATING-from-OpenSpec.md +213 -54
  5. package/QUICKSTART.md +125 -0
  6. package/README.md +450 -150
  7. package/ROADMAP.md +599 -0
  8. package/SCHEMA.md +2355 -256
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +701 -0
  11. package/dist/cli.js +113 -19
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +209 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +268 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +77 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/openapi.js +159 -0
  22. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  23. package/dist/commands/archive/plan/gate.js +323 -0
  24. package/dist/commands/archive/plan/gate.js.map +1 -0
  25. package/dist/commands/archive/plan/landscape.js +180 -0
  26. package/dist/commands/archive/plan/landscape.js.map +1 -0
  27. package/dist/commands/archive/plan/refusal.js +111 -0
  28. package/dist/commands/archive/plan/refusal.js.map +1 -0
  29. package/dist/commands/archive/plan/specs.js +237 -0
  30. package/dist/commands/archive/plan/specs.js.map +1 -0
  31. package/dist/commands/archive/plan/state.js +27 -0
  32. package/dist/commands/archive/plan/state.js.map +1 -0
  33. package/dist/commands/archive/run.js +252 -0
  34. package/dist/commands/archive/run.js.map +1 -0
  35. package/dist/commands/context/context.js +99 -0
  36. package/dist/commands/context/context.js.map +1 -0
  37. package/dist/commands/context/print.js +283 -0
  38. package/dist/commands/context/print.js.map +1 -0
  39. package/dist/commands/delta/delta.js +279 -0
  40. package/dist/commands/delta/delta.js.map +1 -0
  41. package/dist/commands/delta/print.js +205 -0
  42. package/dist/commands/delta/print.js.map +1 -0
  43. package/dist/commands/dependencies.js +9 -7
  44. package/dist/commands/dependencies.js.map +1 -1
  45. package/dist/commands/diff/diff.js +93 -0
  46. package/dist/commands/diff/diff.js.map +1 -0
  47. package/dist/commands/diff/print.js +38 -0
  48. package/dist/commands/diff/print.js.map +1 -0
  49. package/dist/commands/doctor.js +5 -4
  50. package/dist/commands/doctor.js.map +1 -1
  51. package/dist/commands/explain/explain.js +151 -0
  52. package/dist/commands/explain/explain.js.map +1 -0
  53. package/dist/commands/explore.js +29 -24
  54. package/dist/commands/explore.js.map +1 -1
  55. package/dist/commands/gate/gate.js +115 -0
  56. package/dist/commands/gate/gate.js.map +1 -0
  57. package/dist/commands/gate/print.js +54 -0
  58. package/dist/commands/gate/print.js.map +1 -0
  59. package/dist/commands/gherkin/commit.js +146 -0
  60. package/dist/commands/gherkin/commit.js.map +1 -0
  61. package/dist/commands/gherkin/gherkin.js +246 -0
  62. package/dist/commands/gherkin/gherkin.js.map +1 -0
  63. package/dist/commands/gherkin/reconcile.js +149 -0
  64. package/dist/commands/gherkin/reconcile.js.map +1 -0
  65. package/dist/commands/gherkin/render.js +77 -0
  66. package/dist/commands/gherkin/render.js.map +1 -0
  67. package/dist/commands/init/example.js +204 -0
  68. package/dist/commands/init/example.js.map +1 -0
  69. package/dist/commands/init/first-hour.js +28 -0
  70. package/dist/commands/init/first-hour.js.map +1 -0
  71. package/dist/commands/{init.js → init/init.js} +146 -71
  72. package/dist/commands/init/init.js.map +1 -0
  73. package/dist/commands/init/mcp.js +131 -0
  74. package/dist/commands/init/mcp.js.map +1 -0
  75. package/dist/commands/init/options.js +78 -0
  76. package/dist/commands/init/options.js.map +1 -0
  77. package/dist/commands/instructions.js +72 -14
  78. package/dist/commands/instructions.js.map +1 -1
  79. package/dist/commands/list/campaign/campaign.js +65 -0
  80. package/dist/commands/list/campaign/campaign.js.map +1 -0
  81. package/dist/commands/list/campaign/owners.js +65 -0
  82. package/dist/commands/list/campaign/owners.js.map +1 -0
  83. package/dist/commands/list/json.js +157 -0
  84. package/dist/commands/list/json.js.map +1 -0
  85. package/dist/commands/list/list.js +343 -0
  86. package/dist/commands/list/list.js.map +1 -0
  87. package/dist/commands/list/print.js +301 -0
  88. package/dist/commands/list/print.js.map +1 -0
  89. package/dist/commands/list/review.js +120 -0
  90. package/dist/commands/list/review.js.map +1 -0
  91. package/dist/commands/list/views.js +105 -0
  92. package/dist/commands/list/views.js.map +1 -0
  93. package/dist/commands/mcp/dispatch.js +183 -0
  94. package/dist/commands/mcp/dispatch.js.map +1 -0
  95. package/dist/commands/mcp/mcp.js +34 -0
  96. package/dist/commands/mcp/mcp.js.map +1 -0
  97. package/dist/commands/mcp/serve.js +55 -0
  98. package/dist/commands/mcp/serve.js.map +1 -0
  99. package/dist/commands/migrate-openspec/materialize/active.js +170 -0
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  101. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  102. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  103. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  104. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  105. package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
  106. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  107. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  108. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  109. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  110. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  111. package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
  112. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  113. package/dist/commands/migrate-openspec/openspec/error.js +19 -0
  114. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  115. package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
  116. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  117. package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
  118. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  119. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  120. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  121. package/dist/commands/migrate-openspec/print.js +89 -0
  122. package/dist/commands/migrate-openspec/print.js.map +1 -0
  123. package/dist/commands/new/commit.js +76 -0
  124. package/dist/commands/new/commit.js.map +1 -0
  125. package/dist/commands/new/new.js +283 -0
  126. package/dist/commands/new/new.js.map +1 -0
  127. package/dist/commands/new/templates.js +355 -0
  128. package/dist/commands/new/templates.js.map +1 -0
  129. package/dist/commands/open.js +203 -0
  130. package/dist/commands/open.js.map +1 -0
  131. package/dist/commands/policy/format.js +152 -0
  132. package/dist/commands/policy/format.js.map +1 -0
  133. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
  134. package/dist/commands/policy/gate.js.map +1 -0
  135. package/dist/commands/rebase/edit.js +106 -0
  136. package/dist/commands/rebase/edit.js.map +1 -0
  137. package/dist/commands/rebase/living.js +185 -0
  138. package/dist/commands/rebase/living.js.map +1 -0
  139. package/dist/commands/rebase/plan.js +245 -0
  140. package/dist/commands/rebase/plan.js.map +1 -0
  141. package/dist/commands/rebase/rebase.js +275 -0
  142. package/dist/commands/rebase/rebase.js.map +1 -0
  143. package/dist/commands/seed/commit.js +192 -0
  144. package/dist/commands/seed/commit.js.map +1 -0
  145. package/dist/commands/seed/plan.js +133 -0
  146. package/dist/commands/seed/plan.js.map +1 -0
  147. package/dist/commands/seed/seed.js +172 -0
  148. package/dist/commands/seed/seed.js.map +1 -0
  149. package/dist/commands/show/feature.js +178 -0
  150. package/dist/commands/show/feature.js.map +1 -0
  151. package/dist/commands/show/marks.js +24 -0
  152. package/dist/commands/show/marks.js.map +1 -0
  153. package/dist/commands/{show.js → show/service.js} +63 -152
  154. package/dist/commands/show/service.js.map +1 -0
  155. package/dist/commands/show/show.js +77 -0
  156. package/dist/commands/show/show.js.map +1 -0
  157. package/dist/commands/status/json.js +45 -0
  158. package/dist/commands/status/json.js.map +1 -0
  159. package/dist/commands/status/print.js +157 -0
  160. package/dist/commands/status/print.js.map +1 -0
  161. package/dist/commands/status/status.js +119 -0
  162. package/dist/commands/status/status.js.map +1 -0
  163. package/dist/commands/steps/steps.js +189 -0
  164. package/dist/commands/steps/steps.js.map +1 -0
  165. package/dist/commands/subsystem/edit.js +192 -0
  166. package/dist/commands/subsystem/edit.js.map +1 -0
  167. package/dist/commands/subsystem/move.js +265 -0
  168. package/dist/commands/subsystem/move.js.map +1 -0
  169. package/dist/commands/subsystem/query.js +115 -0
  170. package/dist/commands/subsystem/query.js.map +1 -0
  171. package/dist/commands/subsystem/subsystem.js +101 -0
  172. package/dist/commands/subsystem/subsystem.js.map +1 -0
  173. package/dist/commands/subsystem/sync.js +103 -0
  174. package/dist/commands/subsystem/sync.js.map +1 -0
  175. package/dist/commands/subsystem/txn/txn.js +94 -0
  176. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  177. package/dist/commands/subsystem/txn/views.js +70 -0
  178. package/dist/commands/subsystem/txn/views.js.map +1 -0
  179. package/dist/commands/unarchive/manifest.js +160 -0
  180. package/dist/commands/unarchive/manifest.js.map +1 -0
  181. package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
  182. package/dist/commands/unarchive/restore.js.map +1 -0
  183. package/dist/commands/unarchive/unarchive.js +67 -0
  184. package/dist/commands/unarchive/unarchive.js.map +1 -0
  185. package/dist/commands/validate/arch-coverage.js +204 -0
  186. package/dist/commands/validate/arch-coverage.js.map +1 -0
  187. package/dist/commands/validate/checks/fleet-shape.js +296 -0
  188. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  189. package/dist/commands/validate/checks/health-deps.js +55 -0
  190. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  191. package/dist/commands/validate/checks/requirements.js +254 -0
  192. package/dist/commands/validate/checks/requirements.js.map +1 -0
  193. package/dist/commands/validate/checks/sources.js +76 -0
  194. package/dist/commands/validate/checks/sources.js.map +1 -0
  195. package/dist/commands/validate/checks/vocabulary.js +31 -0
  196. package/dist/commands/validate/checks/vocabulary.js.map +1 -0
  197. package/dist/commands/validate/feature.js +216 -0
  198. package/dist/commands/validate/feature.js.map +1 -0
  199. package/dist/commands/validate/fleet/census.js +69 -0
  200. package/dist/commands/validate/fleet/census.js.map +1 -0
  201. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  202. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  203. package/dist/commands/validate/fleet/landscape.js +353 -0
  204. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  205. package/dist/commands/validate/fleet/load.js +52 -0
  206. package/dist/commands/validate/fleet/load.js.map +1 -0
  207. package/dist/commands/validate/fleet/obligations.js +270 -0
  208. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  209. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  210. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  211. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  212. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  213. package/dist/commands/validate/fleet/scorecard/print.js +63 -0
  214. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  215. package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
  216. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  217. package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
  218. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
  219. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  220. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  221. package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
  222. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
  223. package/dist/commands/validate/fleet/usecases/steps.js +197 -0
  224. package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
  225. package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
  226. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
  227. package/dist/commands/validate/fleet/views/ids.js +40 -0
  228. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  229. package/dist/commands/validate/fleet/views/stale.js +59 -0
  230. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  231. package/dist/commands/validate/links/corpus.js +92 -0
  232. package/dist/commands/validate/links/corpus.js.map +1 -0
  233. package/dist/commands/validate/links/glossary.js +75 -0
  234. package/dist/commands/validate/links/glossary.js.map +1 -0
  235. package/dist/commands/validate/report.js +269 -0
  236. package/dist/commands/validate/report.js.map +1 -0
  237. package/dist/commands/validate/service/api.js +338 -0
  238. package/dist/commands/validate/service/api.js.map +1 -0
  239. package/dist/commands/validate/service/events/events.js +219 -0
  240. package/dist/commands/validate/service/events/events.js.map +1 -0
  241. package/dist/commands/validate/service/events/message-producers.js +77 -0
  242. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  243. package/dist/commands/validate/service/evidence-pins.js +131 -0
  244. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  245. package/dist/commands/validate/service/service.js +251 -0
  246. package/dist/commands/validate/service/service.js.map +1 -0
  247. package/dist/commands/validate/service/specs.js +251 -0
  248. package/dist/commands/validate/service/specs.js.map +1 -0
  249. package/dist/commands/validate/service/spine.js +113 -0
  250. package/dist/commands/validate/service/spine.js.map +1 -0
  251. package/dist/commands/validate/validate.js +338 -0
  252. package/dist/commands/validate/validate.js.map +1 -0
  253. package/dist/commands/verify/cross/diff.js +182 -0
  254. package/dist/commands/verify/cross/diff.js.map +1 -0
  255. package/dist/commands/verify/evidence/contract.js +32 -0
  256. package/dist/commands/verify/evidence/contract.js.map +1 -0
  257. package/dist/commands/verify/evidence/pins.js +52 -0
  258. package/dist/commands/verify/evidence/pins.js.map +1 -0
  259. package/dist/commands/verify/evidence/read.js +72 -0
  260. package/dist/commands/verify/evidence/read.js.map +1 -0
  261. package/dist/commands/verify/frozen.js +241 -0
  262. package/dist/commands/verify/frozen.js.map +1 -0
  263. package/dist/commands/verify/record.js +226 -0
  264. package/dist/commands/verify/record.js.map +1 -0
  265. package/dist/commands/verify/report.js +223 -0
  266. package/dist/commands/verify/report.js.map +1 -0
  267. package/dist/commands/verify/results.js +246 -0
  268. package/dist/commands/verify/results.js.map +1 -0
  269. package/dist/commands/verify/verify.js +217 -0
  270. package/dist/commands/verify/verify.js.map +1 -0
  271. package/dist/commands/vouch/contract.js +11 -0
  272. package/dist/commands/vouch/contract.js.map +1 -0
  273. package/dist/commands/vouch/pack/contract.js +2 -0
  274. package/dist/commands/vouch/pack/contract.js.map +1 -0
  275. package/dist/commands/vouch/pack/pack.js +266 -0
  276. package/dist/commands/vouch/pack/pack.js.map +1 -0
  277. package/dist/commands/vouch/pack/print.js +271 -0
  278. package/dist/commands/vouch/pack/print.js.map +1 -0
  279. package/dist/commands/vouch/pack/sections.js +142 -0
  280. package/dist/commands/vouch/pack/sections.js.map +1 -0
  281. package/dist/commands/vouch/prompt/confirm.js +46 -0
  282. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  283. package/dist/commands/vouch/report.js +101 -0
  284. package/dist/commands/vouch/report.js.map +1 -0
  285. package/dist/commands/vouch/run.js +285 -0
  286. package/dist/commands/vouch/run.js.map +1 -0
  287. package/dist/commands/vouch/sample/plan.js +125 -0
  288. package/dist/commands/vouch/sample/plan.js.map +1 -0
  289. package/dist/commands/vouch/sample/print.js +109 -0
  290. package/dist/commands/vouch/sample/print.js.map +1 -0
  291. package/dist/commands/vouch/vet/verify.js +123 -0
  292. package/dist/commands/vouch/vet/verify.js.map +1 -0
  293. package/dist/commands/vouch/vouch.js +176 -0
  294. package/dist/commands/vouch/vouch.js.map +1 -0
  295. package/dist/core/agent/agents-md/artifacts.js +220 -0
  296. package/dist/core/agent/agents-md/artifacts.js.map +1 -0
  297. package/dist/core/agent/agents-md/command-map.js +324 -0
  298. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  299. package/dist/core/agent/agents-md/cycle.js +165 -0
  300. package/dist/core/agent/agents-md/cycle.js.map +1 -0
  301. package/dist/core/agent/agents-md/map/explain.js +34 -0
  302. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  303. package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
  304. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  305. package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
  306. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  307. package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
  308. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  309. package/dist/core/agent/agents-md/map/mcp.js +41 -0
  310. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  311. package/dist/core/agent/agents-md/map/status.js +62 -0
  312. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  313. package/dist/core/agent/agents-md/map/subsystem.js +32 -0
  314. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  315. package/dist/core/agent/agents-md/map/usecases.js +60 -0
  316. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  317. package/dist/core/agent/agents-md/refusals.js +246 -0
  318. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  319. package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
  320. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
  321. package/dist/core/agent/agents-md/spine.js +40 -0
  322. package/dist/core/agent/agents-md/spine.js.map +1 -0
  323. package/dist/core/agent/agents-md.js +170 -0
  324. package/dist/core/agent/agents-md.js.map +1 -0
  325. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +50 -0
  326. package/dist/core/agent/agents-stamp.js.map +1 -0
  327. package/dist/core/agent/contract.js +2 -0
  328. package/dist/core/agent/contract.js.map +1 -0
  329. package/dist/core/agent/protocol.js +193 -0
  330. package/dist/core/agent/protocol.js.map +1 -0
  331. package/dist/core/agent/scaffold.js +259 -0
  332. package/dist/core/agent/scaffold.js.map +1 -0
  333. package/dist/core/agent/support/report.js +103 -0
  334. package/dist/core/agent/support/report.js.map +1 -0
  335. package/dist/core/agent/tools/dialects.js +150 -0
  336. package/dist/core/agent/tools/dialects.js.map +1 -0
  337. package/dist/core/agent/tools/registry.js +228 -0
  338. package/dist/core/agent/tools/registry.js.map +1 -0
  339. package/dist/core/agent/workflows/adopt.js +133 -0
  340. package/dist/core/agent/workflows/adopt.js.map +1 -0
  341. package/dist/core/agent/workflows/check.js +337 -0
  342. package/dist/core/agent/workflows/check.js.map +1 -0
  343. package/dist/core/agent/workflows/closing.js +262 -0
  344. package/dist/core/agent/workflows/closing.js.map +1 -0
  345. package/dist/core/agent/workflows/feature.js +105 -0
  346. package/dist/core/agent/workflows/feature.js.map +1 -0
  347. package/dist/core/agent/workflows/implement.js +105 -0
  348. package/dist/core/agent/workflows/implement.js.map +1 -0
  349. package/dist/core/agent/workflows/reference/authoring.js +209 -0
  350. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  351. package/dist/core/agent/workflows/reference/codes.js +65 -0
  352. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  353. package/dist/core/agent/workflows/reference/done-check.js +188 -0
  354. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  355. package/dist/core/agent/workflows/reference/reference.js +16 -0
  356. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  357. package/dist/core/agent/workflows/reference/spine.js +297 -0
  358. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  359. package/dist/core/asyncapi/baseline/plan.js +110 -0
  360. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  361. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  362. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  363. package/dist/core/asyncapi/depth.js +164 -0
  364. package/dist/core/asyncapi/depth.js.map +1 -0
  365. package/dist/core/asyncapi/digest.js +141 -0
  366. package/dist/core/asyncapi/digest.js.map +1 -0
  367. package/dist/core/asyncapi/merge/components.js +91 -0
  368. package/dist/core/asyncapi/merge/components.js.map +1 -0
  369. package/dist/core/asyncapi/merge/error.js +33 -0
  370. package/dist/core/asyncapi/merge/error.js.map +1 -0
  371. package/dist/core/asyncapi/merge/markers.js +308 -0
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  373. package/dist/core/asyncapi/merge/merge.js +215 -0
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  375. package/dist/core/asyncapi/merge/pin.js +107 -0
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  377. package/dist/core/asyncapi/model.js +11 -0
  378. package/dist/core/asyncapi/model.js.map +1 -0
  379. package/dist/core/asyncapi/producers.js +50 -0
  380. package/dist/core/asyncapi/producers.js.map +1 -0
  381. package/dist/core/{asyncapi.js → asyncapi/read.js} +95 -109
  382. package/dist/core/asyncapi/read.js.map +1 -0
  383. package/dist/core/brief/brief.js +225 -0
  384. package/dist/core/brief/brief.js.map +1 -0
  385. package/dist/core/brief/checks.js +250 -0
  386. package/dist/core/brief/checks.js.map +1 -0
  387. package/dist/core/brief/landscape.js +194 -0
  388. package/dist/core/brief/landscape.js.map +1 -0
  389. package/dist/core/brief/targets.js +226 -0
  390. package/dist/core/brief/targets.js.map +1 -0
  391. package/dist/core/brief/unchecked.js +48 -0
  392. package/dist/core/brief/unchecked.js.map +1 -0
  393. package/dist/core/c4/arch.js +174 -0
  394. package/dist/core/c4/arch.js.map +1 -0
  395. package/dist/core/c4/likec4.js +90 -0
  396. package/dist/core/c4/likec4.js.map +1 -0
  397. package/dist/core/c4/parsed/deployment.js +158 -0
  398. package/dist/core/c4/parsed/deployment.js.map +1 -0
  399. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  400. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  401. package/dist/core/c4/parsed/specification.js +78 -0
  402. package/dist/core/c4/parsed/specification.js.map +1 -0
  403. package/dist/core/c4/parsed/values.js +57 -0
  404. package/dist/core/c4/parsed/values.js.map +1 -0
  405. package/dist/core/c4/parsed/view-ids.js +75 -0
  406. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  407. package/dist/core/c4/project/architecture.js +45 -0
  408. package/dist/core/c4/project/architecture.js.map +1 -0
  409. package/dist/core/c4/project/documents.js +58 -0
  410. package/dist/core/c4/project/documents.js.map +1 -0
  411. package/dist/core/c4/project/load.js +187 -0
  412. package/dist/core/c4/project/load.js.map +1 -0
  413. package/dist/core/c4/project/staged.js +220 -0
  414. package/dist/core/c4/project/staged.js.map +1 -0
  415. package/dist/core/c4/resolve/service.js +159 -0
  416. package/dist/core/c4/resolve/service.js.map +1 -0
  417. package/dist/core/c4/resolve/steps.js +144 -0
  418. package/dist/core/c4/resolve/steps.js.map +1 -0
  419. package/dist/core/c4/seed/fleet-file.js +201 -0
  420. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  421. package/dist/core/c4/seed/items.js +91 -0
  422. package/dist/core/c4/seed/items.js.map +1 -0
  423. package/dist/core/c4/seed/stamp.js +48 -0
  424. package/dist/core/c4/seed/stamp.js.map +1 -0
  425. package/dist/core/c4/seed/template.js +109 -0
  426. package/dist/core/c4/seed/template.js.map +1 -0
  427. package/dist/core/c4/source-mask.js +82 -0
  428. package/dist/core/c4/source-mask.js.map +1 -0
  429. package/dist/core/c4/source-scan.js +227 -0
  430. package/dist/core/c4/source-scan.js.map +1 -0
  431. package/dist/core/c4/splice/authored-source.js +101 -0
  432. package/dist/core/c4/splice/authored-source.js.map +1 -0
  433. package/dist/core/c4/splice/contract.js +10 -0
  434. package/dist/core/c4/splice/contract.js.map +1 -0
  435. package/dist/core/c4/splice/delta-blocks.js +139 -0
  436. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  437. package/dist/core/c4/splice/identity/edges.js +36 -0
  438. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  439. package/dist/core/c4/splice/landscape-merge.js +269 -0
  440. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  441. package/dist/core/c4/splice/placement.js +194 -0
  442. package/dist/core/c4/splice/placement.js.map +1 -0
  443. package/dist/core/c4/workspace.js +174 -0
  444. package/dist/core/c4/workspace.js.map +1 -0
  445. package/dist/core/capabilities/authoring/notes.js +141 -0
  446. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  447. package/dist/core/capabilities/capabilities.js +124 -0
  448. package/dist/core/capabilities/capabilities.js.map +1 -0
  449. package/dist/core/capabilities/delta/doc.js +50 -0
  450. package/dist/core/capabilities/delta/doc.js.map +1 -0
  451. package/dist/core/capabilities/delta/overlay.js +129 -0
  452. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  453. package/dist/core/capabilities/delta/summary.js +57 -0
  454. package/dist/core/capabilities/delta/summary.js.map +1 -0
  455. package/dist/core/capabilities/delta/tree.js +43 -0
  456. package/dist/core/capabilities/delta/tree.js.map +1 -0
  457. package/dist/core/capabilities/delta/uncovered.js +222 -0
  458. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  459. package/dist/core/capabilities/findings.js +342 -0
  460. package/dist/core/capabilities/findings.js.map +1 -0
  461. package/dist/core/capabilities/realizes/findings.js +181 -0
  462. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  463. package/dist/core/capabilities/realizes/join.js +143 -0
  464. package/dist/core/capabilities/realizes/join.js.map +1 -0
  465. package/dist/core/capabilities/rollup.js +199 -0
  466. package/dist/core/capabilities/rollup.js.map +1 -0
  467. package/dist/core/capabilities/tree.js +126 -0
  468. package/dist/core/capabilities/tree.js.map +1 -0
  469. package/dist/core/capabilities/usecase-join.js +277 -0
  470. package/dist/core/capabilities/usecase-join.js.map +1 -0
  471. package/dist/core/coherence/authoring/scaffold.js +177 -0
  472. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  473. package/dist/core/coherence/authoring/sentinels.js +74 -0
  474. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  475. package/dist/core/coherence/coherence.js +287 -0
  476. package/dist/core/coherence/coherence.js.map +1 -0
  477. package/dist/core/coherence/declared.js +269 -0
  478. package/dist/core/coherence/declared.js.map +1 -0
  479. package/dist/core/coherence/events/declared.js +206 -0
  480. package/dist/core/coherence/events/declared.js.map +1 -0
  481. package/dist/core/coherence/events/events.js +204 -0
  482. package/dist/core/coherence/events/events.js.map +1 -0
  483. package/dist/core/coherence/events/grades.js +166 -0
  484. package/dist/core/coherence/events/grades.js.map +1 -0
  485. package/dist/core/coherence/events/lookups.js +122 -0
  486. package/dist/core/coherence/events/lookups.js.map +1 -0
  487. package/dist/core/coherence/events/merged.js +40 -0
  488. package/dist/core/coherence/events/merged.js.map +1 -0
  489. package/dist/core/coherence/living.js +198 -0
  490. package/dist/core/coherence/living.js.map +1 -0
  491. package/dist/core/coherence/lookups.js +155 -0
  492. package/dist/core/coherence/lookups.js.map +1 -0
  493. package/dist/core/coherence/pending.js +39 -0
  494. package/dist/core/coherence/pending.js.map +1 -0
  495. package/dist/core/conflict-markers.js +60 -0
  496. package/dist/core/conflict-markers.js.map +1 -0
  497. package/dist/core/delta/claims.js +73 -0
  498. package/dist/core/delta/claims.js.map +1 -0
  499. package/dist/core/delta/delta.js +296 -0
  500. package/dist/core/delta/delta.js.map +1 -0
  501. package/dist/core/delta/document.js +177 -0
  502. package/dist/core/delta/document.js.map +1 -0
  503. package/dist/core/delta/scope.js +48 -0
  504. package/dist/core/delta/scope.js.map +1 -0
  505. package/dist/core/delta/select.js +237 -0
  506. package/dist/core/delta/select.js.map +1 -0
  507. package/dist/core/dependencies/dependencies.js +141 -0
  508. package/dist/core/dependencies/dependencies.js.map +1 -0
  509. package/dist/core/dependencies/facts.js +165 -0
  510. package/dist/core/dependencies/facts.js.map +1 -0
  511. package/dist/core/dependencies/fanin.js +88 -0
  512. package/dist/core/dependencies/fanin.js.map +1 -0
  513. package/dist/core/dependencies/graph.js +106 -0
  514. package/dist/core/dependencies/graph.js.map +1 -0
  515. package/dist/core/deployment/delta.js +188 -0
  516. package/dist/core/deployment/delta.js.map +1 -0
  517. package/dist/core/deployment/objects.js +145 -0
  518. package/dist/core/deployment/objects.js.map +1 -0
  519. package/dist/core/diff/base-git.js +148 -0
  520. package/dist/core/diff/base-git.js.map +1 -0
  521. package/dist/core/diff/base-state.js +209 -0
  522. package/dist/core/diff/base-state.js.map +1 -0
  523. package/dist/core/diff/current-state.js +96 -0
  524. package/dist/core/diff/current-state.js.map +1 -0
  525. package/dist/core/diff/scope/changed-paths.js +188 -0
  526. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  527. package/dist/core/diff/semantic.js +243 -0
  528. package/dist/core/diff/semantic.js.map +1 -0
  529. package/dist/core/diff/victims.js +247 -0
  530. package/dist/core/diff/victims.js.map +1 -0
  531. package/dist/core/docs.js +7 -64
  532. package/dist/core/docs.js.map +1 -1
  533. package/dist/core/doctor/agents.js +222 -0
  534. package/dist/core/doctor/agents.js.map +1 -0
  535. package/dist/core/doctor/config.js +135 -0
  536. package/dist/core/doctor/config.js.map +1 -0
  537. package/dist/core/doctor/doctor.js +275 -0
  538. package/dist/core/doctor/doctor.js.map +1 -0
  539. package/dist/core/doctor/report.js +13 -0
  540. package/dist/core/doctor/report.js.map +1 -0
  541. package/dist/core/doctor/residue.js +110 -0
  542. package/dist/core/doctor/residue.js.map +1 -0
  543. package/dist/core/document/apply.js +77 -0
  544. package/dist/core/document/apply.js.map +1 -0
  545. package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
  546. package/dist/core/document/frontmatter.js.map +1 -0
  547. package/dist/core/document/grammar/directives.js +143 -0
  548. package/dist/core/document/grammar/directives.js.map +1 -0
  549. package/dist/core/document/parse.js +263 -0
  550. package/dist/core/document/parse.js.map +1 -0
  551. package/dist/core/document/scenarios.js +221 -0
  552. package/dist/core/document/scenarios.js.map +1 -0
  553. package/dist/core/document/spec.js +241 -0
  554. package/dist/core/document/spec.js.map +1 -0
  555. package/dist/core/{config.js → envelope/config.js} +79 -18
  556. package/dist/core/envelope/config.js.map +1 -0
  557. package/dist/core/envelope/json.js +175 -0
  558. package/dist/core/envelope/json.js.map +1 -0
  559. package/dist/core/{version.js → envelope/version.js} +3 -3
  560. package/dist/core/envelope/version.js.map +1 -0
  561. package/dist/core/explain/families.js +175 -0
  562. package/dist/core/explain/families.js.map +1 -0
  563. package/dist/core/explain/fix-tables.js +178 -0
  564. package/dist/core/explain/fix-tables.js.map +1 -0
  565. package/dist/core/explain/lookup.js +181 -0
  566. package/dist/core/explain/lookup.js.map +1 -0
  567. package/dist/core/explain/refusals.js +49 -0
  568. package/dist/core/explain/refusals.js.map +1 -0
  569. package/dist/core/explain/terms.js +144 -0
  570. package/dist/core/explain/terms.js.map +1 -0
  571. package/dist/core/explore/describe.js +105 -0
  572. package/dist/core/explore/describe.js.map +1 -0
  573. package/dist/core/{explore.js → explore/explore.js} +50 -101
  574. package/dist/core/explore/explore.js.map +1 -0
  575. package/dist/core/fleet-context.js +120 -78
  576. package/dist/core/fleet-context.js.map +1 -1
  577. package/dist/core/gate/checks.js +201 -0
  578. package/dist/core/gate/checks.js.map +1 -0
  579. package/dist/core/gate/partners.js +205 -0
  580. package/dist/core/gate/partners.js.map +1 -0
  581. package/dist/core/gate/report.js +47 -0
  582. package/dist/core/gate/report.js.map +1 -0
  583. package/dist/core/gate/verification.js +113 -0
  584. package/dist/core/gate/verification.js.map +1 -0
  585. package/dist/core/gherkin/digest.js +60 -0
  586. package/dist/core/gherkin/digest.js.map +1 -0
  587. package/dist/core/gherkin/emit.js +177 -0
  588. package/dist/core/gherkin/emit.js.map +1 -0
  589. package/dist/core/gherkin/read.js +76 -0
  590. package/dist/core/gherkin/read.js.map +1 -0
  591. package/dist/core/gherkin/stale.js +234 -0
  592. package/dist/core/gherkin/stale.js.map +1 -0
  593. package/dist/core/gherkin/stamp.js +77 -0
  594. package/dist/core/gherkin/stamp.js.map +1 -0
  595. package/dist/core/gherkin/steps/catalogue.js +154 -0
  596. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  597. package/dist/core/gherkin/steps/inventory.js +98 -0
  598. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  599. package/dist/core/gherkin/steps/phrase.js +72 -0
  600. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  601. package/dist/core/glossary/delta.js +106 -0
  602. package/dist/core/glossary/delta.js.map +1 -0
  603. package/dist/core/glossary/tree.js +86 -0
  604. package/dist/core/glossary/tree.js.map +1 -0
  605. package/dist/core/kernel/concurrency.js.map +1 -0
  606. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  607. package/dist/core/kernel/document-bytes.js.map +1 -0
  608. package/dist/core/kernel/fences.js +42 -0
  609. package/dist/core/kernel/fences.js.map +1 -0
  610. package/dist/core/kernel/ids/capability.js +72 -0
  611. package/dist/core/kernel/ids/capability.js.map +1 -0
  612. package/dist/core/kernel/ids/dirs.js +33 -0
  613. package/dist/core/kernel/ids/dirs.js.map +1 -0
  614. package/dist/core/kernel/ids/feature.js +75 -0
  615. package/dist/core/kernel/ids/feature.js.map +1 -0
  616. package/dist/core/kernel/ids/service.js +156 -0
  617. package/dist/core/kernel/ids/service.js.map +1 -0
  618. package/dist/core/kernel/ids/subsystem.js +63 -0
  619. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  620. package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
  621. package/dist/core/kernel/path-safety.js.map +1 -0
  622. package/dist/core/kernel/records.js.map +1 -0
  623. package/dist/core/links/backlinks.js +68 -0
  624. package/dist/core/links/backlinks.js.map +1 -0
  625. package/dist/core/links/case.js +74 -0
  626. package/dist/core/links/case.js.map +1 -0
  627. package/dist/core/links/corpus.js +104 -0
  628. package/dist/core/links/corpus.js.map +1 -0
  629. package/dist/core/links/findings.js +110 -0
  630. package/dist/core/links/findings.js.map +1 -0
  631. package/dist/core/links/parse.js +236 -0
  632. package/dist/core/links/parse.js.map +1 -0
  633. package/dist/core/mcp/argv.js +111 -0
  634. package/dist/core/mcp/argv.js.map +1 -0
  635. package/dist/core/mcp/author-tools.js +72 -0
  636. package/dist/core/mcp/author-tools.js.map +1 -0
  637. package/dist/core/mcp/framing.js +46 -0
  638. package/dist/core/mcp/framing.js.map +1 -0
  639. package/dist/core/mcp/protocol.js +280 -0
  640. package/dist/core/mcp/protocol.js.map +1 -0
  641. package/dist/core/mcp/tools.js +314 -0
  642. package/dist/core/mcp/tools.js.map +1 -0
  643. package/dist/core/obligations/obligations.js +106 -0
  644. package/dist/core/obligations/obligations.js.map +1 -0
  645. package/dist/core/openapi/baseline/gate.js +166 -0
  646. package/dist/core/openapi/baseline/gate.js.map +1 -0
  647. package/dist/core/openapi/baseline/plan.js +112 -0
  648. package/dist/core/openapi/baseline/plan.js.map +1 -0
  649. package/dist/core/openapi/baseline/record.js +175 -0
  650. package/dist/core/openapi/baseline/record.js.map +1 -0
  651. package/dist/core/openapi/depth.js +122 -0
  652. package/dist/core/openapi/depth.js.map +1 -0
  653. package/dist/core/openapi/digest.js +189 -0
  654. package/dist/core/openapi/digest.js.map +1 -0
  655. package/dist/core/{openapi.js → openapi/doc.js} +44 -106
  656. package/dist/core/openapi/doc.js.map +1 -0
  657. package/dist/core/openapi/merge/components.js +234 -0
  658. package/dist/core/openapi/merge/components.js.map +1 -0
  659. package/dist/core/openapi/merge/error.js +26 -0
  660. package/dist/core/openapi/merge/error.js.map +1 -0
  661. package/dist/core/openapi/merge/markers.js +208 -0
  662. package/dist/core/openapi/merge/markers.js.map +1 -0
  663. package/dist/core/openapi/merge/merge.js +256 -0
  664. package/dist/core/openapi/merge/merge.js.map +1 -0
  665. package/dist/core/openapi/merge/pin.js +128 -0
  666. package/dist/core/openapi/merge/pin.js.map +1 -0
  667. package/dist/core/openspec/decide/capabilities.js +244 -0
  668. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  669. package/dist/core/openspec/decide/dispositions.js +63 -0
  670. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  671. package/dist/core/openspec/decide/renames.js +179 -0
  672. package/dist/core/openspec/decide/renames.js.map +1 -0
  673. package/dist/core/openspec/decide/verdict.js +84 -0
  674. package/dist/core/openspec/decide/verdict.js.map +1 -0
  675. package/dist/core/openspec/inventory.js +221 -0
  676. package/dist/core/openspec/inventory.js.map +1 -0
  677. package/dist/core/openspec/model/mapping.js +76 -0
  678. package/dist/core/openspec/model/mapping.js.map +1 -0
  679. package/dist/core/openspec/model/model.js +65 -0
  680. package/dist/core/openspec/model/model.js.map +1 -0
  681. package/dist/core/openspec/scan/changes.js +235 -0
  682. package/dist/core/openspec/scan/changes.js.map +1 -0
  683. package/dist/core/openspec/scan/config.js +200 -0
  684. package/dist/core/openspec/scan/config.js.map +1 -0
  685. package/dist/core/openspec/scan/shape.js +260 -0
  686. package/dist/core/openspec/scan/shape.js.map +1 -0
  687. package/dist/core/openspec/scan/walk.js +133 -0
  688. package/dist/core/openspec/scan/walk.js.map +1 -0
  689. package/dist/core/openspec/scan/workspace.js +71 -0
  690. package/dist/core/openspec/scan/workspace.js.map +1 -0
  691. package/dist/core/owners/codeowners.js +141 -0
  692. package/dist/core/owners/codeowners.js.map +1 -0
  693. package/dist/core/pack/features.js +120 -0
  694. package/dist/core/pack/features.js.map +1 -0
  695. package/dist/core/pack/joins.js +112 -0
  696. package/dist/core/pack/joins.js.map +1 -0
  697. package/dist/core/pack/living.js +137 -0
  698. package/dist/core/pack/living.js.map +1 -0
  699. package/dist/core/pack/pack.js +76 -0
  700. package/dist/core/pack/pack.js.map +1 -0
  701. package/dist/core/permissions/permissions.js +87 -0
  702. package/dist/core/permissions/permissions.js.map +1 -0
  703. package/dist/core/projection/api.js +84 -0
  704. package/dist/core/projection/api.js.map +1 -0
  705. package/dist/core/projection/arch-slice.js +63 -0
  706. package/dist/core/projection/arch-slice.js.map +1 -0
  707. package/dist/core/projection/events.js +34 -0
  708. package/dist/core/projection/events.js.map +1 -0
  709. package/dist/core/provenance/findings.js +208 -0
  710. package/dist/core/provenance/findings.js.map +1 -0
  711. package/dist/core/provenance/git.js +225 -0
  712. package/dist/core/provenance/git.js.map +1 -0
  713. package/dist/core/provenance/gitq/moves.js +182 -0
  714. package/dist/core/provenance/gitq/moves.js.map +1 -0
  715. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  716. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  717. package/dist/core/provenance/sample/scope.js +238 -0
  718. package/dist/core/provenance/sample/scope.js.map +1 -0
  719. package/dist/core/provenance/sample/sections.js +61 -0
  720. package/dist/core/provenance/sample/sections.js.map +1 -0
  721. package/dist/core/provenance/sources.js +263 -0
  722. package/dist/core/provenance/sources.js.map +1 -0
  723. package/dist/core/provenance/stamp.js +232 -0
  724. package/dist/core/provenance/stamp.js.map +1 -0
  725. package/dist/core/provenance/walk.js +157 -0
  726. package/dist/core/provenance/walk.js.map +1 -0
  727. package/dist/core/repo/authored/paths.js +210 -0
  728. package/dist/core/repo/authored/paths.js.map +1 -0
  729. package/dist/core/repo/entries.js +126 -0
  730. package/dist/core/repo/entries.js.map +1 -0
  731. package/dist/core/repo/paths.js +277 -0
  732. package/dist/core/repo/paths.js.map +1 -0
  733. package/dist/core/repo/repo.js +248 -0
  734. package/dist/core/repo/repo.js.map +1 -0
  735. package/dist/core/repo/service-target.js +153 -0
  736. package/dist/core/repo/service-target.js.map +1 -0
  737. package/dist/core/repo/state.js +58 -0
  738. package/dist/core/repo/state.js.map +1 -0
  739. package/dist/core/repo/tree/find.js +52 -0
  740. package/dist/core/repo/tree/find.js.map +1 -0
  741. package/dist/core/repo/tree/fs.js +64 -0
  742. package/dist/core/repo/tree/fs.js.map +1 -0
  743. package/dist/core/repo/tree/marker.js +61 -0
  744. package/dist/core/repo/tree/marker.js.map +1 -0
  745. package/dist/core/repo/tree/views.js +172 -0
  746. package/dist/core/repo/tree/views.js.map +1 -0
  747. package/dist/core/repo/tree/walk.js +234 -0
  748. package/dist/core/repo/tree/walk.js.map +1 -0
  749. package/dist/core/results.js +99 -2
  750. package/dist/core/results.js.map +1 -1
  751. package/dist/core/scaffold/landscape.js +131 -0
  752. package/dist/core/scaffold/landscape.js.map +1 -0
  753. package/dist/core/scaffold/readme.js +84 -0
  754. package/dist/core/scaffold/readme.js.map +1 -0
  755. package/dist/core/staging/commit.js +241 -0
  756. package/dist/core/staging/commit.js.map +1 -0
  757. package/dist/core/staging/interrupted.js +96 -0
  758. package/dist/core/staging/interrupted.js.map +1 -0
  759. package/dist/core/staging/lock.js +206 -0
  760. package/dist/core/staging/lock.js.map +1 -0
  761. package/dist/core/staging/recovery/finding.js +35 -0
  762. package/dist/core/staging/recovery/finding.js.map +1 -0
  763. package/dist/core/staging/recovery/intent.js +98 -0
  764. package/dist/core/staging/recovery/intent.js.map +1 -0
  765. package/dist/core/staging/recovery/recover.js +126 -0
  766. package/dist/core/staging/recovery/recover.js.map +1 -0
  767. package/dist/core/staging/recovery/residue.js +62 -0
  768. package/dist/core/staging/recovery/residue.js.map +1 -0
  769. package/dist/core/staging/snapshot.js +202 -0
  770. package/dist/core/staging/snapshot.js.map +1 -0
  771. package/dist/core/staging/txn/forward.js +171 -0
  772. package/dist/core/staging/txn/forward.js.map +1 -0
  773. package/dist/core/staging/txn/journal.js +139 -0
  774. package/dist/core/staging/txn/journal.js.map +1 -0
  775. package/dist/core/staging/txn/transaction.js +75 -0
  776. package/dist/core/staging/txn/transaction.js.map +1 -0
  777. package/dist/core/staging/writes.js +113 -0
  778. package/dist/core/staging/writes.js.map +1 -0
  779. package/dist/core/status/actions/execution.js +49 -0
  780. package/dist/core/status/actions/execution.js.map +1 -0
  781. package/dist/core/status/contracts.js +102 -0
  782. package/dist/core/status/contracts.js.map +1 -0
  783. package/dist/core/status/feature/artifacts.js +196 -0
  784. package/dist/core/status/feature/artifacts.js.map +1 -0
  785. package/dist/core/status/feature/feature.js +207 -0
  786. package/dist/core/status/feature/feature.js.map +1 -0
  787. package/dist/core/status/feature/next.js +150 -0
  788. package/dist/core/status/feature/next.js.map +1 -0
  789. package/dist/core/status/feature/state.js +21 -0
  790. package/dist/core/status/feature/state.js.map +1 -0
  791. package/dist/core/status/fleet/fleet.js +197 -0
  792. package/dist/core/status/fleet/fleet.js.map +1 -0
  793. package/dist/core/status/fleet/next.js +207 -0
  794. package/dist/core/status/fleet/next.js.map +1 -0
  795. package/dist/core/status/interrupted.js +97 -0
  796. package/dist/core/status/interrupted.js.map +1 -0
  797. package/dist/core/status/report.js +31 -0
  798. package/dist/core/status/report.js.map +1 -0
  799. package/dist/core/status/scan.js +41 -0
  800. package/dist/core/status/scan.js.map +1 -0
  801. package/dist/core/status/verification.js +201 -0
  802. package/dist/core/status/verification.js.map +1 -0
  803. package/dist/core/usecases/capability.js +169 -0
  804. package/dist/core/usecases/capability.js.map +1 -0
  805. package/dist/core/usecases/delta/claims.js +116 -0
  806. package/dist/core/usecases/delta/claims.js.map +1 -0
  807. package/dist/core/usecases/delta/flows.js +103 -0
  808. package/dist/core/usecases/delta/flows.js.map +1 -0
  809. package/dist/core/usecases/delta/overlay.js +72 -0
  810. package/dist/core/usecases/delta/overlay.js.map +1 -0
  811. package/dist/core/usecases/fleet.js +137 -0
  812. package/dist/core/usecases/fleet.js.map +1 -0
  813. package/dist/core/usecases/operations.js +111 -0
  814. package/dist/core/usecases/operations.js.map +1 -0
  815. package/dist/core/usecases/place.js +44 -0
  816. package/dist/core/usecases/place.js.map +1 -0
  817. package/dist/core/usecases/touch.js +101 -0
  818. package/dist/core/usecases/touch.js.map +1 -0
  819. package/dist/core/verify/answers.js +173 -0
  820. package/dist/core/verify/answers.js.map +1 -0
  821. package/dist/core/verify/build.js +150 -0
  822. package/dist/core/verify/build.js.map +1 -0
  823. package/dist/core/verify/checklist.js +201 -0
  824. package/dist/core/verify/checklist.js.map +1 -0
  825. package/dist/core/verify/claims/identity.js +61 -0
  826. package/dist/core/verify/claims/identity.js.map +1 -0
  827. package/dist/core/verify/cross/diff.js +97 -0
  828. package/dist/core/verify/cross/diff.js.map +1 -0
  829. package/dist/core/verify/evidence/contract.js +169 -0
  830. package/dist/core/verify/evidence/contract.js.map +1 -0
  831. package/dist/core/verify/file.js +257 -0
  832. package/dist/core/verify/file.js.map +1 -0
  833. package/dist/core/verify/pins/lint.js +157 -0
  834. package/dist/core/verify/pins/lint.js.map +1 -0
  835. package/dist/core/verify/pins/pin.js +95 -0
  836. package/dist/core/verify/pins/pin.js.map +1 -0
  837. package/dist/core/verify/record.js +142 -0
  838. package/dist/core/verify/record.js.map +1 -0
  839. package/dist/core/verify/store/commit.js +89 -0
  840. package/dist/core/verify/store/commit.js.map +1 -0
  841. package/dist/core/verify/store/render.js +57 -0
  842. package/dist/core/verify/store/render.js.map +1 -0
  843. package/dist/core/vocabulary/health.js +91 -0
  844. package/dist/core/vocabulary/health.js.map +1 -0
  845. package/dist/core/vocabulary/issue.js +58 -0
  846. package/dist/core/vocabulary/issue.js.map +1 -0
  847. package/dist/core/vocabulary/maturity.js +145 -0
  848. package/dist/core/vocabulary/maturity.js.map +1 -0
  849. package/dist/core/{report.js → vocabulary/report.js} +30 -2
  850. package/dist/core/vocabulary/report.js.map +1 -0
  851. package/dist/core/vocabulary/steps.js +266 -0
  852. package/dist/core/vocabulary/steps.js.map +1 -0
  853. package/dist/core/workspace/discover.js +239 -0
  854. package/dist/core/workspace/discover.js.map +1 -0
  855. package/dist/core/workspace/render.js +52 -0
  856. package/dist/core/workspace/render.js.map +1 -0
  857. package/examples/README.md +189 -0
  858. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  859. package/examples/docs/architecture/capabilities.yaml +31 -0
  860. package/examples/docs/architecture/landscape.likec4 +280 -0
  861. package/examples/docs/architecture/obligations.yaml +23 -0
  862. package/examples/docs/architecture/permissions.yaml +50 -0
  863. package/examples/docs/architecture/subsystems.likec4 +11 -0
  864. package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
  865. package/examples/docs/capabilities/checkout/spec.md +55 -0
  866. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  867. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  868. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  869. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  870. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  871. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  872. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
  873. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  874. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  875. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  876. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  877. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  878. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
  879. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  880. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  881. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  882. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  883. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  884. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  885. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  886. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  887. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  888. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  889. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
  890. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  891. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  892. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  893. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  894. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  895. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  896. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  897. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  898. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  899. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  900. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  901. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  902. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  903. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  904. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  905. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  906. package/examples/docs/glossary/order.md +15 -0
  907. package/examples/docs/glossary/payments/authorization.md +14 -0
  908. package/examples/docs/likec4.config.json +9 -0
  909. package/examples/docs/loam.json +3 -0
  910. package/examples/docs/services/checkout-web/model.likec4 +109 -0
  911. package/examples/docs/services/checkout-web/spec.md +91 -0
  912. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  913. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  914. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  915. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  916. package/examples/docs/services/order-service/arch.spec.md +127 -0
  917. package/examples/docs/services/order-service/asyncapi.yaml +108 -0
  918. package/examples/docs/services/order-service/health.yaml +57 -0
  919. package/examples/docs/services/order-service/model.likec4 +138 -0
  920. package/examples/docs/services/order-service/openapi.yaml +257 -0
  921. package/examples/docs/services/order-service/runbook.md +62 -0
  922. package/examples/docs/services/order-service/spec.md +134 -0
  923. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  924. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  925. package/examples/docs/services/payment-service/arch.spec.md +73 -0
  926. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  927. package/examples/docs/services/payment-service/health.yaml +39 -0
  928. package/examples/docs/services/payment-service/model.likec4 +67 -0
  929. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  930. package/examples/docs/services/payment-service/runbook.md +37 -0
  931. package/examples/docs/services/payment-service/spec.md +88 -0
  932. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  933. package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
  934. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  935. package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
  936. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  937. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  938. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  939. package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
  940. package/examples/docs/services/platform/notification-service/health.yaml +35 -0
  941. package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
  942. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  943. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  944. package/examples/docs/services/platform/subsystem.yaml +2 -0
  945. package/examples/fleet.yaml +57 -0
  946. package/package.json +19 -6
  947. package/dist/commands/adopt.js +0 -240
  948. package/dist/commands/adopt.js.map +0 -1
  949. package/dist/commands/archive.js +0 -1313
  950. package/dist/commands/archive.js.map +0 -1
  951. package/dist/commands/delta.js +0 -388
  952. package/dist/commands/delta.js.map +0 -1
  953. package/dist/commands/docs-repo-gate.js.map +0 -1
  954. package/dist/commands/format.js +0 -17
  955. package/dist/commands/format.js.map +0 -1
  956. package/dist/commands/gherkin.js +0 -309
  957. package/dist/commands/gherkin.js.map +0 -1
  958. package/dist/commands/init.js.map +0 -1
  959. package/dist/commands/list.js +0 -295
  960. package/dist/commands/list.js.map +0 -1
  961. package/dist/commands/migrate-openspec.js +0 -950
  962. package/dist/commands/migrate-openspec.js.map +0 -1
  963. package/dist/commands/new.js +0 -413
  964. package/dist/commands/new.js.map +0 -1
  965. package/dist/commands/rebase.js +0 -356
  966. package/dist/commands/rebase.js.map +0 -1
  967. package/dist/commands/show.js.map +0 -1
  968. package/dist/commands/status.js +0 -262
  969. package/dist/commands/status.js.map +0 -1
  970. package/dist/commands/unarchive.js.map +0 -1
  971. package/dist/commands/validate.js +0 -1773
  972. package/dist/commands/validate.js.map +0 -1
  973. package/dist/commands/verify.js +0 -775
  974. package/dist/commands/verify.js.map +0 -1
  975. package/dist/commands/vouch.js +0 -421
  976. package/dist/commands/vouch.js.map +0 -1
  977. package/dist/core/agent.js +0 -2173
  978. package/dist/core/agent.js.map +0 -1
  979. package/dist/core/agents-stamp.js.map +0 -1
  980. package/dist/core/arch.js +0 -130
  981. package/dist/core/arch.js.map +0 -1
  982. package/dist/core/asyncapi.js.map +0 -1
  983. package/dist/core/brief.js +0 -755
  984. package/dist/core/brief.js.map +0 -1
  985. package/dist/core/coherence.js +0 -577
  986. package/dist/core/coherence.js.map +0 -1
  987. package/dist/core/concurrency.js.map +0 -1
  988. package/dist/core/config.js.map +0 -1
  989. package/dist/core/delta.js +0 -476
  990. package/dist/core/delta.js.map +0 -1
  991. package/dist/core/dependencies.js +0 -356
  992. package/dist/core/dependencies.js.map +0 -1
  993. package/dist/core/doctor.js +0 -596
  994. package/dist/core/doctor.js.map +0 -1
  995. package/dist/core/document-bytes.js.map +0 -1
  996. package/dist/core/explore.js.map +0 -1
  997. package/dist/core/frontmatter.js.map +0 -1
  998. package/dist/core/gherkin.js +0 -463
  999. package/dist/core/gherkin.js.map +0 -1
  1000. package/dist/core/health.js +0 -67
  1001. package/dist/core/health.js.map +0 -1
  1002. package/dist/core/ids.js +0 -122
  1003. package/dist/core/ids.js.map +0 -1
  1004. package/dist/core/issue.js +0 -9
  1005. package/dist/core/issue.js.map +0 -1
  1006. package/dist/core/json.js +0 -74
  1007. package/dist/core/json.js.map +0 -1
  1008. package/dist/core/likec4.js +0 -489
  1009. package/dist/core/likec4.js.map +0 -1
  1010. package/dist/core/maturity.js +0 -66
  1011. package/dist/core/maturity.js.map +0 -1
  1012. package/dist/core/openapi-merge.js +0 -552
  1013. package/dist/core/openapi-merge.js.map +0 -1
  1014. package/dist/core/openapi.js.map +0 -1
  1015. package/dist/core/openspec-inventory.js +0 -1440
  1016. package/dist/core/openspec-inventory.js.map +0 -1
  1017. package/dist/core/path-safety.js.map +0 -1
  1018. package/dist/core/provenance.js +0 -787
  1019. package/dist/core/provenance.js.map +0 -1
  1020. package/dist/core/records.js.map +0 -1
  1021. package/dist/core/repo.js +0 -438
  1022. package/dist/core/repo.js.map +0 -1
  1023. package/dist/core/report.js.map +0 -1
  1024. package/dist/core/spec.js +0 -505
  1025. package/dist/core/spec.js.map +0 -1
  1026. package/dist/core/staging.js +0 -890
  1027. package/dist/core/staging.js.map +0 -1
  1028. package/dist/core/status.js +0 -1132
  1029. package/dist/core/status.js.map +0 -1
  1030. package/dist/core/steps.js +0 -72
  1031. package/dist/core/steps.js.map +0 -1
  1032. package/dist/core/verify.js +0 -807
  1033. package/dist/core/verify.js.map +0 -1
  1034. package/dist/core/version.js.map +0 -1
  1035. /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
  1036. /package/dist/core/{records.js → kernel/records.js} +0 -0
@@ -0,0 +1,237 @@
1
+ /**
2
+ * The requirements merge: the feature's ADDED/MODIFIED/REMOVED requirements
3
+ * applied into each living service spec. The contract merges live beside it in
4
+ * `./contracts/` — one file per axis, split out when the OpenAPI half made
5
+ * this one carry two merges.
6
+ *
7
+ * ONE code path for the pair of requirement-carrying files — the business
8
+ * spec.md and the architecture arch.spec.md ride the same delta algebra, the
9
+ * same prose-preserving rewrite and the same guards, parameterized by filename.
10
+ * A fork here would be two places the merge could disagree.
11
+ *
12
+ * Nothing is written. Everything lands in the `Plan`, so a failure on any axis
13
+ * leaves the living docs exactly as they were.
14
+ */
15
+ import { existsSync } from "node:fs";
16
+ import { dirname } from "node:path";
17
+ import { rebaseLinks } from "../../../core/links/parse.js";
18
+ import { planWrite, readUtf8 } from "../../../core/staging/writes.js";
19
+ import { featureSpecPaths, SPEC_AXES } from "../../../core/repo/paths.js";
20
+ import { capabilityDocsDir, glossaryDir, livingCapabilityPaths } from "../../../core/repo/authored/paths.js";
21
+ 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";
26
+ import {} from "../../../core/document/spec.js";
27
+ import { ArchiveFailure } from "./refusal.js";
28
+ import {} from "./state.js";
29
+ export async function planSpecs(config, gated, plan, say) {
30
+ const { featureDir, deltaServices } = gated;
31
+ const { writes } = plan;
32
+ // Requirements merge — apply ADDED/MODIFIED/REMOVED into each living service
33
+ // spec. ONE code path for the pair of requirement-carrying files: the business
34
+ // spec.md and the architecture arch.spec.md ride the same delta algebra, the
35
+ // same prose-preserving rewrite and the same guards, parameterized by filename
36
+ // (SPEC_AXES) — a fork here would be two places the merge could disagree.
37
+ for (const svc of deltaServices) {
38
+ for (const axis of SPEC_AXES) {
39
+ const deltaPath = featureSpecPaths(featureDir, svc)[axis.key];
40
+ if (!existsSync(deltaPath))
41
+ continue;
42
+ // The shared context: this is a deltaServices × SPEC_AXES loop, and a
43
+ // context-less locate is a full fleet walk per iteration.
44
+ const livingPath = (await locateServicePaths(config.docsDir, svc, config.fleet))[axis.key];
45
+ // Resolved BEFORE the delta is parsed, because the parse now depends on
46
+ // it: a requirement's markdown links are relative to the file they were
47
+ // written in, and this merge moves the text two directories up the tree.
48
+ // `core/links/parse.ts`'s `rebaseLinks` states the defect; the ordering
49
+ // here is what lets the fix see both ends of the move, including a
50
+ // 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) }));
52
+ if (!existsSync(livingPath)) {
53
+ // New service (or first arch spec) — create the living file from the
54
+ // ADDED/MODIFIED requirements.
55
+ const created = applyRequirementDelta([], deltaReqs);
56
+ if (created.length === 0) {
57
+ say(` ${axis.label}: ${svc} — nothing to merge (delta leaves no requirements), no living ${axis.file} created`);
58
+ continue;
59
+ }
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)}`));
63
+ say(` ${axis.label}: ${svc} — created living ${axis.file} (${created.length} requirement(s))`);
64
+ continue;
65
+ }
66
+ const livingText = await readUtf8(livingPath);
67
+ // TWO `## Requirements` headings would put the rewrite's one-section
68
+ // invariant to a choice it must not make: the run of the first would be
69
+ // rewritten while the second survived verbatim in the tail — and its
70
+ // requirements, collected by parseRequirements, would land in the run TOO.
71
+ // Mechanical, like a model-less landscape, so merge-failed, not --approve.
72
+ const reqHeadings = sectionHeadings(livingText).filter((h) => isRequirementsHeading(h.text));
73
+ 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`);
75
+ }
76
+ const merged = applyRequirementDelta(parseRequirements(livingText), deltaReqs);
77
+ writes.push(planWrite(livingPath, rewriteRequirementsRun(livingText, merged)));
78
+ const c = summarize(deltaReqs);
79
+ say(` ${axis.label}: ${svc} ← +${c.ADDED} ~${c.MODIFIED} -${c.REMOVED} (now ${merged.length} total)`);
80
+ }
81
+ }
82
+ }
83
+ /**
84
+ * The BUSINESS corpus's merge: a feature's `capabilities/<id>/spec.md` deltas
85
+ * applied into the living `capabilities/<id>/spec.md`.
86
+ *
87
+ * 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
91
+ * `planSpecs` above is only where the living document lives and what a CREATED
92
+ * one says at the top.
93
+ *
94
+ * ARCHIVE CREATES THE LIVING DOCUMENT, by exact analogy with the new-service
95
+ * branch above. The directory IS the list on this axis (`core/capabilities/tree.ts`),
96
+ * so an archive that merged into a file it refused to create would make the
97
+ * whole delta merge nothing — which is the `delta.no-delta-sections` failure
98
+ * class, arriving through the merge instead of through the grammar.
99
+ *
100
+ * NO FRONTMATTER on a created capability document, and that is a decision
101
+ * rather than an omission. Nothing reads a capability document's frontmatter:
102
+ * `readCapabilityTree` classifies by the file's PRESENCE and
103
+ * `readCapabilityVocabulary` takes `description`/`owner` from the YAML side. A
104
+ * `status:` field invented here would be the "second list nothing keeps
105
+ * current" this axis was designed against.
106
+ *
107
+ * AND IT SAYS SO OUT LOUD. Creating the first `capabilities/<id>/spec.md`
108
+ * creates `capabilities/`, which is one of the two ways a fleet opts INTO the
109
+ * capability axis — from the next command on, `loam validate --all` grades a
110
+ * corpus that did not exist before. A merge that changes what the whole fleet
111
+ * is graded on must not do it silently.
112
+ */
113
+ export async function planCapabilities(config, gated, plan, say) {
114
+ const { writes } = plan;
115
+ // Whether `capabilities/` exists is asked BEFORE the loop, because the loop
116
+ // is what would create it; `creating` records whether this run actually
117
+ // materialises a document, so the adoption line below is not printed by a
118
+ // run whose every capability delta merged into a document already there.
119
+ const adopting = !existsSync(capabilityDocsDir(config.docsDir));
120
+ let creating = false;
121
+ for (const doc of gated.capabilityDeltas) {
122
+ const livingPath = livingCapabilityPaths(config.docsDir, doc.id).spec;
123
+ // Same move, same rewrite: `features/<FEAT>/capabilities/<id>/` is two
124
+ // 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) }));
127
+ if (!existsSync(livingPath)) {
128
+ const created = applyRequirementDelta([], deltaReqs);
129
+ if (created.length === 0) {
130
+ say(` capability: ${doc.id} — nothing to merge (delta leaves no requirements), no living spec.md created`);
131
+ continue;
132
+ }
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)}`));
137
+ creating = true;
138
+ 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`);
140
+ continue;
141
+ }
142
+ const livingText = await readUtf8(livingPath);
143
+ // The same one-section invariant as the service axis above, and the same
144
+ // reason it cannot be guessed at.
145
+ const reqHeadings = sectionHeadings(livingText).filter((h) => isRequirementsHeading(h.text));
146
+ 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`);
148
+ }
149
+ const merged = applyRequirementDelta(parseRequirements(livingText), deltaReqs);
150
+ writes.push(planWrite(livingPath, rewriteRequirementsRun(livingText, merged)));
151
+ const c = summarize(deltaReqs);
152
+ say(` capability: ${doc.id} ← +${c.ADDED} ~${c.MODIFIED} -${c.REMOVED} (now ${merged.length} total)`);
153
+ }
154
+ if (adopting && creating) {
155
+ say(` capabilities/ did not exist — this archive opts the fleet into the business axis, and \`loam validate --all\` grades it from now on`);
156
+ }
157
+ }
158
+ /**
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.
171
+ */
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;
185
+ }
186
+ function summarize(reqs) {
187
+ const c = { ADDED: 0, MODIFIED: 0, REMOVED: 0 };
188
+ for (const r of reqs) {
189
+ if (r.kind === "ADDED")
190
+ c.ADDED += 1;
191
+ else if (r.kind === "MODIFIED")
192
+ c.MODIFIED += 1;
193
+ else if (r.kind === "REMOVED")
194
+ c.REMOVED += 1;
195
+ }
196
+ return c;
197
+ }
198
+ /**
199
+ * The vocabulary merge: each `features/<FEAT>/glossary/<term>.md` copied to
200
+ * `glossary/<term>.md`.
201
+ *
202
+ * A WHOLE-FILE COPY, and there is nothing else it could be. A capability delta
203
+ * is folded into a living document by the requirement algebra because the two
204
+ * documents share identified parts; a term document has one part, and merging
205
+ * 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.
209
+ *
210
+ * CREATE-ONLY, which is why this loop has no other branch. A term the living
211
+ * glossary already defines was refused at the gate (`glossary.term-exists`,
212
+ * `core/glossary/delta.ts` has the reasoning), so by the time the plan runs
213
+ * every path here is a file that does not exist. `planWrite` marks it
214
+ * `exclusive`, so a race that created it between the gate and the commit fails
215
+ * the write rather than overwriting somebody.
216
+ *
217
+ * AND IT SAYS SO OUT LOUD when it creates `glossary/`, exactly as
218
+ * `planCapabilities` does for `capabilities/`: the directory's existence is the
219
+ * axis's opt-in, so this merge changes what `loam validate --all` grades from
220
+ * the next command on, and a merge that widens the fleet's own gate must not do
221
+ * it silently.
222
+ */
223
+ export async function planGlossary(config, gated, plan, say) {
224
+ const glossary = await featureGlossary(gated.featureDir);
225
+ if (!glossary.present || glossary.terms.length === 0)
226
+ return;
227
+ // Asked BEFORE the loop, because the loop is what would create it.
228
+ const adopting = !existsSync(glossaryDir(config.docsDir));
229
+ for (const term of glossary.terms) {
230
+ plan.writes.push(planWrite(livingTermPath(config.docsDir, term.id), await readUtf8(term.path)));
231
+ say(` glossary: ${term.id} — created glossary/${term.id}.md`);
232
+ }
233
+ if (adopting) {
234
+ say(` glossary/ did not exist — this archive opts the fleet into the domain vocabulary, and \`loam validate --all\` grades it from now on`);
235
+ }
236
+ }
237
+ //# sourceMappingURL=specs.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * What one phase of an archive hands the next.
3
+ *
4
+ * `Gated` is everything the refusals resolved on the way through — the
5
+ * canonical id, the delta document parsed once, the issue lists. `Plan` is what
6
+ * the merges accumulate. Neither is a bag of conveniences: a value is in here
7
+ * exactly when two phases have to agree about it, and the alternative was
8
+ * fifteen parameters threaded through three functions in the same order.
9
+ */
10
+ import {} from "../../../core/vocabulary/issue.js";
11
+ import {} from "../../../core/staging/writes.js";
12
+ import {} from "../../../core/kernel/ids/dirs.js";
13
+ import {} from "../../../core/kernel/ids/service.js";
14
+ import {} from "../../../core/c4/likec4.js";
15
+ import {} from "../../../core/capabilities/tree.js";
16
+ import {} from "../../../core/staging/interrupted.js";
17
+ export function emptyPlan() {
18
+ return {
19
+ writes: [],
20
+ planWarns: [],
21
+ planGates: [],
22
+ openapiRemovals: [],
23
+ asyncapiRemovals: [],
24
+ architectureServices: new Set(),
25
+ };
26
+ }
27
+ //# sourceMappingURL=state.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,252 @@
1
+ /**
2
+ * The archive itself, under the docs lock: gate, plan, commit.
3
+ *
4
+ * The order is the command's whole safety property. Every refusal happens before
5
+ * a byte is planned (`./plan/gate.ts`), the plan is computed entirely in memory
6
+ * so a failure on any axis leaves the living docs untouched (`./plan/specs.ts`,
7
+ * `./plan/contracts/`, `./plan/landscape.ts`), and only a plan that succeeded
8
+ * on every axis is staged
9
+ * and swapped. `--dry-run` returns between the second and the third.
10
+ */
11
+ import { existsSync } from "node:fs";
12
+ import { mkdir, rename } from "node:fs/promises";
13
+ import { emitJson, repoPath, sayExplain } from "../../core/envelope/json.js";
14
+ import { message, quietPruneEmptyParents, quietRm, rollbackError, rollbackStaged, stageWrites, swapStaged, } from "../../core/staging/commit.js";
15
+ import { clearCommitIntent, writeCommitIntent } from "../../core/staging/recovery/intent.js";
16
+ import { SNAPSHOT_DIR, SnapshotClobberError, snapshotDir, writeSnapshot, } from "../../core/staging/snapshot.js";
17
+ import { enumeratedServices } from "../../core/repo/service-target.js";
18
+ import { FleetContext } from "../../core/fleet-context.js";
19
+ import { gate } from "./plan/gate.js";
20
+ import {} from "./plan/refusal.js";
21
+ import { planCapabilities, planGlossary, planSpecs } from "./plan/specs.js";
22
+ import { planOpenapiContracts } from "./plan/contracts/openapi.js";
23
+ import { planAsyncapiContracts } from "./plan/contracts/asyncapi.js";
24
+ import { planDeployments, planFlows, planLandscape } from "./plan/landscape.js";
25
+ import { emptyPlan } from "./plan/state.js";
26
+ import { issueJson, refuseJson } from "./plan/refusal.js";
27
+ import { ArchiveFailure } from "./plan/refusal.js";
28
+ import { printPlan } from "./plan/refusal.js";
29
+ export async function archiveLocked(config, featureId, opts) {
30
+ const dryRun = opts.dryRun === true;
31
+ const json = opts.json === true;
32
+ // All prose goes through here so `--json` keeps stdout a single JSON document.
33
+ const say = (line = "") => {
34
+ if (!json)
35
+ console.log(line);
36
+ };
37
+ // One read index for the whole run, threaded through every planner's
38
+ // config record: gate, the spec merge and both contract merges each hold
39
+ // per-service loops that resolve living paths through the enumeration, and
40
+ // without a shared context every one of those calls re-walks the fleet —
41
+ // O(services²) work under a lock that guarantees the tree is not moving.
42
+ // The snapshot resolver below reads through the same context, so it pays
43
+ // for that enumeration too.
44
+ const read = { docsDir: config.docsDir, fleet: new FleetContext() };
45
+ const gated = await gate(read, featureId, opts, say);
46
+ if (gated === null)
47
+ return;
48
+ const { id, dirName, featureDir, gating, advisory, archiveDir, archiveDest, recovered, issues } = gated;
49
+ say(`archive ${id}${dryRun ? " (dry run)" : ""}\n`);
50
+ // PLAN — compute every merge in memory. Nothing is written until the whole plan
51
+ // succeeds, so a failure on any axis leaves the living docs untouched.
52
+ const planned = emptyPlan();
53
+ await planSpecs(read, gated, planned, say);
54
+ // The business corpus, beside the service one and before the contracts: both
55
+ // are requirement merges, and reading them together is how a plan stays
56
+ // legible as "what this feature promises" followed by "how it is built".
57
+ await planCapabilities(read, gated, planned, say);
58
+ // The vocabulary the change brings with it, beside the promises it makes:
59
+ // a create-only whole-file copy, refused at the gate if the word already
60
+ // lives (`core/glossary/delta.ts`).
61
+ await planGlossary(read, gated, planned, say);
62
+ await planOpenapiContracts(read, gated, planned, say);
63
+ await planAsyncapiContracts(read, gated, planned, say);
64
+ await planLandscape(config, gated, planned, say);
65
+ // The flows this feature brings, after the elements they draw hops over: the
66
+ // copy is create-only and refused at the gate if the living tree already holds
67
+ // one (`core/usecases/delta/flows.ts`), and it is ordered after the landscape
68
+ // merge so a reader of the plan sees the map change before the sequence drawn
69
+ // on it.
70
+ await planFlows(config, gated, planned, say);
71
+ await planDeployments(config, gated, planned, say);
72
+ const { writes, planWarns, planGates, openapiRemovals, asyncapiRemovals } = planned;
73
+ // Gate on what only the plan could see: a merged operation pointing at a
74
+ // component that exists nowhere, a removal marker addressing no operation.
75
+ // Same doctrine as the coherence gate — a judgment call --approve overrides
76
+ // (unlike the mechanical merge-failed refusals), and a dry run is gated too.
77
+ // Checked after the whole plan so the refusal costs nothing: no write has
78
+ // happened yet either way.
79
+ if (planGates.length > 0 && !opts.approve) {
80
+ const msg = `archive ${id} — BLOCKED: ${planGates.length} issue(s) in the contract merge`;
81
+ if (json) {
82
+ refuseJson("not-coherent", msg, [...issues, ...planWarns, ...planGates], `features/${dirName}`);
83
+ return;
84
+ }
85
+ console.error(`${msg}:`);
86
+ for (const i of planGates)
87
+ console.error(` ✗ ${i.message}`);
88
+ console.error(`\nFix them in the feature's openapi.yaml / asyncapi.yaml — or re-run with --approve to merge anyway.`);
89
+ sayExplain("not-coherent");
90
+ process.exitCode = 1;
91
+ return;
92
+ }
93
+ if (planGates.length > 0) {
94
+ say(`\n ⚠ archiving despite ${planGates.length} contract merge issue(s) (--approve):`);
95
+ for (const i of planGates)
96
+ say(` ✗ ${i.message}`);
97
+ }
98
+ // The plan as data, verb decided now — after the commit everything would read
99
+ // as an update. The `--json` payload is identical for a dry run and the real
100
+ // thing except for `archived`; what WOULD happen is what DOES happen.
101
+ const warnings = [...advisory, ...planWarns];
102
+ const overridden = opts.approve === true ? [...gating, ...planGates] : [];
103
+ const plan = writes.map((w) => ({
104
+ path: repoPath(config.docsDir, w.path),
105
+ action: existsSync(w.path) ? "update" : "create",
106
+ }));
107
+ plan.push({ path: `features/${dirName}`, action: "move", to: `features/archive/${dirName}` });
108
+ const payload = (archived) => ({
109
+ command: "archive",
110
+ feature: id,
111
+ archived,
112
+ path: repoPath(config.docsDir, archiveDest),
113
+ plan,
114
+ warnings: warnings.map((issue) => issueJson(issue, repoPath(config.docsDir, archiveDest))),
115
+ overridden: overridden.map((issue) => issueJson(issue, repoPath(config.docsDir, archiveDest))),
116
+ openapiRemovals,
117
+ asyncapiRemovals,
118
+ // Present only when this run found an interrupted commit and dealt with it:
119
+ // an agent that sees the docs change under it deserves to be told why, and
120
+ // the absent field is the ordinary case.
121
+ ...(recovered === null ? {} : { recovered }),
122
+ });
123
+ if (dryRun) {
124
+ if (json)
125
+ emitJson(payload(false));
126
+ else
127
+ printPlan(config.docsDir, writes, dirName);
128
+ return;
129
+ }
130
+ // COMMIT — the whole plan computed cleanly. Stage every new version beside its
131
+ // target, snapshot what is about to be overwritten, then swap them into place.
132
+ // Staging touches the filesystem — a read-only `architecture/`, a full disk,
133
+ // a target whose pre-image cannot be read. None of that is a bug in loam, and
134
+ // reporting `internal` sends the reader looking for one; it is the same
135
+ // answer as any other merge that could not be computed: nothing was written.
136
+ let staged;
137
+ try {
138
+ staged = await stageWrites(writes);
139
+ }
140
+ catch (err) {
141
+ throw new ArchiveFailure("merge-failed", `${message(err)} — nothing was written`);
142
+ }
143
+ let snapshot = false;
144
+ let createdArchiveDir;
145
+ try {
146
+ // The snapshot's resolver pair: how a docs-relative path decomposes into a
147
+ // service identity, and where that identity lives NOW. Built here — the
148
+ // command layer's view of the tree — and injected, so the snapshot module
149
+ // never learns the repo layout. The seam the flat wave left is now
150
+ // threaded: both answers come from the enumeration, so a service filed
151
+ // into a subsystem keys its snapshot rows by the directory it actually
152
+ // lives in, and the clobber guard grades a leftover claim at that same
153
+ // address. The root-level parse stays as the fallback for the one path
154
+ // shape the enumeration cannot know yet — a service this archive CREATES,
155
+ // which always materialises unfiled at services/<id>/.
156
+ // Tolerant on purpose: a docs repo whose services/ is absent still
157
+ // archives a landscape-only feature exactly as before — the enumeration
158
+ // is empty, every row keys by the flat fallback, and the missing
159
+ // directory stays doctor's diagnosis rather than a merge-failed here.
160
+ const dirOf = new Map((await enumeratedServices(config.docsDir, read.fleet)).map((s) => [s.id, repoPath(config.docsDir, s.dir)]));
161
+ const serviceKeyOf = (rel) => {
162
+ for (const [service, dir] of dirOf) {
163
+ if (rel.startsWith(`${dir}/`))
164
+ return { service, artifact: rel.slice(dir.length + 1) };
165
+ }
166
+ const m = /^services\/([^/]+)\/(.+)$/.exec(rel);
167
+ return m ? { service: m[1], artifact: m[2] } : null;
168
+ };
169
+ const serviceDirOf = (service) => dirOf.get(service) ?? null;
170
+ await writeSnapshot({
171
+ featureDir,
172
+ docsDir: config.docsDir,
173
+ feature: { featureId: id, dirName },
174
+ staged,
175
+ serviceKeyOf,
176
+ serviceDirOf,
177
+ });
178
+ snapshot = true;
179
+ // The journal, fsynced, BEFORE the first rename: swapStaged is N renames and
180
+ // only each one of them is atomic, so a kill between two used to leave a
181
+ // half-merged repo that nothing could name — `doctor` and `status` called it
182
+ // healthy and `validate --all` blamed the delta. Written from `staged`, so
183
+ // it records the same digests the swaps are about to produce.
184
+ await writeCommitIntent(config.docsDir, { command: "archive", restore: "before", feature: id, moveFrom: featureDir, moveTo: archiveDest }, staged);
185
+ await swapStaged(staged);
186
+ createdArchiveDir = await mkdir(archiveDir, { recursive: true });
187
+ await rename(featureDir, archiveDest);
188
+ // Last: while it exists, the commit is in flight.
189
+ await clearCommitIntent(config.docsDir);
190
+ }
191
+ catch (err) {
192
+ if (err instanceof SnapshotClobberError) {
193
+ // Nothing swapped — the refusal happens before the journal is even
194
+ // written — so this only takes the temp files away. Its own code, because
195
+ // the answer is not "re-run": a previous archive of this feature is still
196
+ // sitting in the living docs.
197
+ await rollbackStaged(staged);
198
+ throw new ArchiveFailure("commit-interrupted", err.message);
199
+ }
200
+ // Everything this run made, unmade: the swapped files, the snapshot inside the
201
+ // feature that is staying put, and features/archive/ if we are the ones who
202
+ // created it (mkdir reports nothing when it was already there).
203
+ const failures = await rollbackStaged(staged);
204
+ // The rollback decided the outcome, so the journal has nothing left to
205
+ // describe — including on rollback-incomplete, where the files it names are
206
+ // the ones the message tells a human to look at.
207
+ await clearCommitIntent(config.docsDir);
208
+ // The snapshot goes only when the rollback HELD. On rollback-incomplete it
209
+ // holds the only on-disk pre-images of the very files the message tells the
210
+ // reader to repair by hand — a MODIFIED requirement's previous text appears
211
+ // nowhere else. Retaining it is safe: the next archive of this feature reads
212
+ // it before it would replace it, and refuses if the living docs have moved.
213
+ if (snapshot && failures.length === 0)
214
+ await quietRm(snapshotDir(featureDir));
215
+ // `features/archive/` is shared the moment it exists: another archive can
216
+ // have moved a whole feature into it between our mkdir and this rollback,
217
+ // and a recursive remove of "the directory we created" took that feature —
218
+ // snapshot and all — with it, on OUR failure path, in silence. Empty
219
+ // directories only, stopping at the first that is not.
220
+ if (createdArchiveDir !== undefined)
221
+ await quietPruneEmptyParents(archiveDir, createdArchiveDir);
222
+ // The code is a caller's answer to "can I trust the repo?": merge-failed
223
+ // means yes (rolled back), rollback-incomplete means look at it by hand.
224
+ const wrapped = rollbackError(err, failures);
225
+ const kept = snapshot && failures.length > 0
226
+ ? ` Pre-images of the overwritten files are kept in features/${dirName}/${SNAPSHOT_DIR}/files/.`
227
+ : "";
228
+ throw new ArchiveFailure(failures.length > 0 ? "rollback-incomplete" : "merge-failed", wrapped.message + kept);
229
+ }
230
+ if (json) {
231
+ emitJson(payload(true));
232
+ return;
233
+ }
234
+ console.log(`\n archived: features/${dirName} → features/archive/${dirName}`);
235
+ console.log(` snapshot: features/archive/${dirName}/${SNAPSHOT_DIR}/ — \`loam unarchive ${id}\` puts it back`);
236
+ // The closing line is a claim about the whole docs repo, and it is the line a
237
+ // reader stops at. It may be printed only when this archive left nothing the
238
+ // next `validate --all` will fail on — a service with no model, or a gate the
239
+ // caller told it to merge past. Printing it over either is how a red fleet
240
+ // gets reported as a finished one.
241
+ const incomplete = planWarns.filter((w) => w.code === "service.no-model");
242
+ if (incomplete.length === 0 && overridden.length === 0) {
243
+ console.log(" living spec + landscape are now complete + current.");
244
+ return;
245
+ }
246
+ for (const w of incomplete)
247
+ console.log(` ⚠ ${w.message}`);
248
+ if (overridden.length > 0) {
249
+ console.log(` ⚠ merged past ${overridden.length} gating issue(s) with --approve — the living docs carry them now; \`loam validate --all\` says what they cost.`);
250
+ }
251
+ }
252
+ //# sourceMappingURL=run.js.map