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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (901) hide show
  1. package/CHANGELOG.md +3448 -0
  2. package/COMPARISON.md +91 -3
  3. package/CONTRIBUTING.md +37 -0
  4. package/MIGRATING-from-OpenSpec.md +47 -23
  5. package/QUICKSTART.md +189 -12
  6. package/README.md +274 -65
  7. package/ROADMAP.md +572 -31
  8. package/SCHEMA.md +1709 -155
  9. package/WORKFLOW.md +298 -72
  10. package/dist/cli.js +26 -8
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/adopt/adopt.js +5 -10
  13. package/dist/commands/adopt/adopt.js.map +1 -1
  14. package/dist/commands/adopt/render.js +50 -9
  15. package/dist/commands/adopt/render.js.map +1 -1
  16. package/dist/commands/archive/archive.js +16 -19
  17. package/dist/commands/archive/archive.js.map +1 -1
  18. package/dist/commands/archive/closing.js +42 -0
  19. package/dist/commands/archive/closing.js.map +1 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js +36 -42
  21. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
  22. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  24. package/dist/commands/archive/plan/contracts/openapi.js +77 -43
  25. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
  26. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  28. package/dist/commands/archive/plan/document/head.js +151 -0
  29. package/dist/commands/archive/plan/document/head.js.map +1 -0
  30. package/dist/commands/archive/plan/document/links.js +284 -0
  31. package/dist/commands/archive/plan/document/links.js.map +1 -0
  32. package/dist/commands/archive/plan/document/run.js +136 -0
  33. package/dist/commands/archive/plan/document/run.js.map +1 -0
  34. package/dist/commands/archive/plan/gate.js +21 -19
  35. package/dist/commands/archive/plan/gate.js.map +1 -1
  36. package/dist/commands/archive/plan/landscape.js +167 -30
  37. package/dist/commands/archive/plan/landscape.js.map +1 -1
  38. package/dist/commands/archive/plan/model/extending.js +85 -0
  39. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  40. package/dist/commands/archive/plan/refusal.js +14 -19
  41. package/dist/commands/archive/plan/refusal.js.map +1 -1
  42. package/dist/commands/archive/plan/specs.js +137 -56
  43. package/dist/commands/archive/plan/specs.js.map +1 -1
  44. package/dist/commands/archive/plan/state.js +3 -0
  45. package/dist/commands/archive/plan/state.js.map +1 -1
  46. package/dist/commands/archive/run.js +134 -30
  47. package/dist/commands/archive/run.js.map +1 -1
  48. package/dist/commands/archive/shipped.js +49 -0
  49. package/dist/commands/archive/shipped.js.map +1 -0
  50. package/dist/commands/context/context.js +85 -18
  51. package/dist/commands/context/context.js.map +1 -1
  52. package/dist/commands/context/print.js +29 -7
  53. package/dist/commands/context/print.js.map +1 -1
  54. package/dist/commands/delta/delta.js +102 -14
  55. package/dist/commands/delta/delta.js.map +1 -1
  56. package/dist/commands/delta/print.js +17 -1
  57. package/dist/commands/delta/print.js.map +1 -1
  58. package/dist/commands/dependencies.js +3 -7
  59. package/dist/commands/dependencies.js.map +1 -1
  60. package/dist/commands/diff/diff.js +20 -27
  61. package/dist/commands/diff/diff.js.map +1 -1
  62. package/dist/commands/doctor.js +60 -1
  63. package/dist/commands/doctor.js.map +1 -1
  64. package/dist/commands/explain/explain.js +89 -13
  65. package/dist/commands/explain/explain.js.map +1 -1
  66. package/dist/commands/explore.js +16 -10
  67. package/dist/commands/explore.js.map +1 -1
  68. package/dist/commands/gate/gate.js +45 -8
  69. package/dist/commands/gate/gate.js.map +1 -1
  70. package/dist/commands/gate/print.js +15 -3
  71. package/dist/commands/gate/print.js.map +1 -1
  72. package/dist/commands/gherkin/commit.js +13 -54
  73. package/dist/commands/gherkin/commit.js.map +1 -1
  74. package/dist/commands/gherkin/gherkin.js +36 -20
  75. package/dist/commands/gherkin/gherkin.js.map +1 -1
  76. package/dist/commands/gherkin/reconcile.js +10 -13
  77. package/dist/commands/gherkin/reconcile.js.map +1 -1
  78. package/dist/commands/init/first-hour.js +44 -0
  79. package/dist/commands/init/first-hour.js.map +1 -1
  80. package/dist/commands/init/init.js +18 -22
  81. package/dist/commands/init/init.js.map +1 -1
  82. package/dist/commands/list/campaign/campaign.js +4 -6
  83. package/dist/commands/list/campaign/campaign.js.map +1 -1
  84. package/dist/commands/list/json.js +5 -7
  85. package/dist/commands/list/json.js.map +1 -1
  86. package/dist/commands/list/list.js +44 -29
  87. package/dist/commands/list/list.js.map +1 -1
  88. package/dist/commands/list/print.js +52 -9
  89. package/dist/commands/list/print.js.map +1 -1
  90. package/dist/commands/list/suites/suites.js +140 -0
  91. package/dist/commands/list/suites/suites.js.map +1 -0
  92. package/dist/commands/list/views.js +37 -34
  93. package/dist/commands/list/views.js.map +1 -1
  94. package/dist/commands/mcp/dispatch.js +91 -36
  95. package/dist/commands/mcp/dispatch.js.map +1 -1
  96. package/dist/commands/mcp/mcp.js +56 -15
  97. package/dist/commands/mcp/mcp.js.map +1 -1
  98. package/dist/commands/mcp/serve.js.map +1 -1
  99. package/dist/commands/migrate-openspec/materialize/active.js +27 -22
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
  101. package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
  102. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
  103. package/dist/commands/migrate-openspec/materialize/target.js +2 -2
  104. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
  105. package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
  106. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
  107. package/dist/commands/migrate-openspec/openspec/error.js +7 -8
  108. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
  109. package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
  110. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
  111. package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
  112. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
  113. package/dist/commands/new/capability-template.js +118 -0
  114. package/dist/commands/new/capability-template.js.map +1 -0
  115. package/dist/commands/new/commit.js +8 -22
  116. package/dist/commands/new/commit.js.map +1 -1
  117. package/dist/commands/new/modifies.js +206 -0
  118. package/dist/commands/new/modifies.js.map +1 -0
  119. package/dist/commands/new/new.js +59 -14
  120. package/dist/commands/new/new.js.map +1 -1
  121. package/dist/commands/new/templates.js +48 -124
  122. package/dist/commands/new/templates.js.map +1 -1
  123. package/dist/commands/open.js +3 -7
  124. package/dist/commands/open.js.map +1 -1
  125. package/dist/commands/policy/gate.js +27 -0
  126. package/dist/commands/policy/gate.js.map +1 -1
  127. package/dist/commands/rebase/plan.js +2 -2
  128. package/dist/commands/rebase/plan.js.map +1 -1
  129. package/dist/commands/rebase/rebase.js +60 -35
  130. package/dist/commands/rebase/rebase.js.map +1 -1
  131. package/dist/commands/seed/commit.js +55 -26
  132. package/dist/commands/seed/commit.js.map +1 -1
  133. package/dist/commands/seed/plan.js +158 -13
  134. package/dist/commands/seed/plan.js.map +1 -1
  135. package/dist/commands/seed/seed.js +13 -11
  136. package/dist/commands/seed/seed.js.map +1 -1
  137. package/dist/commands/show/feature.js +9 -5
  138. package/dist/commands/show/feature.js.map +1 -1
  139. package/dist/commands/show/introduced.js +157 -0
  140. package/dist/commands/show/introduced.js.map +1 -0
  141. package/dist/commands/show/marks.js +35 -6
  142. package/dist/commands/show/marks.js.map +1 -1
  143. package/dist/commands/show/service.js +41 -33
  144. package/dist/commands/show/service.js.map +1 -1
  145. package/dist/commands/show/show.js +17 -7
  146. package/dist/commands/show/show.js.map +1 -1
  147. package/dist/commands/status/fleet-next.js +90 -0
  148. package/dist/commands/status/fleet-next.js.map +1 -0
  149. package/dist/commands/status/json.js +2 -0
  150. package/dist/commands/status/json.js.map +1 -1
  151. package/dist/commands/status/print.js +89 -37
  152. package/dist/commands/status/print.js.map +1 -1
  153. package/dist/commands/status/status.js +3 -7
  154. package/dist/commands/status/status.js.map +1 -1
  155. package/dist/commands/steps/steps.js +103 -23
  156. package/dist/commands/steps/steps.js.map +1 -1
  157. package/dist/commands/subsystem/edit.js +7 -7
  158. package/dist/commands/subsystem/edit.js.map +1 -1
  159. package/dist/commands/subsystem/move.js +106 -46
  160. package/dist/commands/subsystem/move.js.map +1 -1
  161. package/dist/commands/subsystem/query.js +2 -4
  162. package/dist/commands/subsystem/query.js.map +1 -1
  163. package/dist/commands/subsystem/subsystem.js +4 -7
  164. package/dist/commands/subsystem/subsystem.js.map +1 -1
  165. package/dist/commands/subsystem/sync.js +289 -74
  166. package/dist/commands/subsystem/sync.js.map +1 -1
  167. package/dist/commands/subsystem/txn/exclude.js +132 -0
  168. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  169. package/dist/commands/subsystem/txn/links.js +128 -0
  170. package/dist/commands/subsystem/txn/links.js.map +1 -0
  171. package/dist/commands/subsystem/txn/report.js +174 -0
  172. package/dist/commands/subsystem/txn/report.js.map +1 -0
  173. package/dist/commands/subsystem/txn/txn.js +147 -45
  174. package/dist/commands/subsystem/txn/txn.js.map +1 -1
  175. package/dist/commands/subsystem/txn/views.js +200 -21
  176. package/dist/commands/subsystem/txn/views.js.map +1 -1
  177. package/dist/commands/tasks/actions.js +107 -0
  178. package/dist/commands/tasks/actions.js.map +1 -0
  179. package/dist/commands/tasks/render.js +253 -0
  180. package/dist/commands/tasks/render.js.map +1 -0
  181. package/dist/commands/tasks/tasks.js +119 -0
  182. package/dist/commands/tasks/tasks.js.map +1 -0
  183. package/dist/commands/unarchive/manifest.js +42 -26
  184. package/dist/commands/unarchive/manifest.js.map +1 -1
  185. package/dist/commands/unarchive/restore.js +83 -33
  186. package/dist/commands/unarchive/restore.js.map +1 -1
  187. package/dist/commands/unarchive/unarchive.js +22 -30
  188. package/dist/commands/unarchive/unarchive.js.map +1 -1
  189. package/dist/commands/validate/arch-coverage.js +78 -27
  190. package/dist/commands/validate/arch-coverage.js.map +1 -1
  191. package/dist/commands/validate/checks/fleet-shape.js +34 -126
  192. package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
  193. package/dist/commands/validate/checks/health-deps.js +9 -6
  194. package/dist/commands/validate/checks/health-deps.js.map +1 -1
  195. package/dist/commands/validate/checks/introduced.js +102 -0
  196. package/dist/commands/validate/checks/introduced.js.map +1 -0
  197. package/dist/commands/validate/checks/requirements.js +18 -8
  198. package/dist/commands/validate/checks/requirements.js.map +1 -1
  199. package/dist/commands/validate/checks/sources.js +11 -2
  200. package/dist/commands/validate/checks/sources.js.map +1 -1
  201. package/dist/commands/validate/coverage/covers-after.js +105 -0
  202. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  203. package/dist/commands/validate/feature.js +26 -20
  204. package/dist/commands/validate/feature.js.map +1 -1
  205. package/dist/commands/validate/fleet/census.js +37 -13
  206. package/dist/commands/validate/fleet/census.js.map +1 -1
  207. package/dist/commands/validate/fleet/landscape.js +144 -126
  208. package/dist/commands/validate/fleet/landscape.js.map +1 -1
  209. package/dist/commands/validate/fleet/load.js +66 -0
  210. package/dist/commands/validate/fleet/load.js.map +1 -1
  211. package/dist/commands/validate/fleet/map/attest.js +98 -0
  212. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  213. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  214. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  215. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  216. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  217. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  218. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  219. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  220. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  221. package/dist/commands/validate/fleet/obligations.js +44 -14
  222. package/dist/commands/validate/fleet/obligations.js.map +1 -1
  223. package/dist/commands/validate/fleet/scorecard/print.js +10 -2
  224. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
  225. package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
  226. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
  227. package/dist/commands/validate/fleet/usecases/place.js.map +1 -1
  228. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  229. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  230. package/dist/commands/validate/fleet/views/ids.js +50 -15
  231. package/dist/commands/validate/fleet/views/ids.js.map +1 -1
  232. package/dist/commands/validate/fleet/views/projects.js +278 -0
  233. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  234. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  235. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  236. package/dist/commands/validate/fleet/views/stale.js +40 -47
  237. package/dist/commands/validate/fleet/views/stale.js.map +1 -1
  238. package/dist/commands/validate/links/corpus.js +1 -4
  239. package/dist/commands/validate/links/corpus.js.map +1 -1
  240. package/dist/commands/validate/links/glossary.js.map +1 -1
  241. package/dist/commands/validate/render/repeats.js +63 -0
  242. package/dist/commands/validate/render/repeats.js.map +1 -0
  243. package/dist/commands/validate/render/rollups.js +115 -0
  244. package/dist/commands/validate/render/rollups.js.map +1 -0
  245. package/dist/commands/validate/render/text.js +199 -0
  246. package/dist/commands/validate/render/text.js.map +1 -0
  247. package/dist/commands/validate/report.js +36 -160
  248. package/dist/commands/validate/report.js.map +1 -1
  249. package/dist/commands/validate/scope.js +113 -0
  250. package/dist/commands/validate/scope.js.map +1 -0
  251. package/dist/commands/validate/service/api.js +21 -107
  252. package/dist/commands/validate/service/api.js.map +1 -1
  253. package/dist/commands/validate/service/contracts/generated.js +134 -0
  254. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  255. package/dist/commands/validate/service/events/events.js +36 -14
  256. package/dist/commands/validate/service/events/events.js.map +1 -1
  257. package/dist/commands/validate/service/events/message-producers.js +1 -1
  258. package/dist/commands/validate/service/events/message-producers.js.map +1 -1
  259. package/dist/commands/validate/service/evidence-pins.js +56 -10
  260. package/dist/commands/validate/service/evidence-pins.js.map +1 -1
  261. package/dist/commands/validate/service/model/diverged.js +226 -0
  262. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  263. package/dist/commands/validate/service/model/grade.js +163 -0
  264. package/dist/commands/validate/service/model/grade.js.map +1 -0
  265. package/dist/commands/validate/service/service.js +121 -61
  266. package/dist/commands/validate/service/service.js.map +1 -1
  267. package/dist/commands/validate/service/specs.js +88 -28
  268. package/dist/commands/validate/service/specs.js.map +1 -1
  269. package/dist/commands/validate/service/spine.js +38 -3
  270. package/dist/commands/validate/service/spine.js.map +1 -1
  271. package/dist/commands/validate/service/usecases/tags.js +113 -0
  272. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  273. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  274. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  275. package/dist/commands/validate/validate.js +85 -60
  276. package/dist/commands/validate/validate.js.map +1 -1
  277. package/dist/commands/verify/cross/diff.js +2 -6
  278. package/dist/commands/verify/cross/diff.js.map +1 -1
  279. package/dist/commands/verify/evidence/contract.js +1 -1
  280. package/dist/commands/verify/evidence/contract.js.map +1 -1
  281. package/dist/commands/verify/evidence/read.js +12 -3
  282. package/dist/commands/verify/evidence/read.js.map +1 -1
  283. package/dist/commands/verify/frozen.js +45 -23
  284. package/dist/commands/verify/frozen.js.map +1 -1
  285. package/dist/commands/verify/record.js +69 -17
  286. package/dist/commands/verify/record.js.map +1 -1
  287. package/dist/commands/verify/report.js +27 -44
  288. package/dist/commands/verify/report.js.map +1 -1
  289. package/dist/commands/verify/results.js +112 -30
  290. package/dist/commands/verify/results.js.map +1 -1
  291. package/dist/commands/verify/verify.js +55 -52
  292. package/dist/commands/verify/verify.js.map +1 -1
  293. package/dist/commands/vouch/pack/pack.js +2 -2
  294. package/dist/commands/vouch/pack/pack.js.map +1 -1
  295. package/dist/commands/vouch/pack/print.js +1 -6
  296. package/dist/commands/vouch/pack/print.js.map +1 -1
  297. package/dist/commands/vouch/pack/sections.js +1 -2
  298. package/dist/commands/vouch/pack/sections.js.map +1 -1
  299. package/dist/commands/vouch/run.js +26 -81
  300. package/dist/commands/vouch/run.js.map +1 -1
  301. package/dist/commands/vouch/sample/plan.js +20 -34
  302. package/dist/commands/vouch/sample/plan.js.map +1 -1
  303. package/dist/commands/vouch/vet/verify.js +39 -7
  304. package/dist/commands/vouch/vet/verify.js.map +1 -1
  305. package/dist/commands/vouch/vouch.js +10 -17
  306. package/dist/commands/vouch/vouch.js.map +1 -1
  307. package/dist/core/agent/agents-md/command-map.js +81 -106
  308. package/dist/core/agent/agents-md/command-map.js.map +1 -1
  309. package/dist/core/agent/agents-md/map/explain.js +21 -9
  310. package/dist/core/agent/agents-md/map/explain.js.map +1 -1
  311. package/dist/core/agent/agents-md/map/lenses/context.js +17 -8
  312. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
  313. package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
  314. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
  315. package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
  316. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
  317. package/dist/core/agent/agents-md/map/mcp.js +10 -7
  318. package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
  319. package/dist/core/agent/agents-md/map/status.js +24 -8
  320. package/dist/core/agent/agents-md/map/status.js.map +1 -1
  321. package/dist/core/agent/agents-md/map/subsystem.js +80 -8
  322. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
  323. package/dist/core/agent/agents-md/map/usecases.js +88 -10
  324. package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
  325. package/dist/core/agent/agents-md/refusals.js +49 -22
  326. package/dist/core/agent/agents-md/refusals.js.map +1 -1
  327. package/dist/core/agent/agents-md.js +39 -6
  328. package/dist/core/agent/agents-md.js.map +1 -1
  329. package/dist/core/agent/agents-stamp.js +10 -0
  330. package/dist/core/agent/agents-stamp.js.map +1 -1
  331. package/dist/core/agent/protocol.js +1 -1
  332. package/dist/core/agent/protocol.js.map +1 -1
  333. package/dist/core/agent/scaffold.js +10 -15
  334. package/dist/core/agent/scaffold.js.map +1 -1
  335. package/dist/core/agent/support/report.js +46 -5
  336. package/dist/core/agent/support/report.js.map +1 -1
  337. package/dist/core/agent/tools/dialects.js +1 -0
  338. package/dist/core/agent/tools/dialects.js.map +1 -1
  339. package/dist/core/agent/tools/registry.js +41 -76
  340. package/dist/core/agent/tools/registry.js.map +1 -1
  341. package/dist/core/agent/workflows/adopt.js +158 -11
  342. package/dist/core/agent/workflows/adopt.js.map +1 -1
  343. package/dist/core/agent/workflows/check.js +78 -39
  344. package/dist/core/agent/workflows/check.js.map +1 -1
  345. package/dist/core/agent/workflows/closing.js +88 -27
  346. package/dist/core/agent/workflows/closing.js.map +1 -1
  347. package/dist/core/agent/workflows/feature.js +128 -13
  348. package/dist/core/agent/workflows/feature.js.map +1 -1
  349. package/dist/core/agent/workflows/implement.js +96 -13
  350. package/dist/core/agent/workflows/implement.js.map +1 -1
  351. package/dist/core/agent/workflows/reference/authoring.js +106 -4
  352. package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
  353. package/dist/core/agent/workflows/reference/codes.js +8 -6
  354. package/dist/core/agent/workflows/reference/codes.js.map +1 -1
  355. package/dist/core/agent/workflows/reference/done-check.js +37 -15
  356. package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
  357. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  358. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  359. package/dist/core/agent/workflows/reference/reference.js +6 -3
  360. package/dist/core/agent/workflows/reference/reference.js.map +1 -1
  361. package/dist/core/agent/workflows/reference/spine.js +68 -27
  362. package/dist/core/agent/workflows/reference/spine.js.map +1 -1
  363. package/dist/core/asyncapi/baseline/plan.js +14 -81
  364. package/dist/core/asyncapi/baseline/plan.js.map +1 -1
  365. package/dist/core/asyncapi/digest.js +30 -25
  366. package/dist/core/asyncapi/digest.js.map +1 -1
  367. package/dist/core/asyncapi/merge/components.js +5 -4
  368. package/dist/core/asyncapi/merge/components.js.map +1 -1
  369. package/dist/core/asyncapi/merge/error.js +7 -2
  370. package/dist/core/asyncapi/merge/error.js.map +1 -1
  371. package/dist/core/asyncapi/merge/markers.js +32 -50
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -1
  373. package/dist/core/asyncapi/merge/merge.js +33 -53
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -1
  375. package/dist/core/asyncapi/merge/pin.js +12 -36
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -1
  377. package/dist/core/asyncapi/model.js.map +1 -1
  378. package/dist/core/asyncapi/read.js +36 -12
  379. package/dist/core/asyncapi/read.js.map +1 -1
  380. package/dist/core/brief/brief.js +96 -36
  381. package/dist/core/brief/brief.js.map +1 -1
  382. package/dist/core/brief/checks.js +138 -3
  383. package/dist/core/brief/checks.js.map +1 -1
  384. package/dist/core/brief/landscape.js +209 -130
  385. package/dist/core/brief/landscape.js.map +1 -1
  386. package/dist/core/brief/map/extend.js +84 -0
  387. package/dist/core/brief/map/extend.js.map +1 -0
  388. package/dist/core/brief/map/owed.js +266 -0
  389. package/dist/core/brief/map/owed.js.map +1 -0
  390. package/dist/core/brief/targets.js +109 -31
  391. package/dist/core/brief/targets.js.map +1 -1
  392. package/dist/core/brief/unchecked.js +14 -3
  393. package/dist/core/brief/unchecked.js.map +1 -1
  394. package/dist/core/c4/arch.js +90 -182
  395. package/dist/core/c4/arch.js.map +1 -1
  396. package/dist/core/c4/direction/direction.js +114 -0
  397. package/dist/core/c4/direction/direction.js.map +1 -0
  398. package/dist/core/c4/likec4.js +169 -14
  399. package/dist/core/c4/likec4.js.map +1 -1
  400. package/dist/core/c4/locate/unlocated.js +150 -0
  401. package/dist/core/c4/locate/unlocated.js.map +1 -0
  402. package/dist/core/c4/parsed/deployment.js +160 -0
  403. package/dist/core/c4/parsed/deployment.js.map +1 -0
  404. package/dist/core/c4/parsed/dynamic-views.js.map +1 -1
  405. package/dist/core/c4/parsed/values.js +54 -1
  406. package/dist/core/c4/parsed/values.js.map +1 -1
  407. package/dist/core/c4/parsed/view-ids.js +39 -1
  408. package/dist/core/c4/parsed/view-ids.js.map +1 -1
  409. package/dist/core/c4/prefetch/fleet.js +134 -0
  410. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  411. package/dist/core/c4/project/architecture.js +123 -7
  412. package/dist/core/c4/project/architecture.js.map +1 -1
  413. package/dist/core/c4/project/batch.js +140 -0
  414. package/dist/core/c4/project/batch.js.map +1 -0
  415. package/dist/core/c4/project/documents.js +43 -12
  416. package/dist/core/c4/project/documents.js.map +1 -1
  417. package/dist/core/c4/project/load.js +79 -43
  418. package/dist/core/c4/project/load.js.map +1 -1
  419. package/dist/core/c4/project/staged.js +277 -0
  420. package/dist/core/c4/project/staged.js.map +1 -0
  421. package/dist/core/c4/resolve/attested.js +0 -0
  422. package/dist/core/c4/resolve/attested.js.map +1 -0
  423. package/dist/core/c4/resolve/external.js +51 -0
  424. package/dist/core/c4/resolve/external.js.map +1 -0
  425. package/dist/core/c4/resolve/service.js +78 -17
  426. package/dist/core/c4/resolve/service.js.map +1 -1
  427. package/dist/core/c4/resolve/steps.js +290 -0
  428. package/dist/core/c4/resolve/steps.js.map +1 -0
  429. package/dist/core/c4/resolve/systems.js +154 -0
  430. package/dist/core/c4/resolve/systems.js.map +1 -0
  431. package/dist/core/c4/root-project/exclude.js +352 -0
  432. package/dist/core/c4/root-project/exclude.js.map +1 -0
  433. package/dist/core/c4/seed/template.js +65 -1
  434. package/dist/core/c4/seed/template.js.map +1 -1
  435. package/dist/core/c4/service-model/created/models.js +96 -0
  436. package/dist/core/c4/service-model/created/models.js.map +1 -0
  437. package/dist/core/c4/service-model/documents.js +47 -0
  438. package/dist/core/c4/service-model/documents.js.map +1 -0
  439. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  440. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  441. package/dist/core/c4/service-model/load.js +165 -0
  442. package/dist/core/c4/service-model/load.js.map +1 -0
  443. package/dist/core/c4/service-model/renderer.js +128 -0
  444. package/dist/core/c4/service-model/renderer.js.map +1 -0
  445. package/dist/core/c4/service-model/shape.js +106 -0
  446. package/dist/core/c4/service-model/shape.js.map +1 -0
  447. package/dist/core/c4/service-model/slice.js +188 -0
  448. package/dist/core/c4/service-model/slice.js.map +1 -0
  449. package/dist/core/c4/source-mask.js +297 -10
  450. package/dist/core/c4/source-mask.js.map +1 -1
  451. package/dist/core/c4/source-scan.js +222 -141
  452. package/dist/core/c4/source-scan.js.map +1 -1
  453. package/dist/core/c4/splice/authored-source.js +79 -13
  454. package/dist/core/c4/splice/authored-source.js.map +1 -1
  455. package/dist/core/c4/splice/contract.js +20 -0
  456. package/dist/core/c4/splice/contract.js.map +1 -1
  457. package/dist/core/c4/splice/delta-blocks.js +20 -20
  458. package/dist/core/c4/splice/delta-blocks.js.map +1 -1
  459. package/dist/core/c4/splice/identity/declared.js +87 -0
  460. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  461. package/dist/core/c4/splice/identity/edges.js +37 -0
  462. package/dist/core/c4/splice/identity/edges.js.map +1 -1
  463. package/dist/core/c4/splice/identity/existing.js +80 -0
  464. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  465. package/dist/core/c4/splice/identity/interior.js +80 -0
  466. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  467. package/dist/core/c4/splice/identity/owner.js +50 -0
  468. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  469. package/dist/core/c4/splice/landscape-merge.js +182 -114
  470. package/dist/core/c4/splice/landscape-merge.js.map +1 -1
  471. package/dist/core/c4/splice/model/merge.js +151 -0
  472. package/dist/core/c4/splice/model/merge.js.map +1 -0
  473. package/dist/core/c4/splice/placement.js +160 -56
  474. package/dist/core/c4/splice/placement.js.map +1 -1
  475. package/dist/core/c4/splice/text/spot.js +131 -0
  476. package/dist/core/c4/splice/text/spot.js.map +1 -0
  477. package/dist/core/c4/workspace.js +13 -19
  478. package/dist/core/c4/workspace.js.map +1 -1
  479. package/dist/core/capabilities/capabilities.js +6 -6
  480. package/dist/core/capabilities/capabilities.js.map +1 -1
  481. package/dist/core/capabilities/delta/doc.js +7 -10
  482. package/dist/core/capabilities/delta/doc.js.map +1 -1
  483. package/dist/core/capabilities/delta/uncovered.js +2 -2
  484. package/dist/core/capabilities/delta/uncovered.js.map +1 -1
  485. package/dist/core/capabilities/findings.js +18 -22
  486. package/dist/core/capabilities/findings.js.map +1 -1
  487. package/dist/core/capabilities/realizes/findings.js +12 -19
  488. package/dist/core/capabilities/realizes/findings.js.map +1 -1
  489. package/dist/core/capabilities/realizes/join.js +0 -20
  490. package/dist/core/capabilities/realizes/join.js.map +1 -1
  491. package/dist/core/capabilities/rollup.js +6 -0
  492. package/dist/core/capabilities/rollup.js.map +1 -1
  493. package/dist/core/capabilities/tree.js +6 -28
  494. package/dist/core/capabilities/tree.js.map +1 -1
  495. package/dist/core/capabilities/usecase-join.js +3 -13
  496. package/dist/core/capabilities/usecase-join.js.map +1 -1
  497. package/dist/core/coherence/authoring/scaffold.js +11 -3
  498. package/dist/core/coherence/authoring/scaffold.js.map +1 -1
  499. package/dist/core/coherence/authoring/sentinels.js +2 -1
  500. package/dist/core/coherence/authoring/sentinels.js.map +1 -1
  501. package/dist/core/coherence/calls/called.js +52 -0
  502. package/dist/core/coherence/calls/called.js.map +1 -0
  503. package/dist/core/coherence/coherence.js +103 -22
  504. package/dist/core/coherence/coherence.js.map +1 -1
  505. package/dist/core/coherence/consumed/operations.js +70 -0
  506. package/dist/core/coherence/consumed/operations.js.map +1 -0
  507. package/dist/core/coherence/consumed/refusal.js +38 -0
  508. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  509. package/dist/core/coherence/covers/health.js +85 -0
  510. package/dist/core/coherence/covers/health.js.map +1 -0
  511. package/dist/core/coherence/declared.js +60 -34
  512. package/dist/core/coherence/declared.js.map +1 -1
  513. package/dist/core/coherence/events/declared.js +44 -59
  514. package/dist/core/coherence/events/declared.js.map +1 -1
  515. package/dist/core/coherence/events/events.js +147 -16
  516. package/dist/core/coherence/events/events.js.map +1 -1
  517. package/dist/core/coherence/events/grades.js +31 -8
  518. package/dist/core/coherence/events/grades.js.map +1 -1
  519. package/dist/core/coherence/events/lookups.js +28 -87
  520. package/dist/core/coherence/events/lookups.js.map +1 -1
  521. package/dist/core/coherence/events/produced.js +100 -0
  522. package/dist/core/coherence/events/produced.js.map +1 -0
  523. package/dist/core/coherence/lookups.js +18 -78
  524. package/dist/core/coherence/lookups.js.map +1 -1
  525. package/dist/core/coherence/retired/archived.js +285 -0
  526. package/dist/core/coherence/retired/archived.js.map +1 -0
  527. package/dist/core/coherence/retired/event-pair.js +62 -0
  528. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  529. package/dist/core/coherence/retired/merged.js +79 -0
  530. package/dist/core/coherence/retired/merged.js.map +1 -0
  531. package/dist/core/coherence/retired/retirement.js +49 -0
  532. package/dist/core/coherence/retired/retirement.js.map +1 -0
  533. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  534. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  535. package/dist/core/coherence/retired/revival/revived.js +297 -0
  536. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  537. package/dist/core/consumers/after.js +113 -0
  538. package/dist/core/consumers/after.js.map +1 -0
  539. package/dist/core/consumers/consumers.js +296 -0
  540. package/dist/core/consumers/consumers.js.map +1 -0
  541. package/dist/core/consumers/current.js +211 -0
  542. package/dist/core/consumers/current.js.map +1 -0
  543. package/dist/core/consumers/scan.js +46 -0
  544. package/dist/core/consumers/scan.js.map +1 -0
  545. package/dist/core/consumers/state.js +27 -0
  546. package/dist/core/consumers/state.js.map +1 -0
  547. package/dist/core/delta/delta.js +51 -6
  548. package/dist/core/delta/delta.js.map +1 -1
  549. package/dist/core/dependencies/fanin.js +2 -2
  550. package/dist/core/dependencies/fanin.js.map +1 -1
  551. package/dist/core/deployment/delta.js +191 -0
  552. package/dist/core/deployment/delta.js.map +1 -0
  553. package/dist/core/deployment/objects.js +145 -0
  554. package/dist/core/deployment/objects.js.map +1 -0
  555. package/dist/core/diff/base-git.js +94 -12
  556. package/dist/core/diff/base-git.js.map +1 -1
  557. package/dist/core/diff/base-state.js +49 -21
  558. package/dist/core/diff/base-state.js.map +1 -1
  559. package/dist/core/diff/joins.js +136 -0
  560. package/dist/core/diff/joins.js.map +1 -0
  561. package/dist/core/diff/scope/changed-paths.js +22 -6
  562. package/dist/core/diff/scope/changed-paths.js.map +1 -1
  563. package/dist/core/diff/scope/edges.js +82 -0
  564. package/dist/core/diff/scope/edges.js.map +1 -0
  565. package/dist/core/diff/semantic.js +100 -31
  566. package/dist/core/diff/semantic.js.map +1 -1
  567. package/dist/core/docs.js +31 -22
  568. package/dist/core/docs.js.map +1 -1
  569. package/dist/core/doctor/agents.js +34 -18
  570. package/dist/core/doctor/agents.js.map +1 -1
  571. package/dist/core/doctor/config.js +7 -3
  572. package/dist/core/doctor/config.js.map +1 -1
  573. package/dist/core/doctor/doctor.js +91 -11
  574. package/dist/core/doctor/doctor.js.map +1 -1
  575. package/dist/core/doctor/report.js.map +1 -1
  576. package/dist/core/doctor/reports/scan.js +242 -0
  577. package/dist/core/doctor/reports/scan.js.map +1 -0
  578. package/dist/core/document/apply.js +158 -11
  579. package/dist/core/document/apply.js.map +1 -1
  580. package/dist/core/document/frontmatter.js +55 -0
  581. package/dist/core/document/frontmatter.js.map +1 -1
  582. package/dist/core/document/parse.js +29 -6
  583. package/dist/core/document/parse.js.map +1 -1
  584. package/dist/core/document/scenarios.js +17 -0
  585. package/dist/core/document/scenarios.js.map +1 -1
  586. package/dist/core/document/spec.js +4 -11
  587. package/dist/core/document/spec.js.map +1 -1
  588. package/dist/core/envelope/config.js +10 -0
  589. package/dist/core/envelope/config.js.map +1 -1
  590. package/dist/core/envelope/json.js +34 -0
  591. package/dist/core/envelope/json.js.map +1 -1
  592. package/dist/core/explain/families.js +26 -21
  593. package/dist/core/explain/families.js.map +1 -1
  594. package/dist/core/explain/lookup.js +14 -1
  595. package/dist/core/explain/lookup.js.map +1 -1
  596. package/dist/core/explain/refusals.js +5 -5
  597. package/dist/core/explain/refusals.js.map +1 -1
  598. package/dist/core/explain/terms/documents.js +227 -0
  599. package/dist/core/explain/terms/documents.js.map +1 -0
  600. package/dist/core/explain/terms/done-check.js +144 -0
  601. package/dist/core/explain/terms/done-check.js.map +1 -0
  602. package/dist/core/explain/terms/entry.js +14 -0
  603. package/dist/core/explain/terms/entry.js.map +1 -0
  604. package/dist/core/explain/terms/stages.js +71 -0
  605. package/dist/core/explain/terms/stages.js.map +1 -0
  606. package/dist/core/explain/terms/tasks.js +97 -0
  607. package/dist/core/explain/terms/tasks.js.map +1 -0
  608. package/dist/core/explain/terms.js +68 -109
  609. package/dist/core/explain/terms.js.map +1 -1
  610. package/dist/core/explore/explore.js +40 -10
  611. package/dist/core/explore/explore.js.map +1 -1
  612. package/dist/core/fleet-context.js +81 -95
  613. package/dist/core/fleet-context.js.map +1 -1
  614. package/dist/core/gate/checks.js +11 -4
  615. package/dist/core/gate/checks.js.map +1 -1
  616. package/dist/core/gate/partners.js +69 -28
  617. package/dist/core/gate/partners.js.map +1 -1
  618. package/dist/core/gate/report.js.map +1 -1
  619. package/dist/core/gate/verification.js +75 -12
  620. package/dist/core/gate/verification.js.map +1 -1
  621. package/dist/core/gherkin/stale.js +13 -37
  622. package/dist/core/gherkin/stale.js.map +1 -1
  623. package/dist/core/glossary/delta.js +10 -7
  624. package/dist/core/glossary/delta.js.map +1 -1
  625. package/dist/core/glossary/tree.js +6 -19
  626. package/dist/core/glossary/tree.js.map +1 -1
  627. package/dist/core/kernel/concurrency.js +19 -0
  628. package/dist/core/kernel/concurrency.js.map +1 -1
  629. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  630. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  631. package/dist/core/kernel/path-safety.js +38 -0
  632. package/dist/core/kernel/path-safety.js.map +1 -1
  633. package/dist/core/kernel/records.js +11 -0
  634. package/dist/core/kernel/records.js.map +1 -1
  635. package/dist/core/links/backlinks.js +1 -3
  636. package/dist/core/links/backlinks.js.map +1 -1
  637. package/dist/core/links/corpus.js +51 -37
  638. package/dist/core/links/corpus.js.map +1 -1
  639. package/dist/core/links/findings.js.map +1 -1
  640. package/dist/core/links/parse.js +38 -9
  641. package/dist/core/links/parse.js.map +1 -1
  642. package/dist/core/mcp/argv.js +101 -0
  643. package/dist/core/mcp/argv.js.map +1 -1
  644. package/dist/core/mcp/author-tools.js +2 -1
  645. package/dist/core/mcp/author-tools.js.map +1 -1
  646. package/dist/core/mcp/protocol.js +2 -2
  647. package/dist/core/mcp/protocol.js.map +1 -1
  648. package/dist/core/mcp/tools.js +43 -33
  649. package/dist/core/mcp/tools.js.map +1 -1
  650. package/dist/core/openapi/baseline/gate.js +53 -12
  651. package/dist/core/openapi/baseline/gate.js.map +1 -1
  652. package/dist/core/openapi/baseline/plan.js +40 -10
  653. package/dist/core/openapi/baseline/plan.js.map +1 -1
  654. package/dist/core/openapi/baseline/record.js +0 -1
  655. package/dist/core/openapi/baseline/record.js.map +1 -1
  656. package/dist/core/openapi/contract-text.js +33 -0
  657. package/dist/core/openapi/contract-text.js.map +1 -0
  658. package/dist/core/openapi/contract-tree.js +301 -0
  659. package/dist/core/openapi/contract-tree.js.map +1 -0
  660. package/dist/core/openapi/depth.js +38 -24
  661. package/dist/core/openapi/depth.js.map +1 -1
  662. package/dist/core/openapi/digest.js +52 -2
  663. package/dist/core/openapi/digest.js.map +1 -1
  664. package/dist/core/openapi/doc.js +12 -4
  665. package/dist/core/openapi/doc.js.map +1 -1
  666. package/dist/core/openapi/merge/components.js +25 -60
  667. package/dist/core/openapi/merge/components.js.map +1 -1
  668. package/dist/core/openapi/merge/error.js +3 -13
  669. package/dist/core/openapi/merge/error.js.map +1 -1
  670. package/dist/core/openapi/merge/markers.js +26 -30
  671. package/dist/core/openapi/merge/markers.js.map +1 -1
  672. package/dist/core/openapi/merge/merge.js +28 -52
  673. package/dist/core/openapi/merge/merge.js.map +1 -1
  674. package/dist/core/openapi/merge/pin.js +17 -35
  675. package/dist/core/openapi/merge/pin.js.map +1 -1
  676. package/dist/core/openspec/decide/verdict.js.map +1 -1
  677. package/dist/core/openspec/inventory.js +4 -5
  678. package/dist/core/openspec/inventory.js.map +1 -1
  679. package/dist/core/openspec/model/mapping.js +30 -28
  680. package/dist/core/openspec/model/mapping.js.map +1 -1
  681. package/dist/core/openspec/model/model.js +12 -7
  682. package/dist/core/openspec/model/model.js.map +1 -1
  683. package/dist/core/openspec/scan/changes.js +10 -4
  684. package/dist/core/openspec/scan/changes.js.map +1 -1
  685. package/dist/core/openspec/scan/config.js +7 -16
  686. package/dist/core/openspec/scan/config.js.map +1 -1
  687. package/dist/core/openspec/scan/shape.js +63 -19
  688. package/dist/core/openspec/scan/shape.js.map +1 -1
  689. package/dist/core/openspec/scan/walk.js +21 -38
  690. package/dist/core/openspec/scan/walk.js.map +1 -1
  691. package/dist/core/pack/living.js +43 -4
  692. package/dist/core/pack/living.js.map +1 -1
  693. package/dist/core/pack/pack.js +50 -6
  694. package/dist/core/pack/pack.js.map +1 -1
  695. package/dist/core/projection/arch-slice.js +2 -2
  696. package/dist/core/projection/arch-slice.js.map +1 -1
  697. package/dist/core/projection/introduced.js +14 -0
  698. package/dist/core/projection/introduced.js.map +1 -0
  699. package/dist/core/provenance/findings.js +48 -12
  700. package/dist/core/provenance/findings.js.map +1 -1
  701. package/dist/core/provenance/git.js +33 -57
  702. package/dist/core/provenance/git.js.map +1 -1
  703. package/dist/core/provenance/gitq/moves.js +71 -114
  704. package/dist/core/provenance/gitq/moves.js.map +1 -1
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
  707. package/dist/core/provenance/sources.js +23 -6
  708. package/dist/core/provenance/sources.js.map +1 -1
  709. package/dist/core/provenance/stamp.js +5 -17
  710. package/dist/core/provenance/stamp.js.map +1 -1
  711. package/dist/core/repo/authored/paths.js +18 -0
  712. package/dist/core/repo/authored/paths.js.map +1 -1
  713. package/dist/core/repo/entries.js.map +1 -1
  714. package/dist/core/repo/paths.js +92 -6
  715. package/dist/core/repo/paths.js.map +1 -1
  716. package/dist/core/repo/repo.js +74 -14
  717. package/dist/core/repo/repo.js.map +1 -1
  718. package/dist/core/repo/tree/find.js +12 -3
  719. package/dist/core/repo/tree/find.js.map +1 -1
  720. package/dist/core/repo/tree/fs.js +27 -1
  721. package/dist/core/repo/tree/fs.js.map +1 -1
  722. package/dist/core/repo/tree/render/body.js +258 -0
  723. package/dist/core/repo/tree/render/body.js.map +1 -0
  724. package/dist/core/repo/tree/render/projects.js +182 -0
  725. package/dist/core/repo/tree/render/projects.js.map +1 -0
  726. package/dist/core/repo/tree/render/service/header.js +125 -0
  727. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  728. package/dist/core/repo/tree/render/service/peers.js +28 -0
  729. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  730. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  731. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  732. package/dist/core/repo/tree/render/service/views.js +78 -0
  733. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  734. package/dist/core/repo/tree/render/stale.js +42 -0
  735. package/dist/core/repo/tree/render/stale.js.map +1 -0
  736. package/dist/core/repo/tree/render/text.js +84 -0
  737. package/dist/core/repo/tree/render/text.js.map +1 -0
  738. package/dist/core/repo/tree/render/views.js +293 -0
  739. package/dist/core/repo/tree/render/views.js.map +1 -0
  740. package/dist/core/repo/tree/walk.js +53 -32
  741. package/dist/core/repo/tree/walk.js.map +1 -1
  742. package/dist/core/results.js +47 -12
  743. package/dist/core/results.js.map +1 -1
  744. package/dist/core/scaffold/landscape.js +121 -13
  745. package/dist/core/scaffold/landscape.js.map +1 -1
  746. package/dist/core/scaffold/legacy.js +271 -0
  747. package/dist/core/scaffold/legacy.js.map +1 -0
  748. package/dist/core/staging/commit.js +26 -15
  749. package/dist/core/staging/commit.js.map +1 -1
  750. package/dist/core/staging/lock.js +74 -12
  751. package/dist/core/staging/lock.js.map +1 -1
  752. package/dist/core/staging/recovery/intent.js +2 -5
  753. package/dist/core/staging/recovery/intent.js.map +1 -1
  754. package/dist/core/staging/recovery/recover.js +84 -6
  755. package/dist/core/staging/recovery/recover.js.map +1 -1
  756. package/dist/core/staging/snapshot/manifest.js +188 -0
  757. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  758. package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +39 -45
  759. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  760. package/dist/core/staging/txn/forward.js +24 -14
  761. package/dist/core/staging/txn/forward.js.map +1 -1
  762. package/dist/core/staging/writes.js.map +1 -1
  763. package/dist/core/status/actions/execution.js +11 -0
  764. package/dist/core/status/actions/execution.js.map +1 -1
  765. package/dist/core/status/contracts.js +39 -15
  766. package/dist/core/status/contracts.js.map +1 -1
  767. package/dist/core/status/feature/artifacts.js +33 -8
  768. package/dist/core/status/feature/artifacts.js.map +1 -1
  769. package/dist/core/status/feature/feature.js +24 -17
  770. package/dist/core/status/feature/feature.js.map +1 -1
  771. package/dist/core/status/feature/next.js +20 -7
  772. package/dist/core/status/feature/next.js.map +1 -1
  773. package/dist/core/status/feature/words.js +96 -0
  774. package/dist/core/status/feature/words.js.map +1 -0
  775. package/dist/core/status/fleet/fleet.js +43 -14
  776. package/dist/core/status/fleet/fleet.js.map +1 -1
  777. package/dist/core/status/fleet/next.js +153 -58
  778. package/dist/core/status/fleet/next.js.map +1 -1
  779. package/dist/core/status/report.js.map +1 -1
  780. package/dist/core/status/scan.js.map +1 -1
  781. package/dist/core/status/verification.js +30 -15
  782. package/dist/core/status/verification.js.map +1 -1
  783. package/dist/core/tasks/packet.js +199 -0
  784. package/dist/core/tasks/packet.js.map +1 -0
  785. package/dist/core/tasks/record.js +43 -0
  786. package/dist/core/tasks/record.js.map +1 -0
  787. package/dist/core/tasks/sources.js +181 -0
  788. package/dist/core/tasks/sources.js.map +1 -0
  789. package/dist/core/tasks/stamps.js +76 -0
  790. package/dist/core/tasks/stamps.js.map +1 -0
  791. package/dist/core/tasks/unit.js +0 -0
  792. package/dist/core/tasks/unit.js.map +1 -0
  793. package/dist/core/usecases/capability.js +11 -14
  794. package/dist/core/usecases/capability.js.map +1 -1
  795. package/dist/core/usecases/delta/claims.js +31 -7
  796. package/dist/core/usecases/delta/claims.js.map +1 -1
  797. package/dist/core/usecases/delta/flows.js +5 -7
  798. package/dist/core/usecases/delta/flows.js.map +1 -1
  799. package/dist/core/usecases/delta/modified.js +315 -0
  800. package/dist/core/usecases/delta/modified.js.map +1 -0
  801. package/dist/core/usecases/delta/overlay.js +32 -191
  802. package/dist/core/usecases/delta/overlay.js.map +1 -1
  803. package/dist/core/usecases/fleet.js +195 -36
  804. package/dist/core/usecases/fleet.js.map +1 -1
  805. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/capability-tag.js +8 -9
  806. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  807. package/dist/core/usecases/grade/feature.js +88 -0
  808. package/dist/core/usecases/grade/feature.js.map +1 -0
  809. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/requirement-tag.js +3 -4
  810. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  811. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/steps.js +102 -33
  812. package/dist/core/usecases/grade/steps.js.map +1 -0
  813. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/usecases.js +23 -10
  814. package/dist/core/usecases/grade/usecases.js.map +1 -0
  815. package/dist/core/usecases/operations.js +26 -14
  816. package/dist/core/usecases/operations.js.map +1 -1
  817. package/dist/core/usecases/place.js.map +1 -1
  818. package/dist/core/usecases/service/exclude.js +119 -0
  819. package/dist/core/usecases/service/exclude.js.map +1 -0
  820. package/dist/core/usecases/service/flows.js +164 -0
  821. package/dist/core/usecases/service/flows.js.map +1 -0
  822. package/dist/core/usecases/suites/participants.js +83 -0
  823. package/dist/core/usecases/suites/participants.js.map +1 -0
  824. package/dist/core/usecases/suites/suites.js +45 -0
  825. package/dist/core/usecases/suites/suites.js.map +1 -0
  826. package/dist/core/verify/answers.js +12 -5
  827. package/dist/core/verify/answers.js.map +1 -1
  828. package/dist/core/verify/build.js +102 -82
  829. package/dist/core/verify/build.js.map +1 -1
  830. package/dist/core/verify/checklist.js +70 -12
  831. package/dist/core/verify/checklist.js.map +1 -1
  832. package/dist/core/verify/location.js +67 -0
  833. package/dist/core/verify/location.js.map +1 -0
  834. package/dist/core/verify/pins/lint.js +3 -2
  835. package/dist/core/verify/pins/lint.js.map +1 -1
  836. package/dist/core/verify/pins/pin.js +1 -1
  837. package/dist/core/verify/pins/pin.js.map +1 -1
  838. package/dist/core/verify/read/file.js +224 -0
  839. package/dist/core/verify/read/file.js.map +1 -0
  840. package/dist/core/verify/{file.js → read/shape.js} +16 -104
  841. package/dist/core/verify/read/shape.js.map +1 -0
  842. package/dist/core/verify/read/union.js +105 -0
  843. package/dist/core/verify/read/union.js.map +1 -0
  844. package/dist/core/verify/record.js +35 -12
  845. package/dist/core/verify/record.js.map +1 -1
  846. package/dist/core/verify/store/commit.js +40 -30
  847. package/dist/core/verify/store/commit.js.map +1 -1
  848. package/dist/core/verify/store/render.js +8 -4
  849. package/dist/core/verify/store/render.js.map +1 -1
  850. package/dist/core/vocabulary/issue.js +4 -0
  851. package/dist/core/vocabulary/issue.js.map +1 -1
  852. package/dist/core/vocabulary/maturity.js +75 -4
  853. package/dist/core/vocabulary/maturity.js.map +1 -1
  854. package/dist/core/vocabulary/report.js +16 -1
  855. package/dist/core/vocabulary/report.js.map +1 -1
  856. package/examples/README.md +54 -11
  857. package/examples/docs/architecture/landscape.likec4 +62 -6
  858. package/examples/docs/architecture/services.likec4 +70 -0
  859. package/examples/docs/architecture/subsystems.likec4 +7 -0
  860. package/examples/docs/architecture/usecases/order-notification.likec4 +16 -7
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
  863. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +4 -1
  864. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
  865. package/examples/docs/likec4.config.json +0 -1
  866. package/examples/docs/services/checkout-web/model.likec4 +39 -56
  867. package/examples/docs/services/order-service/arch.spec.md +13 -6
  868. package/examples/docs/services/order-service/asyncapi.yaml +3 -2
  869. package/examples/docs/services/order-service/model.likec4 +58 -70
  870. package/examples/docs/services/payment-service/arch.spec.md +7 -4
  871. package/examples/docs/services/payment-service/model.likec4 +38 -37
  872. package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
  873. package/examples/docs/services/platform/identity-service/model.likec4 +35 -37
  874. package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
  875. package/examples/docs/services/platform/notification-service/health.yaml +8 -3
  876. package/examples/docs/services/platform/notification-service/model.likec4 +43 -64
  877. package/package.json +1 -1
  878. package/dist/commands/validate/checks/vocabulary.js +0 -31
  879. package/dist/commands/validate/checks/vocabulary.js.map +0 -1
  880. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +0 -1
  881. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +0 -1
  882. package/dist/commands/validate/fleet/usecases/steps.js.map +0 -1
  883. package/dist/commands/validate/fleet/usecases/usecases.js.map +0 -1
  884. package/dist/core/agent/agents-md/artifacts.js +0 -220
  885. package/dist/core/agent/agents-md/artifacts.js.map +0 -1
  886. package/dist/core/agent/agents-md/cycle.js +0 -165
  887. package/dist/core/agent/agents-md/cycle.js.map +0 -1
  888. package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
  889. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
  890. package/dist/core/agent/agents-md/spine.js +0 -40
  891. package/dist/core/agent/agents-md/spine.js.map +0 -1
  892. package/dist/core/coherence/events/merged.js +0 -40
  893. package/dist/core/coherence/events/merged.js.map +0 -1
  894. package/dist/core/diff/current-state.js +0 -96
  895. package/dist/core/diff/current-state.js.map +0 -1
  896. package/dist/core/diff/victims.js +0 -247
  897. package/dist/core/diff/victims.js.map +0 -1
  898. package/dist/core/repo/tree/views.js +0 -172
  899. package/dist/core/repo/tree/views.js.map +0 -1
  900. package/dist/core/staging/snapshot.js.map +0 -1
  901. package/dist/core/verify/file.js.map +0 -1
