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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (901) hide show
  1. package/CHANGELOG.md +3448 -0
  2. package/COMPARISON.md +91 -3
  3. package/CONTRIBUTING.md +37 -0
  4. package/MIGRATING-from-OpenSpec.md +47 -23
  5. package/QUICKSTART.md +189 -12
  6. package/README.md +274 -65
  7. package/ROADMAP.md +572 -31
  8. package/SCHEMA.md +1709 -155
  9. package/WORKFLOW.md +298 -72
  10. package/dist/cli.js +26 -8
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/adopt/adopt.js +5 -10
  13. package/dist/commands/adopt/adopt.js.map +1 -1
  14. package/dist/commands/adopt/render.js +50 -9
  15. package/dist/commands/adopt/render.js.map +1 -1
  16. package/dist/commands/archive/archive.js +16 -19
  17. package/dist/commands/archive/archive.js.map +1 -1
  18. package/dist/commands/archive/closing.js +42 -0
  19. package/dist/commands/archive/closing.js.map +1 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js +36 -42
  21. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
  22. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  24. package/dist/commands/archive/plan/contracts/openapi.js +77 -43
  25. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
  26. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  28. package/dist/commands/archive/plan/document/head.js +151 -0
  29. package/dist/commands/archive/plan/document/head.js.map +1 -0
  30. package/dist/commands/archive/plan/document/links.js +284 -0
  31. package/dist/commands/archive/plan/document/links.js.map +1 -0
  32. package/dist/commands/archive/plan/document/run.js +136 -0
  33. package/dist/commands/archive/plan/document/run.js.map +1 -0
  34. package/dist/commands/archive/plan/gate.js +21 -19
  35. package/dist/commands/archive/plan/gate.js.map +1 -1
  36. package/dist/commands/archive/plan/landscape.js +167 -30
  37. package/dist/commands/archive/plan/landscape.js.map +1 -1
  38. package/dist/commands/archive/plan/model/extending.js +85 -0
  39. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  40. package/dist/commands/archive/plan/refusal.js +14 -19
  41. package/dist/commands/archive/plan/refusal.js.map +1 -1
  42. package/dist/commands/archive/plan/specs.js +137 -56
  43. package/dist/commands/archive/plan/specs.js.map +1 -1
  44. package/dist/commands/archive/plan/state.js +3 -0
  45. package/dist/commands/archive/plan/state.js.map +1 -1
  46. package/dist/commands/archive/run.js +134 -30
  47. package/dist/commands/archive/run.js.map +1 -1
  48. package/dist/commands/archive/shipped.js +49 -0
  49. package/dist/commands/archive/shipped.js.map +1 -0
  50. package/dist/commands/context/context.js +85 -18
  51. package/dist/commands/context/context.js.map +1 -1
  52. package/dist/commands/context/print.js +29 -7
  53. package/dist/commands/context/print.js.map +1 -1
  54. package/dist/commands/delta/delta.js +102 -14
  55. package/dist/commands/delta/delta.js.map +1 -1
  56. package/dist/commands/delta/print.js +17 -1
  57. package/dist/commands/delta/print.js.map +1 -1
  58. package/dist/commands/dependencies.js +3 -7
  59. package/dist/commands/dependencies.js.map +1 -1
  60. package/dist/commands/diff/diff.js +20 -27
  61. package/dist/commands/diff/diff.js.map +1 -1
  62. package/dist/commands/doctor.js +60 -1
  63. package/dist/commands/doctor.js.map +1 -1
  64. package/dist/commands/explain/explain.js +89 -13
  65. package/dist/commands/explain/explain.js.map +1 -1
  66. package/dist/commands/explore.js +16 -10
  67. package/dist/commands/explore.js.map +1 -1
  68. package/dist/commands/gate/gate.js +45 -8
  69. package/dist/commands/gate/gate.js.map +1 -1
  70. package/dist/commands/gate/print.js +15 -3
  71. package/dist/commands/gate/print.js.map +1 -1
  72. package/dist/commands/gherkin/commit.js +13 -54
  73. package/dist/commands/gherkin/commit.js.map +1 -1
  74. package/dist/commands/gherkin/gherkin.js +36 -20
  75. package/dist/commands/gherkin/gherkin.js.map +1 -1
  76. package/dist/commands/gherkin/reconcile.js +10 -13
  77. package/dist/commands/gherkin/reconcile.js.map +1 -1
  78. package/dist/commands/init/first-hour.js +44 -0
  79. package/dist/commands/init/first-hour.js.map +1 -1
  80. package/dist/commands/init/init.js +18 -22
  81. package/dist/commands/init/init.js.map +1 -1
  82. package/dist/commands/list/campaign/campaign.js +4 -6
  83. package/dist/commands/list/campaign/campaign.js.map +1 -1
  84. package/dist/commands/list/json.js +5 -7
  85. package/dist/commands/list/json.js.map +1 -1
  86. package/dist/commands/list/list.js +44 -29
  87. package/dist/commands/list/list.js.map +1 -1
  88. package/dist/commands/list/print.js +52 -9
  89. package/dist/commands/list/print.js.map +1 -1
  90. package/dist/commands/list/suites/suites.js +140 -0
  91. package/dist/commands/list/suites/suites.js.map +1 -0
  92. package/dist/commands/list/views.js +37 -34
  93. package/dist/commands/list/views.js.map +1 -1
  94. package/dist/commands/mcp/dispatch.js +91 -36
  95. package/dist/commands/mcp/dispatch.js.map +1 -1
  96. package/dist/commands/mcp/mcp.js +56 -15
  97. package/dist/commands/mcp/mcp.js.map +1 -1
  98. package/dist/commands/mcp/serve.js.map +1 -1
  99. package/dist/commands/migrate-openspec/materialize/active.js +27 -22
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
  101. package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
  102. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
  103. package/dist/commands/migrate-openspec/materialize/target.js +2 -2
  104. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
  105. package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
  106. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
  107. package/dist/commands/migrate-openspec/openspec/error.js +7 -8
  108. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
  109. package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
  110. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
  111. package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
  112. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
  113. package/dist/commands/new/capability-template.js +118 -0
  114. package/dist/commands/new/capability-template.js.map +1 -0
  115. package/dist/commands/new/commit.js +8 -22
  116. package/dist/commands/new/commit.js.map +1 -1
  117. package/dist/commands/new/modifies.js +206 -0
  118. package/dist/commands/new/modifies.js.map +1 -0
  119. package/dist/commands/new/new.js +59 -14
  120. package/dist/commands/new/new.js.map +1 -1
  121. package/dist/commands/new/templates.js +48 -124
  122. package/dist/commands/new/templates.js.map +1 -1
  123. package/dist/commands/open.js +3 -7
  124. package/dist/commands/open.js.map +1 -1
  125. package/dist/commands/policy/gate.js +27 -0
  126. package/dist/commands/policy/gate.js.map +1 -1
  127. package/dist/commands/rebase/plan.js +2 -2
  128. package/dist/commands/rebase/plan.js.map +1 -1
  129. package/dist/commands/rebase/rebase.js +60 -35
  130. package/dist/commands/rebase/rebase.js.map +1 -1
  131. package/dist/commands/seed/commit.js +55 -26
  132. package/dist/commands/seed/commit.js.map +1 -1
  133. package/dist/commands/seed/plan.js +158 -13
  134. package/dist/commands/seed/plan.js.map +1 -1
  135. package/dist/commands/seed/seed.js +13 -11
  136. package/dist/commands/seed/seed.js.map +1 -1
  137. package/dist/commands/show/feature.js +9 -5
  138. package/dist/commands/show/feature.js.map +1 -1
  139. package/dist/commands/show/introduced.js +157 -0
  140. package/dist/commands/show/introduced.js.map +1 -0
  141. package/dist/commands/show/marks.js +35 -6
  142. package/dist/commands/show/marks.js.map +1 -1
  143. package/dist/commands/show/service.js +41 -33
  144. package/dist/commands/show/service.js.map +1 -1
  145. package/dist/commands/show/show.js +17 -7
  146. package/dist/commands/show/show.js.map +1 -1
  147. package/dist/commands/status/fleet-next.js +90 -0
  148. package/dist/commands/status/fleet-next.js.map +1 -0
  149. package/dist/commands/status/json.js +2 -0
  150. package/dist/commands/status/json.js.map +1 -1
  151. package/dist/commands/status/print.js +89 -37
  152. package/dist/commands/status/print.js.map +1 -1
  153. package/dist/commands/status/status.js +3 -7
  154. package/dist/commands/status/status.js.map +1 -1
  155. package/dist/commands/steps/steps.js +103 -23
  156. package/dist/commands/steps/steps.js.map +1 -1
  157. package/dist/commands/subsystem/edit.js +7 -7
  158. package/dist/commands/subsystem/edit.js.map +1 -1
  159. package/dist/commands/subsystem/move.js +106 -46
  160. package/dist/commands/subsystem/move.js.map +1 -1
  161. package/dist/commands/subsystem/query.js +2 -4
  162. package/dist/commands/subsystem/query.js.map +1 -1
  163. package/dist/commands/subsystem/subsystem.js +4 -7
  164. package/dist/commands/subsystem/subsystem.js.map +1 -1
  165. package/dist/commands/subsystem/sync.js +289 -74
  166. package/dist/commands/subsystem/sync.js.map +1 -1
  167. package/dist/commands/subsystem/txn/exclude.js +132 -0
  168. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  169. package/dist/commands/subsystem/txn/links.js +128 -0
  170. package/dist/commands/subsystem/txn/links.js.map +1 -0
  171. package/dist/commands/subsystem/txn/report.js +174 -0
  172. package/dist/commands/subsystem/txn/report.js.map +1 -0
  173. package/dist/commands/subsystem/txn/txn.js +147 -45
  174. package/dist/commands/subsystem/txn/txn.js.map +1 -1
  175. package/dist/commands/subsystem/txn/views.js +200 -21
  176. package/dist/commands/subsystem/txn/views.js.map +1 -1
  177. package/dist/commands/tasks/actions.js +107 -0
  178. package/dist/commands/tasks/actions.js.map +1 -0
  179. package/dist/commands/tasks/render.js +253 -0
  180. package/dist/commands/tasks/render.js.map +1 -0
  181. package/dist/commands/tasks/tasks.js +119 -0
  182. package/dist/commands/tasks/tasks.js.map +1 -0
  183. package/dist/commands/unarchive/manifest.js +42 -26
  184. package/dist/commands/unarchive/manifest.js.map +1 -1
  185. package/dist/commands/unarchive/restore.js +83 -33
  186. package/dist/commands/unarchive/restore.js.map +1 -1
  187. package/dist/commands/unarchive/unarchive.js +22 -30
  188. package/dist/commands/unarchive/unarchive.js.map +1 -1
  189. package/dist/commands/validate/arch-coverage.js +78 -27
  190. package/dist/commands/validate/arch-coverage.js.map +1 -1
  191. package/dist/commands/validate/checks/fleet-shape.js +34 -126
  192. package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
  193. package/dist/commands/validate/checks/health-deps.js +9 -6
  194. package/dist/commands/validate/checks/health-deps.js.map +1 -1
  195. package/dist/commands/validate/checks/introduced.js +102 -0
  196. package/dist/commands/validate/checks/introduced.js.map +1 -0
  197. package/dist/commands/validate/checks/requirements.js +18 -8
  198. package/dist/commands/validate/checks/requirements.js.map +1 -1
  199. package/dist/commands/validate/checks/sources.js +11 -2
  200. package/dist/commands/validate/checks/sources.js.map +1 -1
  201. package/dist/commands/validate/coverage/covers-after.js +105 -0
  202. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  203. package/dist/commands/validate/feature.js +26 -20
  204. package/dist/commands/validate/feature.js.map +1 -1
  205. package/dist/commands/validate/fleet/census.js +37 -13
  206. package/dist/commands/validate/fleet/census.js.map +1 -1
  207. package/dist/commands/validate/fleet/landscape.js +144 -126
  208. package/dist/commands/validate/fleet/landscape.js.map +1 -1
  209. package/dist/commands/validate/fleet/load.js +66 -0
  210. package/dist/commands/validate/fleet/load.js.map +1 -1
  211. package/dist/commands/validate/fleet/map/attest.js +98 -0
  212. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  213. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  214. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  215. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  216. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  217. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  218. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  219. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  220. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  221. package/dist/commands/validate/fleet/obligations.js +44 -14
  222. package/dist/commands/validate/fleet/obligations.js.map +1 -1
  223. package/dist/commands/validate/fleet/scorecard/print.js +10 -2
  224. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
  225. package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
  226. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
  227. package/dist/commands/validate/fleet/usecases/place.js.map +1 -1
  228. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  229. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  230. package/dist/commands/validate/fleet/views/ids.js +50 -15
  231. package/dist/commands/validate/fleet/views/ids.js.map +1 -1
  232. package/dist/commands/validate/fleet/views/projects.js +278 -0
  233. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  234. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  235. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  236. package/dist/commands/validate/fleet/views/stale.js +40 -47
  237. package/dist/commands/validate/fleet/views/stale.js.map +1 -1
  238. package/dist/commands/validate/links/corpus.js +1 -4
  239. package/dist/commands/validate/links/corpus.js.map +1 -1
  240. package/dist/commands/validate/links/glossary.js.map +1 -1
  241. package/dist/commands/validate/render/repeats.js +63 -0
  242. package/dist/commands/validate/render/repeats.js.map +1 -0
  243. package/dist/commands/validate/render/rollups.js +115 -0
  244. package/dist/commands/validate/render/rollups.js.map +1 -0
  245. package/dist/commands/validate/render/text.js +199 -0
  246. package/dist/commands/validate/render/text.js.map +1 -0
  247. package/dist/commands/validate/report.js +36 -160
  248. package/dist/commands/validate/report.js.map +1 -1
  249. package/dist/commands/validate/scope.js +113 -0
  250. package/dist/commands/validate/scope.js.map +1 -0
  251. package/dist/commands/validate/service/api.js +21 -107
  252. package/dist/commands/validate/service/api.js.map +1 -1
  253. package/dist/commands/validate/service/contracts/generated.js +134 -0
  254. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  255. package/dist/commands/validate/service/events/events.js +36 -14
  256. package/dist/commands/validate/service/events/events.js.map +1 -1
  257. package/dist/commands/validate/service/events/message-producers.js +1 -1
  258. package/dist/commands/validate/service/events/message-producers.js.map +1 -1
  259. package/dist/commands/validate/service/evidence-pins.js +56 -10
  260. package/dist/commands/validate/service/evidence-pins.js.map +1 -1
  261. package/dist/commands/validate/service/model/diverged.js +226 -0
  262. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  263. package/dist/commands/validate/service/model/grade.js +163 -0
  264. package/dist/commands/validate/service/model/grade.js.map +1 -0
  265. package/dist/commands/validate/service/service.js +121 -61
  266. package/dist/commands/validate/service/service.js.map +1 -1
  267. package/dist/commands/validate/service/specs.js +88 -28
  268. package/dist/commands/validate/service/specs.js.map +1 -1
  269. package/dist/commands/validate/service/spine.js +38 -3
  270. package/dist/commands/validate/service/spine.js.map +1 -1
  271. package/dist/commands/validate/service/usecases/tags.js +113 -0
  272. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  273. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  274. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  275. package/dist/commands/validate/validate.js +85 -60
  276. package/dist/commands/validate/validate.js.map +1 -1
  277. package/dist/commands/verify/cross/diff.js +2 -6
  278. package/dist/commands/verify/cross/diff.js.map +1 -1
  279. package/dist/commands/verify/evidence/contract.js +1 -1
  280. package/dist/commands/verify/evidence/contract.js.map +1 -1
  281. package/dist/commands/verify/evidence/read.js +12 -3
  282. package/dist/commands/verify/evidence/read.js.map +1 -1
  283. package/dist/commands/verify/frozen.js +45 -23
  284. package/dist/commands/verify/frozen.js.map +1 -1
  285. package/dist/commands/verify/record.js +69 -17
  286. package/dist/commands/verify/record.js.map +1 -1
  287. package/dist/commands/verify/report.js +27 -44
  288. package/dist/commands/verify/report.js.map +1 -1
  289. package/dist/commands/verify/results.js +112 -30
  290. package/dist/commands/verify/results.js.map +1 -1
  291. package/dist/commands/verify/verify.js +55 -52
  292. package/dist/commands/verify/verify.js.map +1 -1
  293. package/dist/commands/vouch/pack/pack.js +2 -2
  294. package/dist/commands/vouch/pack/pack.js.map +1 -1
  295. package/dist/commands/vouch/pack/print.js +1 -6
  296. package/dist/commands/vouch/pack/print.js.map +1 -1
  297. package/dist/commands/vouch/pack/sections.js +1 -2
  298. package/dist/commands/vouch/pack/sections.js.map +1 -1
  299. package/dist/commands/vouch/run.js +26 -81
  300. package/dist/commands/vouch/run.js.map +1 -1
  301. package/dist/commands/vouch/sample/plan.js +20 -34
  302. package/dist/commands/vouch/sample/plan.js.map +1 -1
  303. package/dist/commands/vouch/vet/verify.js +39 -7
  304. package/dist/commands/vouch/vet/verify.js.map +1 -1
  305. package/dist/commands/vouch/vouch.js +10 -17
  306. package/dist/commands/vouch/vouch.js.map +1 -1
  307. package/dist/core/agent/agents-md/command-map.js +81 -106
  308. package/dist/core/agent/agents-md/command-map.js.map +1 -1
  309. package/dist/core/agent/agents-md/map/explain.js +21 -9
  310. package/dist/core/agent/agents-md/map/explain.js.map +1 -1
  311. package/dist/core/agent/agents-md/map/lenses/context.js +17 -8
  312. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
  313. package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
  314. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
  315. package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
  316. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
  317. package/dist/core/agent/agents-md/map/mcp.js +10 -7
  318. package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
  319. package/dist/core/agent/agents-md/map/status.js +24 -8
  320. package/dist/core/agent/agents-md/map/status.js.map +1 -1
  321. package/dist/core/agent/agents-md/map/subsystem.js +80 -8
  322. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
  323. package/dist/core/agent/agents-md/map/usecases.js +88 -10
  324. package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
  325. package/dist/core/agent/agents-md/refusals.js +49 -22
  326. package/dist/core/agent/agents-md/refusals.js.map +1 -1
  327. package/dist/core/agent/agents-md.js +39 -6
  328. package/dist/core/agent/agents-md.js.map +1 -1
  329. package/dist/core/agent/agents-stamp.js +10 -0
  330. package/dist/core/agent/agents-stamp.js.map +1 -1
  331. package/dist/core/agent/protocol.js +1 -1
  332. package/dist/core/agent/protocol.js.map +1 -1
  333. package/dist/core/agent/scaffold.js +10 -15
  334. package/dist/core/agent/scaffold.js.map +1 -1
  335. package/dist/core/agent/support/report.js +46 -5
  336. package/dist/core/agent/support/report.js.map +1 -1
  337. package/dist/core/agent/tools/dialects.js +1 -0
  338. package/dist/core/agent/tools/dialects.js.map +1 -1
  339. package/dist/core/agent/tools/registry.js +41 -76
  340. package/dist/core/agent/tools/registry.js.map +1 -1
  341. package/dist/core/agent/workflows/adopt.js +158 -11
  342. package/dist/core/agent/workflows/adopt.js.map +1 -1
  343. package/dist/core/agent/workflows/check.js +78 -39
  344. package/dist/core/agent/workflows/check.js.map +1 -1
  345. package/dist/core/agent/workflows/closing.js +88 -27
  346. package/dist/core/agent/workflows/closing.js.map +1 -1
  347. package/dist/core/agent/workflows/feature.js +128 -13
  348. package/dist/core/agent/workflows/feature.js.map +1 -1
  349. package/dist/core/agent/workflows/implement.js +96 -13
  350. package/dist/core/agent/workflows/implement.js.map +1 -1
  351. package/dist/core/agent/workflows/reference/authoring.js +106 -4
  352. package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
  353. package/dist/core/agent/workflows/reference/codes.js +8 -6
  354. package/dist/core/agent/workflows/reference/codes.js.map +1 -1
  355. package/dist/core/agent/workflows/reference/done-check.js +37 -15
  356. package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
  357. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  358. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  359. package/dist/core/agent/workflows/reference/reference.js +6 -3
  360. package/dist/core/agent/workflows/reference/reference.js.map +1 -1
  361. package/dist/core/agent/workflows/reference/spine.js +68 -27
  362. package/dist/core/agent/workflows/reference/spine.js.map +1 -1
  363. package/dist/core/asyncapi/baseline/plan.js +14 -81
  364. package/dist/core/asyncapi/baseline/plan.js.map +1 -1
  365. package/dist/core/asyncapi/digest.js +30 -25
  366. package/dist/core/asyncapi/digest.js.map +1 -1
  367. package/dist/core/asyncapi/merge/components.js +5 -4
  368. package/dist/core/asyncapi/merge/components.js.map +1 -1
  369. package/dist/core/asyncapi/merge/error.js +7 -2
  370. package/dist/core/asyncapi/merge/error.js.map +1 -1
  371. package/dist/core/asyncapi/merge/markers.js +32 -50
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -1
  373. package/dist/core/asyncapi/merge/merge.js +33 -53
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -1
  375. package/dist/core/asyncapi/merge/pin.js +12 -36
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -1
  377. package/dist/core/asyncapi/model.js.map +1 -1
  378. package/dist/core/asyncapi/read.js +36 -12
  379. package/dist/core/asyncapi/read.js.map +1 -1
  380. package/dist/core/brief/brief.js +96 -36
  381. package/dist/core/brief/brief.js.map +1 -1
  382. package/dist/core/brief/checks.js +138 -3
  383. package/dist/core/brief/checks.js.map +1 -1
  384. package/dist/core/brief/landscape.js +209 -130
  385. package/dist/core/brief/landscape.js.map +1 -1
  386. package/dist/core/brief/map/extend.js +84 -0
  387. package/dist/core/brief/map/extend.js.map +1 -0
  388. package/dist/core/brief/map/owed.js +266 -0
  389. package/dist/core/brief/map/owed.js.map +1 -0
  390. package/dist/core/brief/targets.js +109 -31
  391. package/dist/core/brief/targets.js.map +1 -1
  392. package/dist/core/brief/unchecked.js +14 -3
  393. package/dist/core/brief/unchecked.js.map +1 -1
  394. package/dist/core/c4/arch.js +90 -182
  395. package/dist/core/c4/arch.js.map +1 -1
  396. package/dist/core/c4/direction/direction.js +114 -0
  397. package/dist/core/c4/direction/direction.js.map +1 -0
  398. package/dist/core/c4/likec4.js +169 -14
  399. package/dist/core/c4/likec4.js.map +1 -1
  400. package/dist/core/c4/locate/unlocated.js +150 -0
  401. package/dist/core/c4/locate/unlocated.js.map +1 -0
  402. package/dist/core/c4/parsed/deployment.js +160 -0
  403. package/dist/core/c4/parsed/deployment.js.map +1 -0
  404. package/dist/core/c4/parsed/dynamic-views.js.map +1 -1
  405. package/dist/core/c4/parsed/values.js +54 -1
  406. package/dist/core/c4/parsed/values.js.map +1 -1
  407. package/dist/core/c4/parsed/view-ids.js +39 -1
  408. package/dist/core/c4/parsed/view-ids.js.map +1 -1
  409. package/dist/core/c4/prefetch/fleet.js +134 -0
  410. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  411. package/dist/core/c4/project/architecture.js +123 -7
  412. package/dist/core/c4/project/architecture.js.map +1 -1
  413. package/dist/core/c4/project/batch.js +140 -0
  414. package/dist/core/c4/project/batch.js.map +1 -0
  415. package/dist/core/c4/project/documents.js +43 -12
  416. package/dist/core/c4/project/documents.js.map +1 -1
  417. package/dist/core/c4/project/load.js +79 -43
  418. package/dist/core/c4/project/load.js.map +1 -1
  419. package/dist/core/c4/project/staged.js +277 -0
  420. package/dist/core/c4/project/staged.js.map +1 -0
  421. package/dist/core/c4/resolve/attested.js +0 -0
  422. package/dist/core/c4/resolve/attested.js.map +1 -0
  423. package/dist/core/c4/resolve/external.js +51 -0
  424. package/dist/core/c4/resolve/external.js.map +1 -0
  425. package/dist/core/c4/resolve/service.js +78 -17
  426. package/dist/core/c4/resolve/service.js.map +1 -1
  427. package/dist/core/c4/resolve/steps.js +290 -0
  428. package/dist/core/c4/resolve/steps.js.map +1 -0
  429. package/dist/core/c4/resolve/systems.js +154 -0
  430. package/dist/core/c4/resolve/systems.js.map +1 -0
  431. package/dist/core/c4/root-project/exclude.js +352 -0
  432. package/dist/core/c4/root-project/exclude.js.map +1 -0
  433. package/dist/core/c4/seed/template.js +65 -1
  434. package/dist/core/c4/seed/template.js.map +1 -1
  435. package/dist/core/c4/service-model/created/models.js +96 -0
  436. package/dist/core/c4/service-model/created/models.js.map +1 -0
  437. package/dist/core/c4/service-model/documents.js +47 -0
  438. package/dist/core/c4/service-model/documents.js.map +1 -0
  439. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  440. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  441. package/dist/core/c4/service-model/load.js +165 -0
  442. package/dist/core/c4/service-model/load.js.map +1 -0
  443. package/dist/core/c4/service-model/renderer.js +128 -0
  444. package/dist/core/c4/service-model/renderer.js.map +1 -0
  445. package/dist/core/c4/service-model/shape.js +106 -0
  446. package/dist/core/c4/service-model/shape.js.map +1 -0
  447. package/dist/core/c4/service-model/slice.js +188 -0
  448. package/dist/core/c4/service-model/slice.js.map +1 -0
  449. package/dist/core/c4/source-mask.js +297 -10
  450. package/dist/core/c4/source-mask.js.map +1 -1
  451. package/dist/core/c4/source-scan.js +222 -141
  452. package/dist/core/c4/source-scan.js.map +1 -1
  453. package/dist/core/c4/splice/authored-source.js +79 -13
  454. package/dist/core/c4/splice/authored-source.js.map +1 -1
  455. package/dist/core/c4/splice/contract.js +20 -0
  456. package/dist/core/c4/splice/contract.js.map +1 -1
  457. package/dist/core/c4/splice/delta-blocks.js +20 -20
  458. package/dist/core/c4/splice/delta-blocks.js.map +1 -1
  459. package/dist/core/c4/splice/identity/declared.js +87 -0
  460. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  461. package/dist/core/c4/splice/identity/edges.js +37 -0
  462. package/dist/core/c4/splice/identity/edges.js.map +1 -1
  463. package/dist/core/c4/splice/identity/existing.js +80 -0
  464. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  465. package/dist/core/c4/splice/identity/interior.js +80 -0
  466. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  467. package/dist/core/c4/splice/identity/owner.js +50 -0
  468. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  469. package/dist/core/c4/splice/landscape-merge.js +182 -114
  470. package/dist/core/c4/splice/landscape-merge.js.map +1 -1
  471. package/dist/core/c4/splice/model/merge.js +151 -0
  472. package/dist/core/c4/splice/model/merge.js.map +1 -0
  473. package/dist/core/c4/splice/placement.js +160 -56
  474. package/dist/core/c4/splice/placement.js.map +1 -1
  475. package/dist/core/c4/splice/text/spot.js +131 -0
  476. package/dist/core/c4/splice/text/spot.js.map +1 -0
  477. package/dist/core/c4/workspace.js +13 -19
  478. package/dist/core/c4/workspace.js.map +1 -1
  479. package/dist/core/capabilities/capabilities.js +6 -6
  480. package/dist/core/capabilities/capabilities.js.map +1 -1
  481. package/dist/core/capabilities/delta/doc.js +7 -10
  482. package/dist/core/capabilities/delta/doc.js.map +1 -1
  483. package/dist/core/capabilities/delta/uncovered.js +2 -2
  484. package/dist/core/capabilities/delta/uncovered.js.map +1 -1
  485. package/dist/core/capabilities/findings.js +18 -22
  486. package/dist/core/capabilities/findings.js.map +1 -1
  487. package/dist/core/capabilities/realizes/findings.js +12 -19
  488. package/dist/core/capabilities/realizes/findings.js.map +1 -1
  489. package/dist/core/capabilities/realizes/join.js +0 -20
  490. package/dist/core/capabilities/realizes/join.js.map +1 -1
  491. package/dist/core/capabilities/rollup.js +6 -0
  492. package/dist/core/capabilities/rollup.js.map +1 -1
  493. package/dist/core/capabilities/tree.js +6 -28
  494. package/dist/core/capabilities/tree.js.map +1 -1
  495. package/dist/core/capabilities/usecase-join.js +3 -13
  496. package/dist/core/capabilities/usecase-join.js.map +1 -1
  497. package/dist/core/coherence/authoring/scaffold.js +11 -3
  498. package/dist/core/coherence/authoring/scaffold.js.map +1 -1
  499. package/dist/core/coherence/authoring/sentinels.js +2 -1
  500. package/dist/core/coherence/authoring/sentinels.js.map +1 -1
  501. package/dist/core/coherence/calls/called.js +52 -0
  502. package/dist/core/coherence/calls/called.js.map +1 -0
  503. package/dist/core/coherence/coherence.js +103 -22
  504. package/dist/core/coherence/coherence.js.map +1 -1
  505. package/dist/core/coherence/consumed/operations.js +70 -0
  506. package/dist/core/coherence/consumed/operations.js.map +1 -0
  507. package/dist/core/coherence/consumed/refusal.js +38 -0
  508. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  509. package/dist/core/coherence/covers/health.js +85 -0
  510. package/dist/core/coherence/covers/health.js.map +1 -0
  511. package/dist/core/coherence/declared.js +60 -34
  512. package/dist/core/coherence/declared.js.map +1 -1
  513. package/dist/core/coherence/events/declared.js +44 -59
  514. package/dist/core/coherence/events/declared.js.map +1 -1
  515. package/dist/core/coherence/events/events.js +147 -16
  516. package/dist/core/coherence/events/events.js.map +1 -1
  517. package/dist/core/coherence/events/grades.js +31 -8
  518. package/dist/core/coherence/events/grades.js.map +1 -1
  519. package/dist/core/coherence/events/lookups.js +28 -87
  520. package/dist/core/coherence/events/lookups.js.map +1 -1
  521. package/dist/core/coherence/events/produced.js +100 -0
  522. package/dist/core/coherence/events/produced.js.map +1 -0
  523. package/dist/core/coherence/lookups.js +18 -78
  524. package/dist/core/coherence/lookups.js.map +1 -1
  525. package/dist/core/coherence/retired/archived.js +285 -0
  526. package/dist/core/coherence/retired/archived.js.map +1 -0
  527. package/dist/core/coherence/retired/event-pair.js +62 -0
  528. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  529. package/dist/core/coherence/retired/merged.js +79 -0
  530. package/dist/core/coherence/retired/merged.js.map +1 -0
  531. package/dist/core/coherence/retired/retirement.js +49 -0
  532. package/dist/core/coherence/retired/retirement.js.map +1 -0
  533. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  534. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  535. package/dist/core/coherence/retired/revival/revived.js +297 -0
  536. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  537. package/dist/core/consumers/after.js +113 -0
  538. package/dist/core/consumers/after.js.map +1 -0
  539. package/dist/core/consumers/consumers.js +296 -0
  540. package/dist/core/consumers/consumers.js.map +1 -0
  541. package/dist/core/consumers/current.js +211 -0
  542. package/dist/core/consumers/current.js.map +1 -0
  543. package/dist/core/consumers/scan.js +46 -0
  544. package/dist/core/consumers/scan.js.map +1 -0
  545. package/dist/core/consumers/state.js +27 -0
  546. package/dist/core/consumers/state.js.map +1 -0
  547. package/dist/core/delta/delta.js +51 -6
  548. package/dist/core/delta/delta.js.map +1 -1
  549. package/dist/core/dependencies/fanin.js +2 -2
  550. package/dist/core/dependencies/fanin.js.map +1 -1
  551. package/dist/core/deployment/delta.js +191 -0
  552. package/dist/core/deployment/delta.js.map +1 -0
  553. package/dist/core/deployment/objects.js +145 -0
  554. package/dist/core/deployment/objects.js.map +1 -0
  555. package/dist/core/diff/base-git.js +94 -12
  556. package/dist/core/diff/base-git.js.map +1 -1
  557. package/dist/core/diff/base-state.js +49 -21
  558. package/dist/core/diff/base-state.js.map +1 -1
  559. package/dist/core/diff/joins.js +136 -0
  560. package/dist/core/diff/joins.js.map +1 -0
  561. package/dist/core/diff/scope/changed-paths.js +22 -6
  562. package/dist/core/diff/scope/changed-paths.js.map +1 -1
  563. package/dist/core/diff/scope/edges.js +82 -0
  564. package/dist/core/diff/scope/edges.js.map +1 -0
  565. package/dist/core/diff/semantic.js +100 -31
  566. package/dist/core/diff/semantic.js.map +1 -1
  567. package/dist/core/docs.js +31 -22
  568. package/dist/core/docs.js.map +1 -1
  569. package/dist/core/doctor/agents.js +34 -18
  570. package/dist/core/doctor/agents.js.map +1 -1
  571. package/dist/core/doctor/config.js +7 -3
  572. package/dist/core/doctor/config.js.map +1 -1
  573. package/dist/core/doctor/doctor.js +91 -11
  574. package/dist/core/doctor/doctor.js.map +1 -1
  575. package/dist/core/doctor/report.js.map +1 -1
  576. package/dist/core/doctor/reports/scan.js +242 -0
  577. package/dist/core/doctor/reports/scan.js.map +1 -0
  578. package/dist/core/document/apply.js +158 -11
  579. package/dist/core/document/apply.js.map +1 -1
  580. package/dist/core/document/frontmatter.js +55 -0
  581. package/dist/core/document/frontmatter.js.map +1 -1
  582. package/dist/core/document/parse.js +29 -6
  583. package/dist/core/document/parse.js.map +1 -1
  584. package/dist/core/document/scenarios.js +17 -0
  585. package/dist/core/document/scenarios.js.map +1 -1
  586. package/dist/core/document/spec.js +4 -11
  587. package/dist/core/document/spec.js.map +1 -1
  588. package/dist/core/envelope/config.js +10 -0
  589. package/dist/core/envelope/config.js.map +1 -1
  590. package/dist/core/envelope/json.js +34 -0
  591. package/dist/core/envelope/json.js.map +1 -1
  592. package/dist/core/explain/families.js +26 -21
  593. package/dist/core/explain/families.js.map +1 -1
  594. package/dist/core/explain/lookup.js +14 -1
  595. package/dist/core/explain/lookup.js.map +1 -1
  596. package/dist/core/explain/refusals.js +5 -5
  597. package/dist/core/explain/refusals.js.map +1 -1
  598. package/dist/core/explain/terms/documents.js +227 -0
  599. package/dist/core/explain/terms/documents.js.map +1 -0
  600. package/dist/core/explain/terms/done-check.js +144 -0
  601. package/dist/core/explain/terms/done-check.js.map +1 -0
  602. package/dist/core/explain/terms/entry.js +14 -0
  603. package/dist/core/explain/terms/entry.js.map +1 -0
  604. package/dist/core/explain/terms/stages.js +71 -0
  605. package/dist/core/explain/terms/stages.js.map +1 -0
  606. package/dist/core/explain/terms/tasks.js +97 -0
  607. package/dist/core/explain/terms/tasks.js.map +1 -0
  608. package/dist/core/explain/terms.js +68 -109
  609. package/dist/core/explain/terms.js.map +1 -1
  610. package/dist/core/explore/explore.js +40 -10
  611. package/dist/core/explore/explore.js.map +1 -1
  612. package/dist/core/fleet-context.js +81 -95
  613. package/dist/core/fleet-context.js.map +1 -1
  614. package/dist/core/gate/checks.js +11 -4
  615. package/dist/core/gate/checks.js.map +1 -1
  616. package/dist/core/gate/partners.js +69 -28
  617. package/dist/core/gate/partners.js.map +1 -1
  618. package/dist/core/gate/report.js.map +1 -1
  619. package/dist/core/gate/verification.js +75 -12
  620. package/dist/core/gate/verification.js.map +1 -1
  621. package/dist/core/gherkin/stale.js +13 -37
  622. package/dist/core/gherkin/stale.js.map +1 -1
  623. package/dist/core/glossary/delta.js +10 -7
  624. package/dist/core/glossary/delta.js.map +1 -1
  625. package/dist/core/glossary/tree.js +6 -19
  626. package/dist/core/glossary/tree.js.map +1 -1
  627. package/dist/core/kernel/concurrency.js +19 -0
  628. package/dist/core/kernel/concurrency.js.map +1 -1
  629. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  630. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  631. package/dist/core/kernel/path-safety.js +38 -0
  632. package/dist/core/kernel/path-safety.js.map +1 -1
  633. package/dist/core/kernel/records.js +11 -0
  634. package/dist/core/kernel/records.js.map +1 -1
  635. package/dist/core/links/backlinks.js +1 -3
  636. package/dist/core/links/backlinks.js.map +1 -1
  637. package/dist/core/links/corpus.js +51 -37
  638. package/dist/core/links/corpus.js.map +1 -1
  639. package/dist/core/links/findings.js.map +1 -1
  640. package/dist/core/links/parse.js +38 -9
  641. package/dist/core/links/parse.js.map +1 -1
  642. package/dist/core/mcp/argv.js +101 -0
  643. package/dist/core/mcp/argv.js.map +1 -1
  644. package/dist/core/mcp/author-tools.js +2 -1
  645. package/dist/core/mcp/author-tools.js.map +1 -1
  646. package/dist/core/mcp/protocol.js +2 -2
  647. package/dist/core/mcp/protocol.js.map +1 -1
  648. package/dist/core/mcp/tools.js +43 -33
  649. package/dist/core/mcp/tools.js.map +1 -1
  650. package/dist/core/openapi/baseline/gate.js +53 -12
  651. package/dist/core/openapi/baseline/gate.js.map +1 -1
  652. package/dist/core/openapi/baseline/plan.js +40 -10
  653. package/dist/core/openapi/baseline/plan.js.map +1 -1
  654. package/dist/core/openapi/baseline/record.js +0 -1
  655. package/dist/core/openapi/baseline/record.js.map +1 -1
  656. package/dist/core/openapi/contract-text.js +33 -0
  657. package/dist/core/openapi/contract-text.js.map +1 -0
  658. package/dist/core/openapi/contract-tree.js +301 -0
  659. package/dist/core/openapi/contract-tree.js.map +1 -0
  660. package/dist/core/openapi/depth.js +38 -24
  661. package/dist/core/openapi/depth.js.map +1 -1
  662. package/dist/core/openapi/digest.js +52 -2
  663. package/dist/core/openapi/digest.js.map +1 -1
  664. package/dist/core/openapi/doc.js +12 -4
  665. package/dist/core/openapi/doc.js.map +1 -1
  666. package/dist/core/openapi/merge/components.js +25 -60
  667. package/dist/core/openapi/merge/components.js.map +1 -1
  668. package/dist/core/openapi/merge/error.js +3 -13
  669. package/dist/core/openapi/merge/error.js.map +1 -1
  670. package/dist/core/openapi/merge/markers.js +26 -30
  671. package/dist/core/openapi/merge/markers.js.map +1 -1
  672. package/dist/core/openapi/merge/merge.js +28 -52
  673. package/dist/core/openapi/merge/merge.js.map +1 -1
  674. package/dist/core/openapi/merge/pin.js +17 -35
  675. package/dist/core/openapi/merge/pin.js.map +1 -1
  676. package/dist/core/openspec/decide/verdict.js.map +1 -1
  677. package/dist/core/openspec/inventory.js +4 -5
  678. package/dist/core/openspec/inventory.js.map +1 -1
  679. package/dist/core/openspec/model/mapping.js +30 -28
  680. package/dist/core/openspec/model/mapping.js.map +1 -1
  681. package/dist/core/openspec/model/model.js +12 -7
  682. package/dist/core/openspec/model/model.js.map +1 -1
  683. package/dist/core/openspec/scan/changes.js +10 -4
  684. package/dist/core/openspec/scan/changes.js.map +1 -1
  685. package/dist/core/openspec/scan/config.js +7 -16
  686. package/dist/core/openspec/scan/config.js.map +1 -1
  687. package/dist/core/openspec/scan/shape.js +63 -19
  688. package/dist/core/openspec/scan/shape.js.map +1 -1
  689. package/dist/core/openspec/scan/walk.js +21 -38
  690. package/dist/core/openspec/scan/walk.js.map +1 -1
  691. package/dist/core/pack/living.js +43 -4
  692. package/dist/core/pack/living.js.map +1 -1
  693. package/dist/core/pack/pack.js +50 -6
  694. package/dist/core/pack/pack.js.map +1 -1
  695. package/dist/core/projection/arch-slice.js +2 -2
  696. package/dist/core/projection/arch-slice.js.map +1 -1
  697. package/dist/core/projection/introduced.js +14 -0
  698. package/dist/core/projection/introduced.js.map +1 -0
  699. package/dist/core/provenance/findings.js +48 -12
  700. package/dist/core/provenance/findings.js.map +1 -1
  701. package/dist/core/provenance/git.js +33 -57
  702. package/dist/core/provenance/git.js.map +1 -1
  703. package/dist/core/provenance/gitq/moves.js +71 -114
  704. package/dist/core/provenance/gitq/moves.js.map +1 -1
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
  707. package/dist/core/provenance/sources.js +23 -6
  708. package/dist/core/provenance/sources.js.map +1 -1
  709. package/dist/core/provenance/stamp.js +5 -17
  710. package/dist/core/provenance/stamp.js.map +1 -1
  711. package/dist/core/repo/authored/paths.js +18 -0
  712. package/dist/core/repo/authored/paths.js.map +1 -1
  713. package/dist/core/repo/entries.js.map +1 -1
  714. package/dist/core/repo/paths.js +92 -6
  715. package/dist/core/repo/paths.js.map +1 -1
  716. package/dist/core/repo/repo.js +74 -14
  717. package/dist/core/repo/repo.js.map +1 -1
  718. package/dist/core/repo/tree/find.js +12 -3
  719. package/dist/core/repo/tree/find.js.map +1 -1
  720. package/dist/core/repo/tree/fs.js +27 -1
  721. package/dist/core/repo/tree/fs.js.map +1 -1
  722. package/dist/core/repo/tree/render/body.js +258 -0
  723. package/dist/core/repo/tree/render/body.js.map +1 -0
  724. package/dist/core/repo/tree/render/projects.js +182 -0
  725. package/dist/core/repo/tree/render/projects.js.map +1 -0
  726. package/dist/core/repo/tree/render/service/header.js +125 -0
  727. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  728. package/dist/core/repo/tree/render/service/peers.js +28 -0
  729. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  730. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  731. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  732. package/dist/core/repo/tree/render/service/views.js +78 -0
  733. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  734. package/dist/core/repo/tree/render/stale.js +42 -0
  735. package/dist/core/repo/tree/render/stale.js.map +1 -0
  736. package/dist/core/repo/tree/render/text.js +84 -0
  737. package/dist/core/repo/tree/render/text.js.map +1 -0
  738. package/dist/core/repo/tree/render/views.js +293 -0
  739. package/dist/core/repo/tree/render/views.js.map +1 -0
  740. package/dist/core/repo/tree/walk.js +53 -32
  741. package/dist/core/repo/tree/walk.js.map +1 -1
  742. package/dist/core/results.js +47 -12
  743. package/dist/core/results.js.map +1 -1
  744. package/dist/core/scaffold/landscape.js +121 -13
  745. package/dist/core/scaffold/landscape.js.map +1 -1
  746. package/dist/core/scaffold/legacy.js +271 -0
  747. package/dist/core/scaffold/legacy.js.map +1 -0
  748. package/dist/core/staging/commit.js +26 -15
  749. package/dist/core/staging/commit.js.map +1 -1
  750. package/dist/core/staging/lock.js +74 -12
  751. package/dist/core/staging/lock.js.map +1 -1
  752. package/dist/core/staging/recovery/intent.js +2 -5
  753. package/dist/core/staging/recovery/intent.js.map +1 -1
  754. package/dist/core/staging/recovery/recover.js +84 -6
  755. package/dist/core/staging/recovery/recover.js.map +1 -1
  756. package/dist/core/staging/snapshot/manifest.js +188 -0
  757. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  758. package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +39 -45
  759. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  760. package/dist/core/staging/txn/forward.js +24 -14
  761. package/dist/core/staging/txn/forward.js.map +1 -1
  762. package/dist/core/staging/writes.js.map +1 -1
  763. package/dist/core/status/actions/execution.js +11 -0
  764. package/dist/core/status/actions/execution.js.map +1 -1
  765. package/dist/core/status/contracts.js +39 -15
  766. package/dist/core/status/contracts.js.map +1 -1
  767. package/dist/core/status/feature/artifacts.js +33 -8
  768. package/dist/core/status/feature/artifacts.js.map +1 -1
  769. package/dist/core/status/feature/feature.js +24 -17
  770. package/dist/core/status/feature/feature.js.map +1 -1
  771. package/dist/core/status/feature/next.js +20 -7
  772. package/dist/core/status/feature/next.js.map +1 -1
  773. package/dist/core/status/feature/words.js +96 -0
  774. package/dist/core/status/feature/words.js.map +1 -0
  775. package/dist/core/status/fleet/fleet.js +43 -14
  776. package/dist/core/status/fleet/fleet.js.map +1 -1
  777. package/dist/core/status/fleet/next.js +153 -58
  778. package/dist/core/status/fleet/next.js.map +1 -1
  779. package/dist/core/status/report.js.map +1 -1
  780. package/dist/core/status/scan.js.map +1 -1
  781. package/dist/core/status/verification.js +30 -15
  782. package/dist/core/status/verification.js.map +1 -1
  783. package/dist/core/tasks/packet.js +199 -0
  784. package/dist/core/tasks/packet.js.map +1 -0
  785. package/dist/core/tasks/record.js +43 -0
  786. package/dist/core/tasks/record.js.map +1 -0
  787. package/dist/core/tasks/sources.js +181 -0
  788. package/dist/core/tasks/sources.js.map +1 -0
  789. package/dist/core/tasks/stamps.js +76 -0
  790. package/dist/core/tasks/stamps.js.map +1 -0
  791. package/dist/core/tasks/unit.js +0 -0
  792. package/dist/core/tasks/unit.js.map +1 -0
  793. package/dist/core/usecases/capability.js +11 -14
  794. package/dist/core/usecases/capability.js.map +1 -1
  795. package/dist/core/usecases/delta/claims.js +31 -7
  796. package/dist/core/usecases/delta/claims.js.map +1 -1
  797. package/dist/core/usecases/delta/flows.js +5 -7
  798. package/dist/core/usecases/delta/flows.js.map +1 -1
  799. package/dist/core/usecases/delta/modified.js +315 -0
  800. package/dist/core/usecases/delta/modified.js.map +1 -0
  801. package/dist/core/usecases/delta/overlay.js +32 -191
  802. package/dist/core/usecases/delta/overlay.js.map +1 -1
  803. package/dist/core/usecases/fleet.js +195 -36
  804. package/dist/core/usecases/fleet.js.map +1 -1
  805. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/capability-tag.js +8 -9
  806. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  807. package/dist/core/usecases/grade/feature.js +88 -0
  808. package/dist/core/usecases/grade/feature.js.map +1 -0
  809. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/requirement-tag.js +3 -4
  810. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  811. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/steps.js +102 -33
  812. package/dist/core/usecases/grade/steps.js.map +1 -0
  813. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/usecases.js +23 -10
  814. package/dist/core/usecases/grade/usecases.js.map +1 -0
  815. package/dist/core/usecases/operations.js +26 -14
  816. package/dist/core/usecases/operations.js.map +1 -1
  817. package/dist/core/usecases/place.js.map +1 -1
  818. package/dist/core/usecases/service/exclude.js +119 -0
  819. package/dist/core/usecases/service/exclude.js.map +1 -0
  820. package/dist/core/usecases/service/flows.js +164 -0
  821. package/dist/core/usecases/service/flows.js.map +1 -0
  822. package/dist/core/usecases/suites/participants.js +83 -0
  823. package/dist/core/usecases/suites/participants.js.map +1 -0
  824. package/dist/core/usecases/suites/suites.js +45 -0
  825. package/dist/core/usecases/suites/suites.js.map +1 -0
  826. package/dist/core/verify/answers.js +12 -5
  827. package/dist/core/verify/answers.js.map +1 -1
  828. package/dist/core/verify/build.js +102 -82
  829. package/dist/core/verify/build.js.map +1 -1
  830. package/dist/core/verify/checklist.js +70 -12
  831. package/dist/core/verify/checklist.js.map +1 -1
  832. package/dist/core/verify/location.js +67 -0
  833. package/dist/core/verify/location.js.map +1 -0
  834. package/dist/core/verify/pins/lint.js +3 -2
  835. package/dist/core/verify/pins/lint.js.map +1 -1
  836. package/dist/core/verify/pins/pin.js +1 -1
  837. package/dist/core/verify/pins/pin.js.map +1 -1
  838. package/dist/core/verify/read/file.js +224 -0
  839. package/dist/core/verify/read/file.js.map +1 -0
  840. package/dist/core/verify/{file.js → read/shape.js} +16 -104
  841. package/dist/core/verify/read/shape.js.map +1 -0
  842. package/dist/core/verify/read/union.js +105 -0
  843. package/dist/core/verify/read/union.js.map +1 -0
  844. package/dist/core/verify/record.js +35 -12
  845. package/dist/core/verify/record.js.map +1 -1
  846. package/dist/core/verify/store/commit.js +40 -30
  847. package/dist/core/verify/store/commit.js.map +1 -1
  848. package/dist/core/verify/store/render.js +8 -4
  849. package/dist/core/verify/store/render.js.map +1 -1
  850. package/dist/core/vocabulary/issue.js +4 -0
  851. package/dist/core/vocabulary/issue.js.map +1 -1
  852. package/dist/core/vocabulary/maturity.js +75 -4
  853. package/dist/core/vocabulary/maturity.js.map +1 -1
  854. package/dist/core/vocabulary/report.js +16 -1
  855. package/dist/core/vocabulary/report.js.map +1 -1
  856. package/examples/README.md +54 -11
  857. package/examples/docs/architecture/landscape.likec4 +62 -6
  858. package/examples/docs/architecture/services.likec4 +70 -0
  859. package/examples/docs/architecture/subsystems.likec4 +7 -0
  860. package/examples/docs/architecture/usecases/order-notification.likec4 +16 -7
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
  863. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +4 -1
  864. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
  865. package/examples/docs/likec4.config.json +0 -1
  866. package/examples/docs/services/checkout-web/model.likec4 +39 -56
  867. package/examples/docs/services/order-service/arch.spec.md +13 -6
  868. package/examples/docs/services/order-service/asyncapi.yaml +3 -2
  869. package/examples/docs/services/order-service/model.likec4 +58 -70
  870. package/examples/docs/services/payment-service/arch.spec.md +7 -4
  871. package/examples/docs/services/payment-service/model.likec4 +38 -37
  872. package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
  873. package/examples/docs/services/platform/identity-service/model.likec4 +35 -37
  874. package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
  875. package/examples/docs/services/platform/notification-service/health.yaml +8 -3
  876. package/examples/docs/services/platform/notification-service/model.likec4 +43 -64
  877. package/package.json +1 -1
  878. package/dist/commands/validate/checks/vocabulary.js +0 -31
  879. package/dist/commands/validate/checks/vocabulary.js.map +0 -1
  880. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +0 -1
  881. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +0 -1
  882. package/dist/commands/validate/fleet/usecases/steps.js.map +0 -1
  883. package/dist/commands/validate/fleet/usecases/usecases.js.map +0 -1
  884. package/dist/core/agent/agents-md/artifacts.js +0 -220
  885. package/dist/core/agent/agents-md/artifacts.js.map +0 -1
  886. package/dist/core/agent/agents-md/cycle.js +0 -165
  887. package/dist/core/agent/agents-md/cycle.js.map +0 -1
  888. package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
  889. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
  890. package/dist/core/agent/agents-md/spine.js +0 -40
  891. package/dist/core/agent/agents-md/spine.js.map +0 -1
  892. package/dist/core/coherence/events/merged.js +0 -40
  893. package/dist/core/coherence/events/merged.js.map +0 -1
  894. package/dist/core/diff/current-state.js +0 -96
  895. package/dist/core/diff/current-state.js.map +0 -1
  896. package/dist/core/diff/victims.js +0 -247
  897. package/dist/core/diff/victims.js.map +0 -1
  898. package/dist/core/repo/tree/views.js +0 -172
  899. package/dist/core/repo/tree/views.js.map +0 -1
  900. package/dist/core/staging/snapshot.js.map +0 -1
  901. package/dist/core/verify/file.js.map +0 -1
