@ybotok/loam 0.2.0-alpha.1 → 0.2.0-alpha.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (901) hide show
  1. package/CHANGELOG.md +3448 -0
  2. package/COMPARISON.md +91 -3
  3. package/CONTRIBUTING.md +37 -0
  4. package/MIGRATING-from-OpenSpec.md +47 -23
  5. package/QUICKSTART.md +189 -12
  6. package/README.md +274 -65
  7. package/ROADMAP.md +572 -31
  8. package/SCHEMA.md +1709 -155
  9. package/WORKFLOW.md +298 -72
  10. package/dist/cli.js +26 -8
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/adopt/adopt.js +5 -10
  13. package/dist/commands/adopt/adopt.js.map +1 -1
  14. package/dist/commands/adopt/render.js +50 -9
  15. package/dist/commands/adopt/render.js.map +1 -1
  16. package/dist/commands/archive/archive.js +16 -19
  17. package/dist/commands/archive/archive.js.map +1 -1
  18. package/dist/commands/archive/closing.js +42 -0
  19. package/dist/commands/archive/closing.js.map +1 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js +36 -42
  21. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
  22. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  24. package/dist/commands/archive/plan/contracts/openapi.js +77 -43
  25. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
  26. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  28. package/dist/commands/archive/plan/document/head.js +151 -0
  29. package/dist/commands/archive/plan/document/head.js.map +1 -0
  30. package/dist/commands/archive/plan/document/links.js +284 -0
  31. package/dist/commands/archive/plan/document/links.js.map +1 -0
  32. package/dist/commands/archive/plan/document/run.js +136 -0
  33. package/dist/commands/archive/plan/document/run.js.map +1 -0
  34. package/dist/commands/archive/plan/gate.js +21 -19
  35. package/dist/commands/archive/plan/gate.js.map +1 -1
  36. package/dist/commands/archive/plan/landscape.js +167 -30
  37. package/dist/commands/archive/plan/landscape.js.map +1 -1
  38. package/dist/commands/archive/plan/model/extending.js +85 -0
  39. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  40. package/dist/commands/archive/plan/refusal.js +14 -19
  41. package/dist/commands/archive/plan/refusal.js.map +1 -1
  42. package/dist/commands/archive/plan/specs.js +137 -56
  43. package/dist/commands/archive/plan/specs.js.map +1 -1
  44. package/dist/commands/archive/plan/state.js +3 -0
  45. package/dist/commands/archive/plan/state.js.map +1 -1
  46. package/dist/commands/archive/run.js +134 -30
  47. package/dist/commands/archive/run.js.map +1 -1
  48. package/dist/commands/archive/shipped.js +49 -0
  49. package/dist/commands/archive/shipped.js.map +1 -0
  50. package/dist/commands/context/context.js +85 -18
  51. package/dist/commands/context/context.js.map +1 -1
  52. package/dist/commands/context/print.js +29 -7
  53. package/dist/commands/context/print.js.map +1 -1
  54. package/dist/commands/delta/delta.js +102 -14
  55. package/dist/commands/delta/delta.js.map +1 -1
  56. package/dist/commands/delta/print.js +17 -1
  57. package/dist/commands/delta/print.js.map +1 -1
  58. package/dist/commands/dependencies.js +3 -7
  59. package/dist/commands/dependencies.js.map +1 -1
  60. package/dist/commands/diff/diff.js +20 -27
  61. package/dist/commands/diff/diff.js.map +1 -1
  62. package/dist/commands/doctor.js +60 -1
  63. package/dist/commands/doctor.js.map +1 -1
  64. package/dist/commands/explain/explain.js +89 -13
  65. package/dist/commands/explain/explain.js.map +1 -1
  66. package/dist/commands/explore.js +16 -10
  67. package/dist/commands/explore.js.map +1 -1
  68. package/dist/commands/gate/gate.js +45 -8
  69. package/dist/commands/gate/gate.js.map +1 -1
  70. package/dist/commands/gate/print.js +15 -3
  71. package/dist/commands/gate/print.js.map +1 -1
  72. package/dist/commands/gherkin/commit.js +13 -54
  73. package/dist/commands/gherkin/commit.js.map +1 -1
  74. package/dist/commands/gherkin/gherkin.js +36 -20
  75. package/dist/commands/gherkin/gherkin.js.map +1 -1
  76. package/dist/commands/gherkin/reconcile.js +10 -13
  77. package/dist/commands/gherkin/reconcile.js.map +1 -1
  78. package/dist/commands/init/first-hour.js +44 -0
  79. package/dist/commands/init/first-hour.js.map +1 -1
  80. package/dist/commands/init/init.js +18 -22
  81. package/dist/commands/init/init.js.map +1 -1
  82. package/dist/commands/list/campaign/campaign.js +4 -6
  83. package/dist/commands/list/campaign/campaign.js.map +1 -1
  84. package/dist/commands/list/json.js +5 -7
  85. package/dist/commands/list/json.js.map +1 -1
  86. package/dist/commands/list/list.js +44 -29
  87. package/dist/commands/list/list.js.map +1 -1
  88. package/dist/commands/list/print.js +52 -9
  89. package/dist/commands/list/print.js.map +1 -1
  90. package/dist/commands/list/suites/suites.js +140 -0
  91. package/dist/commands/list/suites/suites.js.map +1 -0
  92. package/dist/commands/list/views.js +37 -34
  93. package/dist/commands/list/views.js.map +1 -1
  94. package/dist/commands/mcp/dispatch.js +91 -36
  95. package/dist/commands/mcp/dispatch.js.map +1 -1
  96. package/dist/commands/mcp/mcp.js +56 -15
  97. package/dist/commands/mcp/mcp.js.map +1 -1
  98. package/dist/commands/mcp/serve.js.map +1 -1
  99. package/dist/commands/migrate-openspec/materialize/active.js +27 -22
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
  101. package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
  102. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
  103. package/dist/commands/migrate-openspec/materialize/target.js +2 -2
  104. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
  105. package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
  106. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
  107. package/dist/commands/migrate-openspec/openspec/error.js +7 -8
  108. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
  109. package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
  110. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
  111. package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
  112. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
  113. package/dist/commands/new/capability-template.js +118 -0
  114. package/dist/commands/new/capability-template.js.map +1 -0
  115. package/dist/commands/new/commit.js +8 -22
  116. package/dist/commands/new/commit.js.map +1 -1
  117. package/dist/commands/new/modifies.js +206 -0
  118. package/dist/commands/new/modifies.js.map +1 -0
  119. package/dist/commands/new/new.js +59 -14
  120. package/dist/commands/new/new.js.map +1 -1
  121. package/dist/commands/new/templates.js +48 -124
  122. package/dist/commands/new/templates.js.map +1 -1
  123. package/dist/commands/open.js +3 -7
  124. package/dist/commands/open.js.map +1 -1
  125. package/dist/commands/policy/gate.js +27 -0
  126. package/dist/commands/policy/gate.js.map +1 -1
  127. package/dist/commands/rebase/plan.js +2 -2
  128. package/dist/commands/rebase/plan.js.map +1 -1
  129. package/dist/commands/rebase/rebase.js +60 -35
  130. package/dist/commands/rebase/rebase.js.map +1 -1
  131. package/dist/commands/seed/commit.js +55 -26
  132. package/dist/commands/seed/commit.js.map +1 -1
  133. package/dist/commands/seed/plan.js +158 -13
  134. package/dist/commands/seed/plan.js.map +1 -1
  135. package/dist/commands/seed/seed.js +13 -11
  136. package/dist/commands/seed/seed.js.map +1 -1
  137. package/dist/commands/show/feature.js +9 -5
  138. package/dist/commands/show/feature.js.map +1 -1
  139. package/dist/commands/show/introduced.js +157 -0
  140. package/dist/commands/show/introduced.js.map +1 -0
  141. package/dist/commands/show/marks.js +35 -6
  142. package/dist/commands/show/marks.js.map +1 -1
  143. package/dist/commands/show/service.js +41 -33
  144. package/dist/commands/show/service.js.map +1 -1
  145. package/dist/commands/show/show.js +17 -7
  146. package/dist/commands/show/show.js.map +1 -1
  147. package/dist/commands/status/fleet-next.js +90 -0
  148. package/dist/commands/status/fleet-next.js.map +1 -0
  149. package/dist/commands/status/json.js +2 -0
  150. package/dist/commands/status/json.js.map +1 -1
  151. package/dist/commands/status/print.js +89 -37
  152. package/dist/commands/status/print.js.map +1 -1
  153. package/dist/commands/status/status.js +3 -7
  154. package/dist/commands/status/status.js.map +1 -1
  155. package/dist/commands/steps/steps.js +103 -23
  156. package/dist/commands/steps/steps.js.map +1 -1
  157. package/dist/commands/subsystem/edit.js +7 -7
  158. package/dist/commands/subsystem/edit.js.map +1 -1
  159. package/dist/commands/subsystem/move.js +106 -46
  160. package/dist/commands/subsystem/move.js.map +1 -1
  161. package/dist/commands/subsystem/query.js +2 -4
  162. package/dist/commands/subsystem/query.js.map +1 -1
  163. package/dist/commands/subsystem/subsystem.js +4 -7
  164. package/dist/commands/subsystem/subsystem.js.map +1 -1
  165. package/dist/commands/subsystem/sync.js +289 -74
  166. package/dist/commands/subsystem/sync.js.map +1 -1
  167. package/dist/commands/subsystem/txn/exclude.js +132 -0
  168. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  169. package/dist/commands/subsystem/txn/links.js +128 -0
  170. package/dist/commands/subsystem/txn/links.js.map +1 -0
  171. package/dist/commands/subsystem/txn/report.js +174 -0
  172. package/dist/commands/subsystem/txn/report.js.map +1 -0
  173. package/dist/commands/subsystem/txn/txn.js +147 -45
  174. package/dist/commands/subsystem/txn/txn.js.map +1 -1
  175. package/dist/commands/subsystem/txn/views.js +200 -21
  176. package/dist/commands/subsystem/txn/views.js.map +1 -1
  177. package/dist/commands/tasks/actions.js +107 -0
  178. package/dist/commands/tasks/actions.js.map +1 -0
  179. package/dist/commands/tasks/render.js +253 -0
  180. package/dist/commands/tasks/render.js.map +1 -0
  181. package/dist/commands/tasks/tasks.js +119 -0
  182. package/dist/commands/tasks/tasks.js.map +1 -0
  183. package/dist/commands/unarchive/manifest.js +42 -26
  184. package/dist/commands/unarchive/manifest.js.map +1 -1
  185. package/dist/commands/unarchive/restore.js +83 -33
  186. package/dist/commands/unarchive/restore.js.map +1 -1
  187. package/dist/commands/unarchive/unarchive.js +22 -30
  188. package/dist/commands/unarchive/unarchive.js.map +1 -1
  189. package/dist/commands/validate/arch-coverage.js +78 -27
  190. package/dist/commands/validate/arch-coverage.js.map +1 -1
  191. package/dist/commands/validate/checks/fleet-shape.js +34 -126
  192. package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
  193. package/dist/commands/validate/checks/health-deps.js +9 -6
  194. package/dist/commands/validate/checks/health-deps.js.map +1 -1
  195. package/dist/commands/validate/checks/introduced.js +102 -0
  196. package/dist/commands/validate/checks/introduced.js.map +1 -0
  197. package/dist/commands/validate/checks/requirements.js +18 -8
  198. package/dist/commands/validate/checks/requirements.js.map +1 -1
  199. package/dist/commands/validate/checks/sources.js +11 -2
  200. package/dist/commands/validate/checks/sources.js.map +1 -1
  201. package/dist/commands/validate/coverage/covers-after.js +105 -0
  202. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  203. package/dist/commands/validate/feature.js +26 -20
  204. package/dist/commands/validate/feature.js.map +1 -1
  205. package/dist/commands/validate/fleet/census.js +37 -13
  206. package/dist/commands/validate/fleet/census.js.map +1 -1
  207. package/dist/commands/validate/fleet/landscape.js +144 -126
  208. package/dist/commands/validate/fleet/landscape.js.map +1 -1
  209. package/dist/commands/validate/fleet/load.js +66 -0
  210. package/dist/commands/validate/fleet/load.js.map +1 -1
  211. package/dist/commands/validate/fleet/map/attest.js +98 -0
  212. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  213. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  214. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  215. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  216. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  217. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  218. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  219. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  220. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  221. package/dist/commands/validate/fleet/obligations.js +44 -14
  222. package/dist/commands/validate/fleet/obligations.js.map +1 -1
  223. package/dist/commands/validate/fleet/scorecard/print.js +10 -2
  224. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
  225. package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
  226. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
  227. package/dist/commands/validate/fleet/usecases/place.js.map +1 -1
  228. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  229. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  230. package/dist/commands/validate/fleet/views/ids.js +50 -15
  231. package/dist/commands/validate/fleet/views/ids.js.map +1 -1
  232. package/dist/commands/validate/fleet/views/projects.js +278 -0
  233. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  234. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  235. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  236. package/dist/commands/validate/fleet/views/stale.js +40 -47
  237. package/dist/commands/validate/fleet/views/stale.js.map +1 -1
  238. package/dist/commands/validate/links/corpus.js +1 -4
  239. package/dist/commands/validate/links/corpus.js.map +1 -1
  240. package/dist/commands/validate/links/glossary.js.map +1 -1
  241. package/dist/commands/validate/render/repeats.js +63 -0
  242. package/dist/commands/validate/render/repeats.js.map +1 -0
  243. package/dist/commands/validate/render/rollups.js +115 -0
  244. package/dist/commands/validate/render/rollups.js.map +1 -0
  245. package/dist/commands/validate/render/text.js +199 -0
  246. package/dist/commands/validate/render/text.js.map +1 -0
  247. package/dist/commands/validate/report.js +36 -160
  248. package/dist/commands/validate/report.js.map +1 -1
  249. package/dist/commands/validate/scope.js +113 -0
  250. package/dist/commands/validate/scope.js.map +1 -0
  251. package/dist/commands/validate/service/api.js +21 -107
  252. package/dist/commands/validate/service/api.js.map +1 -1
  253. package/dist/commands/validate/service/contracts/generated.js +134 -0
  254. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  255. package/dist/commands/validate/service/events/events.js +36 -14
  256. package/dist/commands/validate/service/events/events.js.map +1 -1
  257. package/dist/commands/validate/service/events/message-producers.js +1 -1
  258. package/dist/commands/validate/service/events/message-producers.js.map +1 -1
  259. package/dist/commands/validate/service/evidence-pins.js +56 -10
  260. package/dist/commands/validate/service/evidence-pins.js.map +1 -1
  261. package/dist/commands/validate/service/model/diverged.js +226 -0
  262. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  263. package/dist/commands/validate/service/model/grade.js +163 -0
  264. package/dist/commands/validate/service/model/grade.js.map +1 -0
  265. package/dist/commands/validate/service/service.js +121 -61
  266. package/dist/commands/validate/service/service.js.map +1 -1
  267. package/dist/commands/validate/service/specs.js +88 -28
  268. package/dist/commands/validate/service/specs.js.map +1 -1
  269. package/dist/commands/validate/service/spine.js +38 -3
  270. package/dist/commands/validate/service/spine.js.map +1 -1
  271. package/dist/commands/validate/service/usecases/tags.js +113 -0
  272. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  273. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  274. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  275. package/dist/commands/validate/validate.js +85 -60
  276. package/dist/commands/validate/validate.js.map +1 -1
  277. package/dist/commands/verify/cross/diff.js +2 -6
  278. package/dist/commands/verify/cross/diff.js.map +1 -1
  279. package/dist/commands/verify/evidence/contract.js +1 -1
  280. package/dist/commands/verify/evidence/contract.js.map +1 -1
  281. package/dist/commands/verify/evidence/read.js +12 -3
  282. package/dist/commands/verify/evidence/read.js.map +1 -1
  283. package/dist/commands/verify/frozen.js +45 -23
  284. package/dist/commands/verify/frozen.js.map +1 -1
  285. package/dist/commands/verify/record.js +69 -17
  286. package/dist/commands/verify/record.js.map +1 -1
  287. package/dist/commands/verify/report.js +27 -44
  288. package/dist/commands/verify/report.js.map +1 -1
  289. package/dist/commands/verify/results.js +112 -30
  290. package/dist/commands/verify/results.js.map +1 -1
  291. package/dist/commands/verify/verify.js +55 -52
  292. package/dist/commands/verify/verify.js.map +1 -1
  293. package/dist/commands/vouch/pack/pack.js +2 -2
  294. package/dist/commands/vouch/pack/pack.js.map +1 -1
  295. package/dist/commands/vouch/pack/print.js +1 -6
  296. package/dist/commands/vouch/pack/print.js.map +1 -1
  297. package/dist/commands/vouch/pack/sections.js +1 -2
  298. package/dist/commands/vouch/pack/sections.js.map +1 -1
  299. package/dist/commands/vouch/run.js +26 -81
  300. package/dist/commands/vouch/run.js.map +1 -1
  301. package/dist/commands/vouch/sample/plan.js +20 -34
  302. package/dist/commands/vouch/sample/plan.js.map +1 -1
  303. package/dist/commands/vouch/vet/verify.js +39 -7
  304. package/dist/commands/vouch/vet/verify.js.map +1 -1
  305. package/dist/commands/vouch/vouch.js +10 -17
  306. package/dist/commands/vouch/vouch.js.map +1 -1
  307. package/dist/core/agent/agents-md/command-map.js +81 -106
  308. package/dist/core/agent/agents-md/command-map.js.map +1 -1
  309. package/dist/core/agent/agents-md/map/explain.js +21 -9
  310. package/dist/core/agent/agents-md/map/explain.js.map +1 -1
  311. package/dist/core/agent/agents-md/map/lenses/context.js +17 -8
  312. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
  313. package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
  314. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
  315. package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
  316. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
  317. package/dist/core/agent/agents-md/map/mcp.js +10 -7
  318. package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
  319. package/dist/core/agent/agents-md/map/status.js +24 -8
  320. package/dist/core/agent/agents-md/map/status.js.map +1 -1
  321. package/dist/core/agent/agents-md/map/subsystem.js +80 -8
  322. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
  323. package/dist/core/agent/agents-md/map/usecases.js +88 -10
  324. package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
  325. package/dist/core/agent/agents-md/refusals.js +49 -22
  326. package/dist/core/agent/agents-md/refusals.js.map +1 -1
  327. package/dist/core/agent/agents-md.js +39 -6
  328. package/dist/core/agent/agents-md.js.map +1 -1
  329. package/dist/core/agent/agents-stamp.js +10 -0
  330. package/dist/core/agent/agents-stamp.js.map +1 -1
  331. package/dist/core/agent/protocol.js +1 -1
  332. package/dist/core/agent/protocol.js.map +1 -1
  333. package/dist/core/agent/scaffold.js +10 -15
  334. package/dist/core/agent/scaffold.js.map +1 -1
  335. package/dist/core/agent/support/report.js +46 -5
  336. package/dist/core/agent/support/report.js.map +1 -1
  337. package/dist/core/agent/tools/dialects.js +1 -0
  338. package/dist/core/agent/tools/dialects.js.map +1 -1
  339. package/dist/core/agent/tools/registry.js +41 -76
  340. package/dist/core/agent/tools/registry.js.map +1 -1
  341. package/dist/core/agent/workflows/adopt.js +158 -11
  342. package/dist/core/agent/workflows/adopt.js.map +1 -1
  343. package/dist/core/agent/workflows/check.js +78 -39
  344. package/dist/core/agent/workflows/check.js.map +1 -1
  345. package/dist/core/agent/workflows/closing.js +88 -27
  346. package/dist/core/agent/workflows/closing.js.map +1 -1
  347. package/dist/core/agent/workflows/feature.js +128 -13
  348. package/dist/core/agent/workflows/feature.js.map +1 -1
  349. package/dist/core/agent/workflows/implement.js +96 -13
  350. package/dist/core/agent/workflows/implement.js.map +1 -1
  351. package/dist/core/agent/workflows/reference/authoring.js +106 -4
  352. package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
  353. package/dist/core/agent/workflows/reference/codes.js +8 -6
  354. package/dist/core/agent/workflows/reference/codes.js.map +1 -1
  355. package/dist/core/agent/workflows/reference/done-check.js +37 -15
  356. package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
  357. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  358. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  359. package/dist/core/agent/workflows/reference/reference.js +6 -3
  360. package/dist/core/agent/workflows/reference/reference.js.map +1 -1
  361. package/dist/core/agent/workflows/reference/spine.js +68 -27
  362. package/dist/core/agent/workflows/reference/spine.js.map +1 -1
  363. package/dist/core/asyncapi/baseline/plan.js +14 -81
  364. package/dist/core/asyncapi/baseline/plan.js.map +1 -1
  365. package/dist/core/asyncapi/digest.js +30 -25
  366. package/dist/core/asyncapi/digest.js.map +1 -1
  367. package/dist/core/asyncapi/merge/components.js +5 -4
  368. package/dist/core/asyncapi/merge/components.js.map +1 -1
  369. package/dist/core/asyncapi/merge/error.js +7 -2
  370. package/dist/core/asyncapi/merge/error.js.map +1 -1
  371. package/dist/core/asyncapi/merge/markers.js +32 -50
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -1
  373. package/dist/core/asyncapi/merge/merge.js +33 -53
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -1
  375. package/dist/core/asyncapi/merge/pin.js +12 -36
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -1
  377. package/dist/core/asyncapi/model.js.map +1 -1
  378. package/dist/core/asyncapi/read.js +36 -12
  379. package/dist/core/asyncapi/read.js.map +1 -1
  380. package/dist/core/brief/brief.js +96 -36
  381. package/dist/core/brief/brief.js.map +1 -1
  382. package/dist/core/brief/checks.js +138 -3
  383. package/dist/core/brief/checks.js.map +1 -1
  384. package/dist/core/brief/landscape.js +209 -130
  385. package/dist/core/brief/landscape.js.map +1 -1
  386. package/dist/core/brief/map/extend.js +84 -0
  387. package/dist/core/brief/map/extend.js.map +1 -0
  388. package/dist/core/brief/map/owed.js +266 -0
  389. package/dist/core/brief/map/owed.js.map +1 -0
  390. package/dist/core/brief/targets.js +109 -31
  391. package/dist/core/brief/targets.js.map +1 -1
  392. package/dist/core/brief/unchecked.js +14 -3
  393. package/dist/core/brief/unchecked.js.map +1 -1
  394. package/dist/core/c4/arch.js +90 -182
  395. package/dist/core/c4/arch.js.map +1 -1
  396. package/dist/core/c4/direction/direction.js +114 -0
  397. package/dist/core/c4/direction/direction.js.map +1 -0
  398. package/dist/core/c4/likec4.js +169 -14
  399. package/dist/core/c4/likec4.js.map +1 -1
  400. package/dist/core/c4/locate/unlocated.js +150 -0
  401. package/dist/core/c4/locate/unlocated.js.map +1 -0
  402. package/dist/core/c4/parsed/deployment.js +160 -0
  403. package/dist/core/c4/parsed/deployment.js.map +1 -0
  404. package/dist/core/c4/parsed/dynamic-views.js.map +1 -1
  405. package/dist/core/c4/parsed/values.js +54 -1
  406. package/dist/core/c4/parsed/values.js.map +1 -1
  407. package/dist/core/c4/parsed/view-ids.js +39 -1
  408. package/dist/core/c4/parsed/view-ids.js.map +1 -1
  409. package/dist/core/c4/prefetch/fleet.js +134 -0
  410. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  411. package/dist/core/c4/project/architecture.js +123 -7
  412. package/dist/core/c4/project/architecture.js.map +1 -1
  413. package/dist/core/c4/project/batch.js +140 -0
  414. package/dist/core/c4/project/batch.js.map +1 -0
  415. package/dist/core/c4/project/documents.js +43 -12
  416. package/dist/core/c4/project/documents.js.map +1 -1
  417. package/dist/core/c4/project/load.js +79 -43
  418. package/dist/core/c4/project/load.js.map +1 -1
  419. package/dist/core/c4/project/staged.js +277 -0
  420. package/dist/core/c4/project/staged.js.map +1 -0
  421. package/dist/core/c4/resolve/attested.js +0 -0
  422. package/dist/core/c4/resolve/attested.js.map +1 -0
  423. package/dist/core/c4/resolve/external.js +51 -0
  424. package/dist/core/c4/resolve/external.js.map +1 -0
  425. package/dist/core/c4/resolve/service.js +78 -17
  426. package/dist/core/c4/resolve/service.js.map +1 -1
  427. package/dist/core/c4/resolve/steps.js +290 -0
  428. package/dist/core/c4/resolve/steps.js.map +1 -0
  429. package/dist/core/c4/resolve/systems.js +154 -0
  430. package/dist/core/c4/resolve/systems.js.map +1 -0
  431. package/dist/core/c4/root-project/exclude.js +352 -0
  432. package/dist/core/c4/root-project/exclude.js.map +1 -0
  433. package/dist/core/c4/seed/template.js +65 -1
  434. package/dist/core/c4/seed/template.js.map +1 -1
  435. package/dist/core/c4/service-model/created/models.js +96 -0
  436. package/dist/core/c4/service-model/created/models.js.map +1 -0
  437. package/dist/core/c4/service-model/documents.js +47 -0
  438. package/dist/core/c4/service-model/documents.js.map +1 -0
  439. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  440. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  441. package/dist/core/c4/service-model/load.js +165 -0
  442. package/dist/core/c4/service-model/load.js.map +1 -0
  443. package/dist/core/c4/service-model/renderer.js +128 -0
  444. package/dist/core/c4/service-model/renderer.js.map +1 -0
  445. package/dist/core/c4/service-model/shape.js +106 -0
  446. package/dist/core/c4/service-model/shape.js.map +1 -0
  447. package/dist/core/c4/service-model/slice.js +188 -0
  448. package/dist/core/c4/service-model/slice.js.map +1 -0
  449. package/dist/core/c4/source-mask.js +297 -10
  450. package/dist/core/c4/source-mask.js.map +1 -1
  451. package/dist/core/c4/source-scan.js +222 -141
  452. package/dist/core/c4/source-scan.js.map +1 -1
  453. package/dist/core/c4/splice/authored-source.js +79 -13
  454. package/dist/core/c4/splice/authored-source.js.map +1 -1
  455. package/dist/core/c4/splice/contract.js +20 -0
  456. package/dist/core/c4/splice/contract.js.map +1 -1
  457. package/dist/core/c4/splice/delta-blocks.js +20 -20
  458. package/dist/core/c4/splice/delta-blocks.js.map +1 -1
  459. package/dist/core/c4/splice/identity/declared.js +87 -0
  460. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  461. package/dist/core/c4/splice/identity/edges.js +37 -0
  462. package/dist/core/c4/splice/identity/edges.js.map +1 -1
  463. package/dist/core/c4/splice/identity/existing.js +80 -0
  464. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  465. package/dist/core/c4/splice/identity/interior.js +80 -0
  466. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  467. package/dist/core/c4/splice/identity/owner.js +50 -0
  468. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  469. package/dist/core/c4/splice/landscape-merge.js +182 -114
  470. package/dist/core/c4/splice/landscape-merge.js.map +1 -1
  471. package/dist/core/c4/splice/model/merge.js +151 -0
  472. package/dist/core/c4/splice/model/merge.js.map +1 -0
  473. package/dist/core/c4/splice/placement.js +160 -56
  474. package/dist/core/c4/splice/placement.js.map +1 -1
  475. package/dist/core/c4/splice/text/spot.js +131 -0
  476. package/dist/core/c4/splice/text/spot.js.map +1 -0
  477. package/dist/core/c4/workspace.js +13 -19
  478. package/dist/core/c4/workspace.js.map +1 -1
  479. package/dist/core/capabilities/capabilities.js +6 -6
  480. package/dist/core/capabilities/capabilities.js.map +1 -1
  481. package/dist/core/capabilities/delta/doc.js +7 -10
  482. package/dist/core/capabilities/delta/doc.js.map +1 -1
  483. package/dist/core/capabilities/delta/uncovered.js +2 -2
  484. package/dist/core/capabilities/delta/uncovered.js.map +1 -1
  485. package/dist/core/capabilities/findings.js +18 -22
  486. package/dist/core/capabilities/findings.js.map +1 -1
  487. package/dist/core/capabilities/realizes/findings.js +12 -19
  488. package/dist/core/capabilities/realizes/findings.js.map +1 -1
  489. package/dist/core/capabilities/realizes/join.js +0 -20
  490. package/dist/core/capabilities/realizes/join.js.map +1 -1
  491. package/dist/core/capabilities/rollup.js +6 -0
  492. package/dist/core/capabilities/rollup.js.map +1 -1
  493. package/dist/core/capabilities/tree.js +6 -28
  494. package/dist/core/capabilities/tree.js.map +1 -1
  495. package/dist/core/capabilities/usecase-join.js +3 -13
  496. package/dist/core/capabilities/usecase-join.js.map +1 -1
  497. package/dist/core/coherence/authoring/scaffold.js +11 -3
  498. package/dist/core/coherence/authoring/scaffold.js.map +1 -1
  499. package/dist/core/coherence/authoring/sentinels.js +2 -1
  500. package/dist/core/coherence/authoring/sentinels.js.map +1 -1
  501. package/dist/core/coherence/calls/called.js +52 -0
  502. package/dist/core/coherence/calls/called.js.map +1 -0
  503. package/dist/core/coherence/coherence.js +103 -22
  504. package/dist/core/coherence/coherence.js.map +1 -1
  505. package/dist/core/coherence/consumed/operations.js +70 -0
  506. package/dist/core/coherence/consumed/operations.js.map +1 -0
  507. package/dist/core/coherence/consumed/refusal.js +38 -0
  508. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  509. package/dist/core/coherence/covers/health.js +85 -0
  510. package/dist/core/coherence/covers/health.js.map +1 -0
  511. package/dist/core/coherence/declared.js +60 -34
  512. package/dist/core/coherence/declared.js.map +1 -1
  513. package/dist/core/coherence/events/declared.js +44 -59
  514. package/dist/core/coherence/events/declared.js.map +1 -1
  515. package/dist/core/coherence/events/events.js +147 -16
  516. package/dist/core/coherence/events/events.js.map +1 -1
  517. package/dist/core/coherence/events/grades.js +31 -8
  518. package/dist/core/coherence/events/grades.js.map +1 -1
  519. package/dist/core/coherence/events/lookups.js +28 -87
  520. package/dist/core/coherence/events/lookups.js.map +1 -1
  521. package/dist/core/coherence/events/produced.js +100 -0
  522. package/dist/core/coherence/events/produced.js.map +1 -0
  523. package/dist/core/coherence/lookups.js +18 -78
  524. package/dist/core/coherence/lookups.js.map +1 -1
  525. package/dist/core/coherence/retired/archived.js +285 -0
  526. package/dist/core/coherence/retired/archived.js.map +1 -0
  527. package/dist/core/coherence/retired/event-pair.js +62 -0
  528. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  529. package/dist/core/coherence/retired/merged.js +79 -0
  530. package/dist/core/coherence/retired/merged.js.map +1 -0
  531. package/dist/core/coherence/retired/retirement.js +49 -0
  532. package/dist/core/coherence/retired/retirement.js.map +1 -0
  533. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  534. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  535. package/dist/core/coherence/retired/revival/revived.js +297 -0
  536. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  537. package/dist/core/consumers/after.js +113 -0
  538. package/dist/core/consumers/after.js.map +1 -0
  539. package/dist/core/consumers/consumers.js +296 -0
  540. package/dist/core/consumers/consumers.js.map +1 -0
  541. package/dist/core/consumers/current.js +211 -0
  542. package/dist/core/consumers/current.js.map +1 -0
  543. package/dist/core/consumers/scan.js +46 -0
  544. package/dist/core/consumers/scan.js.map +1 -0
  545. package/dist/core/consumers/state.js +27 -0
  546. package/dist/core/consumers/state.js.map +1 -0
  547. package/dist/core/delta/delta.js +51 -6
  548. package/dist/core/delta/delta.js.map +1 -1
  549. package/dist/core/dependencies/fanin.js +2 -2
  550. package/dist/core/dependencies/fanin.js.map +1 -1
  551. package/dist/core/deployment/delta.js +191 -0
  552. package/dist/core/deployment/delta.js.map +1 -0
  553. package/dist/core/deployment/objects.js +145 -0
  554. package/dist/core/deployment/objects.js.map +1 -0
  555. package/dist/core/diff/base-git.js +94 -12
  556. package/dist/core/diff/base-git.js.map +1 -1
  557. package/dist/core/diff/base-state.js +49 -21
  558. package/dist/core/diff/base-state.js.map +1 -1
  559. package/dist/core/diff/joins.js +136 -0
  560. package/dist/core/diff/joins.js.map +1 -0
  561. package/dist/core/diff/scope/changed-paths.js +22 -6
  562. package/dist/core/diff/scope/changed-paths.js.map +1 -1
  563. package/dist/core/diff/scope/edges.js +82 -0
  564. package/dist/core/diff/scope/edges.js.map +1 -0
  565. package/dist/core/diff/semantic.js +100 -31
  566. package/dist/core/diff/semantic.js.map +1 -1
  567. package/dist/core/docs.js +31 -22
  568. package/dist/core/docs.js.map +1 -1
  569. package/dist/core/doctor/agents.js +34 -18
  570. package/dist/core/doctor/agents.js.map +1 -1
  571. package/dist/core/doctor/config.js +7 -3
  572. package/dist/core/doctor/config.js.map +1 -1
  573. package/dist/core/doctor/doctor.js +91 -11
  574. package/dist/core/doctor/doctor.js.map +1 -1
  575. package/dist/core/doctor/report.js.map +1 -1
  576. package/dist/core/doctor/reports/scan.js +242 -0
  577. package/dist/core/doctor/reports/scan.js.map +1 -0
  578. package/dist/core/document/apply.js +158 -11
  579. package/dist/core/document/apply.js.map +1 -1
  580. package/dist/core/document/frontmatter.js +55 -0
  581. package/dist/core/document/frontmatter.js.map +1 -1
  582. package/dist/core/document/parse.js +29 -6
  583. package/dist/core/document/parse.js.map +1 -1
  584. package/dist/core/document/scenarios.js +17 -0
  585. package/dist/core/document/scenarios.js.map +1 -1
  586. package/dist/core/document/spec.js +4 -11
  587. package/dist/core/document/spec.js.map +1 -1
  588. package/dist/core/envelope/config.js +10 -0
  589. package/dist/core/envelope/config.js.map +1 -1
  590. package/dist/core/envelope/json.js +34 -0
  591. package/dist/core/envelope/json.js.map +1 -1
  592. package/dist/core/explain/families.js +26 -21
  593. package/dist/core/explain/families.js.map +1 -1
  594. package/dist/core/explain/lookup.js +14 -1
  595. package/dist/core/explain/lookup.js.map +1 -1
  596. package/dist/core/explain/refusals.js +5 -5
  597. package/dist/core/explain/refusals.js.map +1 -1
  598. package/dist/core/explain/terms/documents.js +227 -0
  599. package/dist/core/explain/terms/documents.js.map +1 -0
  600. package/dist/core/explain/terms/done-check.js +144 -0
  601. package/dist/core/explain/terms/done-check.js.map +1 -0
  602. package/dist/core/explain/terms/entry.js +14 -0
  603. package/dist/core/explain/terms/entry.js.map +1 -0
  604. package/dist/core/explain/terms/stages.js +71 -0
  605. package/dist/core/explain/terms/stages.js.map +1 -0
  606. package/dist/core/explain/terms/tasks.js +97 -0
  607. package/dist/core/explain/terms/tasks.js.map +1 -0
  608. package/dist/core/explain/terms.js +68 -109
  609. package/dist/core/explain/terms.js.map +1 -1
  610. package/dist/core/explore/explore.js +40 -10
  611. package/dist/core/explore/explore.js.map +1 -1
  612. package/dist/core/fleet-context.js +81 -95
  613. package/dist/core/fleet-context.js.map +1 -1
  614. package/dist/core/gate/checks.js +11 -4
  615. package/dist/core/gate/checks.js.map +1 -1
  616. package/dist/core/gate/partners.js +69 -28
  617. package/dist/core/gate/partners.js.map +1 -1
  618. package/dist/core/gate/report.js.map +1 -1
  619. package/dist/core/gate/verification.js +75 -12
  620. package/dist/core/gate/verification.js.map +1 -1
  621. package/dist/core/gherkin/stale.js +13 -37
  622. package/dist/core/gherkin/stale.js.map +1 -1
  623. package/dist/core/glossary/delta.js +10 -7
  624. package/dist/core/glossary/delta.js.map +1 -1
  625. package/dist/core/glossary/tree.js +6 -19
  626. package/dist/core/glossary/tree.js.map +1 -1
  627. package/dist/core/kernel/concurrency.js +19 -0
  628. package/dist/core/kernel/concurrency.js.map +1 -1
  629. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  630. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  631. package/dist/core/kernel/path-safety.js +38 -0
  632. package/dist/core/kernel/path-safety.js.map +1 -1
  633. package/dist/core/kernel/records.js +11 -0
  634. package/dist/core/kernel/records.js.map +1 -1
  635. package/dist/core/links/backlinks.js +1 -3
  636. package/dist/core/links/backlinks.js.map +1 -1
  637. package/dist/core/links/corpus.js +51 -37
  638. package/dist/core/links/corpus.js.map +1 -1
  639. package/dist/core/links/findings.js.map +1 -1
  640. package/dist/core/links/parse.js +38 -9
  641. package/dist/core/links/parse.js.map +1 -1
  642. package/dist/core/mcp/argv.js +101 -0
  643. package/dist/core/mcp/argv.js.map +1 -1
  644. package/dist/core/mcp/author-tools.js +2 -1
  645. package/dist/core/mcp/author-tools.js.map +1 -1
  646. package/dist/core/mcp/protocol.js +2 -2
  647. package/dist/core/mcp/protocol.js.map +1 -1
  648. package/dist/core/mcp/tools.js +43 -33
  649. package/dist/core/mcp/tools.js.map +1 -1
  650. package/dist/core/openapi/baseline/gate.js +53 -12
  651. package/dist/core/openapi/baseline/gate.js.map +1 -1
  652. package/dist/core/openapi/baseline/plan.js +40 -10
  653. package/dist/core/openapi/baseline/plan.js.map +1 -1
  654. package/dist/core/openapi/baseline/record.js +0 -1
  655. package/dist/core/openapi/baseline/record.js.map +1 -1
  656. package/dist/core/openapi/contract-text.js +33 -0
  657. package/dist/core/openapi/contract-text.js.map +1 -0
  658. package/dist/core/openapi/contract-tree.js +301 -0
  659. package/dist/core/openapi/contract-tree.js.map +1 -0
  660. package/dist/core/openapi/depth.js +38 -24
  661. package/dist/core/openapi/depth.js.map +1 -1
  662. package/dist/core/openapi/digest.js +52 -2
  663. package/dist/core/openapi/digest.js.map +1 -1
  664. package/dist/core/openapi/doc.js +12 -4
  665. package/dist/core/openapi/doc.js.map +1 -1
  666. package/dist/core/openapi/merge/components.js +25 -60
  667. package/dist/core/openapi/merge/components.js.map +1 -1
  668. package/dist/core/openapi/merge/error.js +3 -13
  669. package/dist/core/openapi/merge/error.js.map +1 -1
  670. package/dist/core/openapi/merge/markers.js +26 -30
  671. package/dist/core/openapi/merge/markers.js.map +1 -1
  672. package/dist/core/openapi/merge/merge.js +28 -52
  673. package/dist/core/openapi/merge/merge.js.map +1 -1
  674. package/dist/core/openapi/merge/pin.js +17 -35
  675. package/dist/core/openapi/merge/pin.js.map +1 -1
  676. package/dist/core/openspec/decide/verdict.js.map +1 -1
  677. package/dist/core/openspec/inventory.js +4 -5
  678. package/dist/core/openspec/inventory.js.map +1 -1
  679. package/dist/core/openspec/model/mapping.js +30 -28
  680. package/dist/core/openspec/model/mapping.js.map +1 -1
  681. package/dist/core/openspec/model/model.js +12 -7
  682. package/dist/core/openspec/model/model.js.map +1 -1
  683. package/dist/core/openspec/scan/changes.js +10 -4
  684. package/dist/core/openspec/scan/changes.js.map +1 -1
  685. package/dist/core/openspec/scan/config.js +7 -16
  686. package/dist/core/openspec/scan/config.js.map +1 -1
  687. package/dist/core/openspec/scan/shape.js +63 -19
  688. package/dist/core/openspec/scan/shape.js.map +1 -1
  689. package/dist/core/openspec/scan/walk.js +21 -38
  690. package/dist/core/openspec/scan/walk.js.map +1 -1
  691. package/dist/core/pack/living.js +43 -4
  692. package/dist/core/pack/living.js.map +1 -1
  693. package/dist/core/pack/pack.js +50 -6
  694. package/dist/core/pack/pack.js.map +1 -1
  695. package/dist/core/projection/arch-slice.js +2 -2
  696. package/dist/core/projection/arch-slice.js.map +1 -1
  697. package/dist/core/projection/introduced.js +14 -0
  698. package/dist/core/projection/introduced.js.map +1 -0
  699. package/dist/core/provenance/findings.js +48 -12
  700. package/dist/core/provenance/findings.js.map +1 -1
  701. package/dist/core/provenance/git.js +33 -57
  702. package/dist/core/provenance/git.js.map +1 -1
  703. package/dist/core/provenance/gitq/moves.js +71 -114
  704. package/dist/core/provenance/gitq/moves.js.map +1 -1
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
  707. package/dist/core/provenance/sources.js +23 -6
  708. package/dist/core/provenance/sources.js.map +1 -1
  709. package/dist/core/provenance/stamp.js +5 -17
  710. package/dist/core/provenance/stamp.js.map +1 -1
  711. package/dist/core/repo/authored/paths.js +18 -0
  712. package/dist/core/repo/authored/paths.js.map +1 -1
  713. package/dist/core/repo/entries.js.map +1 -1
  714. package/dist/core/repo/paths.js +92 -6
  715. package/dist/core/repo/paths.js.map +1 -1
  716. package/dist/core/repo/repo.js +74 -14
  717. package/dist/core/repo/repo.js.map +1 -1
  718. package/dist/core/repo/tree/find.js +12 -3
  719. package/dist/core/repo/tree/find.js.map +1 -1
  720. package/dist/core/repo/tree/fs.js +27 -1
  721. package/dist/core/repo/tree/fs.js.map +1 -1
  722. package/dist/core/repo/tree/render/body.js +258 -0
  723. package/dist/core/repo/tree/render/body.js.map +1 -0
  724. package/dist/core/repo/tree/render/projects.js +182 -0
  725. package/dist/core/repo/tree/render/projects.js.map +1 -0
  726. package/dist/core/repo/tree/render/service/header.js +125 -0
  727. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  728. package/dist/core/repo/tree/render/service/peers.js +28 -0
  729. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  730. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  731. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  732. package/dist/core/repo/tree/render/service/views.js +78 -0
  733. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  734. package/dist/core/repo/tree/render/stale.js +42 -0
  735. package/dist/core/repo/tree/render/stale.js.map +1 -0
  736. package/dist/core/repo/tree/render/text.js +84 -0
  737. package/dist/core/repo/tree/render/text.js.map +1 -0
  738. package/dist/core/repo/tree/render/views.js +293 -0
  739. package/dist/core/repo/tree/render/views.js.map +1 -0
  740. package/dist/core/repo/tree/walk.js +53 -32
  741. package/dist/core/repo/tree/walk.js.map +1 -1
  742. package/dist/core/results.js +47 -12
  743. package/dist/core/results.js.map +1 -1
  744. package/dist/core/scaffold/landscape.js +121 -13
  745. package/dist/core/scaffold/landscape.js.map +1 -1
  746. package/dist/core/scaffold/legacy.js +271 -0
  747. package/dist/core/scaffold/legacy.js.map +1 -0
  748. package/dist/core/staging/commit.js +26 -15
  749. package/dist/core/staging/commit.js.map +1 -1
  750. package/dist/core/staging/lock.js +74 -12
  751. package/dist/core/staging/lock.js.map +1 -1
  752. package/dist/core/staging/recovery/intent.js +2 -5
  753. package/dist/core/staging/recovery/intent.js.map +1 -1
  754. package/dist/core/staging/recovery/recover.js +84 -6
  755. package/dist/core/staging/recovery/recover.js.map +1 -1
  756. package/dist/core/staging/snapshot/manifest.js +188 -0
  757. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  758. package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +39 -45
  759. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  760. package/dist/core/staging/txn/forward.js +24 -14
  761. package/dist/core/staging/txn/forward.js.map +1 -1
  762. package/dist/core/staging/writes.js.map +1 -1
  763. package/dist/core/status/actions/execution.js +11 -0
  764. package/dist/core/status/actions/execution.js.map +1 -1
  765. package/dist/core/status/contracts.js +39 -15
  766. package/dist/core/status/contracts.js.map +1 -1
  767. package/dist/core/status/feature/artifacts.js +33 -8
  768. package/dist/core/status/feature/artifacts.js.map +1 -1
  769. package/dist/core/status/feature/feature.js +24 -17
  770. package/dist/core/status/feature/feature.js.map +1 -1
  771. package/dist/core/status/feature/next.js +20 -7
  772. package/dist/core/status/feature/next.js.map +1 -1
  773. package/dist/core/status/feature/words.js +96 -0
  774. package/dist/core/status/feature/words.js.map +1 -0
  775. package/dist/core/status/fleet/fleet.js +43 -14
  776. package/dist/core/status/fleet/fleet.js.map +1 -1
  777. package/dist/core/status/fleet/next.js +153 -58
  778. package/dist/core/status/fleet/next.js.map +1 -1
  779. package/dist/core/status/report.js.map +1 -1
  780. package/dist/core/status/scan.js.map +1 -1
  781. package/dist/core/status/verification.js +30 -15
  782. package/dist/core/status/verification.js.map +1 -1
  783. package/dist/core/tasks/packet.js +199 -0
  784. package/dist/core/tasks/packet.js.map +1 -0
  785. package/dist/core/tasks/record.js +43 -0
  786. package/dist/core/tasks/record.js.map +1 -0
  787. package/dist/core/tasks/sources.js +181 -0
  788. package/dist/core/tasks/sources.js.map +1 -0
  789. package/dist/core/tasks/stamps.js +76 -0
  790. package/dist/core/tasks/stamps.js.map +1 -0
  791. package/dist/core/tasks/unit.js +0 -0
  792. package/dist/core/tasks/unit.js.map +1 -0
  793. package/dist/core/usecases/capability.js +11 -14
  794. package/dist/core/usecases/capability.js.map +1 -1
  795. package/dist/core/usecases/delta/claims.js +31 -7
  796. package/dist/core/usecases/delta/claims.js.map +1 -1
  797. package/dist/core/usecases/delta/flows.js +5 -7
  798. package/dist/core/usecases/delta/flows.js.map +1 -1
  799. package/dist/core/usecases/delta/modified.js +315 -0
  800. package/dist/core/usecases/delta/modified.js.map +1 -0
  801. package/dist/core/usecases/delta/overlay.js +32 -191
  802. package/dist/core/usecases/delta/overlay.js.map +1 -1
  803. package/dist/core/usecases/fleet.js +195 -36
  804. package/dist/core/usecases/fleet.js.map +1 -1
  805. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/capability-tag.js +8 -9
  806. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  807. package/dist/core/usecases/grade/feature.js +88 -0
  808. package/dist/core/usecases/grade/feature.js.map +1 -0
  809. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/requirement-tag.js +3 -4
  810. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  811. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/steps.js +102 -33
  812. package/dist/core/usecases/grade/steps.js.map +1 -0
  813. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/usecases.js +23 -10
  814. package/dist/core/usecases/grade/usecases.js.map +1 -0
  815. package/dist/core/usecases/operations.js +26 -14
  816. package/dist/core/usecases/operations.js.map +1 -1
  817. package/dist/core/usecases/place.js.map +1 -1
  818. package/dist/core/usecases/service/exclude.js +119 -0
  819. package/dist/core/usecases/service/exclude.js.map +1 -0
  820. package/dist/core/usecases/service/flows.js +164 -0
  821. package/dist/core/usecases/service/flows.js.map +1 -0
  822. package/dist/core/usecases/suites/participants.js +83 -0
  823. package/dist/core/usecases/suites/participants.js.map +1 -0
  824. package/dist/core/usecases/suites/suites.js +45 -0
  825. package/dist/core/usecases/suites/suites.js.map +1 -0
  826. package/dist/core/verify/answers.js +12 -5
  827. package/dist/core/verify/answers.js.map +1 -1
  828. package/dist/core/verify/build.js +102 -82
  829. package/dist/core/verify/build.js.map +1 -1
  830. package/dist/core/verify/checklist.js +70 -12
  831. package/dist/core/verify/checklist.js.map +1 -1
  832. package/dist/core/verify/location.js +67 -0
  833. package/dist/core/verify/location.js.map +1 -0
  834. package/dist/core/verify/pins/lint.js +3 -2
  835. package/dist/core/verify/pins/lint.js.map +1 -1
  836. package/dist/core/verify/pins/pin.js +1 -1
  837. package/dist/core/verify/pins/pin.js.map +1 -1
  838. package/dist/core/verify/read/file.js +224 -0
  839. package/dist/core/verify/read/file.js.map +1 -0
  840. package/dist/core/verify/{file.js → read/shape.js} +16 -104
  841. package/dist/core/verify/read/shape.js.map +1 -0
  842. package/dist/core/verify/read/union.js +105 -0
  843. package/dist/core/verify/read/union.js.map +1 -0
  844. package/dist/core/verify/record.js +35 -12
  845. package/dist/core/verify/record.js.map +1 -1
  846. package/dist/core/verify/store/commit.js +40 -30
  847. package/dist/core/verify/store/commit.js.map +1 -1
  848. package/dist/core/verify/store/render.js +8 -4
  849. package/dist/core/verify/store/render.js.map +1 -1
  850. package/dist/core/vocabulary/issue.js +4 -0
  851. package/dist/core/vocabulary/issue.js.map +1 -1
  852. package/dist/core/vocabulary/maturity.js +75 -4
  853. package/dist/core/vocabulary/maturity.js.map +1 -1
  854. package/dist/core/vocabulary/report.js +16 -1
  855. package/dist/core/vocabulary/report.js.map +1 -1
  856. package/examples/README.md +54 -11
  857. package/examples/docs/architecture/landscape.likec4 +62 -6
  858. package/examples/docs/architecture/services.likec4 +70 -0
  859. package/examples/docs/architecture/subsystems.likec4 +7 -0
  860. package/examples/docs/architecture/usecases/order-notification.likec4 +16 -7
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
  863. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +4 -1
  864. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
  865. package/examples/docs/likec4.config.json +0 -1
  866. package/examples/docs/services/checkout-web/model.likec4 +39 -56
  867. package/examples/docs/services/order-service/arch.spec.md +13 -6
  868. package/examples/docs/services/order-service/asyncapi.yaml +3 -2
  869. package/examples/docs/services/order-service/model.likec4 +58 -70
  870. package/examples/docs/services/payment-service/arch.spec.md +7 -4
  871. package/examples/docs/services/payment-service/model.likec4 +38 -37
  872. package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
  873. package/examples/docs/services/platform/identity-service/model.likec4 +35 -37
  874. package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
  875. package/examples/docs/services/platform/notification-service/health.yaml +8 -3
  876. package/examples/docs/services/platform/notification-service/model.likec4 +43 -64
  877. package/package.json +1 -1
  878. package/dist/commands/validate/checks/vocabulary.js +0 -31
  879. package/dist/commands/validate/checks/vocabulary.js.map +0 -1
  880. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +0 -1
  881. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +0 -1
  882. package/dist/commands/validate/fleet/usecases/steps.js.map +0 -1
  883. package/dist/commands/validate/fleet/usecases/usecases.js.map +0 -1
  884. package/dist/core/agent/agents-md/artifacts.js +0 -220
  885. package/dist/core/agent/agents-md/artifacts.js.map +0 -1
  886. package/dist/core/agent/agents-md/cycle.js +0 -165
  887. package/dist/core/agent/agents-md/cycle.js.map +0 -1
  888. package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
  889. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
  890. package/dist/core/agent/agents-md/spine.js +0 -40
  891. package/dist/core/agent/agents-md/spine.js.map +0 -1
  892. package/dist/core/coherence/events/merged.js +0 -40
  893. package/dist/core/coherence/events/merged.js.map +0 -1
  894. package/dist/core/diff/current-state.js +0 -96
  895. package/dist/core/diff/current-state.js.map +0 -1
  896. package/dist/core/diff/victims.js +0 -247
  897. package/dist/core/diff/victims.js.map +0 -1
  898. package/dist/core/repo/tree/views.js +0 -172
  899. package/dist/core/repo/tree/views.js.map +0 -1
  900. package/dist/core/staging/snapshot.js.map +0 -1
  901. package/dist/core/verify/file.js.map +0 -1