@@ -1,21 +1,23 @@
1
1
  /**
2
2
  * What a feature's own delta DECLARES, per service, indexed once.
3
3
  *
4
- * Seven indexes over the same four files (the delta spec.md, arch.spec.md,
4
+ * Nine indexes over the same four files (the delta spec.md, arch.spec.md,
5
5
  * openapi.yaml, and the living contract they are graded against), built in one
6
6
  * walk because every check downstream joins on the service id and would
7
7
  * otherwise re-read the delta per question. The distinctions here are the ones
8
8
  * the checks cannot make for themselves: an operation a REMOVED requirement
9
9
  * governs is being retired, so it neither claims the contract nor governs
10
10
  * anything after the merge; a removal marker that names an id also defined
11
- * elsewhere in the delta is a RELOCATION, not a retirement; and a marker with
11
+ * elsewhere in the delta is a RELOCATION, not a retirement; a living operation
12
+ * another one replaces at its address, with no marker naming it, leaves the
13
+ * contract all the same; and a marker with
12
14
  * no `operationId` at all is a shape only this walk can see. The capability
13
15
  * gate rides the same loop: both delta spec documents are graded against the
14
16
  * fleet vocabulary here, because coherence.ts and this package's file count
15
17
  * are both at their limits and the walk already holds the parsed documents.
16
18
  */