@@ -0,0 +1,211 @@
1
+ /**
2
+ * The living fleet as it stands on disk, read through the invocation's
3
+ * `FleetContext` into the SAME `ServiceState` shape `core/diff/base-state.ts`
4
+ * builds from git — one shape, so `core/diff/semantic.ts` joins the two sides
5
+ * without caring which one came from the object store.
6
+ *
7
+ * It was `loam diff`'s working-tree side (`core/diff/current-state.ts`) and
8
+ * still is; it moved here because the consumer index (`./consumers.ts`) reads
9
+ * the same fleet for every caller — the diff, the coherence gate and the
10
+ * archive planner — and a reader that only the diff could import was why the
11
+ * gate kept a copy of its own.
12
+ *
13
+ * Containment discipline, per subject and per axis: an artifact that EXISTS
14
+ * but cannot be read (non-UTF-8 spec bytes, a directory sitting where a file
15
+ * belongs, broken contract YAML) degrades that one axis to `unreadable` with
16
+ * its path, and the hash of its bytes when there are bytes to hash — never a
17
+ * thrown enumeration, never an empty list a diff would read as "everything
18
+ * was removed". Absence stays absence: a file deleted
19
+ * between the existence probe and the read is classified by its errno
20
+ * (ENOENT), the same TOCTOU discipline `loadConfig` documents.
21
+ */
22
+ import { existsSync } from "node:fs";
23
+ import { readFile } from "node:fs/promises";
24
+ import { resolve } from "node:path";
25
+ import { serviceResolver } from "../c4/resolve/service.js";
26
+ import { externalProducerOf } from "../c4/resolve/external.js";
27
+ import { readUseCases, useCasesIn } from "../usecases/fleet.js";
28
+ import { repoPath } from "../envelope/json.js";
29
+ import { landscapePath, servicePathsAt } from "../repo/paths.js";
30
+ import { inOrder } from "../kernel/concurrency.js";
31
+ import { bytesDigest, collisions } from "./state.js";
32
+ /**
33
+ * The unreadable arm, carrying the hash of the bytes that would not read
34
+ * (`AxisState`'s `bytes`, which the base side's `axisFrom` fills the same
35
+ * way). The readers this module goes through hand back a parsed document and
36
+ * not its bytes, so this is a second read — paid only on this path, which a
37
+ * healthy fleet never takes.
38
+ */
39
+ async function unreadableAt(abs, rel, error) {
40
+ try {
41
+ return { kind: "unreadable", path: rel, error, bytes: bytesDigest(await readFile(abs)) };
42
+ }
43
+ catch {
44
+ // No bytes to hash (a directory where the file belongs, a file deleted
45
+ // since the first read): an unhashed side proves no identity, so the axis
46
+ // suspends exactly as it always did.
47
+ return { kind: "unreadable", path: rel, error };
48
+ }
49
+ }
50
+ async function readFailure(e, file) {
51
+ const errno = e;
52
+ if (errno.code === "ENOENT")
53
+ return { kind: "absent" };
54
+ return unreadableAt(file.abs, file.rel, e instanceof Error ? e.message : String(e));
55
+ }
56
+ /** One spec-axis file (`spec.md` / `arch.spec.md`) as parsed requirements. */
57
+ async function requirementsAxis(context, abs, rel) {
58
+ if (!existsSync(abs))
59
+ return { kind: "absent" };
60
+ try {
61
+ return { kind: "read", value: await context.readRequirements(abs) };
62
+ }
63
+ catch (e) {
64
+ // decodeDocument's non-UTF-8 refusal lands here too: bytes that would
65
+ // parse as zero requirements must suspend the axis, not empty it.
66
+ return readFailure(e, { abs, rel });
67
+ }
68
+ }
69
+ async function openapiAxis(context, abs, rel) {
70
+ if (!existsSync(abs))
71
+ return { kind: "absent" };
72
+ try {
73
+ const doc = await context.readOpenapi(abs);
74
+ return doc.unreadable
75
+ ? await unreadableAt(abs, rel, doc.error ?? "not a readable OpenAPI document")
76
+ : { kind: "read", value: doc.ops.filter((op) => !op.remove) };
77
+ }
78
+ catch (e) {
79
+ return readFailure(e, { abs, rel });
80
+ }
81
+ }
82
+ /** The event contract as its declarations, and the names it sends — `sent` empty unless it read. */
83
+ async function asyncapiAxis(context, abs, rel) {
84
+ if (!existsSync(abs))
85
+ return { axis: { kind: "absent" }, sent: [] };
86
+ try {
87
+ const doc = await context.readAsyncapi(abs);
88
+ return doc.unreadable
89
+ ? { axis: await unreadableAt(abs, rel, doc.error ?? "not a readable AsyncAPI document"), sent: [] }
90
+ : { axis: { kind: "read", value: doc.messages.filter((m) => m.remove !== true) }, sent: doc.sent };
91
+ }
92
+ catch (e) {
93
+ return { axis: await readFailure(e, { abs, rel }), sent: [] };
94
+ }
95
+ }
96
+ /**
97
+ * The current fleet, one `ServiceState` per enumerated service. The
98
+ * enumeration itself (the tree walk) may throw `DocsRepoUnavailableError` —
99
+ * that is the whole-repo refusal `docsRepoReady` fronts, not a per-subject
100
+ * degradation, and it stays a throw for the command layer to map.
101
+ */
102
+ async function readCurrentFleet(docsDir, context) {
103
+ const entries = await context.listServices(docsDir);
104
+ const states = await inOrder(entries, async (entry) => {
105
+ const paths = servicePathsAt(entry.dir);
106
+ const events = await asyncapiAxis(context, paths.asyncapi, repoPath(docsDir, paths.asyncapi));
107
+ return {
108
+ id: entry.id,
109
+ dir: repoPath(docsDir, entry.dir),
110
+ spec: await requirementsAxis(context, paths.spec, repoPath(docsDir, paths.spec)),
111
+ archSpec: await requirementsAxis(context, paths.archSpec, repoPath(docsDir, paths.archSpec)),
112
+ openapi: await openapiAxis(context, paths.openapi, repoPath(docsDir, paths.openapi)),
113
+ asyncapi: events.axis,
114
+ sent: events.sent,
115
+ };
116
+ });
117
+ const ambiguous = collisions(states);
118
+ return {
119
+ services: new Map(states.filter((s) => !ambiguous.has(s.id)).map((s) => [s.id, s])),
120
+ ambiguous,
121
+ };
122
+ }
123
+ /**
124
+ * One read per invocation, keyed by the invocation's own FleetContext — the
125
+ * `core/coherence/retired/archived.ts` exception to the no-module-cache rule,
126
+ * for its reason: the key IS the per-invocation object, so two runs can never
127
+ * see each other's answer and the entry dies with the context. `validate --all`
128
+ * grades every active feature with one context, and every one of them asks the
129
+ * same fleet who consumes what; without this each feature re-read it. Not a
130
+ * memo ON FleetContext for that module's reason too: the class sits below this
131
+ * package, and the import such a memo needs would point up the DAG.
132
+ */
133
+ const PER_INVOCATION = new WeakMap();
134
+ function memoFor(docsDir, context) {
135
+ let store = PER_INVOCATION.get(context);
136
+ if (store === undefined)
137
+ PER_INVOCATION.set(context, (store = new Map()));
138
+ const key = resolve(docsDir);
139
+ let memo = store.get(key);
140
+ if (memo === undefined)
141
+ store.set(key, (memo = {}));
142
+ return memo;
143
+ }
144
+ /** `readCurrentFleet`, read at most once per invocation. */
145
+ export function livingFleet(docsDir, context) {
146
+ const memo = memoFor(docsDir, context);
147
+ return (memo.fleet ??= readCurrentFleet(docsDir, context));
148
+ }
149
+ /**
150
+ * The map, read at most once per invocation — and read as the PROJECT, never
151
+ * `architecture/landscape.likec4` alone.
152
+ *
153
+ * The spine grades every edge the `architecture/` project declares
154
+ * (`commands/validate/service/spine.ts` reads `fleet.architecture`), and a
155
+ * use-case hop is attributed against that same project. A consumer scan that
156
+ * read one file of it answered "nobody calls it" about an edge drawn in
157
+ * `architecture/calls.likec4`, the gate passed, and the next `validate --all`
158
+ * reported `spine.op-undefined` on that very edge (review 2026-10-12, finding
159
+ * 2) — `core/pack/living.ts` states the same rule for the same reason. One load
160
+ * serves the edges and the hops: two readers of one project are two chances to
161
+ * disagree about which documents it holds.
162
+ *
163
+ * An unreadable project proves nothing either way: `landscape.invalid` is
164
+ * validate's finding to make, and neither a victim nor a doubt invented out of
165
+ * a parse error may point the reader at a file their change never touched. ONE
166
+ * fallback, and it adds only positive evidence: when the project does not parse
167
+ * but `landscape.likec4` does on its own — a broken use-case file beside a good
168
+ * map — the map's own edges still count. They are true of the map either way,
169
+ * and losing them would have let a removal through the gate (and a `loam diff`
170
+ * call it unconsumed) because of a document that has nothing to do with the
171
+ * edge. The use cases stay unreadable: a flow is graded against the whole
172
+ * project or not at all. Whether there is a map at all stays a fact about the
173
+ * FILE, as the pack's `present` does: a repo with no `landscape.likec4` has no
174
+ * map, not an empty project.
175
+ */
176
+ export function livingMap(docsDir, context) {
177
+ const memo = memoFor(docsDir, context);
178
+ return (memo.map ??= (async () => {
179
+ // Every directory id the walk found, the ones two directories claim
180
+ // included — the services and the `ambiguous` ids of `livingFleet` together,
181
+ // which is the set validate resolves the map against (`known` in
182
+ // `commands/validate/service/service.ts`), read off the same memoised
183
+ // enumeration. Directory names, so the producer rule's guard (a services/
184
+ // directory outranks a tag) is handed what it demands.
185
+ const known = new Set((await context.listServices(docsDir)).map((entry) => entry.id));
186
+ const none = () => () => null;
187
+ const mapPath = landscapePath(docsDir);
188
+ if (!existsSync(mapPath)) {
189
+ return { relationships: null, resolve: (id) => id, useCases: await readUseCases({ docsDir, known }), externalProducerRule: none };
190
+ }
191
+ const doc = await context.architecture(docsDir);
192
+ const useCases = useCasesIn(doc, known);
193
+ if (doc.errors.length === 0) {
194
+ const resolve = serviceResolver(doc.elements, known);
195
+ const externalProducerRule = (materialised) => {
196
+ // The living set and its resolver stand whenever the merge creates no
197
+ // directory the walk has not already found — `loam diff`'s read, and
198
+ // most features'.
199
+ const after = materialised.every((id) => known.has(id)) ? known : new Set([...known, ...materialised]);
200
+ const svcOf = after === known ? resolve : serviceResolver(doc.elements, after);
201
+ return (message) => externalProducerOf(message, doc, svcOf, after);
202
+ };
203
+ return { relationships: doc.relationships, resolve, useCases, externalProducerRule };
204
+ }
205
+ const alone = await context.loadLikeC4(mapPath);
206
+ return alone.errors.length > 0
207
+ ? { relationships: null, resolve: (id) => id, useCases, externalProducerRule: none }
208
+ : { relationships: alone.relationships, resolve: serviceResolver(alone.elements, known), useCases, externalProducerRule: none };
209
+ })());
210
+ }
211
+ //# sourceMappingURL=current.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"current.js","sourceRoot":"","sources":["../../../src/core/consumers/current.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The living fleet as it stands on disk, read through the invocation's\n * `FleetContext` into the SAME `ServiceState` shape `core/diff/base-state.ts`\n * builds from git — one shape, so `core/diff/semantic.ts` joins the two sides\n * without caring which one came from the object store.\n *\n * It was `loam diff`'s working-tree side (`core/diff/current-state.ts`) and\n * still is; it moved here because the consumer index (`./consumers.ts`) reads\n * the same fleet for every caller — the diff, the coherence gate and the\n * archive planner — and a reader that only the diff could import was why the\n * gate kept a copy of its own.\n *\n * Containment discipline, per subject and per axis: an artifact that EXISTS\n * but cannot be read (non-UTF-8 spec bytes, a directory sitting where a file\n * belongs, broken contract YAML) degrades that one axis to `unreadable` with\n * its path, and the hash of its bytes when there are bytes to hash — never a\n * thrown enumeration, never an empty list a diff would read as \"everything\n * was removed\". Absence stays absence: a file deleted\n * between the existence probe and the read is classified by its errno\n * (ENOENT), the same TOCTOU discipline `loadConfig` documents.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport type { Rel } from \"../c4/likec4.js\";\nimport { serviceResolver } from \"../c4/resolve/service.js\";\nimport { externalProducerOf } from \"../c4/resolve/external.js\";\nimport { readUseCases, useCasesIn, type UseCaseScan } from \"../usecases/fleet.js\";\nimport type { Requirement } from \"../document/spec.js\";\nimport type { Operation } from \"../openapi/doc.js\";\nimport type { EventMessage } from \"../asyncapi/model.js\";\nimport { repoPath } from \"../envelope/json.js\";\nimport { landscapePath, servicePathsAt } from \"../repo/paths.js\";\nimport { inOrder } from \"../kernel/concurrency.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\nimport type { RawServiceId } from \"../kernel/ids/service.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport { bytesDigest, collisions, type AxisState, type ServiceState } from \"./state.js\";\n\n/**\n * One living service as the consumer index reads it: the diff's four axes, plus\n * the one fact about its event contract the index asks and the diff never\n * compares — which messages it SENDS. Current side only: the base side is read\n * for what changed, and nothing asks who produced a message at the base ref.\n */\nexport interface LivingServiceState extends ServiceState {\n /**\n * The message names an `action: send` operation of the living asyncapi.yaml\n * reaches (`AsyncapiDoc.sent`) — what this service PRODUCES. Empty unless the\n * contract reads: an unreadable one never vouches for a producer.\n */\n sent: readonly string[];\n}\n\nexport interface CurrentFleet {\n /** By service id, in the enumeration's (sorted-walk) order. Ids the `ambiguous` map claims are excluded. */\n services: Map<string, LivingServiceState>;\n /**\n * Ids more than one working-tree directory claims — `subsystem.name-collision`'s\n * live shape, which validate diagnoses. Diffing either claimant would pick a\n * winner nobody chose (a `new Map` collapse here used to keep the LAST one and\n * fabricate a whole change story about a service that never moved), so the\n * subject is suspended exactly as the base side's `ambiguous` map suspends it.\n */\n ambiguous: Map<string, string[]>;\n}\n\n/**\n * The unreadable arm, carrying the hash of the bytes that would not read\n * (`AxisState`'s `bytes`, which the base side's `axisFrom` fills the same\n * way). The readers this module goes through hand back a parsed document and\n * not its bytes, so this is a second read — paid only on this path, which a\n * healthy fleet never takes.\n */\nasync function unreadableAt(abs: string, rel: string, error: string): Promise<AxisState<never>> {\n try {\n return { kind: \"unreadable\", path: rel, error, bytes: bytesDigest(await readFile(abs)) };\n } catch {\n // No bytes to hash (a directory where the file belongs, a file deleted\n // since the first read): an unhashed side proves no identity, so the axis\n // suspends exactly as it always did.\n return { kind: \"unreadable\", path: rel, error };\n }\n}\n\nasync function readFailure(e: unknown, file: { abs: string; rel: string }): Promise<AxisState<never>> {\n const errno = e as NodeJS.ErrnoException;\n if (errno.code === \"ENOENT\") return { kind: \"absent\" };\n return unreadableAt(file.abs, file.rel, e instanceof Error ? e.message : String(e));\n}\n\n/** One spec-axis file (`spec.md` / `arch.spec.md`) as parsed requirements. */\nasync function requirementsAxis(context: FleetContext, abs: string, rel: string): Promise<AxisState<Requirement[]>> {\n if (!existsSync(abs)) return { kind: \"absent\" };\n try {\n return { kind: \"read\", value: await context.readRequirements(abs) };\n } catch (e) {\n // decodeDocument's non-UTF-8 refusal lands here too: bytes that would\n // parse as zero requirements must suspend the axis, not empty it.\n return readFailure(e, { abs, rel });\n }\n}\n\nasync function openapiAxis(context: FleetContext, abs: string, rel: string): Promise<AxisState<Operation[]>> {\n if (!existsSync(abs)) return { kind: \"absent\" };\n try {\n const doc = await context.readOpenapi(abs);\n return doc.unreadable\n ? await unreadableAt(abs, rel, doc.error ?? \"not a readable OpenAPI document\")\n : { kind: \"read\", value: doc.ops.filter((op) => !op.remove) };\n } catch (e) {\n return readFailure(e, { abs, rel });\n }\n}\n\n/** The event contract as its declarations, and the names it sends — `sent` empty unless it read. */\nasync function asyncapiAxis(\n context: FleetContext,\n abs: string,\n rel: string,\n): Promise<{ axis: AxisState<EventMessage[]>; sent: readonly string[] }> {\n if (!existsSync(abs)) return { axis: { kind: \"absent\" }, sent: [] };\n try {\n const doc = await context.readAsyncapi(abs);\n return doc.unreadable\n ? { axis: await unreadableAt(abs, rel, doc.error ?? \"not a readable AsyncAPI document\"), sent: [] }\n : { axis: { kind: \"read\", value: doc.messages.filter((m) => m.remove !== true) }, sent: doc.sent };\n } catch (e) {\n return { axis: await readFailure(e, { abs, rel }), sent: [] };\n }\n}\n\n/**\n * The current fleet, one `ServiceState` per enumerated service. The\n * enumeration itself (the tree walk) may throw `DocsRepoUnavailableError` —\n * that is the whole-repo refusal `docsRepoReady` fronts, not a per-subject\n * degradation, and it stays a throw for the command layer to map.\n */\nasync function readCurrentFleet(docsDir: DocsDir, context: FleetContext): Promise<CurrentFleet> {\n const entries = await context.listServices(docsDir);\n const states = await inOrder(entries, async (entry): Promise<LivingServiceState> => {\n const paths = servicePathsAt(entry.dir);\n const events = await asyncapiAxis(context, paths.asyncapi, repoPath(docsDir, paths.asyncapi));\n return {\n id: entry.id,\n dir: repoPath(docsDir, entry.dir),\n spec: await requirementsAxis(context, paths.spec, repoPath(docsDir, paths.spec)),\n archSpec: await requirementsAxis(context, paths.archSpec, repoPath(docsDir, paths.archSpec)),\n openapi: await openapiAxis(context, paths.openapi, repoPath(docsDir, paths.openapi)),\n asyncapi: events.axis,\n sent: events.sent,\n };\n });\n const ambiguous = collisions(states);\n return {\n services: new Map(states.filter((s) => !ambiguous.has(s.id)).map((s) => [s.id, s])),\n ambiguous,\n };\n}\n\n/**\n * The fleet map half of the living read: the `architecture/` PROJECT's edges,\n * the one resolver every join over them uses, and the use cases drawn on it.\n */\nexport interface LivingMap {\n /** Every relationship the project declares, or `null` when the map proves nothing — absent, or it does not parse. */\n relationships: readonly Rel[] | null;\n /**\n * Element → service, with the enumerated fleet riding in — the resolver the\n * spine and the step graders use. Without the fleet, an edge into a modelled\n * container `payment.api` resolves to a service called \"api\" that has never\n * existed, the join on the provider finds nothing, and the one check\n * standing between a removal and its last consumer answers \"nobody calls it\"\n * (DESIGN's serviceResolver-known row).\n */\n resolve: (id: string) => string;\n useCases: UseCaseScan;\n /**\n * The rule naming the #external element whose `publishes` edge sends a\n * message, or null — validate's own (`externalProducerOf`,\n * `core/c4/resolve/external.ts`), asked of the same project with the same\n * directory ids and a resolver built over them, so the gate and `loam diff`\n * call a message produced exactly where `spine.message-unproduced` stays\n * quiet. Null wherever the PROJECT does not parse, the fallback below\n * included: validate grades the producer against the project or not at all,\n * and an outside producer found on a map it would not accept would pass a\n * removal its next run then reports.\n *\n * `materialised` is the service ids whose `services/<id>/` a feature's merge\n * would create — empty for a reader of the fleet as it stands. They join the\n * directory ids, and the resolver is REBUILT over the union, because the\n * rule's guard (a `services/<id>/` directory outranks the tag) is asked of\n * the directories the next `validate` will see: a feature carrying\n * `specs/legacy-gateway/` creates that directory, the #external element\n * titled `legacy-gateway` — or a topic nested inside it — then resolves to\n * it, and the producer is gone. Asked over the directories as they stood,\n * the gate passed a retirement from the message's only fleet sender, and\n * after the archive `loam diff` reported `diff.message-removed-consumed` and\n * `validate --all` `spine.message-unproduced` (the verification of D1, X2).\n */\n externalProducerRule: (materialised: readonly RawServiceId[]) => (message: string) => string | null;\n}\n\n/** What one invocation has read, per docs root: each half paid for at its first question. */\ninterface Memo {\n fleet?: Promise<CurrentFleet>;\n map?: Promise<LivingMap>;\n}\n\n/**\n * One read per invocation, keyed by the invocation's own FleetContext — the\n * `core/coherence/retired/archived.ts` exception to the no-module-cache rule,\n * for its reason: the key IS the per-invocation object, so two runs can never\n * see each other's answer and the entry dies with the context. `validate --all`\n * grades every active feature with one context, and every one of them asks the\n * same fleet who consumes what; without this each feature re-read it. Not a\n * memo ON FleetContext for that module's reason too: the class sits below this\n * package, and the import such a memo needs would point up the DAG.\n */\nconst PER_INVOCATION = new WeakMap<FleetContext, Map<string, Memo>>();\n\nfunction memoFor(docsDir: DocsDir, context: FleetContext): Memo {\n let store = PER_INVOCATION.get(context);\n if (store === undefined) PER_INVOCATION.set(context, (store = new Map()));\n const key = resolve(docsDir);\n let memo = store.get(key);\n if (memo === undefined) store.set(key, (memo = {}));\n return memo;\n}\n\n/** `readCurrentFleet`, read at most once per invocation. */\nexport function livingFleet(docsDir: DocsDir, context: FleetContext): Promise<CurrentFleet> {\n const memo = memoFor(docsDir, context);\n return (memo.fleet ??= readCurrentFleet(docsDir, context));\n}\n\n/**\n * The map, read at most once per invocation — and read as the PROJECT, never\n * `architecture/landscape.likec4` alone.\n *\n * The spine grades every edge the `architecture/` project declares\n * (`commands/validate/service/spine.ts` reads `fleet.architecture`), and a\n * use-case hop is attributed against that same project. A consumer scan that\n * read one file of it answered \"nobody calls it\" about an edge drawn in\n * `architecture/calls.likec4`, the gate passed, and the next `validate --all`\n * reported `spine.op-undefined` on that very edge (review 2026-10-12, finding\n * 2) — `core/pack/living.ts` states the same rule for the same reason. One load\n * serves the edges and the hops: two readers of one project are two chances to\n * disagree about which documents it holds.\n *\n * An unreadable project proves nothing either way: `landscape.invalid` is\n * validate's finding to make, and neither a victim nor a doubt invented out of\n * a parse error may point the reader at a file their change never touched. ONE\n * fallback, and it adds only positive evidence: when the project does not parse\n * but `landscape.likec4` does on its own — a broken use-case file beside a good\n * map — the map's own edges still count. They are true of the map either way,\n * and losing them would have let a removal through the gate (and a `loam diff`\n * call it unconsumed) because of a document that has nothing to do with the\n * edge. The use cases stay unreadable: a flow is graded against the whole\n * project or not at all. Whether there is a map at all stays a fact about the\n * FILE, as the pack's `present` does: a repo with no `landscape.likec4` has no\n * map, not an empty project.\n */\nexport function livingMap(docsDir: DocsDir, context: FleetContext): Promise<LivingMap> {\n const memo = memoFor(docsDir, context);\n return (memo.map ??= (async (): Promise<LivingMap> => {\n // Every directory id the walk found, the ones two directories claim\n // included — the services and the `ambiguous` ids of `livingFleet` together,\n // which is the set validate resolves the map against (`known` in\n // `commands/validate/service/service.ts`), read off the same memoised\n // enumeration. Directory names, so the producer rule's guard (a services/\n // directory outranks a tag) is handed what it demands.\n const known: ReadonlySet<RawServiceId> = new Set((await context.listServices(docsDir)).map((entry) => entry.id));\n const none = (): ((message: string) => null) => () => null;\n const mapPath = landscapePath(docsDir);\n if (!existsSync(mapPath)) {\n return { relationships: null, resolve: (id) => id, useCases: await readUseCases({ docsDir, known }), externalProducerRule: none };\n }\n const doc = await context.architecture(docsDir);\n const useCases = useCasesIn(doc, known);\n if (doc.errors.length === 0) {\n const resolve = serviceResolver(doc.elements, known);\n const externalProducerRule = (materialised: readonly RawServiceId[]): ((message: string) => string | null) => {\n // The living set and its resolver stand whenever the merge creates no\n // directory the walk has not already found — `loam diff`'s read, and\n // most features'.\n const after = materialised.every((id) => known.has(id)) ? known : new Set([...known, ...materialised]);\n const svcOf = after === known ? resolve : serviceResolver(doc.elements, after);\n return (message) => externalProducerOf(message, doc, svcOf, after);\n };\n return { relationships: doc.relationships, resolve, useCases, externalProducerRule };\n }\n const alone = await context.loadLikeC4(mapPath);\n return alone.errors.length > 0\n ? { relationships: null, resolve: (id) => id, useCases, externalProducerRule: none }\n : { relationships: alone.relationships, resolve: serviceResolver(alone.elements, known), useCases, externalProducerRule: none };\n })());\n}\n"]}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * What one consumer question answers, and the one sentence that phrases it.
3
+ *
4
+ * Moved out of `loam diff`'s victim index (`core/diff/victims.ts`, now
5
+ * `./consumers.ts`) as its own module because three readers phrase the same
6
+ * answer — `loam diff`'s findings, `loam archive`'s overwrite warnings and the
7
+ * coherence gate's refusals — and none of them should have to import the index
8
+ * to name its result type.
9
+ */
10
+ /**
11
+ * Is this a doubt about a consumer DOCUMENT — one loam could not read, or could
12
+ * not tell whose it is? Those are what the removal gate refuses on, as the gate
13
+ * before the one index did: it read every consumer's spec itself, and a file it
14
+ * could not decode either stopped `validate` or was read leniently by `archive`
15
+ * and refused. Filing those as warnings let a removal archive at exit 0 over a
16
+ * Latin-1 spec.md that still named the operation (the one-index review, finding 1).
17
+ *
18
+ * The other two kinds are doubts about a DRAWING, and they stay out of the
19
+ * gate on purpose: `loam seed` draws every edge without an op, so refusing on
20
+ * an op-less caller would turn every removal on a seeded fleet red, and a
21
+ * contested hop is a flow the model cannot attribute (`./consumers.ts` and
22
+ * `core/usecases/operations.ts` say why each is a doubt and never a victim).
23
+ * `loam diff` needs no such split: an unreadable document carries its run to
24
+ * exit 1 through its own `unreadable[]` entry, the drawings do not.
25
+ */
26
+ export function documentDoubt(s) {
27
+ return s.kind === "unreadable" || s.kind === "ambiguous";
28
+ }
29
+ /** What a reader's `details[]` lists for one scan: positive evidence first, then every doubt — the order `loam diff` lists them in. */
30
+ export function scanDetails(scan) {
31
+ return [...scan.victims, ...scan.suspended.map((s) => s.text)];
32
+ }
33
+ /**
34
+ * Three honest phrasings of one consumer scan — never a confident negative
35
+ * over a scan that skipped something it could not check. Beside the type it
36
+ * phrases rather than inside `core/diff/semantic.ts`, because `loam diff` is no longer
37
+ * its only reader: `loam archive`'s overwrite warnings ask the same scan of
38
+ * the same fleet, and one sentence for one answer is what lets a reader meet
39
+ * one vocabulary in both.
40
+ */
41
+ export function consumerStance(scan) {
42
+ return scan.victims.length > 0 ? `${scan.victims.length} current consumer(s) still name it`
43
+ : scan.suspended.length > 0 ? "whether current consumers name it could not be fully answered"
44
+ : "no current consumer names it";
45
+ }
46
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/core/consumers/scan.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAqCH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,aAAa,CAAC,CAAa;IACzC,OAAO,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC;AAC3D,CAAC;AAED,uIAAuI;AACvI,MAAM,UAAU,WAAW,CAAC,IAAkB;IAC5C,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,IAAkB;IAC/C,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,oCAAoC;QACzF,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,+DAA+D;YAC7F,CAAC,CAAC,8BAA8B,CAAC;AACrC,CAAC","sourcesContent":["/**\n * What one consumer question answers, and the one sentence that phrases it.\n *\n * Moved out of `loam diff`'s victim index (`core/diff/victims.ts`, now\n * `./consumers.ts`) as its own module because three readers phrase the same\n * answer — `loam diff`'s findings, `loam archive`'s overwrite warnings and the\n * coherence gate's refusals — and none of them should have to import the index\n * to name its result type.\n */\n\n/**\n * Why one possible consumer could not be checked. Typed, because the readers do\n * not weigh the kinds alike: a doubt about a DOCUMENT (`documentDoubt`) is one\n * the removal gate refuses on, and a doubt about a DRAWING is not.\n */\nexport type SuspensionKind =\n /** A consumer's spec.md or arch.spec.md exists and loam refused to read it — non-UTF-8 bytes, a directory where the file belongs. */\n | \"unreadable\"\n /** Two directories claim the consumer's service id, so neither one's documents were scanned. */\n | \"ambiguous\"\n /** An edge into the provider drawn with no `metadata { op }`: it calls the provider, and nobody wrote down which operation. */\n | \"unlinked\"\n /** A use-case hop whose backing relationships name different operations, this one among them. */\n | \"contested\";\n\n/** One possible consumer the scan could not check, and the sentence that says which and why. */\nexport interface Suspension {\n kind: SuspensionKind;\n /** What every reader shows — the document, the directories, the edge or the hop, by name. */\n text: string;\n}\n\n/**\n * One consumer scan's answer, honest about its own coverage. `victims` is\n * positive evidence; `suspended` names the consumers whose relevant document\n * could not be read (or whose identity is ambiguous), and the callers drawn or\n * flowed too vaguely to attribute, because a scan that skipped a file loam\n * REFUSED to read must never let the caller assert \"nobody names it\" — the\n * fail-open shape this type exists to forbid.\n */\nexport interface ConsumerScan {\n victims: string[];\n suspended: Suspension[];\n}\n\n/**\n * Is this a doubt about a consumer DOCUMENT — one loam could not read, or could\n * not tell whose it is? Those are what the removal gate refuses on, as the gate\n * before the one index did: it read every consumer's spec itself, and a file it\n * could not decode either stopped `validate` or was read leniently by `archive`\n * and refused. Filing those as warnings let a removal archive at exit 0 over a\n * Latin-1 spec.md that still named the operation (the one-index review, finding 1).\n *\n * The other two kinds are doubts about a DRAWING, and they stay out of the\n * gate on purpose: `loam seed` draws every edge without an op, so refusing on\n * an op-less caller would turn every removal on a seeded fleet red, and a\n * contested hop is a flow the model cannot attribute (`./consumers.ts` and\n * `core/usecases/operations.ts` say why each is a doubt and never a victim).\n * `loam diff` needs no such split: an unreadable document carries its run to\n * exit 1 through its own `unreadable[]` entry, the drawings do not.\n */\nexport function documentDoubt(s: Suspension): boolean {\n return s.kind === \"unreadable\" || s.kind === \"ambiguous\";\n}\n\n/** What a reader's `details[]` lists for one scan: positive evidence first, then every doubt — the order `loam diff` lists them in. */\nexport function scanDetails(scan: ConsumerScan): string[] {\n return [...scan.victims, ...scan.suspended.map((s) => s.text)];\n}\n\n/**\n * Three honest phrasings of one consumer scan — never a confident negative\n * over a scan that skipped something it could not check. Beside the type it\n * phrases rather than inside `core/diff/semantic.ts`, because `loam diff` is no longer\n * its only reader: `loam archive`'s overwrite warnings ask the same scan of\n * the same fleet, and one sentence for one answer is what lets a reader meet\n * one vocabulary in both.\n */\nexport function consumerStance(scan: ConsumerScan): string {\n return scan.victims.length > 0 ? `${scan.victims.length} current consumer(s) still name it`\n : scan.suspended.length > 0 ? \"whether current consumers name it could not be fully answered\"\n : \"no current consumer names it\";\n}\n"]}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * One service's four documents, each read or honestly not — the shape every
3
+ * consumer question is asked of.
4
+ *
5
+ * It began as `loam diff`'s (`core/diff/base-state.ts` held it, because the
6
+ * diff was its only reader), and moved here when the consumer index became
7
+ * the one answer the diff, the coherence gate and the archive planner share:
8
+ * the index reads the living fleet in this shape, so the shape lives one level
9
+ * below everything that asks it.
10
+ */
11
+ import { createHash } from "node:crypto";
12
+ /** The `bytes` identity of an unreadable side — the same hash on both sides, so equal means byte-identical. */
13
+ export function bytesDigest(bytes) {
14
+ return createHash("sha256").update(bytes).digest("hex");
15
+ }
16
+ /**
17
+ * Ids claimed by more than one enumerated directory, with every claimant named
18
+ * — the base side's grouping (`core/diff/base-state.ts`) and `./current.ts`'s,
19
+ * so the two sides of a diff refuse the same ambiguity the same way.
20
+ */
21
+ export function collisions(dirs) {
22
+ const byId = new Map();
23
+ for (const d of dirs)
24
+ byId.set(d.id, [...(byId.get(d.id) ?? []), d.dir]);
25
+ return new Map([...byId].filter(([, claimants]) => claimants.length > 1));
26
+ }
27
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/core/consumers/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA0BzC,+GAA+G;AAC/G,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAuBD;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAA4C;IACrE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAoB,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACzE,OAAO,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5E,CAAC","sourcesContent":["/**\n * One service's four documents, each read or honestly not — the shape every\n * consumer question is asked of.\n *\n * It began as `loam diff`'s (`core/diff/base-state.ts` held it, because the\n * diff was its only reader), and moved here when the consumer index became\n * the one answer the diff, the coherence gate and the archive planner share:\n * the index reads the living fleet in this shape, so the shape lives one level\n * below everything that asks it.\n */\nimport { createHash } from \"node:crypto\";\nimport type { Requirement } from \"../document/spec.js\";\nimport type { Operation } from \"../openapi/doc.js\";\nimport type { EventMessage } from \"../asyncapi/model.js\";\nimport type { RawServiceId } from \"../kernel/ids/service.js\";\n\n/**\n * One artifact's state on one side of the diff. `unreadable` is the\n * containment arm: the file exists but could not be read as its kind, so\n * every finding on this axis for this subject is SUSPENDED — \"nobody could\n * look\" must never grade as \"nothing is there\", in either direction.\n *\n * `bytes` is the sha256 of the raw file when there WERE bytes and they refused\n * to parse — absent when the bytes themselves could not be had (a failed\n * `git show`, a directory where the file belongs). It is the one fact an\n * unreadable side can still prove: that it is the same file the other side\n * holds, which `core/diff/semantic.ts`'s `comparable` turns into \"the branch\n * did not touch this contract\" (an AsyncAPI 2.x document is unreadable by policy, and\n * suspending it on every run failed every `loam diff` over a fleet that holds\n * one, whatever the branch changed).\n */\nexport type AxisState<T> =\n | { kind: \"absent\" }\n | { kind: \"read\"; value: T }\n | { kind: \"unreadable\"; path: string; error: string; bytes?: string };\n\n/** The `bytes` identity of an unreadable side — the same hash on both sides, so equal means byte-identical. */\nexport function bytesDigest(bytes: Buffer): string {\n return createHash(\"sha256\").update(bytes).digest(\"hex\");\n}\n\n/**\n * One service on one side of the diff — the same shape for the base ref and\n * the working tree (`./current.ts` builds that one, `core/diff/base-state.ts`\n * the base ref's), which is what lets `core/diff/semantic.ts` join the two\n * without caring which side came from git — and what lets the consumer index\n * (`./consumers.ts`) read the living fleet in the shape the diff already does.\n */\nexport interface ServiceState {\n /** The directory's leaf name — a name read off the tree, so the index may join it into a feature's `specs/<svc>/`. */\n id: RawServiceId;\n /** Docs-relative directory with forward slashes, e.g. `services/billing/payment-service`. */\n dir: string;\n spec: AxisState<Requirement[]>;\n /** Read on both sides for every requirement join — the outbox requirement lives here as often as in spec.md (`./consumers.ts`'s `REQUIREMENT_AXES`). */\n archSpec: AxisState<Requirement[]>;\n /** Operations with `x-loam-remove` markers filtered out: a marker is bookkeeping, never a callable operation. */\n openapi: AxisState<Operation[]>;\n /** Messages with removal markers filtered out, for the same reason. */\n asyncapi: AxisState<EventMessage[]>;\n}\n\n/**\n * Ids claimed by more than one enumerated directory, with every claimant named\n * — the base side's grouping (`core/diff/base-state.ts`) and `./current.ts`'s,\n * so the two sides of a diff refuse the same ambiguity the same way.\n */\nexport function collisions(dirs: readonly { id: string; dir: string }[]): Map<string, string[]> {\n const byId = new Map<string, string[]>();\n for (const d of dirs) byId.set(d.id, [...(byId.get(d.id) ?? []), d.dir]);\n return new Map([...byId].filter(([, claimants]) => claimants.length > 1));\n}\n"]}
@@ -40,13 +40,15 @@
40
40
  import { existsSync } from "node:fs";