@@ -1,16 +1,24 @@
1
- import { loadConfig } from "../../core/envelope/config.js";
2
- import { fail, reportNoConfig } from "../../core/envelope/json.js";
1
+ import { CodedFailure, configOrRefuse, fail } from "../../core/envelope/json.js";
3
2
  import { message } from "../../core/staging/commit.js";
4
3
  import { acquireDocsLock, DocsBusyError } from "../../core/staging/lock.js";
5
- import { ArchiveFailure } from "./plan/refusal.js";
4
+ import {} from "./plan/refusal.js";
6
5
  import { archiveLocked } from "./run.js";
7
6
  import { LandscapeSpliceError } from "../../core/c4/splice/contract.js";
8
7
  import { NotUtf8Error } from "../../core/staging/writes.js";
9
8
  import { OpenapiMergeError } from "../../core/openapi/merge/error.js";
10
9
  import { InterruptedCommitError } from "../../core/staging/interrupted.js";
10
+ /**
11
+ * The code a failed archive answers with. A `CodedFailure` is thrown from the
12
+ * plan phase (nothing written yet) and from the commit's rollback path (whose
13
+ * message says whether the rollback held). Anything that escapes runArchive and
14
+ * matches no arm below is a bug, and reports as `internal`.
15
+ */
11
16
  function archiveErrorCode(err) {
12
- if (err instanceof ArchiveFailure)
17
+ if (err instanceof CodedFailure)
13
18
  return err.code;
19
+ // Another writer holds the docs repo — the lock is taken refuse-fast below.
20
+ if (err instanceof DocsBusyError)
21
+ return "docs-busy";
14
22
  // Every splice refusal is the mechanical merge answer — see the class.
15
23
  if (err instanceof LandscapeSpliceError)
16
24
  return "merge-failed";
@@ -32,7 +40,7 @@ export function registerArchive(program) {
32
40
  program
33
41
  .command("archive")
34
42
  .argument("<featureId>", "feature id, e.g. FEAT-101")
35
- .description("Merge a shipped feature's deltas into the living specs + model, then archive it")
43
+ .description("Merge a finished feature's deltas into the living specs + model, then archive it (checks the documents, not the code)")
36
44
  .option("--approve", "archive despite GATING coherence issues (may corrupt the living docs); advisory warnings never block")
37
45
  .option("--dry-run", "print the whole merge plan and write nothing")
38
46
  .option("--json", "emit the machine contract instead of the human view")
@@ -52,21 +60,10 @@ export function registerArchive(program) {
52
60
  }
53
61
  async function runArchive(featureId, opts) {
54
62
  const json = opts.json === true;
55
- const loaded = await loadConfig();
56
- if (loaded.kind !== "loaded") {
57
- reportNoConfig(json, loaded);
63
+ const config = await configOrRefuse(json);
64
+ if (config === null)
58
65
  return;
59
- }
60
- const config = loaded.config;
61
- let release;
62
- try {
63
- release = await acquireDocsLock(config.docsDir);
64
- }
65
- catch (err) {
66
- if (err instanceof DocsBusyError)
67
- throw new ArchiveFailure("docs-busy", err.message);
68
- throw err;
69
- }
66
+ const release = await acquireDocsLock(config.docsDir);
70
67
  try {
71
68
  await archiveLocked(config, featureId, opts);
72
69
  }
@@ -1 +1 @@
1
- {"version":3,"file":"archive.js","sourceRoot":"","sources":["../../../src/commands/archive/archive.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `loam archive`: fold a finished feature's three axes into the living docs.\n *\n * Registration and the lock, nothing else. Everything the command actually does\n * is under `./plan/` and `./run.ts`, in that order — the gate refuses, the plan\n * computes, the commit swaps.\n */\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"../../core/envelope/config.js\";\nimport { fail, reportNoConfig, type ErrorCode } from \"../../core/envelope/json.js\";\nimport { message } from \"../../core/staging/commit.js\";\nimport { acquireDocsLock, DocsBusyError } from \"../../core/staging/lock.js\";\nimport { ArchiveFailure, type ArchiveOptions } from \"./plan/refusal.js\";\nimport { archiveLocked } from \"./run.js\";\nimport { LandscapeSpliceError } from \"../../core/c4/splice/contract.js\";\nimport { NotUtf8Error } from \"../../core/staging/writes.js\";\nimport { OpenapiMergeError } from \"../../core/openapi/merge/error.js\";\nimport { InterruptedCommitError } from \"../../core/staging/interrupted.js\";\n\n\nfunction archiveErrorCode(err: unknown): ErrorCode {\n if (err instanceof ArchiveFailure) return err.code;\n // Every splice refusal is the mechanical merge answer — see the class.\n if (err instanceof LandscapeSpliceError) return \"merge-failed\";\n if (err instanceof NotUtf8Error) return \"merge-failed\";\n // The merge branch wraps its own call and re-throws as merge-failed; the\n // create branch (`stripOpenapiRemovalMarkers`) does not, so one unreadable\n // feature contract answered merge-failed or `internal` depending on whether\n // the service already had a living openapi.yaml. The code answers \"can I\n // trust the repo?\", and that answer does not turn on which side of the merge\n // the document sat on.\n if (err instanceof OpenapiMergeError) return \"merge-failed\";\n if (err instanceof InterruptedCommitError) return \"commit-interrupted\";\n return \"internal\";\n}\n\n\nexport function registerArchive(program: Command): void {\n program\n .command(\"archive\")\n .argument(\"<featureId>\", \"feature id, e.g. FEAT-101\")\n .description(\"Merge a shipped feature's deltas into the living specs + model, then archive it\")\n .option(\"--approve\", \"archive despite GATING coherence issues (may corrupt the living docs); advisory warnings never block\")\n .option(\"--dry-run\", \"print the whole merge plan and write nothing\")\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .action(async (featureId: string, opts: ArchiveOptions) => {\n const json = opts.json === true;\n try {\n await runArchive(featureId, opts);\n } catch (err) {\n // Plan-phase failures happen before any write; commit-phase failures are\n // rolled back by runArchive, which says so in the message it throws.\n // A file loam cannot decode is one it cannot merge, and that is the same\n // answer as any other merge it could not compute: nothing was written.\n fail(json, archiveErrorCode(err), `archive ${featureId} failed: ${message(err)}`);\n }\n });\n}\n\nasync function runArchive(featureId: string, opts: ArchiveOptions): Promise<void> {\n const json = opts.json === true;\n const loaded = await loadConfig();\n if (loaded.kind !== \"loaded\") {\n reportNoConfig(json, loaded);\n return;\n }\n const config = loaded.config;\n let release: () => Promise<void>;\n try {\n release = await acquireDocsLock(config.docsDir);\n } catch (err) {\n if (err instanceof DocsBusyError) throw new ArchiveFailure(\"docs-busy\", err.message);\n throw err;\n }\n try {\n await archiveLocked(config, featureId, opts);\n } finally {\n await release();\n }\n}\n"]}
1
+ {"version":3,"file":"archive.js","sourceRoot":"","sources":["../../../src/commands/archive/archive.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,IAAI,EAAkB,MAAM,6BAA6B,CAAC;AACjG,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EAAuB,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAE3E;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,GAAY;IACpC,IAAI,GAAG,YAAY,YAAY;QAAE,OAAO,GAAG,CAAC,IAAI,CAAC;IACjD,4EAA4E;IAC5E,IAAI,GAAG,YAAY,aAAa;QAAE,OAAO,WAAW,CAAC;IACrD,uEAAuE;IACvE,IAAI,GAAG,YAAY,oBAAoB;QAAE,OAAO,cAAc,CAAC;IAC/D,IAAI,GAAG,YAAY,YAAY;QAAE,OAAO,cAAc,CAAC;IACvD,yEAAyE;IACzE,2EAA2E;IAC3E,4EAA4E;IAC5E,yEAAyE;IACzE,6EAA6E;IAC7E,uBAAuB;IACvB,IAAI,GAAG,YAAY,iBAAiB;QAAE,OAAO,cAAc,CAAC;IAC5D,IAAI,GAAG,YAAY,sBAAsB;QAAE,OAAO,oBAAoB,CAAC;IACvE,OAAO,UAAU,CAAC;AACpB,CAAC;AAGD,MAAM,UAAU,eAAe,CAAC,OAAgB;IAC9C,OAAO;SACJ,OAAO,CAAC,SAAS,CAAC;SAClB,QAAQ,CAAC,aAAa,EAAE,2BAA2B,CAAC;SACpD,WAAW,CAAC,uHAAuH,CAAC;SACpI,MAAM,CAAC,WAAW,EAAE,sGAAsG,CAAC;SAC3H,MAAM,CAAC,WAAW,EAAE,8CAA8C,CAAC;SACnE,MAAM,CAAC,QAAQ,EAAE,qDAAqD,CAAC;SACvE,MAAM,CAAC,KAAK,EAAE,SAAiB,EAAE,IAAoB,EAAE,EAAE;QACxD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;QAChC,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,yEAAyE;YACzE,qEAAqE;YACrE,yEAAyE;YACzE,uEAAuE;YACvE,IAAI,CAAC,IAAI,EAAE,gBAAgB,CAAC,GAAG,CAAC,EAAE,WAAW,SAAS,YAAY,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpF,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,SAAiB,EAAE,IAAoB;IAC/D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO;IAC5B,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACtD,IAAI,CAAC;QACH,MAAM,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;AACH,CAAC","sourcesContent":["/**\n * `loam archive`: fold a finished feature's three axes into the living docs.\n *\n * Registration and the lock, nothing else. Everything the command actually does\n * is under `./plan/` and `./run.ts`, in that order — the gate refuses, the plan\n * computes, the commit swaps.\n */\nimport type { Command } from \"commander\";\nimport { CodedFailure, configOrRefuse, fail, type ErrorCode } from \"../../core/envelope/json.js\";\nimport { message } from \"../../core/staging/commit.js\";\nimport { acquireDocsLock, DocsBusyError } from \"../../core/staging/lock.js\";\nimport { type ArchiveOptions } from \"./plan/refusal.js\";\nimport { archiveLocked } from \"./run.js\";\nimport { LandscapeSpliceError } from \"../../core/c4/splice/contract.js\";\nimport { NotUtf8Error } from \"../../core/staging/writes.js\";\nimport { OpenapiMergeError } from \"../../core/openapi/merge/error.js\";\nimport { InterruptedCommitError } from \"../../core/staging/interrupted.js\";\n\n/**\n * The code a failed archive answers with. A `CodedFailure` is thrown from the\n * plan phase (nothing written yet) and from the commit's rollback path (whose\n * message says whether the rollback held). Anything that escapes runArchive and\n * matches no arm below is a bug, and reports as `internal`.\n */\nfunction archiveErrorCode(err: unknown): ErrorCode {\n if (err instanceof CodedFailure) return err.code;\n // Another writer holds the docs repo — the lock is taken refuse-fast below.\n if (err instanceof DocsBusyError) return \"docs-busy\";\n // Every splice refusal is the mechanical merge answer — see the class.\n if (err instanceof LandscapeSpliceError) return \"merge-failed\";\n if (err instanceof NotUtf8Error) return \"merge-failed\";\n // The merge branch wraps its own call and re-throws as merge-failed; the\n // create branch (`stripOpenapiRemovalMarkers`) does not, so one unreadable\n // feature contract answered merge-failed or `internal` depending on whether\n // the service already had a living openapi.yaml. The code answers \"can I\n // trust the repo?\", and that answer does not turn on which side of the merge\n // the document sat on.\n if (err instanceof OpenapiMergeError) return \"merge-failed\";\n if (err instanceof InterruptedCommitError) return \"commit-interrupted\";\n return \"internal\";\n}\n\n\nexport function registerArchive(program: Command): void {\n program\n .command(\"archive\")\n .argument(\"<featureId>\", \"feature id, e.g. FEAT-101\")\n .description(\"Merge a finished feature's deltas into the living specs + model, then archive it (checks the documents, not the code)\")\n .option(\"--approve\", \"archive despite GATING coherence issues (may corrupt the living docs); advisory warnings never block\")\n .option(\"--dry-run\", \"print the whole merge plan and write nothing\")\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .action(async (featureId: string, opts: ArchiveOptions) => {\n const json = opts.json === true;\n try {\n await runArchive(featureId, opts);\n } catch (err) {\n // Plan-phase failures happen before any write; commit-phase failures are\n // rolled back by runArchive, which says so in the message it throws.\n // A file loam cannot decode is one it cannot merge, and that is the same\n // answer as any other merge it could not compute: nothing was written.\n fail(json, archiveErrorCode(err), `archive ${featureId} failed: ${message(err)}`);\n }\n });\n}\n\nasync function runArchive(featureId: string, opts: ArchiveOptions): Promise<void> {\n const json = opts.json === true;\n const config = await configOrRefuse(json);\n if (config === null) return;\n const release = await acquireDocsLock(config.docsDir);\n try {\n await archiveLocked(config, featureId, opts);\n } finally {\n await release();\n }\n}\n"]}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The advisories that mean "archive the other feature first" AND name an error
3
+ * the fleet gate reports once this one lands alone — `spec-api.op-undefined`,
4
+ * `spine.op-undefined`, `spec-event.message-undefined`,
5
+ * `spine.message-unproduced`. The delta pair (`delta.modified-pending`,
6
+ * `delta.removed-pending`) is NOT here, because the line below would be false
7
+ * for it: the merge appends a MODIFIED it cannot find and drops a REMOVED one,
8
+ * so `validate --all` reports nothing — the cost lands on the OTHER feature's
9
+ * archive (`delta.added-duplicate`) or nowhere, which is that warning's own
10
+ * sentence to say.
11
+ */
12
+ const ORDERING = new Set([
13
+ "spec-api.op-pending",
14
+ "c4-api.op-pending",
15
+ "spec-event.message-pending",
16
+ "c4-event.message-pending",
17
+ ]);
18
+ /** The `⚠` lines owed in place of the closing claim — empty when the claim is true. */
19
+ export function outstandingLines(state) {
20
+ const lines = [];
21
+ // One line per stale file rather than one line listing them: each names a file
22
+ // a reader opens, and a comma-joined series would have to choose a verb that
23
+ // reads wrong for one of the two counts.
24
+ for (const path of state.staleViews) {
25
+ lines.push(` ⚠ ${path} no longer matches the tree and this map — run \`loam subsystem sync\`.`);
26
+ }
27
+ for (const w of state.planWarns)
28
+ if (w.severity === "error")
29
+ lines.push(` ⚠ ${w.message}`);
30
+ const ordering = state.advisory.filter((i) => ORDERING.has(i.code));
31
+ if (ordering.length > 0) {
32
+ lines.push(` ⚠ ${state.dryRun ? "archiving this now lands" : "this archive landed"} ahead of ${ordering.length} change(s) still in flight ` +
33
+ "that it waits on (the pending warnings above) — `loam validate --all` reports each as an error until that feature archives too.");
34
+ }
35
+ if (state.overridden.length > 0) {
36
+ lines.push(state.dryRun
37
+ ? ` ⚠ --approve would merge past ${state.overridden.length} gating issue(s) — the living docs would carry them; \`loam validate --all\` says what they cost.`
38
+ : ` ⚠ merged past ${state.overridden.length} gating issue(s) with --approve — the living docs carry them now; \`loam validate --all\` says what they cost.`);
39
+ }
40
+ return lines;
41
+ }
42
+ //# sourceMappingURL=closing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"closing.js","sourceRoot":"","sources":["../../../src/commands/archive/closing.ts"],"names":[],"mappings":"AA8BA;;;;;;;;;;GAUG;AACH,MAAM,QAAQ,GAA2B,IAAI,GAAG,CAAY;IAC1D,qBAAqB;IACrB,mBAAmB;IACnB,4BAA4B;IAC5B,0BAA0B;CAC3B,CAAC,CAAC;AAgBH,uFAAuF;AACvF,MAAM,UAAU,gBAAgB,CAAC,KAAkB;IACjD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,6EAA6E;IAC7E,yCAAyC;IACzC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,yEAAyE,CAAC,CAAC;IACnG,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS;QAAE,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5F,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACpE,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CACR,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,qBAAqB,aAAa,QAAQ,CAAC,MAAM,6BAA6B;YAC/H,iIAAiI,CACpI,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CACR,KAAK,CAAC,MAAM;YACV,CAAC,CAAC,kCAAkC,KAAK,CAAC,UAAU,CAAC,MAAM,mGAAmG;YAC9J,CAAC,CAAC,mBAAmB,KAAK,CAAC,UAAU,CAAC,MAAM,gHAAgH,CAC/J,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["/**\n * What the archive still owes the fleet after its merge — the lines that stand\n * in for \"living spec + landscape are now complete + current.\".\n *\n * That closing line is a claim about the whole docs repo, and it is the line a\n * reader stops at. It may be printed only when this archive leaves nothing the\n * next `validate --all` will fail on, so every reason it cannot be is listed\n * here, once, for the real run and the dry run alike. The dry run used to print\n * none of them: `--json` carried `service.no-model` in `warnings`, the real run\n * printed it after the commit, and the text dry run — the one a person reads\n * before deciding — said nothing (the real-fleet review, 2026-10-21).\n *\n * FOUR REASONS, each a breach the next `validate --all` reports:\n *\n * - a plan finding of ERROR severity that does not gate — `service.no-model`,\n * a service this archive brings in without writing its model (a binding the\n * map gains with no directory; one whose directory the archive creates and\n * the merged map draws gets an empty model, `plan/landscape.ts`). Read off the\n * severity, not a code list: the plan files an error exactly when it knows\n * validate will, and a second list here is the copy that drifts;\n * - an advisory that orders this feature behind another one still in flight\n * and softens a fleet-gate error (four of the `*-pending` family): archived\n * first, the merge lands a reference the other feature's merge has not made\n * true yet;\n * - gating issues the caller merged past with `--approve`;\n * - a generated views file the new map no longer matches — known only once\n * the commit has happened, so the dry run cannot name it.\n */\nimport type { Issue, IssueCode } from \"../../core/vocabulary/issue.js\";\n\n/**\n * The advisories that mean \"archive the other feature first\" AND name an error\n * the fleet gate reports once this one lands alone — `spec-api.op-undefined`,\n * `spine.op-undefined`, `spec-event.message-undefined`,\n * `spine.message-unproduced`. The delta pair (`delta.modified-pending`,\n * `delta.removed-pending`) is NOT here, because the line below would be false\n * for it: the merge appends a MODIFIED it cannot find and drops a REMOVED one,\n * so `validate --all` reports nothing — the cost lands on the OTHER feature's\n * archive (`delta.added-duplicate`) or nowhere, which is that warning's own\n * sentence to say.\n */\nconst ORDERING: ReadonlySet<IssueCode> = new Set<IssueCode>([\n \"spec-api.op-pending\",\n \"c4-api.op-pending\",\n \"spec-event.message-pending\",\n \"c4-event.message-pending\",\n]);\n\n/** Everything the archive knows about what it leaves behind. */\nexport interface Outstanding {\n /** The coherence gate's advisory warnings. */\n advisory: readonly Issue[];\n /** The plan's own findings — overwrites, and the services it creates with no model. */\n planWarns: readonly Issue[];\n /** Gating issues `--approve` walked past. */\n overridden: readonly Issue[];\n /** Generated views the committed map no longer matches; empty before a commit. */\n staleViews: readonly string[];\n /** Phrase it as what WOULD remain — the dry run's tense. */\n dryRun: boolean;\n}\n\n/** The `⚠` lines owed in place of the closing claim — empty when the claim is true. */\nexport function outstandingLines(state: Outstanding): string[] {\n const lines: string[] = [];\n // One line per stale file rather than one line listing them: each names a file\n // a reader opens, and a comma-joined series would have to choose a verb that\n // reads wrong for one of the two counts.\n for (const path of state.staleViews) {\n lines.push(` ⚠ ${path} no longer matches the tree and this map — run \\`loam subsystem sync\\`.`);\n }\n for (const w of state.planWarns) if (w.severity === \"error\") lines.push(` ⚠ ${w.message}`);\n const ordering = state.advisory.filter((i) => ORDERING.has(i.code));\n if (ordering.length > 0) {\n lines.push(\n ` ⚠ ${state.dryRun ? \"archiving this now lands\" : \"this archive landed\"} ahead of ${ordering.length} change(s) still in flight ` +\n \"that it waits on (the pending warnings above) — `loam validate --all` reports each as an error until that feature archives too.\",\n );\n }\n if (state.overridden.length > 0) {\n lines.push(\n state.dryRun\n ? ` ⚠ --approve would merge past ${state.overridden.length} gating issue(s) — the living docs would carry them; \\`loam validate --all\\` says what they cost.`\n : ` ⚠ merged past ${state.overridden.length} gating issue(s) with --approve — the living docs carry them now; \\`loam validate --all\\` says what they cost.`,\n );\n }\n return lines;\n}\n"]}
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { existsSync } from "node:fs";
10
10
  import { parse } from "yaml";
11
- import { repoPath } from "../../../../core/envelope/json.js";
11
+ import { CodedFailure, repoPath } from "../../../../core/envelope/json.js";
12
12
  import { planWrite, readUtf8 } from "../../../../core/staging/writes.js";
13
13
  import { featureSpecPaths } from "../../../../core/repo/paths.js";
14
14
  import { locateServicePaths } from "../../../../core/repo/service-target.js";
@@ -18,8 +18,9 @@ import { asyncapiSurfaces } from "../../../../core/asyncapi/baseline/surfaces.js
18
18
  import { AsyncapiMergeError } from "../../../../core/asyncapi/merge/error.js";
19
19
  import { stripAsyncapiMarkers } from "../../../../core/asyncapi/merge/markers.js";
20
20
  import { mergeAsyncapiSlots } from "../../../../core/asyncapi/merge/merge.js";
21
- import { ArchiveFailure } from "../refusal.js";
22
21
  import {} from "../state.js";
22
+ import { consumerClause } from "./consumers.js";
23
+ import { infoDrift, sayQuoted, sayStale, warnInfoDrift, warnOverwrite } from "./verdict-lines.js";
23
24
  /** The per-section overwrite code — three codes, one per slot shape, mirroring the OpenAPI axis's. */
24
25
  function modifiedCode(section) {
25
26
  if (section === "components.messages")
@@ -28,7 +29,7 @@ function modifiedCode(section) {
28
29
  }
29
30
  export async function planAsyncapiContracts(config, gated, plan, say) {
30
31
  const { featureDir, deltaServices } = gated;
31
- const { writes, planWarns, planGates, asyncapiRemovals } = plan;
32
+ const { writes, planGates, asyncapiRemovals } = plan;
32
33
  for (const svc of deltaServices) {
33
34
  const featAsyncapi = featureSpecPaths(featureDir, svc).asyncapi;
34
35
  if (!existsSync(featAsyncapi))
@@ -40,7 +41,7 @@ export async function planAsyncapiContracts(config, gated, plan, say) {
40
41
  // loam cannot read is one it cannot merge, and that is the same answer as
41
42
  // any other merge it could not compute — nothing is written.
42
43
  if (featDoc.unreadable) {
43
- throw new ArchiveFailure("merge-failed", `feature asyncapi ${repoPath(config.docsDir, featAsyncapi)} for ${svc} does not read as an AsyncAPI document (${featDoc.error ?? "not a YAML mapping"}) — the event axis cannot be merged; fix the file, or delete it if this feature has no contract delta`);
44
+ throw new CodedFailure("merge-failed", `feature asyncapi ${repoPath(config.docsDir, featAsyncapi)} for ${svc} does not read as an AsyncAPI document (${featDoc.error ?? "not a YAML mapping"}) — the event axis cannot be merged; fix the file, or delete it if this feature has no contract delta`);
44
45
  }
45
46
  const names = featDoc.messages.filter((m) => m.remove !== true).map((m) => m.name);
46
47
  // An `x-loam-remove` NESTED on an inline channel message retires nothing:
@@ -89,7 +90,8 @@ export async function planAsyncapiContracts(config, gated, plan, say) {
89
90
  say(` asyncapi: ${svc} — created (${names.join(", ")})`);
90
91
  continue;
91
92
  }
92
- const merge = mergeAsyncapiSlots(await readUtf8(livingAsyncapi), featText, svc);
93
+ const livingText = await readUtf8(livingAsyncapi);
94
+ const merge = mergeAsyncapiSlots(livingText, featText, svc);
93
95
  // What the delta declares OUTSIDE the three slot sections — the one
94
96
  // question the merge result cannot answer for the silence below, because
95
97
  // a merge that wrote nothing reports nothing to distinguish "the delta
@@ -108,56 +110,48 @@ export async function planAsyncapiContracts(config, gated, plan, say) {
108
110
  }
109
111
  else if (surfaces.length > 0) {
110
112
  // "The plan wrote less than my delta spells" is the sentence a reader
111
- // cannot infer from an unchanged file — this file's own comment below
112
- // names it for slots, and a components-only delta is the shape where
113
- // silence is indistinguishable from the defect that made it merge
114
- // nothing at all. Not a warning: every surface being a quote is
115
- // correct authoring and the correct merge.
113
+ // cannot infer from an unchanged file — the quote line's own comment
114
+ // (./verdict-lines.ts) names it for slots, and a components-only
115
+ // delta is the shape where silence is indistinguishable from the
116
+ // defect that made it merge nothing at all. Not a warning: every
117
+ // surface being a quote is correct authoring and the correct merge.
116
118
  say(` asyncapi: ${svc} — nothing to write: every one of the ${surfaces.length} component surface(s) this delta declares already stands as living has it`);
117
119
  }
120
+ // Asked whatever the merge wrote: a delta whose ONLY change is its `info`
121
+ // merges nothing at all, and that is exactly the shape that archived in
122
+ // silence (./verdict-lines.ts).
123
+ warnInfoDrift(plan, say, {
124
+ svc, code: "asyncapi.info-not-merged", file: "asyncapi.yaml", carries: "channels, operations and components",
125
+ labels: infoDrift(parse(livingText), parse(featText)),
126
+ });
118
127
  if (merge.removed.length > 0) {
119
128
  asyncapiRemovals.push({ service: svc, slots: merge.removed.map((slot) => slot.label) });
120
129
  for (const slot of merge.removed)
121
130
  say(` - removes ${slot.label}`);
122
131
  }
123
- // Said out loud, because "the plan wrote less than my delta spells" is
124
- // the one thing a reader cannot infer from a merged file. Not a warning:
125
- // quoting the contract around your change is correct authoring, and
126
- // leaving the quote alone is the correct merge.
127
- for (const slot of merge.quoted) {
128
- say(` · quotes ${slot.label} — unchanged since it was pinned, left as living has it`);
129
- }
130
- // The surface half's mirrors of the three lines around them. A component
131
- // surface reaches the reader by exactly the same three sentences a slot
132
- // does, because it is graded by exactly the same verdict.
133
- for (const id of merge.componentsQuoted) {
134
- say(` · quotes components.${id} — unchanged since it was pinned, left as living has it`);
135
- }
136
- // Stale surfaces reaching the merge at all means --approve pushed past
137
- // the gate's asyncapi.baseline-stale — the plan still names what it cost.
138
- for (const slot of merge.baselineStale) {
139
- say(` ⚠ stale baseline on ${slot.label} — the living value moved since this delta was pinned; the overwrite is what --approve chose`);
140
- }
141
- for (const id of merge.componentsStale) {
142
- say(` ⚠ stale baseline on components.${id} — the living value moved since this delta was pinned; the overwrite is what --approve chose`);
143
- }
132
+ // The quote and stale lines (./verdict-lines.ts says why each is said),
133
+ // the component surfaces' lines mirroring the slots' around them.
134
+ sayQuoted(say, merge.quoted.map((slot) => slot.label));
135
+ sayQuoted(say, merge.componentsQuoted.map((id) => `components.${id}`));
136
+ sayStale(say, merge.baselineStale.map((slot) => slot.label));
137
+ sayStale(say, merge.componentsStale.map((id) => `components.${id}`));
144
138
  for (const id of merge.componentsModified) {
145
- planWarns.push({
146
- severity: "warn",
147
- code: "asyncapi.component-modified",
148
- subject: svc,
139
+ warnOverwrite(plan, say, {
140
+ svc, code: "asyncapi.component-modified", label: `components.${id}`,
149
141
  message: `${svc}: the delta declares components.${id}, which the living AsyncAPI already has with different content — the merge overwrites the living component wholesale`,
150
142
  });
151
- say(` ⚠ overwrites components.${id} — the living definition differs`);
152
143
  }
153
144
  for (const slot of merge.modified) {
154
- planWarns.push({
155
- severity: "warn",
156
- code: modifiedCode(slot.section),
157
- subject: svc,
145
+ // A message is the one slot a consumer names (`Consumes:` lines,
146
+ // `consumes` edges), so only `asyncapi.message-modified` says who the
147
+ // overwrite lands on — the OpenAPI planner's sentence, through the
148
+ // same scan (./consumers.ts). Channels and operations join by nothing.
149
+ const name = merge.modifiedMessageNames.get(slot.label);
150
+ const named = name === undefined ? null : consumerClause(await config.consumers.message(svc, name));
151
+ warnOverwrite(plan, say, {
152
+ svc, code: modifiedCode(slot.section), label: slot.label, named,
158
153
  message: `${svc}: the delta redefines ${slot.label}, which the living AsyncAPI already has — the merge overwrites the living slot wholesale`,
159
154
  });
160
- say(` ⚠ overwrites ${slot.label} — the living definition differs`);
161
155
  }
162
156
  for (const ref of merge.unresolved) {
163
157
  planGates.push({
@@ -170,7 +164,7 @@ export async function planAsyncapiContracts(config, gated, plan, say) {
170
164
  }
171
165
  catch (err) {
172
166
  if (err instanceof AsyncapiMergeError)
173
- throw new ArchiveFailure("merge-failed", err.message);
167
+ throw new CodedFailure("merge-failed", err.message);
174
168
  throw err;
175
169
  }
176
170
  }
@@ -1 +1 @@
1
- {"version":3,"file":"asyncapi.js","sourceRoot":"","sources":["../../../../../src/commands/archive/plan/contracts/asyncapi.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The AsyncAPI contract merge: the feature's asyncapi deltas folded into each\n * living event contract — the event axis's mirror of ./openapi.ts, slot-keyed\n * where that one is path-keyed.\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 { parse } from \"yaml\";\nimport { repoPath } from \"../../../../core/envelope/json.js\";\nimport { planWrite, readUtf8 } from \"../../../../core/staging/writes.js\";\nimport { featureSpecPaths } from \"../../../../core/repo/paths.js\";\nimport { locateServicePaths } from \"../../../../core/repo/service-target.js\";\nimport { readAsyncapi } from \"../../../../core/asyncapi/read.js\";\nimport { asyncapiSlots, type AsyncapiSection } from \"../../../../core/asyncapi/digest.js\";\nimport { asyncapiSurfaces } from \"../../../../core/asyncapi/baseline/surfaces.js\";\nimport { AsyncapiMergeError } from \"../../../../core/asyncapi/merge/error.js\";\nimport { stripAsyncapiMarkers } from \"../../../../core/asyncapi/merge/markers.js\";\nimport { mergeAsyncapiSlots, type AsyncapiMergeResult } from \"../../../../core/asyncapi/merge/merge.js\";\nimport { ArchiveFailure } from \"../refusal.js\";\nimport { type Gated, type Plan } from \"../state.js\";\nimport type { FleetContext } from \"../../../../core/fleet-context.js\";\nimport type { IssueCode } from \"../../../../core/vocabulary/issue.js\";\nimport type { DocsDir } from \"../../../../core/kernel/ids/dirs.js\";\n\n/** The per-section overwrite code — three codes, one per slot shape, mirroring the OpenAPI axis's. */\nfunction modifiedCode(section: AsyncapiSection): IssueCode {\n if (section === \"components.messages\") return \"asyncapi.message-modified\";\n return section === \"channels\" ? \"asyncapi.channel-modified\" : \"asyncapi.operation-modified\";\n}\n\nexport async function planAsyncapiContracts(\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, planWarns, planGates, asyncapiRemovals } = plan;\n for (const svc of deltaServices) {\n const featAsyncapi = featureSpecPaths(featureDir, svc).asyncapi;\n if (!existsSync(featAsyncapi)) continue;\n const featText = await readUtf8(featAsyncapi);\n const featDoc = await readAsyncapi(featAsyncapi);\n // Coherence grades `asyncapi.invalid` and gates on it; the merge stays\n // mechanical under --approve for the OpenAPI planner's reason: a document\n // loam cannot read is one it cannot merge, and that is the same answer as\n // any other merge it could not compute — nothing is written.\n if (featDoc.unreadable) {\n throw new ArchiveFailure(\n \"merge-failed\",\n `feature asyncapi ${repoPath(config.docsDir, featAsyncapi)} for ${svc} does not read as an AsyncAPI document (${featDoc.error ?? \"not a YAML mapping\"}) — the event axis cannot be merged; fix the file, or delete it if this feature has no contract delta`,\n );\n }\n const names = featDoc.messages.filter((m) => m.remove !== true).map((m) => m.name);\n // An `x-loam-remove` NESTED on an inline channel message retires nothing:\n // an inline message is channel-slot interior (SCHEMA.md's decision), so\n // the marker is just channel content — and when the restated channel is\n // otherwise identical to living, not even that: the merge deduplicates it\n // away and the marker lands in no bucket at all. The merge is safe either\n // way (the deep strip keeps the key out of living), but the author asked\n // for a removal that will not happen, and silence there is how a retired\n // message would stay on the wire — openapi.remove-marker-path-level's\n // lesson at the nested depth. Gated like the other plan-visible breaches,\n // --approve and all.\n for (const m of featDoc.messages) {\n if (m.remove !== true || !m.slot.startsWith(\"channels.\")) continue;\n const channel = m.slot.slice(\"channels.\".length, m.slot.lastIndexOf(\".messages.\"));\n planGates.push({\n severity: \"error\",\n code: \"asyncapi.remove-marker-inline\",\n subject: svc,\n message: `${svc}: '${m.slot}' carries x-loam-remove nested on an inline channel message — inline messages are channel interior, not slots, so this retires nothing. Retire the whole channel (x-loam-remove: true at channels.${channel}), or declare the message under components.messages (the channel $ref-ing it) and put the marker there.`,\n });\n }\n // The shared context, for the OpenAPI planner's reason: once per delta\n // service must not mean one fleet walk per delta service.\n const livingAsyncapi = (await locateServicePaths(config.docsDir, svc, config.fleet)).asyncapi;\n try {\n if (!existsSync(livingAsyncapi)) {\n // A removal against a non-existent contract is gated by coherence;\n // under --approve the strip drops the markers, so the one thing left\n // to decide is whether a document remains. It must not when nothing\n // survives: an asyncapi.yaml's very PRESENCE is graded on this axis\n // (absence is `service.no-asyncapi`'s question, silence otherwise),\n // so a slotless or all-markers delta creating an empty living\n // contract would put a presence claim on a service that has none.\n // SLOTS only, deliberately, now that component surfaces merge: a\n // document holding schemas and no channel, operation or message\n // declares no event at all, and creating it would make exactly the\n // presence claim this branch exists to refuse.\n const surviving = asyncapiSlots(parse(featText)).filter((slot) => !slot.remove);\n if (surviving.length === 0) {\n say(` asyncapi: ${svc} — nothing to merge (the delta declares no surviving slots), no living asyncapi.yaml created`);\n continue;\n }\n writes.push(planWrite(livingAsyncapi, stripAsyncapiMarkers(featText, svc)));\n say(` asyncapi: ${svc} — created (${names.join(\", \")})`);\n continue;\n }\n const merge: AsyncapiMergeResult = mergeAsyncapiSlots(await readUtf8(livingAsyncapi), featText, svc);\n // What the delta declares OUTSIDE the three slot sections — the one\n // question the merge result cannot answer for the silence below, because\n // a merge that wrote nothing reports nothing to distinguish \"the delta\n // was all quotes\" from \"the delta was all schemas and I dropped them\".\n const surfaces = asyncapiSurfaces(parse(featText));\n if (merge.text !== null) {\n writes.push(planWrite(livingAsyncapi, merge.text));\n // The parenthesised list names the MESSAGES the delta declares, and a\n // delta whose whole change is a component surface has none — so this\n // printed `merged ()`, the same empty-parenthesis lie the create\n // branch above is commented for: it reads as \"this merge wrote\n // nothing\" about a merge that just published a shared schema to every\n // consumer of the fleet. Drop the parentheses when there is nothing to\n // put in them; the surface lines below name what actually moved.\n say(` asyncapi: ${svc} — merged${names.length > 0 ? ` (${names.join(\", \")})` : \"\"}`);\n } else if (surfaces.length > 0) {\n // \"The plan wrote less than my delta spells\" is the sentence a reader\n // cannot infer from an unchanged file — this file's own comment below\n // names it for slots, and a components-only delta is the shape where\n // silence is indistinguishable from the defect that made it merge\n // nothing at all. Not a warning: every surface being a quote is\n // correct authoring and the correct merge.\n say(` asyncapi: ${svc} — nothing to write: every one of the ${surfaces.length} component surface(s) this delta declares already stands as living has it`);\n }\n if (merge.removed.length > 0) {\n asyncapiRemovals.push({ service: svc, slots: merge.removed.map((slot) => slot.label) });\n for (const slot of merge.removed) say(` - removes ${slot.label}`);\n }\n // Said out loud, because \"the plan wrote less than my delta spells\" is\n // the one thing a reader cannot infer from a merged file. Not a warning:\n // quoting the contract around your change is correct authoring, and\n // leaving the quote alone is the correct merge.\n for (const slot of merge.quoted) {\n say(` · quotes ${slot.label} — unchanged since it was pinned, left as living has it`);\n }\n // The surface half's mirrors of the three lines around them. A component\n // surface reaches the reader by exactly the same three sentences a slot\n // does, because it is graded by exactly the same verdict.\n for (const id of merge.componentsQuoted) {\n say(` · quotes components.${id} — unchanged since it was pinned, left as living has it`);\n }\n // Stale surfaces reaching the merge at all means --approve pushed past\n // the gate's asyncapi.baseline-stale — the plan still names what it cost.\n for (const slot of merge.baselineStale) {\n say(` ⚠ stale baseline on ${slot.label} — the living value moved since this delta was pinned; the overwrite is what --approve chose`);\n }\n for (const id of merge.componentsStale) {\n say(` ⚠ stale baseline on components.${id} — the living value moved since this delta was pinned; the overwrite is what --approve chose`);\n }\n for (const id of merge.componentsModified) {\n planWarns.push({\n severity: \"warn\",\n code: \"asyncapi.component-modified\",\n subject: svc,\n message: `${svc}: the delta declares components.${id}, which the living AsyncAPI already has with different content — the merge overwrites the living component wholesale`,\n });\n say(` ⚠ overwrites components.${id} — the living definition differs`);\n }\n for (const slot of merge.modified) {\n planWarns.push({\n severity: \"warn\",\n code: modifiedCode(slot.section),\n subject: svc,\n message: `${svc}: the delta redefines ${slot.label}, which the living AsyncAPI already has — the merge overwrites the living slot wholesale`,\n });\n say(` ⚠ overwrites ${slot.label} — the living definition differs`);\n }\n for (const ref of merge.unresolved) {\n planGates.push({\n severity: \"error\",\n code: \"asyncapi.ref-unresolved\",\n subject: svc,\n message: `${svc}: $ref '${ref}' resolves in neither the feature's asyncapi.yaml nor the living one — the merged document would carry a dangling reference`,\n });\n }\n } catch (err) {\n if (err instanceof AsyncapiMergeError) throw new ArchiveFailure(\"merge-failed\", err.message);\n throw err;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"asyncapi.js","sourceRoot":"","sources":["../../../../../src/commands/archive/plan/contracts/asyncapi.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The AsyncAPI contract merge: the feature's asyncapi deltas folded into each\n * living event contract — the event axis's mirror of ./openapi.ts, slot-keyed\n * where that one is path-keyed.\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 { parse } from \"yaml\";\nimport { CodedFailure, repoPath } from \"../../../../core/envelope/json.js\";\nimport { planWrite, readUtf8 } from \"../../../../core/staging/writes.js\";\nimport { featureSpecPaths } from \"../../../../core/repo/paths.js\";\nimport { locateServicePaths } from \"../../../../core/repo/service-target.js\";\nimport { readAsyncapi } from \"../../../../core/asyncapi/read.js\";\nimport { asyncapiSlots, type AsyncapiSection } from \"../../../../core/asyncapi/digest.js\";\nimport { asyncapiSurfaces } from \"../../../../core/asyncapi/baseline/surfaces.js\";\nimport { AsyncapiMergeError } from \"../../../../core/asyncapi/merge/error.js\";\nimport { stripAsyncapiMarkers } from \"../../../../core/asyncapi/merge/markers.js\";\nimport { mergeAsyncapiSlots, type AsyncapiMergeResult } from \"../../../../core/asyncapi/merge/merge.js\";\nimport { type Gated, type Plan } from \"../state.js\";\nimport { consumerClause, type ContractConsumers } from \"./consumers.js\";\nimport { infoDrift, sayQuoted, sayStale, warnInfoDrift, warnOverwrite } from \"./verdict-lines.js\";\nimport type { FleetContext } from \"../../../../core/fleet-context.js\";\nimport type { IssueCode } from \"../../../../core/vocabulary/issue.js\";\nimport type { DocsDir } from \"../../../../core/kernel/ids/dirs.js\";\n\n/** The per-section overwrite code — three codes, one per slot shape, mirroring the OpenAPI axis's. */\nfunction modifiedCode(section: AsyncapiSection): IssueCode {\n if (section === \"components.messages\") return \"asyncapi.message-modified\";\n return section === \"channels\" ? \"asyncapi.channel-modified\" : \"asyncapi.operation-modified\";\n}\n\nexport async function planAsyncapiContracts(\n config: { docsDir: DocsDir; fleet: FleetContext; consumers: ContractConsumers },\n gated: Gated,\n plan: Plan,\n say: (line?: string) => void,\n): Promise<void> {\n const { featureDir, deltaServices } = gated;\n const { writes, planGates, asyncapiRemovals } = plan;\n for (const svc of deltaServices) {\n const featAsyncapi = featureSpecPaths(featureDir, svc).asyncapi;\n if (!existsSync(featAsyncapi)) continue;\n const featText = await readUtf8(featAsyncapi);\n const featDoc = await readAsyncapi(featAsyncapi);\n // Coherence grades `asyncapi.invalid` and gates on it; the merge stays\n // mechanical under --approve for the OpenAPI planner's reason: a document\n // loam cannot read is one it cannot merge, and that is the same answer as\n // any other merge it could not compute — nothing is written.\n if (featDoc.unreadable) {\n throw new CodedFailure(\n \"merge-failed\",\n `feature asyncapi ${repoPath(config.docsDir, featAsyncapi)} for ${svc} does not read as an AsyncAPI document (${featDoc.error ?? \"not a YAML mapping\"}) — the event axis cannot be merged; fix the file, or delete it if this feature has no contract delta`,\n );\n }\n const names = featDoc.messages.filter((m) => m.remove !== true).map((m) => m.name);\n // An `x-loam-remove` NESTED on an inline channel message retires nothing:\n // an inline message is channel-slot interior (SCHEMA.md's decision), so\n // the marker is just channel content — and when the restated channel is\n // otherwise identical to living, not even that: the merge deduplicates it\n // away and the marker lands in no bucket at all. The merge is safe either\n // way (the deep strip keeps the key out of living), but the author asked\n // for a removal that will not happen, and silence there is how a retired\n // message would stay on the wire — openapi.remove-marker-path-level's\n // lesson at the nested depth. Gated like the other plan-visible breaches,\n // --approve and all.\n for (const m of featDoc.messages) {\n if (m.remove !== true || !m.slot.startsWith(\"channels.\")) continue;\n const channel = m.slot.slice(\"channels.\".length, m.slot.lastIndexOf(\".messages.\"));\n planGates.push({\n severity: \"error\",\n code: \"asyncapi.remove-marker-inline\",\n subject: svc,\n message: `${svc}: '${m.slot}' carries x-loam-remove nested on an inline channel message — inline messages are channel interior, not slots, so this retires nothing. Retire the whole channel (x-loam-remove: true at channels.${channel}), or declare the message under components.messages (the channel $ref-ing it) and put the marker there.`,\n });\n }\n // The shared context, for the OpenAPI planner's reason: once per delta\n // service must not mean one fleet walk per delta service.\n const livingAsyncapi = (await locateServicePaths(config.docsDir, svc, config.fleet)).asyncapi;\n try {\n if (!existsSync(livingAsyncapi)) {\n // A removal against a non-existent contract is gated by coherence;\n // under --approve the strip drops the markers, so the one thing left\n // to decide is whether a document remains. It must not when nothing\n // survives: an asyncapi.yaml's very PRESENCE is graded on this axis\n // (absence is `service.no-asyncapi`'s question, silence otherwise),\n // so a slotless or all-markers delta creating an empty living\n // contract would put a presence claim on a service that has none.\n // SLOTS only, deliberately, now that component surfaces merge: a\n // document holding schemas and no channel, operation or message\n // declares no event at all, and creating it would make exactly the\n // presence claim this branch exists to refuse.\n const surviving = asyncapiSlots(parse(featText)).filter((slot) => !slot.remove);\n if (surviving.length === 0) {\n say(` asyncapi: ${svc} — nothing to merge (the delta declares no surviving slots), no living asyncapi.yaml created`);\n continue;\n }\n writes.push(planWrite(livingAsyncapi, stripAsyncapiMarkers(featText, svc)));\n say(` asyncapi: ${svc} — created (${names.join(\", \")})`);\n continue;\n }\n const livingText = await readUtf8(livingAsyncapi);\n const merge: AsyncapiMergeResult = mergeAsyncapiSlots(livingText, featText, svc);\n // What the delta declares OUTSIDE the three slot sections — the one\n // question the merge result cannot answer for the silence below, because\n // a merge that wrote nothing reports nothing to distinguish \"the delta\n // was all quotes\" from \"the delta was all schemas and I dropped them\".\n const surfaces = asyncapiSurfaces(parse(featText));\n if (merge.text !== null) {\n writes.push(planWrite(livingAsyncapi, merge.text));\n // The parenthesised list names the MESSAGES the delta declares, and a\n // delta whose whole change is a component surface has none — so this\n // printed `merged ()`, the same empty-parenthesis lie the create\n // branch above is commented for: it reads as \"this merge wrote\n // nothing\" about a merge that just published a shared schema to every\n // consumer of the fleet. Drop the parentheses when there is nothing to\n // put in them; the surface lines below name what actually moved.\n say(` asyncapi: ${svc} — merged${names.length > 0 ? ` (${names.join(\", \")})` : \"\"}`);\n } else if (surfaces.length > 0) {\n // \"The plan wrote less than my delta spells\" is the sentence a reader\n // cannot infer from an unchanged file — the quote line's own comment\n // (./verdict-lines.ts) names it for slots, and a components-only\n // delta is the shape where silence is indistinguishable from the\n // defect that made it merge nothing at all. Not a warning: every\n // surface being a quote is correct authoring and the correct merge.\n say(` asyncapi: ${svc} — nothing to write: every one of the ${surfaces.length} component surface(s) this delta declares already stands as living has it`);\n }\n // Asked whatever the merge wrote: a delta whose ONLY change is its `info`\n // merges nothing at all, and that is exactly the shape that archived in\n // silence (./verdict-lines.ts).\n warnInfoDrift(plan, say, {\n svc, code: \"asyncapi.info-not-merged\", file: \"asyncapi.yaml\", carries: \"channels, operations and components\",\n labels: infoDrift(parse(livingText), parse(featText)),\n });\n if (merge.removed.length > 0) {\n asyncapiRemovals.push({ service: svc, slots: merge.removed.map((slot) => slot.label) });\n for (const slot of merge.removed) say(` - removes ${slot.label}`);\n }\n // The quote and stale lines (./verdict-lines.ts says why each is said),\n // the component surfaces' lines mirroring the slots' around them.\n sayQuoted(say, merge.quoted.map((slot) => slot.label));\n sayQuoted(say, merge.componentsQuoted.map((id) => `components.${id}`));\n sayStale(say, merge.baselineStale.map((slot) => slot.label));\n sayStale(say, merge.componentsStale.map((id) => `components.${id}`));\n for (const id of merge.componentsModified) {\n warnOverwrite(plan, say, {\n svc, code: \"asyncapi.component-modified\", label: `components.${id}`,\n message: `${svc}: the delta declares components.${id}, which the living AsyncAPI already has with different content — the merge overwrites the living component wholesale`,\n });\n }\n for (const slot of merge.modified) {\n // A message is the one slot a consumer names (`Consumes:` lines,\n // `consumes` edges), so only `asyncapi.message-modified` says who the\n // overwrite lands on — the OpenAPI planner's sentence, through the\n // same scan (./consumers.ts). Channels and operations join by nothing.\n const name = merge.modifiedMessageNames.get(slot.label);\n const named = name === undefined ? null : consumerClause(await config.consumers.message(svc, name));\n warnOverwrite(plan, say, {\n svc, code: modifiedCode(slot.section), label: slot.label, named,\n message: `${svc}: the delta redefines ${slot.label}, which the living AsyncAPI already has — the merge overwrites the living slot wholesale`,\n });\n }\n for (const ref of merge.unresolved) {\n planGates.push({\n severity: \"error\",\n code: \"asyncapi.ref-unresolved\",\n subject: svc,\n message: `${svc}: $ref '${ref}' resolves in neither the feature's asyncapi.yaml nor the living one — the merged document would carry a dangling reference`,\n });\n }\n } catch (err) {\n if (err instanceof AsyncapiMergeError) throw new CodedFailure(\"merge-failed\", err.message);\n throw err;\n }\n }\n}\n"]}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Who in the CURRENT fleet consumes what an archive is about to overwrite — the
3
+ * consumers an `openapi.op-modified` / `asyncapi.message-modified` warning
4
+ * names, so "the merge overwrites the living operation wholesale" says whom
5
+ * that lands on instead of leaving the reader to go and find out.
6
+ *
7
+ * NOT A NEW JOIN. This is the one consumer index (core/consumers/consumers.ts)
8
+ * — the one `loam diff` names victims with and the coherence gate refuses on —
9
+ * asked over the living fleet as it stands before the merge: the same edges of
10
+ * the `architecture/` project, the same living requirements, the same use-case
11
+ * hops, the same suspensions for a consumer nobody could read or a caller
12
+ * drawn with no op, and the same sentence for the answer (`consumerStance`).
13
+ * Its `own` list (the provider's own documents) is the gate's to count and is
14
+ * not named here: a warning about whom an overwrite lands on is about OTHER
15
+ * services, as the diff's is.
16
+ *
17
+ * LAZY, AND PAID ONLY WHEN A WARNING FIRES. The index reads every service's
18
+ * four documents (`livingFleet`) and, at the first question, parses the
19
+ * `architecture/` project — through the run's read index, so a second question
20
+ * pays for neither again; the archive's own gate calls coherence without that
21
+ * index, so its read is not shared with this one. Measured 2026-10-10 on the
22
+ * 120-service benchmark fleet (scripts/bench-validate.ts's shape), with one
23
+ * feature overwriting one operation: `archive --dry-run --json` went from a
24
+ * 1216 ms to a 1346 ms median over five runs through tsx (~0.5 s of which is
25
+ * startup); taken apart, about 50 ms of document reads and about 120 ms of
26
+ * LikeC4. An archive that overwrites nothing never builds it.
27
+ *
28
+ * What it does NOT answer: `openapi.component-modified` and
29
+ * `asyncapi.component-modified`. A component's consumers are the operations or
30
+ * messages whose `$ref` closure reaches it, and then THEIR consumers; nothing
31
+ * indexes a contract by component today (an operation carries its closure's
32
+ * digest, not its members), and building that reverse index for a warning is
33
+ * the heavy new structure this reuse was allowed only without.
34
+ */
35
+ import { consumerIndex } from "../../../../core/consumers/consumers.js";
36
+ import { consumerStance, scanDetails } from "../../../../core/consumers/scan.js";
37
+ import { FleetContext } from "../../../../core/fleet-context.js";
38
+ export function contractConsumers(config) {
39
+ // The run's own read index: the planners have already read the delta
40
+ // services' living contracts through it, and the index memoises its fleet
41
+ // and its map on it. Constructing the index reads nothing.
42
+ const index = consumerIndex({ docsDir: config.docsDir, context: config.fleet });
43
+ return {
44
+ op: (provider, operationId) => index.opConsumers(provider, operationId),
45
+ message: (provider, name) => index.messageConsumers(provider, name),
46
+ };
47
+ }
48
+ /**
49
+ * The clause an overwrite warning's message ends with, and the lines its
50
+ * `details` carry: positive evidence first, then what could not be checked —
51
+ * the order `loam diff` lists them in.
52
+ */
53
+ export function consumerClause(scan) {
54
+ return { clause: consumerStance(scan), details: scanDetails(scan) };
55
+ }
56
+ //# sourceMappingURL=consumers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consumers.js","sourceRoot":"","sources":["../../../../../src/commands/archive/plan/contracts/consumers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAqB,MAAM,oCAAoC,CAAC;AACpG,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAWjE,MAAM,UAAU,iBAAiB,CAAC,MAAiD;IACjF,qEAAqE;IACrE,0EAA0E;IAC1E,2DAA2D;IAC3D,MAAM,KAAK,GAAG,aAAa,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAChF,OAAO;QACL,EAAE,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,EAAE,WAAW,CAAC;QACvE,OAAO,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC;KACpE,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAkB;IAC/C,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;AACtE,CAAC","sourcesContent":["/**\n * Who in the CURRENT fleet consumes what an archive is about to overwrite — the\n * consumers an `openapi.op-modified` / `asyncapi.message-modified` warning\n * names, so \"the merge overwrites the living operation wholesale\" says whom\n * that lands on instead of leaving the reader to go and find out.\n *\n * NOT A NEW JOIN. This is the one consumer index (core/consumers/consumers.ts)\n * — the one `loam diff` names victims with and the coherence gate refuses on —\n * asked over the living fleet as it stands before the merge: the same edges of\n * the `architecture/` project, the same living requirements, the same use-case\n * hops, the same suspensions for a consumer nobody could read or a caller\n * drawn with no op, and the same sentence for the answer (`consumerStance`).\n * Its `own` list (the provider's own documents) is the gate's to count and is\n * not named here: a warning about whom an overwrite lands on is about OTHER\n * services, as the diff's is.\n *\n * LAZY, AND PAID ONLY WHEN A WARNING FIRES. The index reads every service's\n * four documents (`livingFleet`) and, at the first question, parses the\n * `architecture/` project — through the run's read index, so a second question\n * pays for neither again; the archive's own gate calls coherence without that\n * index, so its read is not shared with this one. Measured 2026-10-10 on the\n * 120-service benchmark fleet (scripts/bench-validate.ts's shape), with one\n * feature overwriting one operation: `archive --dry-run --json` went from a\n * 1216 ms to a 1346 ms median over five runs through tsx (~0.5 s of which is\n * startup); taken apart, about 50 ms of document reads and about 120 ms of\n * LikeC4. An archive that overwrites nothing never builds it.\n *\n * What it does NOT answer: `openapi.component-modified` and\n * `asyncapi.component-modified`. A component's consumers are the operations or\n * messages whose `$ref` closure reaches it, and then THEIR consumers; nothing\n * indexes a contract by component today (an operation carries its closure's\n * digest, not its members), and building that reverse index for a warning is\n * the heavy new structure this reuse was allowed only without.\n */\nimport { consumerIndex } from \"../../../../core/consumers/consumers.js\";\nimport { consumerStance, scanDetails, type ConsumerScan } from \"../../../../core/consumers/scan.js\";\nimport { FleetContext } from \"../../../../core/fleet-context.js\";\nimport type { DocsDir } from \"../../../../core/kernel/ids/dirs.js\";\n\n/** The two questions the contract planners ask, each answered at most once per run's index. */\nexport interface ContractConsumers {\n /** Current consumers of `provider`'s operation `operationId`. */\n op(provider: string, operationId: string): Promise<ConsumerScan>;\n /** Current consumers of message `name` that `provider` declares. */\n message(provider: string, name: string): Promise<ConsumerScan>;\n}\n\nexport function contractConsumers(config: { docsDir: DocsDir; fleet: FleetContext }): ContractConsumers {\n // The run's own read index: the planners have already read the delta\n // services' living contracts through it, and the index memoises its fleet\n // and its map on it. Constructing the index reads nothing.\n const index = consumerIndex({ docsDir: config.docsDir, context: config.fleet });\n return {\n op: (provider, operationId) => index.opConsumers(provider, operationId),\n message: (provider, name) => index.messageConsumers(provider, name),\n };\n}\n\n/**\n * The clause an overwrite warning's message ends with, and the lines its\n * `details` carry: positive evidence first, then what could not be checked —\n * the order `loam diff` lists them in.\n */\nexport function consumerClause(scan: ConsumerScan): { clause: string; details: string[] } {\n return { clause: consumerStance(scan), details: scanDetails(scan) };\n}\n"]}