17
19
  import { existsSync } from "node:fs";
18
- import { NotUtf8DocumentError } from "../kernel/document-bytes.js";
20
+ import { readOr } from "../openapi/contract-text.js";
19
21
  import { readFile } from "node:fs/promises";
20
22
  import {} from "../kernel/ids/service.js";
21
23
  import { featureSpecPaths } from "../repo/paths.js";
@@ -29,6 +31,8 @@ import { realizesUnknownIssues } from "../capabilities/realizes/findings.js";
29
31
  import { capabilityUnknownIssues } from "../capabilities/findings.js";
30
32
  import { openapiBaselineIssues } from "../openapi/baseline/gate.js";
31
33
  import { readOpenapi } from "../openapi/doc.js";
34
+ import { operationRetirements } from "./retired/retirement.js";
35
+ import { operationArrivals } from "./retired/revival/arrivals.js";
32
36
  export async function declaredByService(scope, svcNames, issues, context) {
33
37
  const { docsDir, featureDir, featureId } = scope;
34
38
  const reqOps = new Map();
@@ -41,6 +45,10 @@ export async function declaredByService(scope, svcNames, issues, context) {
41
45
  const anonymousMarkers = new Map();
42
46
  const featureApiOps = new Set();
43
47
  const unreadableApis = new Set();
48
+ const revivalCandidates = new Map();
49
+ const displacedOps = new Map();
50
+ /** Per service read here: the operationIds its living contract holds, or null when it does not read. */
51
+ const livingIds = new Map();
44
52
  // The capability gate's vocabulary, once per call. Absent or invalid stays
45
53
  // SILENT here — capability.invalid is validate --all's one finding about a
46
54
  // broken file, and an absent file means the fleet never opted in — so with
@@ -108,8 +116,12 @@ export async function declaredByService(scope, svcNames, issues, context) {
108
116
  issues.push(...capabilityUnknownIssues(archReqs, archTarget, capabilityVocab));
109
117
  issues.push(...realizesUnknownIssues(archReqs, archTarget, await capabilityReqs()));
110
118
  }
111
- // Only operations genuinely NEW to this service count as feature-added: authors
112
- // restate the full living API in the delta file (it is a complete document, not a patch).
119
+ // Only operations the living contract does not hold count as feature-added:
120
+ // a delta may restate living operations it does not change (a quote), and
121
+ // a quote adds nothing. "Not in living" is not quite "new", though — an
122
+ // operation an archived feature RETIRED is absent too, and adding it back
123
+ // is `openapi.op-revived`'s question (./retired/revival/revived.ts), asked of the
124
+ // `revivalCandidates` collected below.
113
125
  const featDoc = await readOpenapi(paths.openapi, context);
114
126
  // A feature contract that EXISTS but does not read is a broken document,
115
127
  // not an empty one — the living-side `openapi.invalid` discipline
@@ -131,15 +143,10 @@ export async function declaredByService(scope, svcNames, issues, context) {
131
143
  }
132
144
  const featOps = featDoc.ops;
133
145
  const removals = featOps.filter((op) => op.remove);
134
- // A relocation — same operationId, removal marker on the old slot, upsert
135
- // on the new one — retires nothing. Every rule that asks "is this operation
136
- // going away" must therefore ask the NET set (markers this feature does not
137
- // redefine), while "did the author write a marker at all" asks the raw one.
138
- // Conflating them made moving an endpoint fail three checks at once for a
139
- // change that removes nothing.
140
- const redefined = new Set(featOps.filter((op) => !op.remove).map((op) => op.id));
141
- const markerIds = new Set(removals.map((op) => op.id));
142
- const netRemoved = new Set([...markerIds].filter((id) => !redefined.has(id)));
146
+ // The raw marker set and the NET one (markers minus relocations) —
147
+ // ./retired/retirement.ts owns the rule and says why the two differ; the
148
+ // retired index reads every archived feature through the same function.
149
+ const { markerIds, net: netRemoved } = operationRetirements(featOps);
143
150
  removingOps.set(svc, netRemoved);
144
151
  allMarkerIds.set(svc, markerIds);
145
152
  anonymousMarkers.set(svc, featDoc.anonymousRemovals.length > 0);
@@ -155,8 +162,15 @@ export async function declaredByService(scope, svcNames, issues, context) {
155
162
  message: `${svc}: ${marker.method} ${marker.path} carries x-loam-remove: true but declares no operationId — loam cannot tell which operation it retires; name the operation the living contract has at that slot`,
156
163
  });
157
164
  }