41
41
  import { readFile } from "node:fs/promises";
42
42
  import { relative } from "node:path";
43
- import {} from "../fleet-context.js";
44
- import { parseRequirements } from "../document/parse.js";
43
+ import { FleetContext } from "../fleet-context.js";
44
+ import { parseRequirements, readRequirementsDocument } from "../document/parse.js";
45
45
  import {} from "../document/spec.js";
46
46
  import { featureSpecPaths, SPEC_AXES } from "../repo/paths.js";
47
47
  import { featureUseCasesDir, livingCapabilityPaths } from "../repo/authored/paths.js";
48
48
  import { readCapabilityVocabulary } from "../capabilities/capabilities.js";
49
+ import { extendingModels } from "../c4/service-model/fleet/extending.js";
49
50
  import { flowCoverage } from "../usecases/delta/claims.js";
51
+ import { changedPromiseFlowIssues } from "../usecases/delta/modified.js";
50
52
  import { enumeratedServiceIds, locateServicePaths } from "../repo/service-target.js";
51
53
  import { featureSpecServices } from "../repo/repo.js";
52
54
  import { capabilityDocIssues } from "../capabilities/delta/doc.js";
@@ -100,6 +102,9 @@ export async function deltaShapeIssues(docsDir, featureDir, featureId, context)
100
102
  // holds the rules; nothing here decides anything).
101
103
  const serviceDeltas = [];
102
104
  const capabilityDeltas = [];
105
+ // Each service axis beside its living document, for the one question that
106
+ // needs both: which living flow claims a requirement this feature changes.
107
+ const servicePairs = [];
103
108
  // Both requirement-carrying files per service run the same checks — one code
104
109
  // path parameterized by filename, the merge's own factoring. `where` names
105
110
  // the arch file in messages so a finding cannot be chased into the wrong
@@ -124,6 +129,8 @@ export async function deltaShapeIssues(docsDir, featureDir, featureId, context)
124
129
  const graded = await gradeDelta(scope, (await locateServicePaths(docsDir, service, context))[axis.key], reads);
125
130
  issues.push(...graded.issues);
126
131
  serviceDeltas.push({ service, file: axis.file, reqs: graded.reqs });
132
+ const paths = () => locateServicePaths(docsDir, service, context);
133
+ servicePairs.push({ id: service, axis: axis.key, reqs: graded.reqs, living: graded.living.all, paths });
127
134
  }
128
135
  }
129
136
  for (const doc of capabilities.docs) {
@@ -164,7 +171,7 @@ export async function deltaShapeIssues(docsDir, featureDir, featureId, context)
164
171
  // A feature with no `usecases/` directory is a REAL empty answer, not an
165
172
  // ungraded one: there is no flow, so "no flow keeps this" is true and the
166
173
  // message may say it.
167
- const kept = hasFlows
174
+ const flows = hasFlows
168
175
  ? await flowCoverage({
169
176
  docsDir,
170
177
  featureDir,
@@ -175,13 +182,29 @@ export async function deltaShapeIssues(docsDir, featureDir, featureId, context)
175
182
  // the same, and `core/repo/service-target.ts` prices a fleet
176
183
  // enumeration per call at ~13 ms on a 120-service fleet.
177
184
  vocabulary: context === undefined ? await readCapabilityVocabulary(docsDir) : await context.capabilities(docsDir),
178
- known: new Set(await enumeratedServiceIds(docsDir, context)),
185
+ // The fleet the merge leaves: each `specs/<svc>/` of this feature becomes a
186
+ // `services/<svc>/`, so a hop into a service it introduces resolves to that
187
+ // service in the grade, as it will under the next `validate --all`.
188
+ known: new Set([...(await enumeratedServiceIds(docsDir, context)), ...services]),
189
+ // Decoded or refused by name (`readRequirementsDocument`), never `readFile`'s
190
+ // utf8 — a UTF-16 capability document would read as no requirements and
191
+ // convict every flow naming it.
192
+ read: async (path) => (context === undefined ? parseRequirements(await readRequirementsDocument(path)) : await context.readRequirements(path)),
179
193
  // A function rather than the context itself: one memoised LikeC4 read
180
194
  // does not justify an edge from `core/usecases/` to `fleet-context`, and
181
195
  // the edge would push that package up a DAG level for nothing.
182
196
  ...(context === undefined ? {} : { load: (path) => context.loadLikeC4(path) }),
197
+ // The fleet's extending models, for the merge preview the overlay
198
+ // grades against — read HERE for `vocabulary`'s reason exactly, and as
199
+ // a thunk so the walk pays for it only when a flow is really there.
200
+ // Without it the preview is the pre-routing map and `usecase.flow-invalid`
201
+ // fails open on the one shape it exists for: a hop into
202
+ // `<service-fqn>.<container>`, which the archive routes into that
203
+ // service's own model (verification 2026-09-04, review F8).
204
+ models: () => extendingModels(docsDir, context),
183
205
  })
184
- : { kind: "read", kept: [] };
206
+ : { promises: { kind: "read", kept: [] }, issues: [] };
207
+ const kept = flows.promises;
185
208
  if (kept.kind === "unreadable") {
186
209
  // ERROR, and the archive gate's own `NEVER_OVERRIDABLE` keeps `--approve`
187
210
  // off it. This is the refusal that stops a flow being copied into
@@ -206,6 +229,12 @@ export async function deltaShapeIssues(docsDir, featureDir, featureId, context)
206
229
  `${kept.errors.length} problem(s): ${kept.errors.join("; ")}`,
207
230
  });