158
- const livingDoc = await readOpenapi((await locateServicePaths(docsDir, svc, context)).openapi, context);
165
+ const livingOpenapiPath = (await locateServicePaths(docsDir, svc, context)).openapi;
166
+ const livingDoc = await readOpenapi(livingOpenapiPath, context);
159
167
  const livingOps = livingDoc.ops;
168
+ livingIds.set(svc, livingDoc.unreadable ? null : new Set(livingOps.filter((op) => !op.remove).map((op) => op.id)));
169
+ const sides = { featPath: paths.openapi, featDoc, livingPath: livingOpenapiPath, livingDoc, service: svc };
170
+ const moved = await operationArrivals(sides, context);
171
+ revivalCandidates.set(svc, moved.operations);
172
+ if (moved.displaced.length > 0)
173
+ displacedOps.set(svc, moved.displaced);
160
174
  for (const id of livingDoc.duplicateIds) {
161
175
  const slots = livingOps.filter((op) => op.id === id).map((op) => `${op.method} ${op.path}`);
162
176
  issues.push({
@@ -172,27 +186,14 @@ export async function declaredByService(scope, svcNames, issues, context) {
172
186
  // read when there is one, mirroring the readRequirements pattern above;
173
187
  // the gate itself never touches the filesystem.
174
188
  if (existsSync(paths.openapi)) {
175
- const livingOpenapiPath = (await locateServicePaths(docsDir, svc, context)).openapi;
176
- // `context.readText` DECODES and THROWS on non-UTF-8 bytes, where the
177
- // no-context `readFile` substitutes U+FFFD and lets `readOpenapi`
178
- // flag the document unreadable. Uncaught, one service's UTF-16 living
179
- // contract took down the whole feature target under validate's
180
- // context while archive's no-context path sailed past — the exact
189
+ // `readOr` (../openapi/contract-text.ts, which says why): `context.readText`
190
+ // throws on non-UTF-8 bytes where the no-context `readFile` lets
191
+ // `readOpenapi` flag the document unreadable — the exact
181
192
  // context/no-context divergence doc.ts documents as paid for once.
182
193
  // Either text failing to decode gets the same answer the gate gives
183
194
  // an unreadable parse: that side's surface checks are skipped.
184
- const readOr = async (p) => {
185
- try {
186
- return context === undefined ? await readFile(p, "utf8") : await context.readText(p);
187
- }
188
- catch (err) {
189
- if (err instanceof NotUtf8DocumentError)
190
- return undefined;
191
- throw err;
192
- }
193
- };
194
- const featureText = await readOr(paths.openapi);
195
- const livingText = !existsSync(livingOpenapiPath) ? undefined : await readOr(livingOpenapiPath);
195
+ const featureText = await readOr(paths.openapi, context);
196
+ const livingText = !existsSync(livingOpenapiPath) ? undefined : await readOr(livingOpenapiPath, context);
196
197
  if (featureText !== undefined) {
197
198
  issues.push(...openapiBaselineIssues({ featDoc, livingDoc, featureText, livingText, service: svc, featureId }));
198
199
  }
@@ -246,9 +247,31 @@ export async function declaredByService(scope, svcNames, issues, context) {
246
247
  if (unreadableApis.has(svc))
247
248
  continue;
248
249
  const marked = allMarkerIds.get(svc) ?? new Set();
250
+ const replaced = new Set((displacedOps.get(svc) ?? []).map((d) => d.id));
251
+ const living = livingIds.get(svc);
249
252
  for (const op of required) {
250
253
  if (marked.has(op))
251
254
  continue;
255
+ // A marker is owed only while there is a living operation for it to
256
+ // retire — the event axis's rule (events/declared.ts) on the contract
257
+ // axis. An operation this delta already REPLACES at its address leaves
258
+ // the contract without one, and the marker could not even be written:
259
+ // the slot holds the replacement. So the route the overwrite's
260
+ // `openapi.remove-op-consumed` names — REMOVE the requirement governing
261
+ // the old id — ended in this error, followable only by deleting the
262
+ // requirement's Operations: line, which nothing said (review
263
+ // 2026-10-12, finding 4). And an id the service's living contract does
264
+ // not define is not this service's to mark at all: a REMOVED consumer
265
+ // requirement naming ANOTHER service's operation was told to retire it
266
+ // from its own contract. Both exemptions are facts about a contract
267
+ // loam READ: a living openapi.yaml that does not parse proves neither,
268
+ // so the marker stays owed — the closed direction, and the answer this
269
+ // check gave before either exemption existed. Skipping it there let a
270
+ // REMOVED requirement with no marker pass at exit 0 (the contract
271
+ // review, finding 3); `openapi.invalid` is still validate's finding
272
+ // about the file itself.
273
+ if (replaced.has(op) || (living !== undefined && living !== null && !living.has(op)))
274
+ continue;
252
275
  // Distinguish "no marker at all" from "a marker is there but loam cannot
253
276
  // read which operation it names" — the first asks the author to write the
254
277
  // marker, the second to write the operationId, and telling somebody who
@@ -264,6 +287,9 @@ export async function declaredByService(scope, svcNames, issues, context) {
264
287
  });
265
288
  }
266
289
  }
267
- return { reqOps, removedReqOps, removingOps, allMarkerIds, anonymousMarkers, featureApiOps, unreadableApis };
290
+ return {
291
+ reqOps, removedReqOps, removingOps, allMarkerIds, anonymousMarkers, featureApiOps, unreadableApis, revivalCandidates,
292
+ displacedOps,
293
+ };
268
294
  }
269
295
  //# sourceMappingURL=declared.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"declared.js","sourceRoot":"","sources":["../../../src/core/coherence/declared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What a feature's own delta DECLARES, per service, indexed once.\n *\n * Seven indexes over the same four files (the delta spec.md, arch.spec.md,\n * openapi.yaml, and the living contract they are graded against), built in one\n * walk because every check downstream joins on the service id and would\n * otherwise re-read the delta per question. The distinctions here are the ones\n * the checks cannot make for themselves: an operation a REMOVED requirement\n * governs is being retired, so it neither claims the contract nor governs\n * anything after the merge; a removal marker that names an id also defined\n * elsewhere in the delta is a RELOCATION, not a retirement; and a marker with\n * no `operationId` at all is a shape only this walk can see. The capability\n * gate rides the same loop: both delta spec documents are graded against the\n * fleet vocabulary here, because coherence.ts and this package's file count\n * are both at their limits and the walk already holds the parsed documents.\n */\nimport { existsSync } from \"node:fs\";\nimport { NotUtf8DocumentError } from \"../kernel/document-bytes.js\";\nimport { readFile } from \"node:fs/promises\";\nimport { type PathableService } from \"../kernel/ids/service.js\";\nimport type { Issue } from \"../vocabulary/issue.js\";\nimport { featureSpecPaths } from \"../repo/paths.js\";\nimport { locateServicePaths } from \"../repo/service-target.js\";\nimport { parseRequirements } from \"../document/parse.js\";\nimport { readCapabilityVocabulary } from \"../capabilities/capabilities.js\";\nimport { capabilityRequirementIndex } from \"../capabilities/findings.js\";\nimport { withFeatureCapabilities, withFeatureRequirements } from \"../capabilities/delta/overlay.js\";\nimport { featureCapabilityDeltas } from \"../capabilities/delta/tree.js\";\nimport { realizesUnknownIssues } from \"../capabilities/realizes/findings.js\";\nimport type { CapabilityRequirementIndex } from \"../capabilities/realizes/join.js\";\nimport { capabilityUnknownIssues } from \"../capabilities/findings.js\";\nimport type { Requirement } from \"../document/spec.js\";\nimport { openapiBaselineIssues } from \"../openapi/baseline/gate.js\";\nimport { readOpenapi } from \"../openapi/doc.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport type { DocsDir, FeatureDir } from \"../kernel/ids/dirs.js\";\n\n/** Everything one feature's delta says about its own services. */\nexport interface Declared {\n /** Per service: the operations its non-REMOVED requirements govern. */\n reqOps: Map<PathableService, string[]>;\n /** Per service: the operations its REMOVED requirements governed. */\n removedReqOps: Map<string, Set<string>>;\n /** Per service: operations this feature genuinely retires (markers minus relocations). */\n removingOps: Map<string, Set<string>>;\n /** Per service: every id a removal marker names, relocations included. */\n allMarkerIds: Map<string, Set<string>>;\n /** Per service: does the feature contract carry a marker with no operationId? */\n anonymousMarkers: Map<string, boolean>;\n /** The operationIds genuinely NEW to their service across the whole feature. */\n featureApiOps: Set<string>;\n /**\n * Services whose FEATURE openapi.yaml exists but does not parse. Every check\n * that joins on the feature contract must suspend itself for these — an\n * unreadable document yields the same empty op set as an absent one, and\n * grading against that emptiness produced false errors pointing everywhere\n * but at the broken file.\n */\n unreadableApis: Set<string>;\n}\n\n/** The three facts this walk needs about the feature it is reading. */\nexport interface DeltaScope {\n docsDir: DocsDir;\n featureDir: FeatureDir;\n featureId: string;\n}\n\nexport async function declaredByService(\n scope: DeltaScope,\n svcNames: PathableService[],\n issues: Issue[],\n context?: FleetContext,\n): Promise<Declared> {\n const { docsDir, featureDir, featureId } = scope;\n const reqOps = new Map<PathableService, string[]>();\n const removedReqOps = new Map<string, Set<string>>();\n /** Per service: operations this feature genuinely retires (markers minus relocations). */\n const removingOps = new Map<string, Set<string>>();\n /** Per service: every id a removal marker names, relocations included. */\n const allMarkerIds = new Map<string, Set<string>>();\n /** Per service: does the feature contract carry a marker with no operationId? */\n const anonymousMarkers = new Map<string, boolean>();\n const featureApiOps = new Set<string>();\n const unreadableApis = new Set<string>();\n // The capability gate's vocabulary, once per call. Absent or invalid stays\n // SILENT here — capability.invalid is validate --all's one finding about a\n // broken file, and an absent file means the fleet never opted in — so with\n // either, nothing new gates archive (the roadmap's own trade; the\n // /loam-check row tells agents to fix the YAML first). `grading` is that\n // silence hoisted into a guard, so a silent axis also skips the reads that\n // exist only to feed it.\n //\n // The vocabulary is the one this feature's MERGE would leave behind, not\n // the one on disk: a feature that adds a capability requirement in its own\n // capability delta and `Realizes:` it from its own service delta is the\n // flow the whole axis exists for, and graded against the living tree alone\n // it is refused with `capability.realizes-unknown` — an error, gating\n // archive, for a target the same archive creates. `capabilities/delta/\n // overlay.ts` states the whole judgement. One `existsSync` for a feature\n // that carries no capability delta, which is every feature in a fleet that\n // has not adopted the axis.\n const capabilityDeltas =\n context === undefined ? await featureCapabilityDeltas(featureDir) : await context.featureCapabilityDeltas(featureDir);\n const capabilityVocab = withFeatureCapabilities(\n context === undefined ? await readCapabilityVocabulary(docsDir) : await context.capabilities(docsDir),\n capabilityDeltas.docs.map((d) => d.id),\n );\n const grading = capabilityVocab.present && capabilityVocab.invalid === undefined;\n // The `Realizes:` index, built at most ONCE per feature and only if some\n // delta document actually reaches the grading branch. Lazy rather than\n // eager because it reads every capability document in the fleet, and a\n // feature whose deltas carry no requirement file at all must not pay for\n // that — the same \"a silent axis skips the reads that feed it\" rule\n // `grading` above states, one level deeper.\n let pendingIndex: Promise<CapabilityRequirementIndex> | null = null;\n const capabilityReqs = (): Promise<CapabilityRequirementIndex> => {\n const read = context === undefined\n ? async (p: string): Promise<Requirement[]> => parseRequirements(await readFile(p, \"utf8\"))\n : (p: string): Promise<Requirement[]> => context.readRequirements(p);\n // The living index first, then widened by what this feature's capability\n // deltas ADD or MODIFY. Both halves are inside the lazy thunk, so a\n // feature whose deltas carry no requirement file at all pays for neither.\n pendingIndex ??= capabilityRequirementIndex(capabilityVocab, read).then(async (index) =>\n withFeatureRequirements(\n index,\n await Promise.all(capabilityDeltas.docs.map(async (d) => ({ id: d.id, reqs: await read(d.spec) }))),\n ),\n );\n return pendingIndex;\n };\n for (const svc of svcNames) {\n const paths = featureSpecPaths(featureDir, svc);\n if (existsSync(paths.spec)) {\n const reqs = context === undefined\n ? parseRequirements(await readFile(paths.spec, \"utf8\"))\n : await context.readRequirements(paths.spec);\n // REMOVED requirements are being retired along with their operations — their\n // ops neither claim the contract (E1) nor govern anything after the merge.\n reqOps.set(svc, reqs.filter((r) => r.kind !== \"REMOVED\").flatMap((r) => r.operations));\n removedReqOps.set(\n svc,\n new Set(reqs.filter((r) => r.kind === \"REMOVED\").flatMap((r) => r.operations)),\n );\n if (grading) {\n const target = { where: `${svc}: spec.md`, subject: svc };\n issues.push(...capabilityUnknownIssues(reqs, target, capabilityVocab));\n issues.push(...realizesUnknownIssues(reqs, target, await capabilityReqs()));\n }\n }\n // The delta arch.spec.md carries the same grammar and merges the same\n // way, so an undeclared capability in it gates identically. Nothing else\n // in this walk needs the arch delta, so the read itself sits behind\n // `grading` — and it is NOT always cached: `validate --feature` passes a\n // context, but archive's plan gate (commands/archive/plan/gate.ts) calls\n // featureCoherence without one, so this parse is paid fresh there.\n if (grading && existsSync(paths.archSpec)) {\n const archReqs = context === undefined\n ? parseRequirements(await readFile(paths.archSpec, \"utf8\"))\n : await context.readRequirements(paths.archSpec);\n const archTarget = { where: `${svc}: arch.spec.md`, subject: svc };\n issues.push(...capabilityUnknownIssues(archReqs, archTarget, capabilityVocab));\n issues.push(...realizesUnknownIssues(archReqs, archTarget, await capabilityReqs()));\n }\n // Only operations genuinely NEW to this service count as feature-added: authors\n // restate the full living API in the delta file (it is a complete document, not a patch).\n const featDoc = await readOpenapi(paths.openapi, context);\n // A feature contract that EXISTS but does not read is a broken document,\n // not an empty one — the living-side `openapi.invalid` discipline\n // (validate/service/api.ts), applied to the delta. Before this check,\n // `validate --feature` said nothing about the file at all: the empty\n // parse silently skipped every baseline pin and removal marker in it,\n // and E1 graded requirements against a contract that was never read.\n // The rest of this service's contract-axis checks are suspended — every\n // one of them would be an opinion about a document nobody could open.\n if (featDoc.unreadable) {\n unreadableApis.add(svc);\n issues.push({\n severity: \"error\",\n code: \"openapi.invalid\",\n subject: svc,\n message: `${svc}: this feature's openapi.yaml does not parse${featDoc.error === undefined ? \"\" : ` (${featDoc.error})`} — the contract axis is unchecked and the merge would have nothing true to write. Fix the YAML first.`,\n });\n continue;\n }\n const featOps = featDoc.ops;\n const removals = featOps.filter((op) => op.remove);\n // A relocation — same operationId, removal marker on the old slot, upsert\n // on the new one — retires nothing. Every rule that asks \"is this operation\n // going away\" must therefore ask the NET set (markers this feature does not\n // redefine), while \"did the author write a marker at all\" asks the raw one.\n // Conflating them made moving an endpoint fail three checks at once for a\n // change that removes nothing.\n const redefined = new Set(featOps.filter((op) => !op.remove).map((op) => op.id));\n const markerIds = new Set(removals.map((op) => op.id));\n const netRemoved = new Set([...markerIds].filter((id) => !redefined.has(id)));\n removingOps.set(svc, netRemoved);\n allMarkerIds.set(svc, markerIds);\n anonymousMarkers.set(svc, featDoc.anonymousRemovals.length > 0);\n\n // A marker with no operationId names a slot but no operation. Every\n // id-keyed check is blind to it, so it used to travel all the way into the\n // living contract as a literal `x-loam-remove: true` — the one feature-only\n // key that must never be published.\n for (const marker of featDoc.anonymousRemovals) {\n issues.push({\n severity: \"error\",\n code: \"openapi.remove-marker-anonymous\",\n subject: svc,\n message: `${svc}: ${marker.method} ${marker.path} carries x-loam-remove: true but declares no operationId — loam cannot tell which operation it retires; name the operation the living contract has at that slot`,\n });\n }\n\n const livingDoc = await readOpenapi((await locateServicePaths(docsDir, svc, context)).openapi, context);\n const livingOps = livingDoc.ops;\n for (const id of livingDoc.duplicateIds) {\n const slots = livingOps.filter((op) => op.id === id).map((op) => `${op.method} ${op.path}`);\n issues.push({\n severity: \"warn\",\n code: \"openapi.duplicate-operationid\",\n subject: svc,\n message: `${svc}: the living OpenAPI defines operationId '${id}' at ${slots.join(\" and \")} — every join on the id (a requirement's Operations: line, an edge's metadata { op }, a removal marker) picks one of those slots arbitrarily`,\n });\n }\n // The baseline axis — operation pins, path-item keys and components —\n // graded in its own package (openapi/baseline/gate.ts), slot-keyed\n // exactly as the merge writes. Texts come through the context's memoized\n // read when there is one, mirroring the readRequirements pattern above;\n // the gate itself never touches the filesystem.\n if (existsSync(paths.openapi)) {\n const livingOpenapiPath = (await locateServicePaths(docsDir, svc, context)).openapi;\n // `context.readText` DECODES and THROWS on non-UTF-8 bytes, where the\n // no-context `readFile` substitutes U+FFFD and lets `readOpenapi`\n // flag the document unreadable. Uncaught, one service's UTF-16 living\n // contract took down the whole feature target under validate's\n // context while archive's no-context path sailed past — the exact\n // context/no-context divergence doc.ts documents as paid for once.\n // Either text failing to decode gets the same answer the gate gives\n // an unreadable parse: that side's surface checks are skipped.\n const readOr = async (p: string): Promise<string | undefined> => {\n try {\n return context === undefined ? await readFile(p, \"utf8\") : await context.readText(p);\n } catch (err) {\n if (err instanceof NotUtf8DocumentError) return undefined;\n throw err;\n }\n };\n const featureText = await readOr(paths.openapi);\n const livingText = !existsSync(livingOpenapiPath) ? undefined : await readOr(livingOpenapiPath);\n if (featureText !== undefined) {\n issues.push(\n ...openapiBaselineIssues({ featDoc, livingDoc, featureText, livingText, service: svc, featureId }),\n );\n }\n }\n\n if (featOps.length > 0) {\n const living = new Set(livingOps.filter((op) => !op.remove).map((op) => op.id));\n for (const op of featOps) {\n if (!op.remove && !living.has(op.id)) featureApiOps.add(op.id);\n }\n\n // Removal is exact: the feature names both an operationId and the\n // path+method slot it expects to delete. That catches stale deltas whose\n // target moved or was already retired before the archive planner runs.\n const justified = removedReqOps.get(svc) ?? new Set<string>();\n for (const marker of removals) {\n const target = livingOps.find((op) => op.path === marker.path && op.method === marker.method);\n if (target === undefined) {\n issues.push({\n severity: \"error\",\n code: \"openapi.remove-target-missing\",\n subject: svc,\n message: `${svc}: removal marker for '${marker.id}' addresses ${marker.method} ${marker.path}, but no living operation exists there`,\n });\n } else if (target.id !== marker.id) {\n issues.push({\n severity: \"error\",\n code: \"openapi.remove-target-mismatch\",\n subject: svc,\n message: `${svc}: removal marker names '${marker.id}' at ${marker.method} ${marker.path}, but the living operation there is '${target.id}'`,\n });\n }\n // A relocation needs no REMOVED requirement: the requirement governing\n // the operation stays, the operation only changes address.\n if (!netRemoved.has(marker.id)) continue;\n if (!justified.has(marker.id)) {\n issues.push({\n severity: \"error\",\n code: \"openapi.remove-marker-unjustified\",\n subject: svc,\n message: `${svc}: removal marker for '${marker.id}' is not governed by a REMOVED requirement's Operations: line`,\n });\n }\n }\n }\n }\n for (const [svc, required] of removedReqOps) {\n // The markers live in the unreadable file — \"no matching marker\" would\n // be a claim about a document nobody could open.\n if (unreadableApis.has(svc)) continue;\n const marked = allMarkerIds.get(svc) ?? new Set<string>();\n for (const op of required) {\n if (marked.has(op)) continue;\n // Distinguish \"no marker at all\" from \"a marker is there but loam cannot\n // read which operation it names\" — the first asks the author to write the\n // marker, the second to write the operationId, and telling somebody who\n // already wrote the marker that there is none sends them looking for a\n // file they are staring at.\n issues.push({\n severity: \"error\",\n code: \"openapi.remove-marker-missing\",\n subject: svc,\n message: anonymousMarkers.get(svc) === true\n ? `${svc}: REMOVED requirement governs '${op}', and its feature openapi.yaml carries an x-loam-remove: true marker with no operationId — name '${op}' on that marker`\n : `${svc}: REMOVED requirement governs '${op}', but its feature openapi.yaml has no matching x-loam-remove: true marker`,\n });\n }\n }\n return { reqOps, removedReqOps, removingOps, allMarkerIds, anonymousMarkers, featureApiOps, unreadableApis };\n}\n"]}
1
+ {"version":3,"file":"declared.js","sourceRoot":"","sources":["../../../src/core/coherence/declared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What a feature's own delta DECLARES, per service, indexed once.\n *\n * Nine indexes over the same four files (the delta spec.md, arch.spec.md,\n * openapi.yaml, and the living contract they are graded against), built in one\n * walk because every check downstream joins on the service id and would\n * otherwise re-read the delta per question. The distinctions here are the ones\n * the checks cannot make for themselves: an operation a REMOVED requirement\n * governs is being retired, so it neither claims the contract nor governs\n * anything after the merge; a removal marker that names an id also defined\n * elsewhere in the delta is a RELOCATION, not a retirement; a living operation\n * another one replaces at its address, with no marker naming it, leaves the\n * contract all the same; and a marker with\n * no `operationId` at all is a shape only this walk can see. The capability\n * gate rides the same loop: both delta spec documents are graded against the\n * fleet vocabulary here, because coherence.ts and this package's file count\n * are both at their limits and the walk already holds the parsed documents.\n */\nimport { existsSync } from \"node:fs\";\nimport { readOr } from \"../openapi/contract-text.js\";\nimport { readFile } from \"node:fs/promises\";\nimport { type PathableService } from \"../kernel/ids/service.js\";\nimport type { Issue } from \"../vocabulary/issue.js\";\nimport { featureSpecPaths } from \"../repo/paths.js\";\nimport { locateServicePaths } from \"../repo/service-target.js\";\nimport { parseRequirements } from \"../document/parse.js\";\nimport { readCapabilityVocabulary } from \"../capabilities/capabilities.js\";\nimport { capabilityRequirementIndex } from \"../capabilities/findings.js\";\nimport { withFeatureCapabilities, withFeatureRequirements } from \"../capabilities/delta/overlay.js\";\nimport { featureCapabilityDeltas } from \"../capabilities/delta/tree.js\";\nimport { realizesUnknownIssues } from \"../capabilities/realizes/findings.js\";\nimport type { CapabilityRequirementIndex } from \"../capabilities/realizes/join.js\";\nimport { capabilityUnknownIssues } from \"../capabilities/findings.js\";\nimport type { Requirement } from \"../document/spec.js\";\nimport { openapiBaselineIssues } from \"../openapi/baseline/gate.js\";\nimport { readOpenapi } from \"../openapi/doc.js\";\nimport { operationRetirements } from \"./retired/retirement.js\";\nimport { operationArrivals, type Arrival, type Displacement } from \"./retired/revival/arrivals.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport type { DocsDir, FeatureDir } from \"../kernel/ids/dirs.js\";\n\n/** Everything one feature's delta says about its own services. */\nexport interface Declared {\n /** Per service: the operations its non-REMOVED requirements govern. */\n reqOps: Map<PathableService, string[]>;\n /** Per service: the operations its REMOVED requirements governed. */\n removedReqOps: Map<PathableService, Set<string>>;\n /** Per service: operations this feature genuinely retires (markers minus relocations). */\n removingOps: Map<string, Set<string>>;\n /** Per service: every id a removal marker names, relocations included. */\n allMarkerIds: Map<string, Set<string>>;\n /** Per service: does the feature contract carry a marker with no operationId? */\n anonymousMarkers: Map<string, boolean>;\n /** The operationIds the living contract of their service does not hold, across the whole feature — new, or revived (see `revivalCandidates`). */\n featureApiOps: Set<string>;\n /**\n * Services whose FEATURE openapi.yaml exists but does not parse. Every check\n * that joins on the feature contract must suspend itself for these — an\n * unreadable document yields the same empty op set as an absent one, and\n * grading against that emptiness produced false errors pointing everywhere\n * but at the broken file.\n */\n unreadableApis: Set<string>;\n /**\n * Per service: every (operationId, address) the contract the archive would\n * write has and the living one lacks — an addition, or a revival of what an\n * archived feature retired or moved away, which the living contract alone\n * cannot tell apart. coherence.ts asks the retired index (./retired/) only\n * when one of these lists is non-empty.\n */\n revivalCandidates: Map<PathableService, Arrival[]>;\n /**\n * Per service: every living operationId the contract the archive would\n * write answers nowhere while no removal marker names it — replaced at its\n * address by another operation (./retired/revival/arrivals.ts). The\n * removal gate's consumers are asked of these too: the loss is the same,\n * only the spelling differs.\n */\n displacedOps: Map<PathableService, Displacement[]>;\n}\n\n/** The three facts this walk needs about the feature it is reading. */\nexport interface DeltaScope {\n docsDir: DocsDir;\n featureDir: FeatureDir;\n featureId: string;\n}\n\nexport async function declaredByService(\n scope: DeltaScope,\n svcNames: PathableService[],\n issues: Issue[],\n context?: FleetContext,\n): Promise<Declared> {\n const { docsDir, featureDir, featureId } = scope;\n const reqOps = new Map<PathableService, string[]>();\n const removedReqOps = new Map<PathableService, Set<string>>();\n /** Per service: operations this feature genuinely retires (markers minus relocations). */\n const removingOps = new Map<string, Set<string>>();\n /** Per service: every id a removal marker names, relocations included. */\n const allMarkerIds = new Map<string, Set<string>>();\n /** Per service: does the feature contract carry a marker with no operationId? */\n const anonymousMarkers = new Map<string, boolean>();\n const featureApiOps = new Set<string>();\n const unreadableApis = new Set<string>();\n const revivalCandidates = new Map<PathableService, Arrival[]>();\n const displacedOps = new Map<PathableService, Displacement[]>();\n /** Per service read here: the operationIds its living contract holds, or null when it does not read. */\n const livingIds = new Map<string, ReadonlySet<string> | null>();\n // The capability gate's vocabulary, once per call. Absent or invalid stays\n // SILENT here — capability.invalid is validate --all's one finding about a\n // broken file, and an absent file means the fleet never opted in — so with\n // either, nothing new gates archive (the roadmap's own trade; the\n // /loam-check row tells agents to fix the YAML first). `grading` is that\n // silence hoisted into a guard, so a silent axis also skips the reads that\n // exist only to feed it.\n //\n // The vocabulary is the one this feature's MERGE would leave behind, not\n // the one on disk: a feature that adds a capability requirement in its own\n // capability delta and `Realizes:` it from its own service delta is the\n // flow the whole axis exists for, and graded against the living tree alone\n // it is refused with `capability.realizes-unknown` — an error, gating\n // archive, for a target the same archive creates. `capabilities/delta/\n // overlay.ts` states the whole judgement. One `existsSync` for a feature\n // that carries no capability delta, which is every feature in a fleet that\n // has not adopted the axis.\n const capabilityDeltas =\n context === undefined ? await featureCapabilityDeltas(featureDir) : await context.featureCapabilityDeltas(featureDir);\n const capabilityVocab = withFeatureCapabilities(\n context === undefined ? await readCapabilityVocabulary(docsDir) : await context.capabilities(docsDir),\n capabilityDeltas.docs.map((d) => d.id),\n );\n const grading = capabilityVocab.present && capabilityVocab.invalid === undefined;\n // The `Realizes:` index, built at most ONCE per feature and only if some\n // delta document actually reaches the grading branch. Lazy rather than\n // eager because it reads every capability document in the fleet, and a\n // feature whose deltas carry no requirement file at all must not pay for\n // that — the same \"a silent axis skips the reads that feed it\" rule\n // `grading` above states, one level deeper.\n let pendingIndex: Promise<CapabilityRequirementIndex> | null = null;\n const capabilityReqs = (): Promise<CapabilityRequirementIndex> => {\n const read = context === undefined\n ? async (p: string): Promise<Requirement[]> => parseRequirements(await readFile(p, \"utf8\"))\n : (p: string): Promise<Requirement[]> => context.readRequirements(p);\n // The living index first, then widened by what this feature's capability\n // deltas ADD or MODIFY. Both halves are inside the lazy thunk, so a\n // feature whose deltas carry no requirement file at all pays for neither.\n pendingIndex ??= capabilityRequirementIndex(capabilityVocab, read).then(async (index) =>\n withFeatureRequirements(\n index,\n await Promise.all(capabilityDeltas.docs.map(async (d) => ({ id: d.id, reqs: await read(d.spec) }))),\n ),\n );\n return pendingIndex;\n };\n for (const svc of svcNames) {\n const paths = featureSpecPaths(featureDir, svc);\n if (existsSync(paths.spec)) {\n const reqs = context === undefined\n ? parseRequirements(await readFile(paths.spec, \"utf8\"))\n : await context.readRequirements(paths.spec);\n // REMOVED requirements are being retired along with their operations — their\n // ops neither claim the contract (E1) nor govern anything after the merge.\n reqOps.set(svc, reqs.filter((r) => r.kind !== \"REMOVED\").flatMap((r) => r.operations));\n removedReqOps.set(\n svc,\n new Set(reqs.filter((r) => r.kind === \"REMOVED\").flatMap((r) => r.operations)),\n );\n if (grading) {\n const target = { where: `${svc}: spec.md`, subject: svc };\n issues.push(...capabilityUnknownIssues(reqs, target, capabilityVocab));\n issues.push(...realizesUnknownIssues(reqs, target, await capabilityReqs()));\n }\n }\n // The delta arch.spec.md carries the same grammar and merges the same\n // way, so an undeclared capability in it gates identically. Nothing else\n // in this walk needs the arch delta, so the read itself sits behind\n // `grading` — and it is NOT always cached: `validate --feature` passes a\n // context, but archive's plan gate (commands/archive/plan/gate.ts) calls\n // featureCoherence without one, so this parse is paid fresh there.\n if (grading && existsSync(paths.archSpec)) {\n const archReqs = context === undefined\n ? parseRequirements(await readFile(paths.archSpec, \"utf8\"))\n : await context.readRequirements(paths.archSpec);\n const archTarget = { where: `${svc}: arch.spec.md`, subject: svc };\n issues.push(...capabilityUnknownIssues(archReqs, archTarget, capabilityVocab));\n issues.push(...realizesUnknownIssues(archReqs, archTarget, await capabilityReqs()));\n }\n // Only operations the living contract does not hold count as feature-added:\n // a delta may restate living operations it does not change (a quote), and\n // a quote adds nothing. \"Not in living\" is not quite \"new\", though — an\n // operation an archived feature RETIRED is absent too, and adding it back\n // is `openapi.op-revived`'s question (./retired/revival/revived.ts), asked of the\n // `revivalCandidates` collected below.\n const featDoc = await readOpenapi(paths.openapi, context);\n // A feature contract that EXISTS but does not read is a broken document,\n // not an empty one — the living-side `openapi.invalid` discipline\n // (validate/service/api.ts), applied to the delta. Before this check,\n // `validate --feature` said nothing about the file at all: the empty\n // parse silently skipped every baseline pin and removal marker in it,\n // and E1 graded requirements against a contract that was never read.\n // The rest of this service's contract-axis checks are suspended — every\n // one of them would be an opinion about a document nobody could open.\n if (featDoc.unreadable) {\n unreadableApis.add(svc);\n issues.push({\n severity: \"error\",\n code: \"openapi.invalid\",\n subject: svc,\n message: `${svc}: this feature's openapi.yaml does not parse${featDoc.error === undefined ? \"\" : ` (${featDoc.error})`} — the contract axis is unchecked and the merge would have nothing true to write. Fix the YAML first.`,\n });\n continue;\n }\n const featOps = featDoc.ops;\n const removals = featOps.filter((op) => op.remove);\n // The raw marker set and the NET one (markers minus relocations) —\n // ./retired/retirement.ts owns the rule and says why the two differ; the\n // retired index reads every archived feature through the same function.\n const { markerIds, net: netRemoved } = operationRetirements(featOps);\n removingOps.set(svc, netRemoved);\n allMarkerIds.set(svc, markerIds);\n anonymousMarkers.set(svc, featDoc.anonymousRemovals.length > 0);\n\n // A marker with no operationId names a slot but no operation. Every\n // id-keyed check is blind to it, so it used to travel all the way into the\n // living contract as a literal `x-loam-remove: true` — the one feature-only\n // key that must never be published.\n for (const marker of featDoc.anonymousRemovals) {\n issues.push({\n severity: \"error\",\n code: \"openapi.remove-marker-anonymous\",\n subject: svc,\n message: `${svc}: ${marker.method} ${marker.path} carries x-loam-remove: true but declares no operationId — loam cannot tell which operation it retires; name the operation the living contract has at that slot`,\n });\n }\n\n const livingOpenapiPath = (await locateServicePaths(docsDir, svc, context)).openapi;\n const livingDoc = await readOpenapi(livingOpenapiPath, context);\n const livingOps = livingDoc.ops;\n livingIds.set(svc, livingDoc.unreadable ? null : new Set(livingOps.filter((op) => !op.remove).map((op) => op.id)));\n const sides = { featPath: paths.openapi, featDoc, livingPath: livingOpenapiPath, livingDoc, service: svc };\n const moved = await operationArrivals(sides, context);\n revivalCandidates.set(svc, moved.operations);\n if (moved.displaced.length > 0) displacedOps.set(svc, moved.displaced);\n for (const id of livingDoc.duplicateIds) {\n const slots = livingOps.filter((op) => op.id === id).map((op) => `${op.method} ${op.path}`);\n issues.push({\n severity: \"warn\",\n code: \"openapi.duplicate-operationid\",\n subject: svc,\n message: `${svc}: the living OpenAPI defines operationId '${id}' at ${slots.join(\" and \")} — every join on the id (a requirement's Operations: line, an edge's metadata { op }, a removal marker) picks one of those slots arbitrarily`,\n });\n }\n // The baseline axis — operation pins, path-item keys and components —\n // graded in its own package (openapi/baseline/gate.ts), slot-keyed\n // exactly as the merge writes. Texts come through the context's memoized\n // read when there is one, mirroring the readRequirements pattern above;\n // the gate itself never touches the filesystem.\n if (existsSync(paths.openapi)) {\n // `readOr` (../openapi/contract-text.ts, which says why): `context.readText`\n // throws on non-UTF-8 bytes where the no-context `readFile` lets\n // `readOpenapi` flag the document unreadable — the exact\n // context/no-context divergence doc.ts documents as paid for once.\n // Either text failing to decode gets the same answer the gate gives\n // an unreadable parse: that side's surface checks are skipped.\n const featureText = await readOr(paths.openapi, context);\n const livingText = !existsSync(livingOpenapiPath) ? undefined : await readOr(livingOpenapiPath, context);\n if (featureText !== undefined) {\n issues.push(\n ...openapiBaselineIssues({ featDoc, livingDoc, featureText, livingText, service: svc, featureId }),\n );\n }\n }\n\n if (featOps.length > 0) {\n const living = new Set(livingOps.filter((op) => !op.remove).map((op) => op.id));\n for (const op of featOps) {\n if (!op.remove && !living.has(op.id)) featureApiOps.add(op.id);\n }\n\n // Removal is exact: the feature names both an operationId and the\n // path+method slot it expects to delete. That catches stale deltas whose\n // target moved or was already retired before the archive planner runs.\n const justified = removedReqOps.get(svc) ?? new Set<string>();\n for (const marker of removals) {\n const target = livingOps.find((op) => op.path === marker.path && op.method === marker.method);\n if (target === undefined) {\n issues.push({\n severity: \"error\",\n code: \"openapi.remove-target-missing\",\n subject: svc,\n message: `${svc}: removal marker for '${marker.id}' addresses ${marker.method} ${marker.path}, but no living operation exists there`,\n });\n } else if (target.id !== marker.id) {\n issues.push({\n severity: \"error\",\n code: \"openapi.remove-target-mismatch\",\n subject: svc,\n message: `${svc}: removal marker names '${marker.id}' at ${marker.method} ${marker.path}, but the living operation there is '${target.id}'`,\n });\n }\n // A relocation needs no REMOVED requirement: the requirement governing\n // the operation stays, the operation only changes address.\n if (!netRemoved.has(marker.id)) continue;\n if (!justified.has(marker.id)) {\n issues.push({\n severity: \"error\",\n code: \"openapi.remove-marker-unjustified\",\n subject: svc,\n message: `${svc}: removal marker for '${marker.id}' is not governed by a REMOVED requirement's Operations: line`,\n });\n }\n }\n }\n }\n for (const [svc, required] of removedReqOps) {\n // The markers live in the unreadable file — \"no matching marker\" would\n // be a claim about a document nobody could open.\n if (unreadableApis.has(svc)) continue;\n const marked = allMarkerIds.get(svc) ?? new Set<string>();\n const replaced = new Set((displacedOps.get(svc) ?? []).map((d) => d.id));\n const living = livingIds.get(svc);\n for (const op of required) {\n if (marked.has(op)) continue;\n // A marker is owed only while there is a living operation for it to\n // retire — the event axis's rule (events/declared.ts) on the contract\n // axis. An operation this delta already REPLACES at its address leaves\n // the contract without one, and the marker could not even be written:\n // the slot holds the replacement. So the route the overwrite's\n // `openapi.remove-op-consumed` names — REMOVE the requirement governing\n // the old id — ended in this error, followable only by deleting the\n // requirement's Operations: line, which nothing said (review\n // 2026-10-12, finding 4). And an id the service's living contract does\n // not define is not this service's to mark at all: a REMOVED consumer\n // requirement naming ANOTHER service's operation was told to retire it\n // from its own contract. Both exemptions are facts about a contract\n // loam READ: a living openapi.yaml that does not parse proves neither,\n // so the marker stays owed — the closed direction, and the answer this\n // check gave before either exemption existed. Skipping it there let a\n // REMOVED requirement with no marker pass at exit 0 (the contract\n // review, finding 3); `openapi.invalid` is still validate's finding\n // about the file itself.\n if (replaced.has(op) || (living !== undefined && living !== null && !living.has(op))) continue;\n // Distinguish \"no marker at all\" from \"a marker is there but loam cannot\n // read which operation it names\" — the first asks the author to write the\n // marker, the second to write the operationId, and telling somebody who\n // already wrote the marker that there is none sends them looking for a\n // file they are staring at.\n issues.push({\n severity: \"error\",\n code: \"openapi.remove-marker-missing\",\n subject: svc,\n message: anonymousMarkers.get(svc) === true\n ? `${svc}: REMOVED requirement governs '${op}', and its feature openapi.yaml carries an x-loam-remove: true marker with no operationId — name '${op}' on that marker`\n : `${svc}: REMOVED requirement governs '${op}', but its feature openapi.yaml has no matching x-loam-remove: true marker`,\n });\n }\n }\n return {\n reqOps, removedReqOps, removingOps, allMarkerIds, anonymousMarkers, featureApiOps, unreadableApis, revivalCandidates,\n displacedOps,\n };\n}\n"]}
@@ -6,8 +6,8 @@
6
6
  * feature document's readability (`asyncapi.invalid` suspends the rest, the
7
7
  * unreadableApis discipline), the baseline pins and removal-marker exactness
8
8
  * (./grades.ts, slot-keyed), the removal↔REMOVED-requirement justification
9
- * join, and the merge simulation (./merged.ts) the cross-axis checks grade
10
- * against. What it cannot answer alone — who still consumes a message, what
9
+ * join, and the merge simulation (../retired/merged.ts) the cross-axis
10
+ * checks grade against. What it cannot answer alone — who still consumes a message, what
11
11
  * other features are adding — lives in ./lookups.ts, and the cross-axis
12
12
  * grading of edges and requirement lines in ./events.ts.
13
13
  *
@@ -23,16 +23,15 @@
23
23
  */
24
24
  import { existsSync } from "node:fs";
25
25
  import { readFile } from "node:fs/promises";
26
- import { parse } from "yaml";
27
- import { NotUtf8DocumentError } from "../../kernel/document-bytes.js";
28
26
  import {} from "../../kernel/ids/service.js";
29
27
  import { featureSpecPaths, SPEC_AXES } from "../../repo/paths.js";
30
28
  import { locateServicePaths } from "../../repo/service-target.js";
31
29
  import { parseRequirements } from "../../document/parse.js";
32
- import { asyncapiSlots } from "../../asyncapi/digest.js";
33
30
  import { readAsyncapi } from "../../asyncapi/read.js";
34
31
  import { gradeBaselines, gradeMarkers } from "./grades.js";
35
- import { mergedAsyncapiDoc } from "./merged.js";
32
+ import { messageRetirements } from "../retired/retirement.js";
33
+ import { eventArrivals } from "../retired/revival/arrivals.js";
34
+ import { readEventPair } from "../retired/event-pair.js";
36
35
  /**
37
36
  * The delta's `Publishes:`/`Consumes:` lines for one service, split by
38
37
  * requirement fate — read from BOTH spec files, because the outbox
@@ -62,25 +61,16 @@ export async function deltaEventLines(scope, service, context) {
62
61
  }
63
62
  return { removed, links };
64
63
  }
65
- /** Read a document's text, answering undefined for bytes that do not decode — ../declared.ts's guard. */
66
- async function readOr(p, context) {
67
- try {
68
- return context === undefined ? await readFile(p, "utf8") : await context.readText(p);
69
- }
70
- catch (err) {
71
- if (err instanceof NotUtf8DocumentError)
72
- return undefined;
73
- throw err;
74
- }
75
- }
76
64
  export async function declaredEvents(scope, svcNames, issues, context) {
77
65
  const { docsDir, featureDir, featureId } = scope;
78
66
  const featureDocs = new Map();
79
67
  const mergedDocs = new Map();
80
68
  const netRemoved = new Map();
81
69
  const stoppedSending = new Map();
70
+ const sentAfter = new Map();
82
71
  const links = new Map();
83
72
  const unreadable = new Set();
73
+ const revivalCandidates = new Map();
84
74
  for (const svc of svcNames) {
85
75
  const featPath = featureSpecPaths(featureDir, svc).asyncapi;
86
76
  const { removed: justifiedMsgs, links: svcLinks } = await deltaEventLines(scope, svc, context);
@@ -125,53 +115,39 @@ export async function declaredEvents(scope, svcNames, issues, context) {
125
115
  severity: "error",
126
116
  code: "asyncapi.invalid",
127
117
  subject: svc,
128
- message: `${svc}: this feature's asyncapi.yaml does not parse${featDoc.error === undefined ? "" : ` (${featDoc.error})`} — the event axis is unchecked and the merge would have nothing true to write. Fix the YAML first.`,
118
+ message: `${svc}: this feature's asyncapi.yaml does not read as AsyncAPI 3.0${featDoc.error === undefined ? "" : ` (${featDoc.error})`} — the event axis is unchecked and the merge would have nothing true to write. Fix the document first.`,
129
119
  });
130
120
  continue;
131
121
  }
132
122
  featureDocs.set(svc, featDoc);
133
- const featText = await readOr(featPath, context);
134
- // Parsed ONCE and kept: the slot walk and the surface half of the baseline
135
- // grade read the same resolved tree, and a second `parse` of the same
136
- // bytes is a second chance for the two halves to disagree about what the
137
- // delta declares.
138
- const featPlain = featText === undefined ? {} : parse(featText);
139
- const featSlots = asyncapiSlots(featPlain);
140
- // The living side of every slot judgement. Absent is a real answer —
141
- // everything the delta spells is new, and a baseline only means
142
- // something for a slot that already exists. Unreadable is NOT an
143
- // answer: grading pins or markers against an empty parse would call
144
- // every restatement new and every marker stale, so both checks stand
145
- // down and the (later) merge refuses the unreadable side by name.
146
- const livingText = !existsSync(livingPath) || livingDoc.unreadable ? undefined : await readOr(livingPath, context);
147
- const livingPlain = livingText === undefined ? {} : parse(livingText);
148
- const livingSlots = new Map(asyncapiSlots(livingPlain).map((s) => [`${s.section}\0${s.key}`, s]));
123
+ // Both sides' texts, trees and slots, read the one way rebase's
124
+ // standalone revival read reads them too (../retired/event-pair.ts owns
125
+ // the guards: absent living is an answer, unreadable living is not).
126
+ const read = await readEventPair({ featPath, featDoc, livingPath, livingDoc, service: svc }, context);
127
+ const { featSlots, livingText } = read;
128
+ revivalCandidates.set(svc, eventArrivals(read));
129
+ // The pair's one simulation, which the revival candidates above have
130
+ // already asked: absent living included, where it is the create branch.
131
+ const sends = read.merged()?.doc.sent;
132
+ if (sends !== undefined)
133
+ sentAfter.set(svc, sends);
149
134
  if (livingText !== undefined) {
150
- gradeBaselines({ featSlots, livingSlots, featPlain, livingPlain, svc, featureId }, issues);
151
- gradeMarkers({ featDoc, livingDoc, featSlots, livingSlots }, svc, issues);
152
- if (featText !== undefined) {
153
- const merged = mergedAsyncapiDoc({ livingText, livingDoc, featureText: featText, service: svc });
154
- if (merged !== undefined) {
155
- mergedDocs.set(svc, merged);
156
- stoppedSending.set(svc, livingDoc.sent.filter((m) => !merged.sent.includes(m)));
157
- }
135
+ gradeBaselines({ ...read, svc, featureId }, issues);
136
+ gradeMarkers(read, svc, issues);
137
+ // The pair's one simulation — the revival candidates above have already
138
+ // asked it, comparing it with the living contract.
139
+ const merged = read.merged()?.doc;
140
+ if (merged !== undefined) {
141
+ mergedDocs.set(svc, merged);
142
+ stoppedSending.set(svc, livingDoc.sent.filter((m) => !merged.sent.includes(m)));
158
143
  }
159
144
  }
160
- // A relocation — same message name, marker on the old key, declaration
161
- // at a new one — retires nothing. "Is this message going away" asks the
162
- // NET set; "did the author write a marker" asks the raw one,
163
- // ../declared.ts's distinction verbatim. Two raw sets, because the two
164
- // marker shapes carry different debts: a message-slot marker must be
165
- // justified by a REMOVED requirement, while a channel-slot removal needs
166
- // exactness only (requirements join on message names, never channel
167
- // keys — SCHEMA.md) and its living inline interior leaves with it.
168
- const markerNames = new Set(featDoc.messages.filter((m) => m.remove === true && m.slot.startsWith("components.messages.")).map((m) => m.name));
169
- const channelRemovals = featSlots.filter((s) => s.section === "channels" && s.remove).map((s) => s.key);
170
- const inlineRetired = new Set(livingDoc.messages
171
- .filter((m) => channelRemovals.some((ck) => m.slot.startsWith(`channels.${ck}.messages.`)))
172
- .map((m) => m.name));
173
- const redeclared = new Set(featDoc.messages.filter((m) => m.remove !== true).map((m) => m.name));
174
- const net = new Set([...markerNames, ...inlineRetired].filter((name) => !redeclared.has(name)));
145
+ // The raw marker sets and the NET one (minus relocations) —
146
+ // ../retired/retirement.ts owns the rule and says why each set exists;
147
+ // the retired index reads every archived feature through the same
148
+ // function, against that feature's snapshot pre-image instead of the
149
+ // living contract on disk.
150
+ const { markerNames, inlineRetired, redeclared, net } = messageRetirements(featDoc, featSlots, livingDoc);
175
151
  netRemoved.set(svc, net);
176
152
  for (const name of markerNames) {
177
153
  if (redeclared.has(name) || justifiedMsgs.has(name))
@@ -188,11 +164,20 @@ export async function declaredEvents(scope, svcNames, issues, context) {
188
164
  // and satisfied by ANY marker taking it out, relocation included: a
189
165
  // message-slot marker naming it, or a channel-slot removal whose
190
166
  // living inline interior declares it (the SCHEMA-sanctioned way to
191
- // retire an inline declaration).
167
+ // retire an inline declaration). And owed only while the MERGE would
168
+ // still declare it: a slot re-keyed to another name takes the message
169
+ // out with no marker, and none could be written there — the key holds
170
+ // the re-keyed declaration — so the route `asyncapi.remove-message-
171
+ // consumed` names (REMOVE the requirement whose Publishes: line names
172
+ // it) ended in this error, `openapi.remove-marker-missing`'s deadlock
173
+ // one axis over.
192
174
  if (markerNames.has(m) || inlineRetired.has(m))
193
175
  continue;
194
176
  if (livingDoc.unreadable || !livingDoc.messages.some((msg) => msg.name === m))
195
177
  continue;
178
+ const after = mergedDocs.get(svc);
179
+ if (after !== undefined && !after.messages.some((msg) => msg.name === m))
180
+ continue;
196
181
  issues.push({
197
182
  severity: "error",
198
183
  code: "asyncapi.remove-marker-missing",
@@ -201,6 +186,6 @@ export async function declaredEvents(scope, svcNames, issues, context) {
201
186
  });
202
187
  }
203
188
  }
204
- return { featureDocs, mergedDocs, netRemoved, stoppedSending, links, unreadable };
189
+ return { featureDocs, mergedDocs, netRemoved, stoppedSending, sentAfter, links, unreadable, revivalCandidates };
205
190
  }
206
191
  //# sourceMappingURL=declared.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"declared.js","sourceRoot":"","sources":["../../../../src/core/coherence/events/declared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What a feature's asyncapi deltas DECLARE, per service — ../declared.ts's\n * mirror on the event axis, indexed in one walk and graded as it goes.\n *\n * The walk owns every check that reads ONE service's pair of contracts: the\n * feature document's readability (`asyncapi.invalid` suspends the rest, the\n * unreadableApis discipline), the baseline pins and removal-marker exactness\n * (./grades.ts, slot-keyed), the removal↔REMOVED-requirement justification\n * join, and the merge simulation (./merged.ts) the cross-axis checks grade\n * against. What it cannot answer alone — who still consumes a message, what\n * other features are adding — lives in ./lookups.ts, and the cross-axis\n * grading of edges and requirement lines in ./events.ts.\n *\n * Slot identity is core/asyncapi/digest.ts's: three sections, and an inline\n * channel message is channel-slot interior — a marker NESTED on one makes\n * the channel an EDIT against the channel's pin, never a message removal,\n * so nothing here reads it as one. A CHANNEL-slot removal, by contrast,\n * takes its living inline interior with it (SCHEMA.md's decision), so the\n * justification join counts those inline names as marked: without that, a\n * message declared only inline was a deadlock — the sanctioned channel\n * marker graded remove-marker-missing, and the components.messages marker\n * the error suggested graded remove-target-missing.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { parse } from \"yaml\";\nimport { NotUtf8DocumentError } from \"../../kernel/document-bytes.js\";\nimport { type PathableService } from \"../../kernel/ids/service.js\";\nimport type { Issue } from \"../../vocabulary/issue.js\";\nimport { featureSpecPaths, SPEC_AXES } from \"../../repo/paths.js\";\nimport { locateServicePaths } from \"../../repo/service-target.js\";\nimport { parseRequirements } from \"../../document/parse.js\";\nimport { asyncapiSlots, type AsyncapiSlot } from \"../../asyncapi/digest.js\";\nimport { readAsyncapi } from \"../../asyncapi/read.js\";\nimport type { AsyncapiDoc } from \"../../asyncapi/model.js\";\nimport type { FleetContext } from \"../../fleet-context.js\";\nimport type { DocsDir, FeatureDir } from \"../../kernel/ids/dirs.js\";\nimport { gradeBaselines, gradeMarkers } from \"./grades.js\";\nimport { mergedAsyncapiDoc } from \"./merged.js\";\n\n/** The three facts this walk needs about the feature it is reading. */\nexport interface EventDeltaScope {\n docsDir: DocsDir;\n featureDir: FeatureDir;\n featureId: string;\n}\n\n/** One delta requirement's `Publishes:`/`Consumes:` claim — what ./events.ts grades against the contract. */\nexport interface EventLink {\n direction: \"publishes\" | \"consumes\";\n message: string;\n requirement: string;\n}\n\n/** Everything one feature's asyncapi deltas say about their own services. */\nexport interface DeclaredEvents {\n /** Per touched service: the feature delta's parse — present only where the file exists and reads. */\n featureDocs: Map<PathableService, AsyncapiDoc>;\n /**\n * Per touched service: the living contract as the MERGE would leave it\n * (./merged.ts) — present where a feature delta sits over a readable\n * living contract and the simulation had an answer. What `declares()` and\n * the consumer gate's wire half read, so the gate grades the post-archive\n * contract rather than the union of two documents one of which is leaving.\n */\n mergedDocs: Map<PathableService, AsyncapiDoc>;\n /**\n * Per service: message names this feature genuinely retires — message-slot\n * markers plus a removed channel's living INLINE interior (SCHEMA.md:\n * retiring a whole channel retires its inline messages with it), minus\n * redeclarations.\n */\n netRemoved: Map<string, Set<string>>;\n /**\n * Per service: messages the living contract SENDS that the merged one\n * would not — a channel or operation removal, or an edit, stopping\n * production while the declaration may well survive. The wire half of the\n * consumer question (./events.ts); empty where no simulation ran.\n */\n stoppedSending: Map<string, string[]>;\n /**\n * Per service in the walk: the delta's non-REMOVED `Publishes:`/`Consumes:`\n * lines — read once HERE and graded in ./events.ts, the indexed-in-one-walk\n * rule this record exists for (the same lines used to be re-read and\n * re-parsed per question on the context-less archive-gate path).\n */\n links: Map<PathableService, EventLink[]>;\n /** Services whose FEATURE asyncapi.yaml exists but does not parse — every event check suspends for them. */\n unreadable: Set<string>;\n}\n\n/**\n * The delta's `Publishes:`/`Consumes:` lines for one service, split by\n * requirement fate — read from BOTH spec files, because the outbox\n * requirement in arch.spec.md is the canonical home of an event line. A\n * REMOVED requirement's lines justify removals; everything else's are\n * claims ./events.ts grades against the contract.\n */\nexport async function deltaEventLines(\n scope: EventDeltaScope,\n service: PathableService,\n context?: FleetContext,\n): Promise<{ removed: Set<string>; links: EventLink[] }> {\n const removed = new Set<string>();\n const links: EventLink[] = [];\n for (const axis of SPEC_AXES) {\n const p = featureSpecPaths(scope.featureDir, service)[axis.key];\n if (!existsSync(p)) continue;\n const reqs = context === undefined\n ? parseRequirements(await readFile(p, \"utf8\"))\n : await context.readRequirements(p);\n for (const r of reqs) {\n if (r.kind === \"REMOVED\") {\n for (const m of [...r.publishes, ...r.consumes]) removed.add(m);\n continue;\n }\n links.push(...r.publishes.map((m) => ({ direction: \"publishes\" as const, message: m, requirement: r.name })));\n links.push(...r.consumes.map((m) => ({ direction: \"consumes\" as const, message: m, requirement: r.name })));\n }\n }\n return { removed, links };\n}\n\n/** Read a document's text, answering undefined for bytes that do not decode — ../declared.ts's guard. */\nasync function readOr(p: string, context?: FleetContext): Promise<string | undefined> {\n try {\n return context === undefined ? await readFile(p, \"utf8\") : await context.readText(p);\n } catch (err) {\n if (err instanceof NotUtf8DocumentError) return undefined;\n throw err;\n }\n}\n\nexport async function declaredEvents(\n scope: EventDeltaScope,\n svcNames: PathableService[],\n issues: Issue[],\n context?: FleetContext,\n): Promise<DeclaredEvents> {\n const { docsDir, featureDir, featureId } = scope;\n const featureDocs = new Map<PathableService, AsyncapiDoc>();\n const mergedDocs = new Map<PathableService, AsyncapiDoc>();\n const netRemoved = new Map<string, Set<string>>();\n const stoppedSending = new Map<string, string[]>();\n const links = new Map<PathableService, EventLink[]>();\n const unreadable = new Set<string>();\n for (const svc of svcNames) {\n const featPath = featureSpecPaths(featureDir, svc).asyncapi;\n const { removed: justifiedMsgs, links: svcLinks } = await deltaEventLines(scope, svc, context);\n links.set(svc, svcLinks);\n // The living contract is read only where a question will be asked of it:\n // no event delta and no REMOVED line means no marker debt and no slot to\n // grade. The unguarded read was an eager parse per touched service —\n // paid on every archive, whose gate runs without a FleetContext — for an\n // answer nothing consumed.\n if (!existsSync(featPath) && justifiedMsgs.size === 0) continue;\n const livingPath = (await locateServicePaths(docsDir, svc, context)).asyncapi;\n const livingDoc = await readAsyncapi(livingPath, context);\n if (!existsSync(featPath)) {\n // No event delta — but a REMOVED requirement may still be walking away\n // from a message the LIVING contract declares, and the marker that\n // retires the declaration has to ride in the same feature. Only\n // messages the living contract actually carries are owed one: an event\n // contract is optional, and a fleet retiring a requirement over a\n // message no contract declares owes no file.\n for (const m of justifiedMsgs) {\n if (livingDoc.unreadable || !livingDoc.messages.some((msg) => msg.name === m)) continue;\n issues.push({\n severity: \"error\",\n code: \"asyncapi.remove-marker-missing\",\n subject: svc,\n message: `${svc}: a REMOVED requirement's Publishes:/Consumes: line names '${m}', which the living asyncapi.yaml still declares, but this feature carries no matching x-loam-remove: true marker in specs/${svc}/asyncapi.yaml`,\n });\n }\n continue;\n }\n const featDoc = await readAsyncapi(featPath, context);\n // A feature contract that EXISTS but does not read is a broken document,\n // not an empty one — openapi.invalid's discipline (../declared.ts),\n // applied to the event axis: the rest of this service's event checks are\n // suspended, because every one of them would be an opinion about a\n // document nobody could open.\n if (featDoc.unreadable) {\n unreadable.add(svc);\n issues.push({\n severity: \"error\",\n code: \"asyncapi.invalid\",\n subject: svc,\n message: `${svc}: this feature's asyncapi.yaml does not parse${featDoc.error === undefined ? \"\" : ` (${featDoc.error})`} — the event axis is unchecked and the merge would have nothing true to write. Fix the YAML first.`,\n });\n continue;\n }\n featureDocs.set(svc, featDoc);\n\n const featText = await readOr(featPath, context);\n // Parsed ONCE and kept: the slot walk and the surface half of the baseline\n // grade read the same resolved tree, and a second `parse` of the same\n // bytes is a second chance for the two halves to disagree about what the\n // delta declares.\n const featPlain: unknown = featText === undefined ? {} : parse(featText);\n const featSlots = asyncapiSlots(featPlain);\n // The living side of every slot judgement. Absent is a real answer —\n // everything the delta spells is new, and a baseline only means\n // something for a slot that already exists. Unreadable is NOT an\n // answer: grading pins or markers against an empty parse would call\n // every restatement new and every marker stale, so both checks stand\n // down and the (later) merge refuses the unreadable side by name.\n const livingText = !existsSync(livingPath) || livingDoc.unreadable ? undefined : await readOr(livingPath, context);\n const livingPlain: unknown = livingText === undefined ? {} : parse(livingText);\n const livingSlots = new Map<string, AsyncapiSlot>(\n asyncapiSlots(livingPlain).map((s) => [`${s.section}\\0${s.key}`, s]),\n );\n\n if (livingText !== undefined) {\n gradeBaselines({ featSlots, livingSlots, featPlain, livingPlain, svc, featureId }, issues);\n gradeMarkers({ featDoc, livingDoc, featSlots, livingSlots }, svc, issues);\n if (featText !== undefined) {\n const merged = mergedAsyncapiDoc({ livingText, livingDoc, featureText: featText, service: svc });\n if (merged !== undefined) {\n mergedDocs.set(svc, merged);\n stoppedSending.set(svc, livingDoc.sent.filter((m) => !merged.sent.includes(m)));\n }\n }\n }\n\n // A relocation — same message name, marker on the old key, declaration\n // at a new one — retires nothing. \"Is this message going away\" asks the\n // NET set; \"did the author write a marker\" asks the raw one,\n // ../declared.ts's distinction verbatim. Two raw sets, because the two\n // marker shapes carry different debts: a message-slot marker must be\n // justified by a REMOVED requirement, while a channel-slot removal needs\n // exactness only (requirements join on message names, never channel\n // keys — SCHEMA.md) and its living inline interior leaves with it.\n const markerNames = new Set(\n featDoc.messages.filter((m) => m.remove === true && m.slot.startsWith(\"components.messages.\")).map((m) => m.name),\n );\n const channelRemovals = featSlots.filter((s) => s.section === \"channels\" && s.remove).map((s) => s.key);\n const inlineRetired = new Set(\n livingDoc.messages\n .filter((m) => channelRemovals.some((ck) => m.slot.startsWith(`channels.${ck}.messages.`)))\n .map((m) => m.name),\n );\n const redeclared = new Set(featDoc.messages.filter((m) => m.remove !== true).map((m) => m.name));\n const net = new Set([...markerNames, ...inlineRetired].filter((name) => !redeclared.has(name)));\n netRemoved.set(svc, net);\n\n for (const name of markerNames) {\n if (redeclared.has(name) || justifiedMsgs.has(name)) continue;\n issues.push({\n severity: \"error\",\n code: \"asyncapi.remove-marker-unjustified\",\n subject: svc,\n message: `${svc}: removal marker for message '${name}' is not justified by a REMOVED requirement's Publishes:/Consumes: line`,\n });\n }\n for (const m of justifiedMsgs) {\n // Owed only while the living contract still declares the message —\n // and satisfied by ANY marker taking it out, relocation included: a\n // message-slot marker naming it, or a channel-slot removal whose\n // living inline interior declares it (the SCHEMA-sanctioned way to\n // retire an inline declaration).\n if (markerNames.has(m) || inlineRetired.has(m)) continue;\n if (livingDoc.unreadable || !livingDoc.messages.some((msg) => msg.name === m)) continue;\n issues.push({\n severity: \"error\",\n code: \"asyncapi.remove-marker-missing\",\n subject: svc,\n message: `${svc}: a REMOVED requirement's Publishes:/Consumes: line names '${m}', which the living asyncapi.yaml still declares, but this feature's asyncapi.yaml has no matching x-loam-remove: true marker`,\n });\n }\n }\n return { featureDocs, mergedDocs, netRemoved, stoppedSending, links, unreadable };\n}\n"]}
1
+ {"version":3,"file":"declared.js","sourceRoot":"","sources":["../../../../src/core/coherence/events/declared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What a feature's asyncapi deltas DECLARE, per service — ../declared.ts's\n * mirror on the event axis, indexed in one walk and graded as it goes.\n *\n * The walk owns every check that reads ONE service's pair of contracts: the\n * feature document's readability (`asyncapi.invalid` suspends the rest, the\n * unreadableApis discipline), the baseline pins and removal-marker exactness\n * (./grades.ts, slot-keyed), the removal↔REMOVED-requirement justification\n * join, and the merge simulation (../retired/merged.ts) the cross-axis\n * checks grade against. What it cannot answer alone — who still consumes a message, what\n * other features are adding — lives in ./lookups.ts, and the cross-axis\n * grading of edges and requirement lines in ./events.ts.\n *\n * Slot identity is core/asyncapi/digest.ts's: three sections, and an inline\n * channel message is channel-slot interior — a marker NESTED on one makes\n * the channel an EDIT against the channel's pin, never a message removal,\n * so nothing here reads it as one. A CHANNEL-slot removal, by contrast,\n * takes its living inline interior with it (SCHEMA.md's decision), so the\n * justification join counts those inline names as marked: without that, a\n * message declared only inline was a deadlock — the sanctioned channel\n * marker graded remove-marker-missing, and the components.messages marker\n * the error suggested graded remove-target-missing.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { type PathableService } from \"../../kernel/ids/service.js\";\nimport type { Issue } from \"../../vocabulary/issue.js\";\nimport { featureSpecPaths, SPEC_AXES } from \"../../repo/paths.js\";\nimport { locateServicePaths } from \"../../repo/service-target.js\";\nimport { parseRequirements } from \"../../document/parse.js\";\nimport { readAsyncapi } from \"../../asyncapi/read.js\";\nimport type { AsyncapiDoc } from \"../../asyncapi/model.js\";\nimport type { FleetContext } from \"../../fleet-context.js\";\nimport type { DocsDir, FeatureDir } from \"../../kernel/ids/dirs.js\";\nimport { gradeBaselines, gradeMarkers } from \"./grades.js\";\nimport { messageRetirements } from \"../retired/retirement.js\";\nimport { eventArrivals, type EventArrivals } from \"../retired/revival/arrivals.js\";\nimport { readEventPair } from \"../retired/event-pair.js\";\n\n/** The three facts this walk needs about the feature it is reading. */\nexport interface EventDeltaScope {\n docsDir: DocsDir;\n featureDir: FeatureDir;\n featureId: string;\n}\n\n/** One delta requirement's `Publishes:`/`Consumes:` claim — what ./events.ts grades against the contract. */\nexport interface EventLink {\n direction: \"publishes\" | \"consumes\";\n message: string;\n requirement: string;\n}\n\n/** Everything one feature's asyncapi deltas say about their own services. */\nexport interface DeclaredEvents {\n /** Per touched service: the feature delta's parse — present only where the file exists and reads. */\n featureDocs: Map<PathableService, AsyncapiDoc>;\n /**\n * Per touched service: the living contract as the MERGE would leave it\n * (../retired/merged.ts) — present where a feature delta sits over a\n * readable living contract and the simulation had an answer. What `declares()` and\n * the consumer gate's wire half read, so the gate grades the post-archive\n * contract rather than the union of two documents one of which is leaving.\n */\n mergedDocs: Map<PathableService, AsyncapiDoc>;\n /**\n * Per service: message names this feature genuinely retires — message-slot\n * markers plus a removed channel's living INLINE interior (SCHEMA.md:\n * retiring a whole channel retires its inline messages with it), minus\n * redeclarations.\n */\n netRemoved: Map<string, Set<string>>;\n /**\n * Per service: messages the living contract SENDS that the merged one\n * would not — a channel or operation removal, or an edit, stopping\n * production while the declaration may well survive. The wire half of the\n * consumer question (./events.ts); empty where no simulation ran.\n */\n stoppedSending: Map<string, string[]>;\n /**\n * Per touched service whose feature asyncapi.yaml reads: the names its\n * contract would SEND once the archive writes it — the merged contract over a\n * readable living one, and the create branch's document where none exists\n * (a feature may move production to a service with no contract yet). Absent\n * where the simulation stands down: an unreadable living contract, or a pair\n * the merge refuses. What the consumer gate asks for the senders that keep a\n * message produced after this merge (./events.ts), so a service absent here\n * that this feature carries a delta for vouches for nothing.\n */\n sentAfter: Map<PathableService, readonly string[]>;\n /**\n * Per service in the walk: the delta's non-REMOVED `Publishes:`/`Consumes:`\n * lines — read once HERE and graded in ./events.ts, the indexed-in-one-walk\n * rule this record exists for (the same lines used to be re-read and\n * re-parsed per question on the context-less archive-gate path).\n */\n links: Map<PathableService, EventLink[]>;\n /** Services whose FEATURE asyncapi.yaml exists but does not parse — every event check suspends for them. */\n unreadable: Set<string>;\n /**\n * Per touched service: the slots the delta declares that the living\n * contract lacks, and the message names the contract the archive would\n * write declares where the living one does not — new, or a revival of what\n * an archived feature retired or moved away, which the living contract\n * alone cannot tell apart. ./events.ts asks the retired index (../retired/)\n * only when one of these is non-empty.\n */\n revivalCandidates: Map<PathableService, EventArrivals>;\n}\n\n/**\n * The delta's `Publishes:`/`Consumes:` lines for one service, split by\n * requirement fate — read from BOTH spec files, because the outbox\n * requirement in arch.spec.md is the canonical home of an event line. A\n * REMOVED requirement's lines justify removals; everything else's are\n * claims ./events.ts grades against the contract.\n */\nexport async function deltaEventLines(\n scope: EventDeltaScope,\n service: PathableService,\n context?: FleetContext,\n): Promise<{ removed: Set<string>; links: EventLink[] }> {\n const removed = new Set<string>();\n const links: EventLink[] = [];\n for (const axis of SPEC_AXES) {\n const p = featureSpecPaths(scope.featureDir, service)[axis.key];\n if (!existsSync(p)) continue;\n const reqs = context === undefined\n ? parseRequirements(await readFile(p, \"utf8\"))\n : await context.readRequirements(p);\n for (const r of reqs) {\n if (r.kind === \"REMOVED\") {\n for (const m of [...r.publishes, ...r.consumes]) removed.add(m);\n continue;\n }\n links.push(...r.publishes.map((m) => ({ direction: \"publishes\" as const, message: m, requirement: r.name })));\n links.push(...r.consumes.map((m) => ({ direction: \"consumes\" as const, message: m, requirement: r.name })));\n }\n }\n return { removed, links };\n}\n\nexport async function declaredEvents(\n scope: EventDeltaScope,\n svcNames: PathableService[],\n issues: Issue[],\n context?: FleetContext,\n): Promise<DeclaredEvents> {\n const { docsDir, featureDir, featureId } = scope;\n const featureDocs = new Map<PathableService, AsyncapiDoc>();\n const mergedDocs = new Map<PathableService, AsyncapiDoc>();\n const netRemoved = new Map<string, Set<string>>();\n const stoppedSending = new Map<string, string[]>();\n const sentAfter = new Map<PathableService, readonly string[]>();\n const links = new Map<PathableService, EventLink[]>();\n const unreadable = new Set<string>();\n const revivalCandidates = new Map<PathableService, EventArrivals>();\n for (const svc of svcNames) {\n const featPath = featureSpecPaths(featureDir, svc).asyncapi;\n const { removed: justifiedMsgs, links: svcLinks } = await deltaEventLines(scope, svc, context);\n links.set(svc, svcLinks);\n // The living contract is read only where a question will be asked of it:\n // no event delta and no REMOVED line means no marker debt and no slot to\n // grade. The unguarded read was an eager parse per touched service —\n // paid on every archive, whose gate runs without a FleetContext — for an\n // answer nothing consumed.\n if (!existsSync(featPath) && justifiedMsgs.size === 0) continue;\n const livingPath = (await locateServicePaths(docsDir, svc, context)).asyncapi;\n const livingDoc = await readAsyncapi(livingPath, context);\n if (!existsSync(featPath)) {\n // No event delta — but a REMOVED requirement may still be walking away\n // from a message the LIVING contract declares, and the marker that\n // retires the declaration has to ride in the same feature. Only\n // messages the living contract actually carries are owed one: an event\n // contract is optional, and a fleet retiring a requirement over a\n // message no contract declares owes no file.\n for (const m of justifiedMsgs) {\n if (livingDoc.unreadable || !livingDoc.messages.some((msg) => msg.name === m)) continue;\n issues.push({\n severity: \"error\",\n code: \"asyncapi.remove-marker-missing\",\n subject: svc,\n message: `${svc}: a REMOVED requirement's Publishes:/Consumes: line names '${m}', which the living asyncapi.yaml still declares, but this feature carries no matching x-loam-remove: true marker in specs/${svc}/asyncapi.yaml`,\n });\n }\n continue;\n }\n const featDoc = await readAsyncapi(featPath, context);\n // A feature contract that EXISTS but does not read is a broken document,\n // not an empty one — openapi.invalid's discipline (../declared.ts),\n // applied to the event axis: the rest of this service's event checks are\n // suspended, because every one of them would be an opinion about a\n // document nobody could open.\n if (featDoc.unreadable) {\n unreadable.add(svc);\n issues.push({\n severity: \"error\",\n code: \"asyncapi.invalid\",\n subject: svc,\n message: `${svc}: this feature's asyncapi.yaml does not read as AsyncAPI 3.0${featDoc.error === undefined ? \"\" : ` (${featDoc.error})`} — the event axis is unchecked and the merge would have nothing true to write. Fix the document first.`,\n });\n continue;\n }\n featureDocs.set(svc, featDoc);\n\n // Both sides' texts, trees and slots, read the one way rebase's\n // standalone revival read reads them too (../retired/event-pair.ts owns\n // the guards: absent living is an answer, unreadable living is not).\n const read = await readEventPair({ featPath, featDoc, livingPath, livingDoc, service: svc }, context);\n const { featSlots, livingText } = read;\n revivalCandidates.set(svc, eventArrivals(read));\n // The pair's one simulation, which the revival candidates above have\n // already asked: absent living included, where it is the create branch.\n const sends = read.merged()?.doc.sent;\n if (sends !== undefined) sentAfter.set(svc, sends);\n\n if (livingText !== undefined) {\n gradeBaselines({ ...read, svc, featureId }, issues);\n gradeMarkers(read, svc, issues);\n // The pair's one simulation — the revival candidates above have already\n // asked it, comparing it with the living contract.\n const merged = read.merged()?.doc;\n if (merged !== undefined) {\n mergedDocs.set(svc, merged);\n stoppedSending.set(svc, livingDoc.sent.filter((m) => !merged.sent.includes(m)));\n }\n }\n\n // The raw marker sets and the NET one (minus relocations) —\n // ../retired/retirement.ts owns the rule and says why each set exists;\n // the retired index reads every archived feature through the same\n // function, against that feature's snapshot pre-image instead of the\n // living contract on disk.\n const { markerNames, inlineRetired, redeclared, net } = messageRetirements(featDoc, featSlots, livingDoc);\n netRemoved.set(svc, net);\n\n for (const name of markerNames) {\n if (redeclared.has(name) || justifiedMsgs.has(name)) continue;\n issues.push({\n severity: \"error\",\n code: \"asyncapi.remove-marker-unjustified\",\n subject: svc,\n message: `${svc}: removal marker for message '${name}' is not justified by a REMOVED requirement's Publishes:/Consumes: line`,\n });\n }\n for (const m of justifiedMsgs) {\n // Owed only while the living contract still declares the message —\n // and satisfied by ANY marker taking it out, relocation included: a\n // message-slot marker naming it, or a channel-slot removal whose\n // living inline interior declares it (the SCHEMA-sanctioned way to\n // retire an inline declaration). And owed only while the MERGE would\n // still declare it: a slot re-keyed to another name takes the message\n // out with no marker, and none could be written there — the key holds\n // the re-keyed declaration — so the route `asyncapi.remove-message-\n // consumed` names (REMOVE the requirement whose Publishes: line names\n // it) ended in this error, `openapi.remove-marker-missing`'s deadlock\n // one axis over.\n if (markerNames.has(m) || inlineRetired.has(m)) continue;\n if (livingDoc.unreadable || !livingDoc.messages.some((msg) => msg.name === m)) continue;\n const after = mergedDocs.get(svc);\n if (after !== undefined && !after.messages.some((msg) => msg.name === m)) continue;\n issues.push({\n severity: \"error\",\n code: \"asyncapi.remove-marker-missing\",\n subject: svc,\n message: `${svc}: a REMOVED requirement's Publishes:/Consumes: line names '${m}', which the living asyncapi.yaml still declares, but this feature's asyncapi.yaml has no matching x-loam-remove: true marker`,\n });\n }\n }\n return { featureDocs, mergedDocs, netRemoved, stoppedSending, sentAfter, links, unreadable, revivalCandidates };\n}\n"]}