208
231
  }
232
+ // And the flows that DID read, graded as `validate --all` grades them once
233
+ // living: every hop against the post-merge map, every `#cap-`/`#req-` tag
234
+ // against the vocabulary and requirements the merge leaves
235
+ // (`core/usecases/grade/feature.ts`). Before this, a hop nothing backs and a
236
+ // `#req-` tag nothing resolves archived clean and turned the fleet red.
237
+ issues.push(...flows.issues);
209
238
  // The `Realizes:` join, both directions, over documents this walk has already
210
239
  // parsed. Skipped entirely when the feature carries no capability delta,
211
240
  // which is every feature in a fleet that has not adopted the business axis —
@@ -228,6 +257,22 @@ export async function deltaShapeIssues(docsDir, featureDir, featureId, context)
228
257
  living: () => livingRealizers(docsDir, context),
229
258
  })));
230
259
  }
260
+ // The living flows whose `#req-` tag claims a promise this feature rewrites or
261
+ // retires (`core/usecases/delta/modified.ts`). Asked only when a requirement is
262
+ // MODIFIED or REMOVED, on either corpus, so no other feature reads a flow for it.
263
+ if ([...capabilityDeltas, ...servicePairs].some((doc) => doc.reqs.some((r) => r.kind === "MODIFIED" || r.kind === "REMOVED"))) {
264
+ const ctx = context ?? new FleetContext();
265
+ issues.push(...(await changedPromiseFlowIssues({
266
+ docsDir,
267
+ capabilities: capabilityDeltas,
268
+ services: servicePairs,
269
+ vocabulary: await ctx.capabilities(docsDir),
270
+ known: new Set(await enumeratedServiceIds(docsDir, ctx)),
271
+ serviceModel: (paths) => ctx.serviceModel(docsDir, paths),
272
+ architecture: () => ctx.architecture(docsDir),
273
+ readRequirements: (path) => ctx.readRequirements(path),
274
+ })));
275
+ }
231
276
  return issues;
232
277
  }
233
278
  /**
@@ -236,7 +281,7 @@ export async function deltaShapeIssues(docsDir, featureDir, featureId, context)
236
281
  * there still realize a capability requirement this feature retires?
237
282
  *
238
283
  * The same shape and the same cost `openapi.remove-op-consumed` pays through
239
- * `coherence/lookups.ts` one axis over, and for the same reason — the merge
284
+ * the consumer index (`core/consumers/`) one axis over, and for the same reason — the merge
240
285
  * deletes the promise while the `Realizes:` line stays, so the very next
241
286
  * `validate --all` reports a breach on a repository whose author was never in
242
287
  * this feature. Called behind a thunk (`removedRealizedIssues` invokes it only