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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1036) hide show
  1. package/CHANGELOG.md +2635 -86
  2. package/COMPARISON.md +80 -63
  3. package/CONTRIBUTING.md +84 -0
  4. package/MIGRATING-from-OpenSpec.md +213 -54
  5. package/QUICKSTART.md +125 -0
  6. package/README.md +450 -150
  7. package/ROADMAP.md +599 -0
  8. package/SCHEMA.md +2355 -256
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +701 -0
  11. package/dist/cli.js +113 -19
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +209 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +268 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +77 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/openapi.js +159 -0
  22. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  23. package/dist/commands/archive/plan/gate.js +323 -0
  24. package/dist/commands/archive/plan/gate.js.map +1 -0
  25. package/dist/commands/archive/plan/landscape.js +180 -0
  26. package/dist/commands/archive/plan/landscape.js.map +1 -0
  27. package/dist/commands/archive/plan/refusal.js +111 -0
  28. package/dist/commands/archive/plan/refusal.js.map +1 -0
  29. package/dist/commands/archive/plan/specs.js +237 -0
  30. package/dist/commands/archive/plan/specs.js.map +1 -0
  31. package/dist/commands/archive/plan/state.js +27 -0
  32. package/dist/commands/archive/plan/state.js.map +1 -0
  33. package/dist/commands/archive/run.js +252 -0
  34. package/dist/commands/archive/run.js.map +1 -0
  35. package/dist/commands/context/context.js +99 -0
  36. package/dist/commands/context/context.js.map +1 -0
  37. package/dist/commands/context/print.js +283 -0
  38. package/dist/commands/context/print.js.map +1 -0
  39. package/dist/commands/delta/delta.js +279 -0
  40. package/dist/commands/delta/delta.js.map +1 -0
  41. package/dist/commands/delta/print.js +205 -0
  42. package/dist/commands/delta/print.js.map +1 -0
  43. package/dist/commands/dependencies.js +9 -7
  44. package/dist/commands/dependencies.js.map +1 -1
  45. package/dist/commands/diff/diff.js +93 -0
  46. package/dist/commands/diff/diff.js.map +1 -0
  47. package/dist/commands/diff/print.js +38 -0
  48. package/dist/commands/diff/print.js.map +1 -0
  49. package/dist/commands/doctor.js +5 -4
  50. package/dist/commands/doctor.js.map +1 -1
  51. package/dist/commands/explain/explain.js +151 -0
  52. package/dist/commands/explain/explain.js.map +1 -0
  53. package/dist/commands/explore.js +29 -24
  54. package/dist/commands/explore.js.map +1 -1
  55. package/dist/commands/gate/gate.js +115 -0
  56. package/dist/commands/gate/gate.js.map +1 -0
  57. package/dist/commands/gate/print.js +54 -0
  58. package/dist/commands/gate/print.js.map +1 -0
  59. package/dist/commands/gherkin/commit.js +146 -0
  60. package/dist/commands/gherkin/commit.js.map +1 -0
  61. package/dist/commands/gherkin/gherkin.js +246 -0
  62. package/dist/commands/gherkin/gherkin.js.map +1 -0
  63. package/dist/commands/gherkin/reconcile.js +149 -0
  64. package/dist/commands/gherkin/reconcile.js.map +1 -0
  65. package/dist/commands/gherkin/render.js +77 -0
  66. package/dist/commands/gherkin/render.js.map +1 -0
  67. package/dist/commands/init/example.js +204 -0
  68. package/dist/commands/init/example.js.map +1 -0
  69. package/dist/commands/init/first-hour.js +28 -0
  70. package/dist/commands/init/first-hour.js.map +1 -0
  71. package/dist/commands/{init.js → init/init.js} +146 -71
  72. package/dist/commands/init/init.js.map +1 -0
  73. package/dist/commands/init/mcp.js +131 -0
  74. package/dist/commands/init/mcp.js.map +1 -0
  75. package/dist/commands/init/options.js +78 -0
  76. package/dist/commands/init/options.js.map +1 -0
  77. package/dist/commands/instructions.js +72 -14
  78. package/dist/commands/instructions.js.map +1 -1
  79. package/dist/commands/list/campaign/campaign.js +65 -0
  80. package/dist/commands/list/campaign/campaign.js.map +1 -0
  81. package/dist/commands/list/campaign/owners.js +65 -0
  82. package/dist/commands/list/campaign/owners.js.map +1 -0
  83. package/dist/commands/list/json.js +157 -0
  84. package/dist/commands/list/json.js.map +1 -0
  85. package/dist/commands/list/list.js +343 -0
  86. package/dist/commands/list/list.js.map +1 -0
  87. package/dist/commands/list/print.js +301 -0
  88. package/dist/commands/list/print.js.map +1 -0
  89. package/dist/commands/list/review.js +120 -0
  90. package/dist/commands/list/review.js.map +1 -0
  91. package/dist/commands/list/views.js +105 -0
  92. package/dist/commands/list/views.js.map +1 -0
  93. package/dist/commands/mcp/dispatch.js +183 -0
  94. package/dist/commands/mcp/dispatch.js.map +1 -0
  95. package/dist/commands/mcp/mcp.js +34 -0
  96. package/dist/commands/mcp/mcp.js.map +1 -0
  97. package/dist/commands/mcp/serve.js +55 -0
  98. package/dist/commands/mcp/serve.js.map +1 -0
  99. package/dist/commands/migrate-openspec/materialize/active.js +170 -0
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  101. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  102. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  103. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  104. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  105. package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
  106. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  107. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  108. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  109. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  110. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  111. package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
  112. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  113. package/dist/commands/migrate-openspec/openspec/error.js +19 -0
  114. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  115. package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
  116. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  117. package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
  118. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  119. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  120. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  121. package/dist/commands/migrate-openspec/print.js +89 -0
  122. package/dist/commands/migrate-openspec/print.js.map +1 -0
  123. package/dist/commands/new/commit.js +76 -0
  124. package/dist/commands/new/commit.js.map +1 -0
  125. package/dist/commands/new/new.js +283 -0
  126. package/dist/commands/new/new.js.map +1 -0
  127. package/dist/commands/new/templates.js +355 -0
  128. package/dist/commands/new/templates.js.map +1 -0
  129. package/dist/commands/open.js +203 -0
  130. package/dist/commands/open.js.map +1 -0
  131. package/dist/commands/policy/format.js +152 -0
  132. package/dist/commands/policy/format.js.map +1 -0
  133. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
  134. package/dist/commands/policy/gate.js.map +1 -0
  135. package/dist/commands/rebase/edit.js +106 -0
  136. package/dist/commands/rebase/edit.js.map +1 -0
  137. package/dist/commands/rebase/living.js +185 -0
  138. package/dist/commands/rebase/living.js.map +1 -0
  139. package/dist/commands/rebase/plan.js +245 -0
  140. package/dist/commands/rebase/plan.js.map +1 -0
  141. package/dist/commands/rebase/rebase.js +275 -0
  142. package/dist/commands/rebase/rebase.js.map +1 -0
  143. package/dist/commands/seed/commit.js +192 -0
  144. package/dist/commands/seed/commit.js.map +1 -0
  145. package/dist/commands/seed/plan.js +133 -0
  146. package/dist/commands/seed/plan.js.map +1 -0
  147. package/dist/commands/seed/seed.js +172 -0
  148. package/dist/commands/seed/seed.js.map +1 -0
  149. package/dist/commands/show/feature.js +178 -0
  150. package/dist/commands/show/feature.js.map +1 -0
  151. package/dist/commands/show/marks.js +24 -0
  152. package/dist/commands/show/marks.js.map +1 -0
  153. package/dist/commands/{show.js → show/service.js} +63 -152
  154. package/dist/commands/show/service.js.map +1 -0
  155. package/dist/commands/show/show.js +77 -0
  156. package/dist/commands/show/show.js.map +1 -0
  157. package/dist/commands/status/json.js +45 -0
  158. package/dist/commands/status/json.js.map +1 -0
  159. package/dist/commands/status/print.js +157 -0
  160. package/dist/commands/status/print.js.map +1 -0
  161. package/dist/commands/status/status.js +119 -0
  162. package/dist/commands/status/status.js.map +1 -0
  163. package/dist/commands/steps/steps.js +189 -0
  164. package/dist/commands/steps/steps.js.map +1 -0
  165. package/dist/commands/subsystem/edit.js +192 -0
  166. package/dist/commands/subsystem/edit.js.map +1 -0
  167. package/dist/commands/subsystem/move.js +265 -0
  168. package/dist/commands/subsystem/move.js.map +1 -0
  169. package/dist/commands/subsystem/query.js +115 -0
  170. package/dist/commands/subsystem/query.js.map +1 -0
  171. package/dist/commands/subsystem/subsystem.js +101 -0
  172. package/dist/commands/subsystem/subsystem.js.map +1 -0
  173. package/dist/commands/subsystem/sync.js +103 -0
  174. package/dist/commands/subsystem/sync.js.map +1 -0
  175. package/dist/commands/subsystem/txn/txn.js +94 -0
  176. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  177. package/dist/commands/subsystem/txn/views.js +70 -0
  178. package/dist/commands/subsystem/txn/views.js.map +1 -0
  179. package/dist/commands/unarchive/manifest.js +160 -0
  180. package/dist/commands/unarchive/manifest.js.map +1 -0
  181. package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
  182. package/dist/commands/unarchive/restore.js.map +1 -0
  183. package/dist/commands/unarchive/unarchive.js +67 -0
  184. package/dist/commands/unarchive/unarchive.js.map +1 -0
  185. package/dist/commands/validate/arch-coverage.js +204 -0
  186. package/dist/commands/validate/arch-coverage.js.map +1 -0
  187. package/dist/commands/validate/checks/fleet-shape.js +296 -0
  188. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  189. package/dist/commands/validate/checks/health-deps.js +55 -0
  190. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  191. package/dist/commands/validate/checks/requirements.js +254 -0
  192. package/dist/commands/validate/checks/requirements.js.map +1 -0
  193. package/dist/commands/validate/checks/sources.js +76 -0
  194. package/dist/commands/validate/checks/sources.js.map +1 -0
  195. package/dist/commands/validate/checks/vocabulary.js +31 -0
  196. package/dist/commands/validate/checks/vocabulary.js.map +1 -0
  197. package/dist/commands/validate/feature.js +216 -0
  198. package/dist/commands/validate/feature.js.map +1 -0
  199. package/dist/commands/validate/fleet/census.js +69 -0
  200. package/dist/commands/validate/fleet/census.js.map +1 -0
  201. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  202. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  203. package/dist/commands/validate/fleet/landscape.js +353 -0
  204. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  205. package/dist/commands/validate/fleet/load.js +52 -0
  206. package/dist/commands/validate/fleet/load.js.map +1 -0
  207. package/dist/commands/validate/fleet/obligations.js +270 -0
  208. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  209. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  210. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  211. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  212. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  213. package/dist/commands/validate/fleet/scorecard/print.js +63 -0
  214. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  215. package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
  216. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  217. package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
  218. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
  219. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  220. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  221. package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
  222. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
  223. package/dist/commands/validate/fleet/usecases/steps.js +197 -0
  224. package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
  225. package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
  226. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
  227. package/dist/commands/validate/fleet/views/ids.js +40 -0
  228. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  229. package/dist/commands/validate/fleet/views/stale.js +59 -0
  230. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  231. package/dist/commands/validate/links/corpus.js +92 -0
  232. package/dist/commands/validate/links/corpus.js.map +1 -0
  233. package/dist/commands/validate/links/glossary.js +75 -0
  234. package/dist/commands/validate/links/glossary.js.map +1 -0
  235. package/dist/commands/validate/report.js +269 -0
  236. package/dist/commands/validate/report.js.map +1 -0
  237. package/dist/commands/validate/service/api.js +338 -0
  238. package/dist/commands/validate/service/api.js.map +1 -0
  239. package/dist/commands/validate/service/events/events.js +219 -0
  240. package/dist/commands/validate/service/events/events.js.map +1 -0
  241. package/dist/commands/validate/service/events/message-producers.js +77 -0
  242. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  243. package/dist/commands/validate/service/evidence-pins.js +131 -0
  244. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  245. package/dist/commands/validate/service/service.js +251 -0
  246. package/dist/commands/validate/service/service.js.map +1 -0
  247. package/dist/commands/validate/service/specs.js +251 -0
  248. package/dist/commands/validate/service/specs.js.map +1 -0
  249. package/dist/commands/validate/service/spine.js +113 -0
  250. package/dist/commands/validate/service/spine.js.map +1 -0
  251. package/dist/commands/validate/validate.js +338 -0
  252. package/dist/commands/validate/validate.js.map +1 -0
  253. package/dist/commands/verify/cross/diff.js +182 -0
  254. package/dist/commands/verify/cross/diff.js.map +1 -0
  255. package/dist/commands/verify/evidence/contract.js +32 -0
  256. package/dist/commands/verify/evidence/contract.js.map +1 -0
  257. package/dist/commands/verify/evidence/pins.js +52 -0
  258. package/dist/commands/verify/evidence/pins.js.map +1 -0
  259. package/dist/commands/verify/evidence/read.js +72 -0
  260. package/dist/commands/verify/evidence/read.js.map +1 -0
  261. package/dist/commands/verify/frozen.js +241 -0
  262. package/dist/commands/verify/frozen.js.map +1 -0
  263. package/dist/commands/verify/record.js +226 -0
  264. package/dist/commands/verify/record.js.map +1 -0
  265. package/dist/commands/verify/report.js +223 -0
  266. package/dist/commands/verify/report.js.map +1 -0
  267. package/dist/commands/verify/results.js +246 -0
  268. package/dist/commands/verify/results.js.map +1 -0
  269. package/dist/commands/verify/verify.js +217 -0
  270. package/dist/commands/verify/verify.js.map +1 -0
  271. package/dist/commands/vouch/contract.js +11 -0
  272. package/dist/commands/vouch/contract.js.map +1 -0
  273. package/dist/commands/vouch/pack/contract.js +2 -0
  274. package/dist/commands/vouch/pack/contract.js.map +1 -0
  275. package/dist/commands/vouch/pack/pack.js +266 -0
  276. package/dist/commands/vouch/pack/pack.js.map +1 -0
  277. package/dist/commands/vouch/pack/print.js +271 -0
  278. package/dist/commands/vouch/pack/print.js.map +1 -0
  279. package/dist/commands/vouch/pack/sections.js +142 -0
  280. package/dist/commands/vouch/pack/sections.js.map +1 -0
  281. package/dist/commands/vouch/prompt/confirm.js +46 -0
  282. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  283. package/dist/commands/vouch/report.js +101 -0
  284. package/dist/commands/vouch/report.js.map +1 -0
  285. package/dist/commands/vouch/run.js +285 -0
  286. package/dist/commands/vouch/run.js.map +1 -0
  287. package/dist/commands/vouch/sample/plan.js +125 -0
  288. package/dist/commands/vouch/sample/plan.js.map +1 -0
  289. package/dist/commands/vouch/sample/print.js +109 -0
  290. package/dist/commands/vouch/sample/print.js.map +1 -0
  291. package/dist/commands/vouch/vet/verify.js +123 -0
  292. package/dist/commands/vouch/vet/verify.js.map +1 -0
  293. package/dist/commands/vouch/vouch.js +176 -0
  294. package/dist/commands/vouch/vouch.js.map +1 -0
  295. package/dist/core/agent/agents-md/artifacts.js +220 -0
  296. package/dist/core/agent/agents-md/artifacts.js.map +1 -0
  297. package/dist/core/agent/agents-md/command-map.js +324 -0
  298. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  299. package/dist/core/agent/agents-md/cycle.js +165 -0
  300. package/dist/core/agent/agents-md/cycle.js.map +1 -0
  301. package/dist/core/agent/agents-md/map/explain.js +34 -0
  302. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  303. package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
  304. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  305. package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
  306. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  307. package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
  308. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  309. package/dist/core/agent/agents-md/map/mcp.js +41 -0
  310. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  311. package/dist/core/agent/agents-md/map/status.js +62 -0
  312. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  313. package/dist/core/agent/agents-md/map/subsystem.js +32 -0
  314. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  315. package/dist/core/agent/agents-md/map/usecases.js +60 -0
  316. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  317. package/dist/core/agent/agents-md/refusals.js +246 -0
  318. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  319. package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
  320. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
  321. package/dist/core/agent/agents-md/spine.js +40 -0
  322. package/dist/core/agent/agents-md/spine.js.map +1 -0
  323. package/dist/core/agent/agents-md.js +170 -0
  324. package/dist/core/agent/agents-md.js.map +1 -0
  325. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +50 -0
  326. package/dist/core/agent/agents-stamp.js.map +1 -0
  327. package/dist/core/agent/contract.js +2 -0
  328. package/dist/core/agent/contract.js.map +1 -0
  329. package/dist/core/agent/protocol.js +193 -0
  330. package/dist/core/agent/protocol.js.map +1 -0
  331. package/dist/core/agent/scaffold.js +259 -0
  332. package/dist/core/agent/scaffold.js.map +1 -0
  333. package/dist/core/agent/support/report.js +103 -0
  334. package/dist/core/agent/support/report.js.map +1 -0
  335. package/dist/core/agent/tools/dialects.js +150 -0
  336. package/dist/core/agent/tools/dialects.js.map +1 -0
  337. package/dist/core/agent/tools/registry.js +228 -0
  338. package/dist/core/agent/tools/registry.js.map +1 -0
  339. package/dist/core/agent/workflows/adopt.js +133 -0
  340. package/dist/core/agent/workflows/adopt.js.map +1 -0
  341. package/dist/core/agent/workflows/check.js +337 -0
  342. package/dist/core/agent/workflows/check.js.map +1 -0
  343. package/dist/core/agent/workflows/closing.js +262 -0
  344. package/dist/core/agent/workflows/closing.js.map +1 -0
  345. package/dist/core/agent/workflows/feature.js +105 -0
  346. package/dist/core/agent/workflows/feature.js.map +1 -0
  347. package/dist/core/agent/workflows/implement.js +105 -0
  348. package/dist/core/agent/workflows/implement.js.map +1 -0
  349. package/dist/core/agent/workflows/reference/authoring.js +209 -0
  350. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  351. package/dist/core/agent/workflows/reference/codes.js +65 -0
  352. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  353. package/dist/core/agent/workflows/reference/done-check.js +188 -0
  354. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  355. package/dist/core/agent/workflows/reference/reference.js +16 -0
  356. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  357. package/dist/core/agent/workflows/reference/spine.js +297 -0
  358. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  359. package/dist/core/asyncapi/baseline/plan.js +110 -0
  360. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  361. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  362. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  363. package/dist/core/asyncapi/depth.js +164 -0
  364. package/dist/core/asyncapi/depth.js.map +1 -0
  365. package/dist/core/asyncapi/digest.js +141 -0
  366. package/dist/core/asyncapi/digest.js.map +1 -0
  367. package/dist/core/asyncapi/merge/components.js +91 -0
  368. package/dist/core/asyncapi/merge/components.js.map +1 -0
  369. package/dist/core/asyncapi/merge/error.js +33 -0
  370. package/dist/core/asyncapi/merge/error.js.map +1 -0
  371. package/dist/core/asyncapi/merge/markers.js +308 -0
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  373. package/dist/core/asyncapi/merge/merge.js +215 -0
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  375. package/dist/core/asyncapi/merge/pin.js +107 -0
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  377. package/dist/core/asyncapi/model.js +11 -0
  378. package/dist/core/asyncapi/model.js.map +1 -0
  379. package/dist/core/asyncapi/producers.js +50 -0
  380. package/dist/core/asyncapi/producers.js.map +1 -0
  381. package/dist/core/{asyncapi.js → asyncapi/read.js} +95 -109
  382. package/dist/core/asyncapi/read.js.map +1 -0
  383. package/dist/core/brief/brief.js +225 -0
  384. package/dist/core/brief/brief.js.map +1 -0
  385. package/dist/core/brief/checks.js +250 -0
  386. package/dist/core/brief/checks.js.map +1 -0
  387. package/dist/core/brief/landscape.js +194 -0
  388. package/dist/core/brief/landscape.js.map +1 -0
  389. package/dist/core/brief/targets.js +226 -0
  390. package/dist/core/brief/targets.js.map +1 -0
  391. package/dist/core/brief/unchecked.js +48 -0
  392. package/dist/core/brief/unchecked.js.map +1 -0
  393. package/dist/core/c4/arch.js +174 -0
  394. package/dist/core/c4/arch.js.map +1 -0
  395. package/dist/core/c4/likec4.js +90 -0
  396. package/dist/core/c4/likec4.js.map +1 -0
  397. package/dist/core/c4/parsed/deployment.js +158 -0
  398. package/dist/core/c4/parsed/deployment.js.map +1 -0
  399. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  400. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  401. package/dist/core/c4/parsed/specification.js +78 -0
  402. package/dist/core/c4/parsed/specification.js.map +1 -0
  403. package/dist/core/c4/parsed/values.js +57 -0
  404. package/dist/core/c4/parsed/values.js.map +1 -0
  405. package/dist/core/c4/parsed/view-ids.js +75 -0
  406. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  407. package/dist/core/c4/project/architecture.js +45 -0
  408. package/dist/core/c4/project/architecture.js.map +1 -0
  409. package/dist/core/c4/project/documents.js +58 -0
  410. package/dist/core/c4/project/documents.js.map +1 -0
  411. package/dist/core/c4/project/load.js +187 -0
  412. package/dist/core/c4/project/load.js.map +1 -0
  413. package/dist/core/c4/project/staged.js +220 -0
  414. package/dist/core/c4/project/staged.js.map +1 -0
  415. package/dist/core/c4/resolve/service.js +159 -0
  416. package/dist/core/c4/resolve/service.js.map +1 -0
  417. package/dist/core/c4/resolve/steps.js +144 -0
  418. package/dist/core/c4/resolve/steps.js.map +1 -0
  419. package/dist/core/c4/seed/fleet-file.js +201 -0
  420. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  421. package/dist/core/c4/seed/items.js +91 -0
  422. package/dist/core/c4/seed/items.js.map +1 -0
  423. package/dist/core/c4/seed/stamp.js +48 -0
  424. package/dist/core/c4/seed/stamp.js.map +1 -0
  425. package/dist/core/c4/seed/template.js +109 -0
  426. package/dist/core/c4/seed/template.js.map +1 -0
  427. package/dist/core/c4/source-mask.js +82 -0
  428. package/dist/core/c4/source-mask.js.map +1 -0
  429. package/dist/core/c4/source-scan.js +227 -0
  430. package/dist/core/c4/source-scan.js.map +1 -0
  431. package/dist/core/c4/splice/authored-source.js +101 -0
  432. package/dist/core/c4/splice/authored-source.js.map +1 -0
  433. package/dist/core/c4/splice/contract.js +10 -0
  434. package/dist/core/c4/splice/contract.js.map +1 -0
  435. package/dist/core/c4/splice/delta-blocks.js +139 -0
  436. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  437. package/dist/core/c4/splice/identity/edges.js +36 -0
  438. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  439. package/dist/core/c4/splice/landscape-merge.js +269 -0
  440. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  441. package/dist/core/c4/splice/placement.js +194 -0
  442. package/dist/core/c4/splice/placement.js.map +1 -0
  443. package/dist/core/c4/workspace.js +174 -0
  444. package/dist/core/c4/workspace.js.map +1 -0
  445. package/dist/core/capabilities/authoring/notes.js +141 -0
  446. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  447. package/dist/core/capabilities/capabilities.js +124 -0
  448. package/dist/core/capabilities/capabilities.js.map +1 -0
  449. package/dist/core/capabilities/delta/doc.js +50 -0
  450. package/dist/core/capabilities/delta/doc.js.map +1 -0
  451. package/dist/core/capabilities/delta/overlay.js +129 -0
  452. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  453. package/dist/core/capabilities/delta/summary.js +57 -0
  454. package/dist/core/capabilities/delta/summary.js.map +1 -0
  455. package/dist/core/capabilities/delta/tree.js +43 -0
  456. package/dist/core/capabilities/delta/tree.js.map +1 -0
  457. package/dist/core/capabilities/delta/uncovered.js +222 -0
  458. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  459. package/dist/core/capabilities/findings.js +342 -0
  460. package/dist/core/capabilities/findings.js.map +1 -0
  461. package/dist/core/capabilities/realizes/findings.js +181 -0
  462. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  463. package/dist/core/capabilities/realizes/join.js +143 -0
  464. package/dist/core/capabilities/realizes/join.js.map +1 -0
  465. package/dist/core/capabilities/rollup.js +199 -0
  466. package/dist/core/capabilities/rollup.js.map +1 -0
  467. package/dist/core/capabilities/tree.js +126 -0
  468. package/dist/core/capabilities/tree.js.map +1 -0
  469. package/dist/core/capabilities/usecase-join.js +277 -0
  470. package/dist/core/capabilities/usecase-join.js.map +1 -0
  471. package/dist/core/coherence/authoring/scaffold.js +177 -0
  472. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  473. package/dist/core/coherence/authoring/sentinels.js +74 -0
  474. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  475. package/dist/core/coherence/coherence.js +287 -0
  476. package/dist/core/coherence/coherence.js.map +1 -0
  477. package/dist/core/coherence/declared.js +269 -0
  478. package/dist/core/coherence/declared.js.map +1 -0
  479. package/dist/core/coherence/events/declared.js +206 -0
  480. package/dist/core/coherence/events/declared.js.map +1 -0
  481. package/dist/core/coherence/events/events.js +204 -0
  482. package/dist/core/coherence/events/events.js.map +1 -0
  483. package/dist/core/coherence/events/grades.js +166 -0
  484. package/dist/core/coherence/events/grades.js.map +1 -0
  485. package/dist/core/coherence/events/lookups.js +122 -0
  486. package/dist/core/coherence/events/lookups.js.map +1 -0
  487. package/dist/core/coherence/events/merged.js +40 -0
  488. package/dist/core/coherence/events/merged.js.map +1 -0
  489. package/dist/core/coherence/living.js +198 -0
  490. package/dist/core/coherence/living.js.map +1 -0
  491. package/dist/core/coherence/lookups.js +155 -0
  492. package/dist/core/coherence/lookups.js.map +1 -0
  493. package/dist/core/coherence/pending.js +39 -0
  494. package/dist/core/coherence/pending.js.map +1 -0
  495. package/dist/core/conflict-markers.js +60 -0
  496. package/dist/core/conflict-markers.js.map +1 -0
  497. package/dist/core/delta/claims.js +73 -0
  498. package/dist/core/delta/claims.js.map +1 -0
  499. package/dist/core/delta/delta.js +296 -0
  500. package/dist/core/delta/delta.js.map +1 -0
  501. package/dist/core/delta/document.js +177 -0
  502. package/dist/core/delta/document.js.map +1 -0
  503. package/dist/core/delta/scope.js +48 -0
  504. package/dist/core/delta/scope.js.map +1 -0
  505. package/dist/core/delta/select.js +237 -0
  506. package/dist/core/delta/select.js.map +1 -0
  507. package/dist/core/dependencies/dependencies.js +141 -0
  508. package/dist/core/dependencies/dependencies.js.map +1 -0
  509. package/dist/core/dependencies/facts.js +165 -0
  510. package/dist/core/dependencies/facts.js.map +1 -0
  511. package/dist/core/dependencies/fanin.js +88 -0
  512. package/dist/core/dependencies/fanin.js.map +1 -0
  513. package/dist/core/dependencies/graph.js +106 -0
  514. package/dist/core/dependencies/graph.js.map +1 -0
  515. package/dist/core/deployment/delta.js +188 -0
  516. package/dist/core/deployment/delta.js.map +1 -0
  517. package/dist/core/deployment/objects.js +145 -0
  518. package/dist/core/deployment/objects.js.map +1 -0
  519. package/dist/core/diff/base-git.js +148 -0
  520. package/dist/core/diff/base-git.js.map +1 -0
  521. package/dist/core/diff/base-state.js +209 -0
  522. package/dist/core/diff/base-state.js.map +1 -0
  523. package/dist/core/diff/current-state.js +96 -0
  524. package/dist/core/diff/current-state.js.map +1 -0
  525. package/dist/core/diff/scope/changed-paths.js +188 -0
  526. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  527. package/dist/core/diff/semantic.js +243 -0
  528. package/dist/core/diff/semantic.js.map +1 -0
  529. package/dist/core/diff/victims.js +247 -0
  530. package/dist/core/diff/victims.js.map +1 -0
  531. package/dist/core/docs.js +7 -64
  532. package/dist/core/docs.js.map +1 -1
  533. package/dist/core/doctor/agents.js +222 -0
  534. package/dist/core/doctor/agents.js.map +1 -0
  535. package/dist/core/doctor/config.js +135 -0
  536. package/dist/core/doctor/config.js.map +1 -0
  537. package/dist/core/doctor/doctor.js +275 -0
  538. package/dist/core/doctor/doctor.js.map +1 -0
  539. package/dist/core/doctor/report.js +13 -0
  540. package/dist/core/doctor/report.js.map +1 -0
  541. package/dist/core/doctor/residue.js +110 -0
  542. package/dist/core/doctor/residue.js.map +1 -0
  543. package/dist/core/document/apply.js +77 -0
  544. package/dist/core/document/apply.js.map +1 -0
  545. package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
  546. package/dist/core/document/frontmatter.js.map +1 -0
  547. package/dist/core/document/grammar/directives.js +143 -0
  548. package/dist/core/document/grammar/directives.js.map +1 -0
  549. package/dist/core/document/parse.js +263 -0
  550. package/dist/core/document/parse.js.map +1 -0
  551. package/dist/core/document/scenarios.js +221 -0
  552. package/dist/core/document/scenarios.js.map +1 -0
  553. package/dist/core/document/spec.js +241 -0
  554. package/dist/core/document/spec.js.map +1 -0
  555. package/dist/core/{config.js → envelope/config.js} +79 -18
  556. package/dist/core/envelope/config.js.map +1 -0
  557. package/dist/core/envelope/json.js +175 -0
  558. package/dist/core/envelope/json.js.map +1 -0
  559. package/dist/core/{version.js → envelope/version.js} +3 -3
  560. package/dist/core/envelope/version.js.map +1 -0
  561. package/dist/core/explain/families.js +175 -0
  562. package/dist/core/explain/families.js.map +1 -0
  563. package/dist/core/explain/fix-tables.js +178 -0
  564. package/dist/core/explain/fix-tables.js.map +1 -0
  565. package/dist/core/explain/lookup.js +181 -0
  566. package/dist/core/explain/lookup.js.map +1 -0
  567. package/dist/core/explain/refusals.js +49 -0
  568. package/dist/core/explain/refusals.js.map +1 -0
  569. package/dist/core/explain/terms.js +144 -0
  570. package/dist/core/explain/terms.js.map +1 -0
  571. package/dist/core/explore/describe.js +105 -0
  572. package/dist/core/explore/describe.js.map +1 -0
  573. package/dist/core/{explore.js → explore/explore.js} +50 -101
  574. package/dist/core/explore/explore.js.map +1 -0
  575. package/dist/core/fleet-context.js +120 -78
  576. package/dist/core/fleet-context.js.map +1 -1
  577. package/dist/core/gate/checks.js +201 -0
  578. package/dist/core/gate/checks.js.map +1 -0
  579. package/dist/core/gate/partners.js +205 -0
  580. package/dist/core/gate/partners.js.map +1 -0
  581. package/dist/core/gate/report.js +47 -0
  582. package/dist/core/gate/report.js.map +1 -0
  583. package/dist/core/gate/verification.js +113 -0
  584. package/dist/core/gate/verification.js.map +1 -0
  585. package/dist/core/gherkin/digest.js +60 -0
  586. package/dist/core/gherkin/digest.js.map +1 -0
  587. package/dist/core/gherkin/emit.js +177 -0
  588. package/dist/core/gherkin/emit.js.map +1 -0
  589. package/dist/core/gherkin/read.js +76 -0
  590. package/dist/core/gherkin/read.js.map +1 -0
  591. package/dist/core/gherkin/stale.js +234 -0
  592. package/dist/core/gherkin/stale.js.map +1 -0
  593. package/dist/core/gherkin/stamp.js +77 -0
  594. package/dist/core/gherkin/stamp.js.map +1 -0
  595. package/dist/core/gherkin/steps/catalogue.js +154 -0
  596. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  597. package/dist/core/gherkin/steps/inventory.js +98 -0
  598. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  599. package/dist/core/gherkin/steps/phrase.js +72 -0
  600. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  601. package/dist/core/glossary/delta.js +106 -0
  602. package/dist/core/glossary/delta.js.map +1 -0
  603. package/dist/core/glossary/tree.js +86 -0
  604. package/dist/core/glossary/tree.js.map +1 -0
  605. package/dist/core/kernel/concurrency.js.map +1 -0
  606. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  607. package/dist/core/kernel/document-bytes.js.map +1 -0
  608. package/dist/core/kernel/fences.js +42 -0
  609. package/dist/core/kernel/fences.js.map +1 -0
  610. package/dist/core/kernel/ids/capability.js +72 -0
  611. package/dist/core/kernel/ids/capability.js.map +1 -0
  612. package/dist/core/kernel/ids/dirs.js +33 -0
  613. package/dist/core/kernel/ids/dirs.js.map +1 -0
  614. package/dist/core/kernel/ids/feature.js +75 -0
  615. package/dist/core/kernel/ids/feature.js.map +1 -0
  616. package/dist/core/kernel/ids/service.js +156 -0
  617. package/dist/core/kernel/ids/service.js.map +1 -0
  618. package/dist/core/kernel/ids/subsystem.js +63 -0
  619. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  620. package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
  621. package/dist/core/kernel/path-safety.js.map +1 -0
  622. package/dist/core/kernel/records.js.map +1 -0
  623. package/dist/core/links/backlinks.js +68 -0
  624. package/dist/core/links/backlinks.js.map +1 -0
  625. package/dist/core/links/case.js +74 -0
  626. package/dist/core/links/case.js.map +1 -0
  627. package/dist/core/links/corpus.js +104 -0
  628. package/dist/core/links/corpus.js.map +1 -0
  629. package/dist/core/links/findings.js +110 -0
  630. package/dist/core/links/findings.js.map +1 -0
  631. package/dist/core/links/parse.js +236 -0
  632. package/dist/core/links/parse.js.map +1 -0
  633. package/dist/core/mcp/argv.js +111 -0
  634. package/dist/core/mcp/argv.js.map +1 -0
  635. package/dist/core/mcp/author-tools.js +72 -0
  636. package/dist/core/mcp/author-tools.js.map +1 -0
  637. package/dist/core/mcp/framing.js +46 -0
  638. package/dist/core/mcp/framing.js.map +1 -0
  639. package/dist/core/mcp/protocol.js +280 -0
  640. package/dist/core/mcp/protocol.js.map +1 -0
  641. package/dist/core/mcp/tools.js +314 -0
  642. package/dist/core/mcp/tools.js.map +1 -0
  643. package/dist/core/obligations/obligations.js +106 -0
  644. package/dist/core/obligations/obligations.js.map +1 -0
  645. package/dist/core/openapi/baseline/gate.js +166 -0
  646. package/dist/core/openapi/baseline/gate.js.map +1 -0
  647. package/dist/core/openapi/baseline/plan.js +112 -0
  648. package/dist/core/openapi/baseline/plan.js.map +1 -0
  649. package/dist/core/openapi/baseline/record.js +175 -0
  650. package/dist/core/openapi/baseline/record.js.map +1 -0
  651. package/dist/core/openapi/depth.js +122 -0
  652. package/dist/core/openapi/depth.js.map +1 -0
  653. package/dist/core/openapi/digest.js +189 -0
  654. package/dist/core/openapi/digest.js.map +1 -0
  655. package/dist/core/{openapi.js → openapi/doc.js} +44 -106
  656. package/dist/core/openapi/doc.js.map +1 -0
  657. package/dist/core/openapi/merge/components.js +234 -0
  658. package/dist/core/openapi/merge/components.js.map +1 -0
  659. package/dist/core/openapi/merge/error.js +26 -0
  660. package/dist/core/openapi/merge/error.js.map +1 -0
  661. package/dist/core/openapi/merge/markers.js +208 -0
  662. package/dist/core/openapi/merge/markers.js.map +1 -0
  663. package/dist/core/openapi/merge/merge.js +256 -0
  664. package/dist/core/openapi/merge/merge.js.map +1 -0
  665. package/dist/core/openapi/merge/pin.js +128 -0
  666. package/dist/core/openapi/merge/pin.js.map +1 -0
  667. package/dist/core/openspec/decide/capabilities.js +244 -0
  668. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  669. package/dist/core/openspec/decide/dispositions.js +63 -0
  670. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  671. package/dist/core/openspec/decide/renames.js +179 -0
  672. package/dist/core/openspec/decide/renames.js.map +1 -0
  673. package/dist/core/openspec/decide/verdict.js +84 -0
  674. package/dist/core/openspec/decide/verdict.js.map +1 -0
  675. package/dist/core/openspec/inventory.js +221 -0
  676. package/dist/core/openspec/inventory.js.map +1 -0
  677. package/dist/core/openspec/model/mapping.js +76 -0
  678. package/dist/core/openspec/model/mapping.js.map +1 -0
  679. package/dist/core/openspec/model/model.js +65 -0
  680. package/dist/core/openspec/model/model.js.map +1 -0
  681. package/dist/core/openspec/scan/changes.js +235 -0
  682. package/dist/core/openspec/scan/changes.js.map +1 -0
  683. package/dist/core/openspec/scan/config.js +200 -0
  684. package/dist/core/openspec/scan/config.js.map +1 -0
  685. package/dist/core/openspec/scan/shape.js +260 -0
  686. package/dist/core/openspec/scan/shape.js.map +1 -0
  687. package/dist/core/openspec/scan/walk.js +133 -0
  688. package/dist/core/openspec/scan/walk.js.map +1 -0
  689. package/dist/core/openspec/scan/workspace.js +71 -0
  690. package/dist/core/openspec/scan/workspace.js.map +1 -0
  691. package/dist/core/owners/codeowners.js +141 -0
  692. package/dist/core/owners/codeowners.js.map +1 -0
  693. package/dist/core/pack/features.js +120 -0
  694. package/dist/core/pack/features.js.map +1 -0
  695. package/dist/core/pack/joins.js +112 -0
  696. package/dist/core/pack/joins.js.map +1 -0
  697. package/dist/core/pack/living.js +137 -0
  698. package/dist/core/pack/living.js.map +1 -0
  699. package/dist/core/pack/pack.js +76 -0
  700. package/dist/core/pack/pack.js.map +1 -0
  701. package/dist/core/permissions/permissions.js +87 -0
  702. package/dist/core/permissions/permissions.js.map +1 -0
  703. package/dist/core/projection/api.js +84 -0
  704. package/dist/core/projection/api.js.map +1 -0
  705. package/dist/core/projection/arch-slice.js +63 -0
  706. package/dist/core/projection/arch-slice.js.map +1 -0
  707. package/dist/core/projection/events.js +34 -0
  708. package/dist/core/projection/events.js.map +1 -0
  709. package/dist/core/provenance/findings.js +208 -0
  710. package/dist/core/provenance/findings.js.map +1 -0
  711. package/dist/core/provenance/git.js +225 -0
  712. package/dist/core/provenance/git.js.map +1 -0
  713. package/dist/core/provenance/gitq/moves.js +182 -0
  714. package/dist/core/provenance/gitq/moves.js.map +1 -0
  715. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  716. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  717. package/dist/core/provenance/sample/scope.js +238 -0
  718. package/dist/core/provenance/sample/scope.js.map +1 -0
  719. package/dist/core/provenance/sample/sections.js +61 -0
  720. package/dist/core/provenance/sample/sections.js.map +1 -0
  721. package/dist/core/provenance/sources.js +263 -0
  722. package/dist/core/provenance/sources.js.map +1 -0
  723. package/dist/core/provenance/stamp.js +232 -0
  724. package/dist/core/provenance/stamp.js.map +1 -0
  725. package/dist/core/provenance/walk.js +157 -0
  726. package/dist/core/provenance/walk.js.map +1 -0
  727. package/dist/core/repo/authored/paths.js +210 -0
  728. package/dist/core/repo/authored/paths.js.map +1 -0
  729. package/dist/core/repo/entries.js +126 -0
  730. package/dist/core/repo/entries.js.map +1 -0
  731. package/dist/core/repo/paths.js +277 -0
  732. package/dist/core/repo/paths.js.map +1 -0
  733. package/dist/core/repo/repo.js +248 -0
  734. package/dist/core/repo/repo.js.map +1 -0
  735. package/dist/core/repo/service-target.js +153 -0
  736. package/dist/core/repo/service-target.js.map +1 -0
  737. package/dist/core/repo/state.js +58 -0
  738. package/dist/core/repo/state.js.map +1 -0
  739. package/dist/core/repo/tree/find.js +52 -0
  740. package/dist/core/repo/tree/find.js.map +1 -0
  741. package/dist/core/repo/tree/fs.js +64 -0
  742. package/dist/core/repo/tree/fs.js.map +1 -0
  743. package/dist/core/repo/tree/marker.js +61 -0
  744. package/dist/core/repo/tree/marker.js.map +1 -0
  745. package/dist/core/repo/tree/views.js +172 -0
  746. package/dist/core/repo/tree/views.js.map +1 -0
  747. package/dist/core/repo/tree/walk.js +234 -0
  748. package/dist/core/repo/tree/walk.js.map +1 -0
  749. package/dist/core/results.js +99 -2
  750. package/dist/core/results.js.map +1 -1
  751. package/dist/core/scaffold/landscape.js +131 -0
  752. package/dist/core/scaffold/landscape.js.map +1 -0
  753. package/dist/core/scaffold/readme.js +84 -0
  754. package/dist/core/scaffold/readme.js.map +1 -0
  755. package/dist/core/staging/commit.js +241 -0
  756. package/dist/core/staging/commit.js.map +1 -0
  757. package/dist/core/staging/interrupted.js +96 -0
  758. package/dist/core/staging/interrupted.js.map +1 -0
  759. package/dist/core/staging/lock.js +206 -0
  760. package/dist/core/staging/lock.js.map +1 -0
  761. package/dist/core/staging/recovery/finding.js +35 -0
  762. package/dist/core/staging/recovery/finding.js.map +1 -0
  763. package/dist/core/staging/recovery/intent.js +98 -0
  764. package/dist/core/staging/recovery/intent.js.map +1 -0
  765. package/dist/core/staging/recovery/recover.js +126 -0
  766. package/dist/core/staging/recovery/recover.js.map +1 -0
  767. package/dist/core/staging/recovery/residue.js +62 -0
  768. package/dist/core/staging/recovery/residue.js.map +1 -0
  769. package/dist/core/staging/snapshot.js +202 -0
  770. package/dist/core/staging/snapshot.js.map +1 -0
  771. package/dist/core/staging/txn/forward.js +171 -0
  772. package/dist/core/staging/txn/forward.js.map +1 -0
  773. package/dist/core/staging/txn/journal.js +139 -0
  774. package/dist/core/staging/txn/journal.js.map +1 -0
  775. package/dist/core/staging/txn/transaction.js +75 -0
  776. package/dist/core/staging/txn/transaction.js.map +1 -0
  777. package/dist/core/staging/writes.js +113 -0
  778. package/dist/core/staging/writes.js.map +1 -0
  779. package/dist/core/status/actions/execution.js +49 -0
  780. package/dist/core/status/actions/execution.js.map +1 -0
  781. package/dist/core/status/contracts.js +102 -0
  782. package/dist/core/status/contracts.js.map +1 -0
  783. package/dist/core/status/feature/artifacts.js +196 -0
  784. package/dist/core/status/feature/artifacts.js.map +1 -0
  785. package/dist/core/status/feature/feature.js +207 -0
  786. package/dist/core/status/feature/feature.js.map +1 -0
  787. package/dist/core/status/feature/next.js +150 -0
  788. package/dist/core/status/feature/next.js.map +1 -0
  789. package/dist/core/status/feature/state.js +21 -0
  790. package/dist/core/status/feature/state.js.map +1 -0
  791. package/dist/core/status/fleet/fleet.js +197 -0
  792. package/dist/core/status/fleet/fleet.js.map +1 -0
  793. package/dist/core/status/fleet/next.js +207 -0
  794. package/dist/core/status/fleet/next.js.map +1 -0
  795. package/dist/core/status/interrupted.js +97 -0
  796. package/dist/core/status/interrupted.js.map +1 -0
  797. package/dist/core/status/report.js +31 -0
  798. package/dist/core/status/report.js.map +1 -0
  799. package/dist/core/status/scan.js +41 -0
  800. package/dist/core/status/scan.js.map +1 -0
  801. package/dist/core/status/verification.js +201 -0
  802. package/dist/core/status/verification.js.map +1 -0
  803. package/dist/core/usecases/capability.js +169 -0
  804. package/dist/core/usecases/capability.js.map +1 -0
  805. package/dist/core/usecases/delta/claims.js +116 -0
  806. package/dist/core/usecases/delta/claims.js.map +1 -0
  807. package/dist/core/usecases/delta/flows.js +103 -0
  808. package/dist/core/usecases/delta/flows.js.map +1 -0
  809. package/dist/core/usecases/delta/overlay.js +72 -0
  810. package/dist/core/usecases/delta/overlay.js.map +1 -0
  811. package/dist/core/usecases/fleet.js +137 -0
  812. package/dist/core/usecases/fleet.js.map +1 -0
  813. package/dist/core/usecases/operations.js +111 -0
  814. package/dist/core/usecases/operations.js.map +1 -0
  815. package/dist/core/usecases/place.js +44 -0
  816. package/dist/core/usecases/place.js.map +1 -0
  817. package/dist/core/usecases/touch.js +101 -0
  818. package/dist/core/usecases/touch.js.map +1 -0
  819. package/dist/core/verify/answers.js +173 -0
  820. package/dist/core/verify/answers.js.map +1 -0
  821. package/dist/core/verify/build.js +150 -0
  822. package/dist/core/verify/build.js.map +1 -0
  823. package/dist/core/verify/checklist.js +201 -0
  824. package/dist/core/verify/checklist.js.map +1 -0
  825. package/dist/core/verify/claims/identity.js +61 -0
  826. package/dist/core/verify/claims/identity.js.map +1 -0
  827. package/dist/core/verify/cross/diff.js +97 -0
  828. package/dist/core/verify/cross/diff.js.map +1 -0
  829. package/dist/core/verify/evidence/contract.js +169 -0
  830. package/dist/core/verify/evidence/contract.js.map +1 -0
  831. package/dist/core/verify/file.js +257 -0
  832. package/dist/core/verify/file.js.map +1 -0
  833. package/dist/core/verify/pins/lint.js +157 -0
  834. package/dist/core/verify/pins/lint.js.map +1 -0
  835. package/dist/core/verify/pins/pin.js +95 -0
  836. package/dist/core/verify/pins/pin.js.map +1 -0
  837. package/dist/core/verify/record.js +142 -0
  838. package/dist/core/verify/record.js.map +1 -0
  839. package/dist/core/verify/store/commit.js +89 -0
  840. package/dist/core/verify/store/commit.js.map +1 -0
  841. package/dist/core/verify/store/render.js +57 -0
  842. package/dist/core/verify/store/render.js.map +1 -0
  843. package/dist/core/vocabulary/health.js +91 -0
  844. package/dist/core/vocabulary/health.js.map +1 -0
  845. package/dist/core/vocabulary/issue.js +58 -0
  846. package/dist/core/vocabulary/issue.js.map +1 -0
  847. package/dist/core/vocabulary/maturity.js +145 -0
  848. package/dist/core/vocabulary/maturity.js.map +1 -0
  849. package/dist/core/{report.js → vocabulary/report.js} +30 -2
  850. package/dist/core/vocabulary/report.js.map +1 -0
  851. package/dist/core/vocabulary/steps.js +266 -0
  852. package/dist/core/vocabulary/steps.js.map +1 -0
  853. package/dist/core/workspace/discover.js +239 -0
  854. package/dist/core/workspace/discover.js.map +1 -0
  855. package/dist/core/workspace/render.js +52 -0
  856. package/dist/core/workspace/render.js.map +1 -0
  857. package/examples/README.md +189 -0
  858. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  859. package/examples/docs/architecture/capabilities.yaml +31 -0
  860. package/examples/docs/architecture/landscape.likec4 +280 -0
  861. package/examples/docs/architecture/obligations.yaml +23 -0
  862. package/examples/docs/architecture/permissions.yaml +50 -0
  863. package/examples/docs/architecture/subsystems.likec4 +11 -0
  864. package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
  865. package/examples/docs/capabilities/checkout/spec.md +55 -0
  866. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  867. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  868. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  869. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  870. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  871. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  872. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
  873. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  874. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  875. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  876. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  877. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  878. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
  879. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  880. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  881. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  882. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  883. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  884. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  885. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  886. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  887. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  888. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  889. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
  890. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  891. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  892. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  893. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  894. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  895. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  896. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  897. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  898. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  899. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  900. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  901. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  902. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  903. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  904. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  905. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  906. package/examples/docs/glossary/order.md +15 -0
  907. package/examples/docs/glossary/payments/authorization.md +14 -0
  908. package/examples/docs/likec4.config.json +9 -0
  909. package/examples/docs/loam.json +3 -0
  910. package/examples/docs/services/checkout-web/model.likec4 +109 -0
  911. package/examples/docs/services/checkout-web/spec.md +91 -0
  912. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  913. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  914. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  915. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  916. package/examples/docs/services/order-service/arch.spec.md +127 -0
  917. package/examples/docs/services/order-service/asyncapi.yaml +108 -0
  918. package/examples/docs/services/order-service/health.yaml +57 -0
  919. package/examples/docs/services/order-service/model.likec4 +138 -0
  920. package/examples/docs/services/order-service/openapi.yaml +257 -0
  921. package/examples/docs/services/order-service/runbook.md +62 -0
  922. package/examples/docs/services/order-service/spec.md +134 -0
  923. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  924. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  925. package/examples/docs/services/payment-service/arch.spec.md +73 -0
  926. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  927. package/examples/docs/services/payment-service/health.yaml +39 -0
  928. package/examples/docs/services/payment-service/model.likec4 +67 -0
  929. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  930. package/examples/docs/services/payment-service/runbook.md +37 -0
  931. package/examples/docs/services/payment-service/spec.md +88 -0
  932. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  933. package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
  934. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  935. package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
  936. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  937. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  938. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  939. package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
  940. package/examples/docs/services/platform/notification-service/health.yaml +35 -0
  941. package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
  942. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  943. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  944. package/examples/docs/services/platform/subsystem.yaml +2 -0
  945. package/examples/fleet.yaml +57 -0
  946. package/package.json +19 -6
  947. package/dist/commands/adopt.js +0 -240
  948. package/dist/commands/adopt.js.map +0 -1
  949. package/dist/commands/archive.js +0 -1313
  950. package/dist/commands/archive.js.map +0 -1
  951. package/dist/commands/delta.js +0 -388
  952. package/dist/commands/delta.js.map +0 -1
  953. package/dist/commands/docs-repo-gate.js.map +0 -1
  954. package/dist/commands/format.js +0 -17
  955. package/dist/commands/format.js.map +0 -1
  956. package/dist/commands/gherkin.js +0 -309
  957. package/dist/commands/gherkin.js.map +0 -1
  958. package/dist/commands/init.js.map +0 -1
  959. package/dist/commands/list.js +0 -295
  960. package/dist/commands/list.js.map +0 -1
  961. package/dist/commands/migrate-openspec.js +0 -950
  962. package/dist/commands/migrate-openspec.js.map +0 -1
  963. package/dist/commands/new.js +0 -413
  964. package/dist/commands/new.js.map +0 -1
  965. package/dist/commands/rebase.js +0 -356
  966. package/dist/commands/rebase.js.map +0 -1
  967. package/dist/commands/show.js.map +0 -1
  968. package/dist/commands/status.js +0 -262
  969. package/dist/commands/status.js.map +0 -1
  970. package/dist/commands/unarchive.js.map +0 -1
  971. package/dist/commands/validate.js +0 -1773
  972. package/dist/commands/validate.js.map +0 -1
  973. package/dist/commands/verify.js +0 -775
  974. package/dist/commands/verify.js.map +0 -1
  975. package/dist/commands/vouch.js +0 -421
  976. package/dist/commands/vouch.js.map +0 -1
  977. package/dist/core/agent.js +0 -2173
  978. package/dist/core/agent.js.map +0 -1
  979. package/dist/core/agents-stamp.js.map +0 -1
  980. package/dist/core/arch.js +0 -130
  981. package/dist/core/arch.js.map +0 -1
  982. package/dist/core/asyncapi.js.map +0 -1
  983. package/dist/core/brief.js +0 -755
  984. package/dist/core/brief.js.map +0 -1
  985. package/dist/core/coherence.js +0 -577
  986. package/dist/core/coherence.js.map +0 -1
  987. package/dist/core/concurrency.js.map +0 -1
  988. package/dist/core/config.js.map +0 -1
  989. package/dist/core/delta.js +0 -476
  990. package/dist/core/delta.js.map +0 -1
  991. package/dist/core/dependencies.js +0 -356
  992. package/dist/core/dependencies.js.map +0 -1
  993. package/dist/core/doctor.js +0 -596
  994. package/dist/core/doctor.js.map +0 -1
  995. package/dist/core/document-bytes.js.map +0 -1
  996. package/dist/core/explore.js.map +0 -1
  997. package/dist/core/frontmatter.js.map +0 -1
  998. package/dist/core/gherkin.js +0 -463
  999. package/dist/core/gherkin.js.map +0 -1
  1000. package/dist/core/health.js +0 -67
  1001. package/dist/core/health.js.map +0 -1
  1002. package/dist/core/ids.js +0 -122
  1003. package/dist/core/ids.js.map +0 -1
  1004. package/dist/core/issue.js +0 -9
  1005. package/dist/core/issue.js.map +0 -1
  1006. package/dist/core/json.js +0 -74
  1007. package/dist/core/json.js.map +0 -1
  1008. package/dist/core/likec4.js +0 -489
  1009. package/dist/core/likec4.js.map +0 -1
  1010. package/dist/core/maturity.js +0 -66
  1011. package/dist/core/maturity.js.map +0 -1
  1012. package/dist/core/openapi-merge.js +0 -552
  1013. package/dist/core/openapi-merge.js.map +0 -1
  1014. package/dist/core/openapi.js.map +0 -1
  1015. package/dist/core/openspec-inventory.js +0 -1440
  1016. package/dist/core/openspec-inventory.js.map +0 -1
  1017. package/dist/core/path-safety.js.map +0 -1
  1018. package/dist/core/provenance.js +0 -787
  1019. package/dist/core/provenance.js.map +0 -1
  1020. package/dist/core/records.js.map +0 -1
  1021. package/dist/core/repo.js +0 -438
  1022. package/dist/core/repo.js.map +0 -1
  1023. package/dist/core/report.js.map +0 -1
  1024. package/dist/core/spec.js +0 -505
  1025. package/dist/core/spec.js.map +0 -1
  1026. package/dist/core/staging.js +0 -890
  1027. package/dist/core/staging.js.map +0 -1
  1028. package/dist/core/status.js +0 -1132
  1029. package/dist/core/status.js.map +0 -1
  1030. package/dist/core/steps.js +0 -72
  1031. package/dist/core/steps.js.map +0 -1
  1032. package/dist/core/verify.js +0 -807
  1033. package/dist/core/verify.js.map +0 -1
  1034. package/dist/core/version.js.map +0 -1
  1035. /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
  1036. /package/dist/core/{records.js → kernel/records.js} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../../src/core/asyncapi/merge/merge.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The archive-time merge on the event axis: a feature's asyncapi delta folded\n * into the living contract, and every condition the caller has to surface\n * afterwards — the OpenAPI merge's shape, slot-keyed instead of path-keyed.\n *\n * The result type carries far more than the merged text on purpose. A merge\n * that quietly overwrote a slot, deleted a message, or ran against a stale\n * baseline is not an error — it is a fact the archiving human has to be told,\n * and a return value nobody can forget to read is the only place that\n * survives a refactor.\n *\n * Every SHAPE question — which slots does the feature declare, what does the\n * living contract hold at a (section, key) — is answered from the RESOLVED\n * plain trees, never from the AST node: an alias node is not a map even when\n * it resolves to one, and reading it as absent is how the OpenAPI merge once\n * dropped whole contract deltas. The WRITES walk the AST, string-key-matched,\n * and refuse aliases — one shared value backs every use of an anchor, so\n * writing through one would rewrite every other node that aliases it.\n */\nimport { isDeepStrictEqual } from \"node:util\";\nimport { isMap, parseDocument } from \"yaml\";\nimport { classifyBaselineDigests } from \"../../openapi/digest.js\";\nimport { asyncapiSlots, slotDigest, type AsyncapiSection } from \"../digest.js\";\nimport { danglingRefs } from \"../depth.js\";\nimport { messageName } from \"../read.js\";\nimport { readBaselineRecord } from \"../../openapi/baseline/record.js\";\nimport { asyncapiSurfaces } from \"../baseline/surfaces.js\";\nimport { errorMessage, AsyncapiMergeError } from \"./error.js\";\nimport { mergeAsyncapiComponents } from \"./components.js\";\nimport {\n deleteSlot,\n refuseAmbiguousSlotKeys,\n sectionAstPath,\n setSlotValue,\n slotLabel,\n withoutFeatureMarkers,\n writableSection,\n} from \"./markers.js\";\n\n/** One slot the merge acted on — the section decides which per-section code the plan reports. */\nexport interface AsyncapiSlotOutcome {\n section: AsyncapiSection;\n /** `slotLabel` of the slot — the message's join name included where it has one. */\n label: string;\n}\n\n/** What an asyncapi slot merge computed, including every condition the caller must surface. */\nexport interface AsyncapiMergeResult {\n /**\n * The merged living document, or null when nothing was written — every slot\n * and surface a quote, or the delta restating nothing at all. It used to be\n * null for a document declaring no SLOT whatever its components said, and a\n * delta whose whole change was a shared schema archived at exit 0 having\n * merged nothing.\n */\n text: string | null;\n /** Living slots overwritten with different content. */\n modified: AsyncapiSlotOutcome[];\n /** Living slots deleted by `x-loam-remove: true` markers. */\n removed: AsyncapiSlotOutcome[];\n /**\n * Slots the delta QUOTED — pinned, and equal to their own baseline — so the\n * merge left the living contract's own copy alone. Reported rather than\n * silent: \"your delta mentions this and I did not write it\" is exactly the\n * sentence whose absence made the OpenAPI revert invisible.\n */\n quoted: AsyncapiSlotOutcome[];\n /**\n * Slots whose pin matches neither the delta's own content nor the living\n * one: edited here AND changed by somebody else in between.\n * `asyncapi.baseline-stale` refuses these at the gate; the merge still\n * overwrites, because reaching it at all means `--approve` said to.\n */\n baselineStale: AsyncapiSlotOutcome[];\n /**\n * `<kind>/<name>` of living component SURFACES overwritten with different\n * content — the three fields below are the surface half's mirror of\n * `modified`, `quoted` and `baselineStale`, and they are spelled together on\n * the result and on `noop()` for the same reason those are: the plan reads\n * this object field by field, and a key present on one shape and missing\n * from the other makes \"no delta\" and \"a delta that merged nothing\"\n * structurally different answers to the same question.\n */\n componentsModified: string[];\n /** Surfaces the delta QUOTED — not copied, living's copy kept. */\n componentsQuoted: string[];\n /** Surfaces written on a stale record entry — under `--approve`, like the slots. */\n componentsStale: string[];\n /** Local refs the MERGE left dangling: unresolved in the merged tree and not already dangling in living. */\n unresolved: string[];\n}\n\n/**\n * Merge the feature's slots into the living AsyncAPI structurally (YAML AST,\n * not text splicing). A feature document restating NOTHING — neither a slot\n * nor a component surface — is a successful no-op; one whose whole delta is a\n * `components.schemas` entry is merged like any other, through\n * `mergeAsyncapiComponents` at the end of this function. Per slot, the pin\n * decides: a QUOTE is never a merge input — not even\n * under `--approve`, because overriding a gate is a decision and reverting a\n * slot nobody edited is a bug — while `stale` still writes, since reaching\n * the merge at all means `--approve` said to. A removal marker deletes its\n * exact target and the section key when the section empties; everything\n * published goes through the deep marker strip.\n */\nexport function mergeAsyncapiSlots(\n livingText: string,\n featureText: string,\n service: string,\n): AsyncapiMergeResult {\n const feature = parseDocument(featureText);\n if (feature.errors.length > 0) {\n throw new AsyncapiMergeError(\"feature\", service, feature.errors[0]!.message);\n }\n // Two pairs whose keys stringify identically (404 and \"404\") would make\n // the resolved walk and the string-matched writers disagree about which\n // node a slot names — refused on either side, before any verdict is taken.\n refuseAmbiguousSlotKeys(feature, \"feature\", service);\n let featPlain: unknown;\n try {\n // Resolve aliases once with the document's own anchor context. Calling an\n // individual AST node's toJSON() loses that context and can silently turn\n // an aliased slot into the wrong value.\n featPlain = feature.toJS() ?? {};\n } catch (error) {\n throw new AsyncapiMergeError(\"feature\", service, errorMessage(error));\n }\n const featSlots = asyncapiSlots(featPlain);\n // \"Is there anything to merge?\" is a question about the WHOLE delta, and it\n // was asked of the three slot sections alone — an absence test standing in\n // for the decision. It returned before the living document was even parsed,\n // so `mergeAsyncapiComponents` (the last thing this function does, and the\n // only thing that writes a component surface) never ran: a feature whose\n // entire change was a `components.schemas` entry passed the gate and\n // archived at exit 0 having merged NOTHING. The surfaces answer it too now,\n // over the ONE enumeration the gate and the rebase plan already grade the\n // delta with. Deleting the early return alone would have changed nothing:\n // there was no writer outside the slot loop to fall through to.\n if (featSlots.length === 0 && asyncapiSurfaces(featPlain).length === 0) return noop();\n\n const living = parseDocument(livingText);\n if (living.errors.length > 0) {\n throw new AsyncapiMergeError(\"living\", service, living.errors[0]!.message);\n }\n refuseAmbiguousSlotKeys(living, \"living\", service);\n let livingPlain: unknown;\n try {\n livingPlain = living.toJS() ?? {};\n } catch (error) {\n throw new AsyncapiMergeError(\"living\", service, errorMessage(error));\n }\n const livingBySlot = new Map(asyncapiSlots(livingPlain).map((slot) => [`${slot.section}\\0${slot.key}`, slot]));\n // Read ONCE here, not per surface: `problems` are deliberately ignored — a\n // malformed record is the gate's diagnosis (`asyncapi.baseline-invalid`) and\n // a parser never prints, so what reaches the surface merge is whatever read\n // back cleanly, and an entry that did not is simply absent (= unpinned).\n const { record } = readBaselineRecord(featPlain);\n\n const modified: AsyncapiSlotOutcome[] = [];\n const removed: AsyncapiSlotOutcome[] = [];\n const quoted: AsyncapiSlotOutcome[] = [];\n const baselineStale: AsyncapiSlotOutcome[] = [];\n const touched = new Set<AsyncapiSection>();\n let edited = false;\n for (const slot of featSlots) {\n const before = livingBySlot.get(`${slot.section}\\0${slot.key}`);\n const name = slot.section === \"components.messages\" ? messageName(slot.node, slot.key) : undefined;\n const at = { section: slot.section, label: slotLabel(slot.section, slot.key, name) };\n if (slot.remove) {\n // Coherence validates the marker and gates absent/mismatched targets.\n // The merge remains defensive under --approve: never delete a different\n // message merely because it occupies the requested slot. Channel and\n // operation identity IS the key, so presence is the whole match there.\n if (before === undefined) continue;\n if (slot.section === \"components.messages\" && messageName(before.node, slot.key) !== name) continue;\n writableSection(living, livingPlain, sectionAstPath(slot.section), service);\n if (deleteSlot(living, slot.section, slot.key)) {\n removed.push(at);\n touched.add(slot.section);\n edited = true;\n }\n continue;\n }\n\n const verdict = classifyBaselineDigests(\n slot.basedOn,\n slot.digest,\n before === undefined ? undefined : slotDigest(before.node),\n );\n // A QUOTE is not a merge input. The author wrote this slot down because\n // the document is complete, not because they changed it, so the living\n // contract keeps whatever it holds — including a change that landed after\n // this delta was written. Mechanical, not a judgement: `--approve` does\n // not turn it back on.\n if (verdict === \"quote\") {\n quoted.push(at);\n continue;\n }\n if (verdict === \"stale\") baselineStale.push(at);\n const publish = withoutFeatureMarkers(slot.node);\n // An unpinned restatement equal to the living slot has nothing to write —\n // the component closure's rule, kept here so a never-rebased delta that\n // merely restates the contract does not churn its bytes.\n if (before !== undefined && isDeepStrictEqual(before.node, publish)) continue;\n if (before !== undefined) modified.push(at);\n writableSection(living, livingPlain, sectionAstPath(slot.section), service);\n // Without the strip the living contract would grow a pin to a version of\n // itself — and, on this axis, a marker nested on an inline channel\n // message, invisible to the slot walker (SCHEMA.md's channel-interior\n // decision: the strip works at that nested depth exactly as at slot depth).\n setSlotValue(living, slot.section, slot.key, publish);\n edited = true;\n }\n\n // Removing the last slot leaves a section the contract still spells and\n // nothing declares — delete the emptied mapping, and `components` too when\n // the messages were all it held. After the whole loop, so a removal and an\n // upsert into one section never race the cleanup.\n for (const section of touched) {\n const node = living.getIn(sectionAstPath(section));\n if (!isMap(node) || node.items.length > 0) continue;\n living.deleteIn(sectionAstPath(section));\n if (section === \"components.messages\") {\n const components = living.getIn([\"components\"]);\n if (isMap(components) && components.items.length === 0) living.deleteIn([\"components\"]);\n }\n }\n\n // The surface half, after the slot loop and its section cleanup so a write\n // outside the three sections can never race them. `edited` has to take the\n // closure's answer: without it the verdicts below would be computed and\n // reported while the `!edited` return discarded the document they were\n // computed over — the defect surviving in a new shape, with the plan naming\n // a schema that never reached the living contract.\n const surfaces = mergeAsyncapiComponents({ living, featPlain, livingPlain, record, service });\n const { componentsModified, componentsQuoted, componentsStale } = surfaces;\n if (surfaces.copied) edited = true;\n\n // Nothing written: the living document must not even be re-serialized —\n // byte-identity under an all-quote delta is the whole point of the pin.\n if (!edited) {\n return {\n text: null, modified, removed, quoted, baselineStale,\n componentsModified, componentsQuoted, componentsStale, unresolved: [],\n };\n }\n\n let mergedPlain: unknown;\n let text: string;\n try {\n mergedPlain = living.toJS() ?? {};\n text = living.toString();\n } catch (error) {\n throw new AsyncapiMergeError(\"living\", service, errorMessage(error));\n }\n // The ref sweep grades what the MERGE would leave dangling: a merged slot\n // pointing at something neither document defines, or a removal that took a\n // target the living document still references. Refs already dangling in the\n // living contract are validate's finding (asyncapi.ref-unresolved, warn),\n // not this feature's doing — gating the archive on pre-existing rot would\n // block every delta over an already-rotten contract.\n const preexisting = new Set(danglingRefs(livingPlain));\n const unresolved = danglingRefs(mergedPlain).filter((ref) => !preexisting.has(ref));\n return {\n text, modified, removed, quoted, baselineStale,\n componentsModified, componentsQuoted, componentsStale, unresolved,\n };\n}\n\n/**\n * The successful \"the feature document restates nothing at all\" answer. Every\n * key of the result is spelled here, empty, rather than left off — the reason\n * `AsyncapiMergeResult` gives for the three surface fields.\n */\nfunction noop(): AsyncapiMergeResult {\n return {\n text: null, modified: [], removed: [], quoted: [], baselineStale: [],\n componentsModified: [], componentsQuoted: [], componentsStale: [], unresolved: [],\n };\n}\n"]}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * The pin that tells a QUOTE from an EDIT, on the event axis.
3
+ *
4
+ * A feature's asyncapi.yaml is a complete document, so most of what it spells
5
+ * is quotation: the author restated the living contract around the slot they
6
+ * were changing. Without a pin the merge cannot tell the two apart and
7
+ * upserts both — the exact silent-revert the OpenAPI axis's pin closed, with
8
+ * no overlap between two features required, just two deltas over one service.
9
+ *
10
+ * Separate from `./merge.ts` because this is `loam rebase`'s half: it plans
11
+ * the pins a delta is missing, while the merge only ever reads pins already
12
+ * written. Slot-keyed over the three named sections exactly as the merge
13
+ * upserts (core/asyncapi/digest.ts owns the walker and the section→path
14
+ * spelling); an inline channel message is channel-slot interior and is never
15
+ * pinned on its own — SCHEMA.md's recorded decision.
16
+ */
17
+ import { isMap, parseDocument } from "yaml";
18
+ import { AsyncapiMergeError, errorMessage } from "./error.js";
19
+ import { refuseAmbiguousSlotKeys, slotPair } from "./markers.js";
20
+ import { ASYNCAPI_BASELINE_KEY, asyncapiSlots, slotDigest, } from "../digest.js";
21
+ /**
22
+ * Pin every slot in a feature contract against the living one — what
23
+ * `loam rebase` writes on this axis.
24
+ *
25
+ * The pin is always `slotDigest` of the LIVING slot, never of the delta's
26
+ * own, and that single rule produces both merge verdicts by itself: a slot
27
+ * the author only QUOTED is byte-equal to living, so its pin equals its own
28
+ * content and classifies as a quote; one the author EDITED differs from its
29
+ * pin, so the merge writes it. A slot the living document lacks is
30
+ * `unresolved` and correct — there is no living version of a channel,
31
+ * operation or message the contract does not carry yet.
32
+ */
33
+ export function pinAsyncapiSlots(featureText, livingText, service) {
34
+ const doc = parseDocument(featureText);
35
+ if (doc.errors.length > 0)
36
+ throw new AsyncapiMergeError("feature", service, doc.errors[0].message);
37
+ refuseAmbiguousSlotKeys(doc, "feature", service);
38
+ let featPlain;
39
+ let livingPlain;
40
+ try {
41
+ featPlain = doc.toJS() ?? {};
42
+ }
43
+ catch (error) {
44
+ throw new AsyncapiMergeError("feature", service, errorMessage(error));
45
+ }
46
+ try {
47
+ const parsed = parseDocument(livingText);
48
+ if (parsed.errors.length > 0)
49
+ throw new AsyncapiMergeError("living", service, parsed.errors[0].message);
50
+ refuseAmbiguousSlotKeys(parsed, "living", service);
51
+ livingPlain = parsed.toJS() ?? {};
52
+ }
53
+ catch (error) {
54
+ if (error instanceof AsyncapiMergeError)
55
+ throw error;
56
+ throw new AsyncapiMergeError("living", service, errorMessage(error));
57
+ }
58
+ const livingBySlot = new Map(asyncapiSlots(livingPlain).map((slot) => [`${slot.section}\0${slot.key}`, slot]));
59
+ const pins = [];
60
+ let edited = false;
61
+ for (const slot of asyncapiSlots(featPlain)) {
62
+ // A removal marker asserts a slot rather than restating it, so it has
63
+ // nothing to be based on; `asyncapi.remove-target-missing/-mismatch`
64
+ // are what guard it against a living slot that moved under it.
65
+ if (slot.remove)
66
+ continue;
67
+ const at = { section: slot.section, key: slot.key };
68
+ const from = slot.basedOn ?? null;
69
+ const living = livingBySlot.get(`${slot.section}\0${slot.key}`);
70
+ if (living === undefined || living.node === null || typeof living.node !== "object" || Array.isArray(living.node)) {
71
+ pins.push({ ...at, status: "unresolved", from, to: null });
72
+ continue;
73
+ }
74
+ const digest = slotDigest(living.node);
75
+ if (from === digest) {
76
+ pins.push({ ...at, status: "unchanged", from: digest, to: digest });
77
+ continue;
78
+ }
79
+ // Located string-matched through the same door as every other slot
80
+ // access (markers.ts's slotPair): a channel written `404:` is the YAML
81
+ // number 404, which a raw `getIn("404")` misses — the miss used to grade
82
+ // every non-string-keyed slot `unwritable`, with an alias diagnosis
83
+ // nothing in the document backed, and the gate's own remedy was the
84
+ // command that had just refused. What stays refused: an aliased slot
85
+ // value (one shared value backs every use of an anchor, so stamping
86
+ // through it would pin every other use too — the OpenAPI pin's refusal,
87
+ // for the same data-loss reason) and a slot whose key is not a scalar,
88
+ // which no string can address.
89
+ const pair = slotPair(doc, slot.section, slot.key);
90
+ if (pair === undefined || !isMap(pair.value)) {
91
+ pins.push({ ...at, status: "unwritable", from, to: null });
92
+ continue;
93
+ }
94
+ pins.push({ ...at, status: from === null ? "pinned" : "repinned", from, to: digest });
95
+ pair.value.set(ASYNCAPI_BASELINE_KEY, digest);
96
+ edited = true;
97
+ }
98
+ if (!edited)
99
+ return { text: null, pins };
100
+ try {
101
+ return { text: doc.toString(), pins };
102
+ }
103
+ catch (error) {
104
+ throw new AsyncapiMergeError("feature", service, errorMessage(error));
105
+ }
106
+ }
107
+ //# sourceMappingURL=pin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pin.js","sourceRoot":"","sources":["../../../../src/core/asyncapi/merge/pin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The pin that tells a QUOTE from an EDIT, on the event axis.\n *\n * A feature's asyncapi.yaml is a complete document, so most of what it spells\n * is quotation: the author restated the living contract around the slot they\n * were changing. Without a pin the merge cannot tell the two apart and\n * upserts both — the exact silent-revert the OpenAPI axis's pin closed, with\n * no overlap between two features required, just two deltas over one service.\n *\n * Separate from `./merge.ts` because this is `loam rebase`'s half: it plans\n * the pins a delta is missing, while the merge only ever reads pins already\n * written. Slot-keyed over the three named sections exactly as the merge\n * upserts (core/asyncapi/digest.ts owns the walker and the section→path\n * spelling); an inline channel message is channel-slot interior and is never\n * pinned on its own — SCHEMA.md's recorded decision.\n */\nimport { isMap, parseDocument } from \"yaml\";\nimport { AsyncapiMergeError, errorMessage } from \"./error.js\";\nimport { refuseAmbiguousSlotKeys, slotPair } from \"./markers.js\";\nimport {\n ASYNCAPI_BASELINE_KEY,\n asyncapiSlots,\n slotDigest,\n type AsyncapiSection,\n} from \"../digest.js\";\n\n/** What happened to one slot's `x-loam-based-on`. */\nexport interface AsyncapiSlotPin {\n section: AsyncapiSection;\n key: string;\n status:\n /** It had no pin and now has one. */\n | \"pinned\"\n /** It named an older living version; it now names the current one. */\n | \"repinned\"\n /** It already named the current living version — no write. */\n | \"unchanged\"\n /** The living contract has no slot at this (section, key): this feature is adding it. */\n | \"unresolved\"\n /** Written as a YAML alias (one shared value backs every use) or under a key no string can address — loam will not stamp through either. */\n | \"unwritable\";\n from: string | null;\n to: string | null;\n}\n\nexport interface AsyncapiPinPlan {\n /** The rewritten contract, or null when no pin changes. */\n text: string | null;\n pins: AsyncapiSlotPin[];\n}\n\n/**\n * Pin every slot in a feature contract against the living one — what\n * `loam rebase` writes on this axis.\n *\n * The pin is always `slotDigest` of the LIVING slot, never of the delta's\n * own, and that single rule produces both merge verdicts by itself: a slot\n * the author only QUOTED is byte-equal to living, so its pin equals its own\n * content and classifies as a quote; one the author EDITED differs from its\n * pin, so the merge writes it. A slot the living document lacks is\n * `unresolved` and correct — there is no living version of a channel,\n * operation or message the contract does not carry yet.\n */\nexport function pinAsyncapiSlots(featureText: string, livingText: string, service: string): AsyncapiPinPlan {\n const doc = parseDocument(featureText);\n if (doc.errors.length > 0) throw new AsyncapiMergeError(\"feature\", service, doc.errors[0]!.message);\n refuseAmbiguousSlotKeys(doc, \"feature\", service);\n let featPlain: unknown;\n let livingPlain: unknown;\n try {\n featPlain = doc.toJS() ?? {};\n } catch (error) {\n throw new AsyncapiMergeError(\"feature\", service, errorMessage(error));\n }\n try {\n const parsed = parseDocument(livingText);\n if (parsed.errors.length > 0) throw new AsyncapiMergeError(\"living\", service, parsed.errors[0]!.message);\n refuseAmbiguousSlotKeys(parsed, \"living\", service);\n livingPlain = parsed.toJS() ?? {};\n } catch (error) {\n if (error instanceof AsyncapiMergeError) throw error;\n throw new AsyncapiMergeError(\"living\", service, errorMessage(error));\n }\n\n const livingBySlot = new Map(asyncapiSlots(livingPlain).map((slot) => [`${slot.section}\\0${slot.key}`, slot]));\n const pins: AsyncapiSlotPin[] = [];\n let edited = false;\n for (const slot of asyncapiSlots(featPlain)) {\n // A removal marker asserts a slot rather than restating it, so it has\n // nothing to be based on; `asyncapi.remove-target-missing/-mismatch`\n // are what guard it against a living slot that moved under it.\n if (slot.remove) continue;\n\n const at = { section: slot.section, key: slot.key };\n const from = slot.basedOn ?? null;\n const living = livingBySlot.get(`${slot.section}\\0${slot.key}`);\n if (living === undefined || living.node === null || typeof living.node !== \"object\" || Array.isArray(living.node)) {\n pins.push({ ...at, status: \"unresolved\", from, to: null });\n continue;\n }\n const digest = slotDigest(living.node);\n if (from === digest) {\n pins.push({ ...at, status: \"unchanged\", from: digest, to: digest });\n continue;\n }\n // Located string-matched through the same door as every other slot\n // access (markers.ts's slotPair): a channel written `404:` is the YAML\n // number 404, which a raw `getIn(\"404\")` misses — the miss used to grade\n // every non-string-keyed slot `unwritable`, with an alias diagnosis\n // nothing in the document backed, and the gate's own remedy was the\n // command that had just refused. What stays refused: an aliased slot\n // value (one shared value backs every use of an anchor, so stamping\n // through it would pin every other use too — the OpenAPI pin's refusal,\n // for the same data-loss reason) and a slot whose key is not a scalar,\n // which no string can address.\n const pair = slotPair(doc, slot.section, slot.key);\n if (pair === undefined || !isMap(pair.value)) {\n pins.push({ ...at, status: \"unwritable\", from, to: null });\n continue;\n }\n pins.push({ ...at, status: from === null ? \"pinned\" : \"repinned\", from, to: digest });\n pair.value.set(ASYNCAPI_BASELINE_KEY, digest);\n edited = true;\n }\n\n if (!edited) return { text: null, pins };\n try {\n return { text: doc.toString(), pins };\n } catch (error) {\n throw new AsyncapiMergeError(\"feature\", service, errorMessage(error));\n }\n}\n"]}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The read model of one AsyncAPI document — what `./read.ts`'s walk produces
3
+ * and every consumer of the axis branches on. Split from `read.ts` when the
4
+ * `asyncapiFromText` extraction pushed that module past the 300-line ceiling:
5
+ * the walk and its result are two subjects (`read.ts` says HOW a document is
6
+ * read, this file says WHAT a read answers), and the type block is the seam
7
+ * that already existed. The doctrine comments travel with the fields they
8
+ * explain — they are the documentation of the model, not of the walk.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/core/asyncapi/model.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG","sourcesContent":["/**\n * The read model of one AsyncAPI document — what `./read.ts`'s walk produces\n * and every consumer of the axis branches on. Split from `read.ts` when the\n * `asyncapiFromText` extraction pushed that module past the 300-line ceiling:\n * the walk and its result are two subjects (`read.ts` says HOW a document is\n * read, this file says WHAT a read answers), and the type block is the seam\n * that already existed. The doctrine comments travel with the fields they\n * explain — they are the documentation of the model, not of the walk.\n */\n\n/** One message declaration, as the reader sees it. */\nexport interface EventMessage {\n /**\n * The join token — what a landscape edge's `metadata { publishes }` and a\n * requirement's `Publishes:` line name.\n *\n * The Message Object's own `name` when it has one, otherwise the key it is\n * declared under. Both are legal AsyncAPI, and the key is what an author who\n * never wrote a `name` would reasonably expect to reference; falling back to\n * it means a minimal hand-written contract still joins to the spine.\n */\n name: string;\n /**\n * Where it was declared — `components.messages.<key>` or\n * `channels.<key>.messages.<key>`. Carried so `asyncapi.duplicate-message` can\n * name both slots instead of only saying that a name repeats, the way\n * `openapi.duplicate-operationid` names both `METHOD /path` slots.\n */\n slot: string;\n /**\n * Present when the declaration's payload defines no shape a consumer could\n * code against (`payloadUndeclared`, depth.ts). Set only when true, and\n * never set for a payload declaring a non-JSON `schemaFormat`.\n */\n payloadEmpty?: true;\n /**\n * Present when the declaration carries `x-loam-remove: true` — a FEATURE\n * delta retiring it. A marker asserts a slot rather than declaring a\n * message, so it joins nothing: excluded from sent/received and from\n * duplicate counting, the discipline `core/openapi/doc.ts` set for\n * operation markers. Set only when true, like `payloadEmpty`.\n */\n remove?: true;\n}\n\n/** The parse of one AsyncAPI document: what it declares, and whether it could be read at all. */\nexport interface AsyncapiDoc {\n /** Every message declaration in the document, in document order. */\n messages: EventMessage[];\n /** Message names reachable from an `action: send` operation — what this service PRODUCES. */\n sent: string[];\n /** Message names reachable from an `action: receive` operation — what this service CONSUMES. */\n received: string[];\n /**\n * Names declared in more than one slot. Every join on this axis is by name, so\n * two slots claiming one name is the same ambiguity `openapi.duplicate-operationid`\n * grades: the join picks one arbitrarily and the other declaration is invisible.\n */\n duplicateNames: string[];\n /**\n * True when the file EXISTS but cannot be read as an AsyncAPI document —\n * broken YAML, non-UTF-8 bytes, or a document that is not a mapping. A missing\n * file is not unreadable (absence is `service.no-asyncapi`'s question), and an\n * empty one parses to null and honestly declares nothing.\n */\n unreadable: boolean;\n /** The parser's own message, when there is one to quote back. */\n error?: string;\n /** Internal `#/` refs that resolve to nothing in this document (depth.ts). */\n danglingRefs: string[];\n /**\n * Where `x-loam-remove: true` appears — at ANY depth (digest.ts's\n * `removalMarkerPaths`): the three slot depths the format spec gives the\n * key meaning at, inline channel messages (channel-slot interior the merge\n * strips at that nested depth), and every place the key means nothing —\n * the document root, `info`, a `components` sibling. Feature-only\n * bookkeeping wherever it sits: `validate` grades any of these in a LIVING\n * contract as `asyncapi.remove-marker-living`, and the sweep is as deep as\n * the strip so a leaked marker can never be invisible to it.\n */\n markers: string[];\n}\n"]}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Who produces what across the fleet, read one contract at a time.
3
+ *
4
+ * Separate from `./read.ts` because it asks a question no single document can
5
+ * answer: a message's producer is a claim about some OTHER service's contract,
6
+ * so this walk is the only part of the axis whose answer depends on how much of
7
+ * the fleet was readable. That incompleteness is a value it returns, not a
8
+ * failure it hides — a consumer check that treated an unreadable producer as
9
+ * "nobody sends this" would report a phantom orphan.
10
+ */
11
+ import { readAsyncapi } from "./read.js";
12
+ import { locateServicePaths } from "../repo/service-target.js";
13
+ /**
14
+ * Which services in the fleet declare an `action: send` for each message name.
15
+ *
16
+ * The one question on this axis that no single repository can answer, and the
17
+ * reason `validate --service` reads more than its own service here: a consumer
18
+ * joins to a message the PRODUCER owns, so "does anybody publish this" is a
19
+ * fleet fact. Zero producers is `spine.message-unproduced`; two are
20
+ * `asyncapi.message-contested`, where every consumer's join picks one
21
+ * arbitrarily.
22
+ *
23
+ * The two answers rest on different evidence, and only one of them survives an
24
+ * unreadable contract. Finding two producers is POSITIVE evidence and stays
25
+ * true whatever else in the fleet fails to parse. Finding none is an argument
26
+ * from absence, and one broken file makes it worthless — skipping that service
27
+ * silently would turn its outage into one `spine.message-unproduced` per
28
+ * consuming edge across the whole fleet, every one of them pointing at the
29
+ * wrong repository. So the unreadable services are reported rather than
30
+ * skipped, and the caller suspends the negative answer while any exist.
31
+ *
32
+ * The cost is N small YAML parses, not N LikeC4 workspace spins — the latter is
33
+ * what makes `validate --all` expensive (SCHEMA.md, "Operating at fleet scale"),
34
+ * and a context memoizes these reads across the run.
35
+ */
36
+ export async function producersByMessage(docsDir, services, context) {
37
+ const byMessage = new Map();
38
+ const unreadable = [];
39
+ for (const service of services) {
40
+ const doc = await readAsyncapi((await locateServicePaths(docsDir, service, context)).asyncapi, context);
41
+ if (doc.unreadable) {
42
+ unreadable.push(service);
43
+ continue;
44
+ }
45
+ for (const name of doc.sent)
46
+ byMessage.set(name, [...(byMessage.get(name) ?? []), service]);
47
+ }
48
+ return { byMessage, unreadable };
49
+ }
50
+ //# sourceMappingURL=producers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"producers.js","sourceRoot":"","sources":["../../../src/core/asyncapi/producers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAGzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAe/D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAgB,EAChB,QAAoC,EACpC,OAAsB;IAEtB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC9C,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,CAAC,MAAM,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACxG,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;YACnB,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACzB,SAAS;QACX,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,IAAI;YAAE,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;AACnC,CAAC","sourcesContent":["/**\n * Who produces what across the fleet, read one contract at a time.\n *\n * Separate from `./read.ts` because it asks a question no single document can\n * answer: a message's producer is a claim about some OTHER service's contract,\n * so this walk is the only part of the axis whose answer depends on how much of\n * the fleet was readable. That incompleteness is a value it returns, not a\n * failure it hides — a consumer check that treated an unreadable producer as\n * \"nobody sends this\" would report a phantom orphan.\n */\nimport { readAsyncapi } from \"./read.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport type { PathableService } from \"../kernel/ids/service.js\";\nimport { locateServicePaths } from \"../repo/service-target.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\n\n/** Who produces what across the fleet, and whether that view is complete. */\nexport interface FleetProducers {\n /** Message name → the services declaring an `action: send` for it. */\n byMessage: Map<string, string[]>;\n /**\n * Services whose `asyncapi.yaml` exists and could not be read. Non-empty means\n * the ABSENCE of a producer proves nothing: one of these files may well\n * declare the message, and nobody can tell without fixing it first.\n */\n unreadable: string[];\n}\n\n/**\n * Which services in the fleet declare an `action: send` for each message name.\n *\n * The one question on this axis that no single repository can answer, and the\n * reason `validate --service` reads more than its own service here: a consumer\n * joins to a message the PRODUCER owns, so \"does anybody publish this\" is a\n * fleet fact. Zero producers is `spine.message-unproduced`; two are\n * `asyncapi.message-contested`, where every consumer's join picks one\n * arbitrarily.\n *\n * The two answers rest on different evidence, and only one of them survives an\n * unreadable contract. Finding two producers is POSITIVE evidence and stays\n * true whatever else in the fleet fails to parse. Finding none is an argument\n * from absence, and one broken file makes it worthless — skipping that service\n * silently would turn its outage into one `spine.message-unproduced` per\n * consuming edge across the whole fleet, every one of them pointing at the\n * wrong repository. So the unreadable services are reported rather than\n * skipped, and the caller suspends the negative answer while any exist.\n *\n * The cost is N small YAML parses, not N LikeC4 workspace spins — the latter is\n * what makes `validate --all` expensive (SCHEMA.md, \"Operating at fleet scale\"),\n * and a context memoizes these reads across the run.\n */\nexport async function producersByMessage(\n docsDir: DocsDir,\n services: readonly PathableService[],\n context?: FleetContext,\n): Promise<FleetProducers> {\n const byMessage = new Map<string, string[]>();\n const unreadable: string[] = [];\n for (const service of services) {\n const doc = await readAsyncapi((await locateServicePaths(docsDir, service, context)).asyncapi, context);\n if (doc.unreadable) {\n unreadable.push(service);\n continue;\n }\n for (const name of doc.sent) byMessage.set(name, [...(byMessage.get(name) ?? []), service]);\n }\n return { byMessage, unreadable };\n}\n\n"]}
@@ -2,9 +2,10 @@ import { isUtf8 } from "node:buffer";
2
2
  import { existsSync } from "node:fs";
3
3
  import { readFile } from "node:fs/promises";
4
4
  import { parse } from "yaml";
5
- import { servicePaths } from "./repo.js";
5
+ import { danglingRefs, deref, payloadUndeclared } from "./depth.js";
6
+ import { isSlotRemoval, removalMarkerPaths } from "./digest.js";
6
7
  /**
7
- * The async contract axis: AsyncAPI 3.0, read the way `core/openapi.ts` reads
8
+ * The async contract axis: AsyncAPI 3.0, read the way `core/openapi/doc.ts` reads
8
9
  * OpenAPI — a shallow structural walk over the `yaml` parse, never a real
9
10
  * AsyncAPI parser. `@asyncapi/parser` would be a fourth runtime dependency
10
11
  * (AGENTS.md: adding one is a product decision), and loam needs a slice of the
@@ -18,71 +19,34 @@ import { servicePaths } from "./repo.js";
18
19
  * declares no `operations` at all — so it reads as a contract with no messages
19
20
  * rather than as a silently mis-parsed one.
20
21
  *
21
- * WHAT THIS READER MUST NEVER DO: look inside a message's `payload`. The payload
22
- * is JSON Schema today and may be Avro later, and that switch is meant to be a
23
- * line in the document (`schemaFormat`) rather than a branch in loam. Every
24
- * check on this axis joins on a message NAME; nothing joins on a field. The day
25
- * something here reads a `required` array or a `fields` list, the Avro migration
26
- * stops being free.
22
+ * WHAT THIS READER MUST NEVER DO: join on anything inside a message's `payload`.
23
+ * The payload is JSON Schema today and may be Avro later, and that switch is
24
+ * meant to be a line in the document (`schemaFormat`) rather than a branch in
25
+ * loam. Every check on this axis joins on a message NAME; nothing joins on a
26
+ * field, and nothing under `payload` may ever contribute one. The day
27
+ * something here reads a `required` array or a `fields` list INTO A JOIN, the
28
+ * Avro migration stops being free. The one look the reader takes inside is
29
+ * `payloadUndeclared` (depth.ts) — a presence probe that checks whether any
30
+ * shape was declared at all, reads key existence and never a value, and skips
31
+ * any payload declaring a non-JSON `schemaFormat`, so the stance holds. The
32
+ * slot digests (./digest.ts) are COMPATIBLE with it, not an exception: they
33
+ * hash payload bytes as content equality — a changed payload moves the slot's
34
+ * identity — and content equality is not a join; nothing a digest reads ever
35
+ * contributes a name to the spine.
27
36
  */
28
- /** How deep a `$ref` chain is followed before the reader gives up. */
29
- const MAX_REF_DEPTH = 8;
30
- /**
31
- * Resolve an internal JSON Pointer (`#/a/b/c`) against the document root.
32
- *
33
- * Internal only, matching the OpenAPI axis's documented stance: external
34
- * references — URLs, file paths, anything not starting `#/` — are out of scope,
35
- * left untouched and never graded. That is also why authors are told to keep
36
- * payloads inside the document rather than `$ref`-ing an external `.avsc`: the
37
- * merge cannot carry what this reader cannot see.
37
+ /*
38
+ * The `EventMessage`/`AsyncapiDoc` read model lives in `./model.ts` — split
39
+ * there when the `asyncapiFromText` extraction pushed this module past the
40
+ * 300-line ceiling. This module keeps the walk; that one keeps what the walk
41
+ * answers.
38
42
  */
39
- function resolvePointer(root, ref) {
40
- if (typeof ref !== "string" || !ref.startsWith("#/"))
41
- return undefined;
42
- let node = root;
43
- for (const raw of ref.slice(2).split("/")) {
44
- // JSON Pointer escaping, `~1` before `~0` so an encoded `~1` survives.
45
- const seg = raw.replace(/~1/g, "/").replace(/~0/g, "~");
46
- if (node === null || typeof node !== "object")
47
- return undefined;
48
- node = node[seg];
49
- }
50
- return node;
51
- }
52
43
  /**
53
- * Follow `$ref` hops until a node that is not a reference, or the depth budget
54
- * runs out. The budget is the cycle guard: a document whose `$ref` points at
55
- * itself is legal YAML, and an unbounded walk would hang the whole validate run
56
- * rather than reporting a contract nobody can read.
57
- *
58
- * Returns the resolved node and the last pointer segment that reached it — the
59
- * segment is the declaration key, which is the message-name fallback, and it is
60
- * lost by the time a caller holds only the node.
44
+ * A message's join token: its `name`, or the key it is declared under.
45
+ * Exported for the merge (./merge/merge.ts), whose removal exactness compares
46
+ * this same spelling — a second definition of the fallback rule is how a
47
+ * marker would delete a message the reader joins under a different name.
61
48
  */
62
- function deref(root, node, key) {
63
- let current = node;
64
- let currentKey = key;
65
- for (let hop = 0; hop < MAX_REF_DEPTH; hop += 1) {
66
- if (current === null || typeof current !== "object" || Array.isArray(current))
67
- break;
68
- const ref = current["$ref"];
69
- if (typeof ref !== "string")
70
- break;
71
- const resolved = resolvePointer(root, ref);
72
- if (resolved === undefined)
73
- return { node: undefined, key: currentKey };
74
- const seg = ref.slice(ref.lastIndexOf("/") + 1);
75
- current = resolved;
76
- // An alias keeps the TARGET's key, not the local one it was filed under: a
77
- // channel may list `#/components/messages/PaymentAuthorized` under any alias
78
- // it likes, and the fallback name has to be the declaration's own identity
79
- // or two services aliasing one message differently would stop joining.
80
- currentKey = seg.length > 0 ? seg : currentKey;
81
- }
82
- return { node: current, key: currentKey };
83
- }
84
- /** A message's join token: its `name`, or the key it is declared under. */
85
- function messageName(node, key) {
49
+ export function messageName(node, key) {
86
50
  if (node !== null && typeof node === "object" && !Array.isArray(node)) {
87
51
  const name = node["name"];
88
52
  if (typeof name === "string" && name.trim().length > 0)
@@ -124,13 +88,34 @@ export async function readAsyncapi(asyncapiPath, context) {
124
88
  // document nobody wrote. The openapi axis learned this the same way.
125
89
  if (!isUtf8(bytes))
126
90
  return { ...empty(), unreadable: true, error: "file is not valid UTF-8" };
91
+ return asyncapiFromText(bytes.toString("utf8"));
92
+ }
93
+ /**
94
+ * The same read over text already in hand — the parse half of `readAsyncapi`,
95
+ * split out so `loam diff` can read a contract fetched from a base git ref
96
+ * (core/diff/base-state.ts) without writing it to disk. The YAML-throw catch
97
+ * lives here and nowhere else; `asyncapiDocOf` below owns everything after
98
+ * the parse, and the byte concerns (existence, UTF-8) stay with the reader
99
+ * that holds the bytes.
100
+ */
101
+ export function asyncapiFromText(text) {
127
102
  let doc;
128
103
  try {
129
- doc = parse(bytes.toString("utf8"));
104
+ doc = parse(text);
130
105
  }
131
106
  catch (e) {
132
107
  return { ...empty(), unreadable: true, error: e instanceof Error ? e.message : String(e) };
133
108
  }
109
+ return asyncapiDocOf(doc);
110
+ }
111
+ /**
112
+ * The same read over an already-parsed root — what the coherence gate's
113
+ * merge simulation grades (core/coherence/events/), where the "file" is a
114
+ * document the merge computed and never wrote. One spelling of the walk for
115
+ * both entries, so a simulated contract can never read differently from the
116
+ * living file the archive would produce from it.
117
+ */
118
+ export function asyncapiDocOf(doc) {
134
119
  // A scalar or sequence document has no mapping to look `channels` up in, so
135
120
  // nothing can be concluded from it. null (an empty file) stays readable — it
136
121
  // declares nothing, and says so honestly.
@@ -142,13 +127,20 @@ export async function readAsyncapi(asyncapiPath, context) {
142
127
  const root = doc;
143
128
  const messages = [];
144
129
  const seen = new Map();
145
- const declare = (name, slot) => {
146
- messages.push({ name, slot });
130
+ const declare = (name, slot, node) => {
131
+ // A declaration carrying the removal marker asserts a slot rather than
132
+ // declaring a message: it is listed (with `remove`) so the gate can see
133
+ // it, but it joins nothing — not sent/received, not the duplicate count.
134
+ if (isSlotRemoval(node)) {
135
+ messages.push({ name, slot, remove: true });
136
+ return;
137
+ }
138
+ messages.push({ name, slot, ...(payloadUndeclared(root, node) ? { payloadEmpty: true } : {}) });
147
139
  seen.set(name, [...(seen.get(name) ?? []), slot]);
148
140
  };
149
141
  // `components.messages` — the ordinary place a message is declared.
150
142
  for (const [key, node] of entriesOf(root["components"]?.["messages"])) {
151
- declare(messageName(node, key), `components.messages.${key}`);
143
+ declare(messageName(node, key), `components.messages.${key}`, node);
152
144
  }
153
145
  // `channels.<ck>.messages.<mk>` — an entry here is either an ALIAS of a
154
146
  // components declaration (a `$ref`) or an inline declaration of its own. Only
@@ -157,14 +149,25 @@ export async function readAsyncapi(asyncapiPath, context) {
157
149
  // spec's own examples use.
158
150
  const channelMessages = new Map();
159
151
  for (const [ck, channel] of entriesOf(root["channels"])) {
152
+ // A channel-slot removal retires the whole channel, inline interior
153
+ // included: nothing under it declares or joins anything any more.
154
+ if (isSlotRemoval(channel)) {
155
+ channelMessages.set(ck, []);
156
+ continue;
157
+ }
160
158
  const names = [];
161
159
  for (const [mk, entry] of entriesOf(channel?.["messages"])) {
162
160
  const isAlias = entry !== null && typeof entry === "object" && !Array.isArray(entry) && "$ref" in entry;
163
161
  const { node, key } = deref(root, entry, mk);
164
162
  const name = messageName(node, key);
165
- names.push(name);
163
+ // A name whose declaration is being retired stays off the channel's
164
+ // list, whether the marker sits on the aliased components entry or on
165
+ // the inline declaration itself — the operation fallback below must
166
+ // not join through a message the feature is removing.
167
+ if (!isSlotRemoval(node))
168
+ names.push(name);
166
169
  if (!isAlias)
167
- declare(name, `channels.${ck}.messages.${mk}`);
170
+ declare(name, `channels.${ck}.messages.${mk}`, node);
168
171
  }
169
172
  channelMessages.set(ck, names);
170
173
  }
@@ -172,6 +175,10 @@ export async function readAsyncapi(asyncapiPath, context) {
172
175
  const received = new Set();
173
176
  for (const [, operation] of entriesOf(root["operations"])) {
174
177
  const op = operation;
178
+ // An operation-slot removal retires the operation: it contributes no
179
+ // send/receive whatever its `action` says.
180
+ if (isSlotRemoval(op))
181
+ continue;
175
182
  const action = op?.["action"];
176
183
  if (action !== "send" && action !== "receive")
177
184
  continue;
@@ -189,6 +196,10 @@ export async function readAsyncapi(asyncapiPath, context) {
189
196
  // the service produces.
190
197
  if (node === undefined && key === "")
191
198
  continue;
199
+ // A pointer into a declaration being retired joins nothing either —
200
+ // the marker means the message is leaving the contract.
201
+ if (isSlotRemoval(node))
202
+ continue;
192
203
  const name = messageName(node, key);
193
204
  if (name.length > 0)
194
205
  into.add(name);
@@ -204,50 +215,25 @@ export async function readAsyncapi(asyncapiPath, context) {
204
215
  into.add(name);
205
216
  }
206
217
  const duplicateNames = [...seen].filter(([, slots]) => slots.length > 1).map(([name]) => name);
207
- return { messages, sent: [...sent], received: [...received], duplicateNames, unreadable: false };
218
+ return {
219
+ messages,
220
+ sent: [...sent],
221
+ received: [...received],
222
+ duplicateNames,
223
+ unreadable: false,
224
+ danglingRefs: danglingRefs(root),
225
+ // One deep scan rather than pushes scattered through the walk above: the
226
+ // walk only visits the depths that JOIN, and a marker leaked anywhere
227
+ // else (the root, `info`) was invisible to the living sweep while the
228
+ // strip still owed its removal.
229
+ markers: removalMarkerPaths(root, ""),
230
+ };
208
231
  }
209
232
  function empty() {
210
- return { messages: [], sent: [], received: [], duplicateNames: [], unreadable: false };
233
+ return { messages: [], sent: [], received: [], duplicateNames: [], unreadable: false, danglingRefs: [], markers: [] };
211
234
  }
212
235
  /** The slots one message name is declared in — what `asyncapi.duplicate-message` names. */
213
236
  export function slotsOf(doc, name) {
214
237
  return doc.messages.filter((m) => m.name === name).map((m) => m.slot);
215
238
  }
216
- /**
217
- * Which services in the fleet declare an `action: send` for each message name.
218
- *
219
- * The one question on this axis that no single repository can answer, and the
220
- * reason `validate --service` reads more than its own service here: a consumer
221
- * joins to a message the PRODUCER owns, so "does anybody publish this" is a
222
- * fleet fact. Zero producers is `spine.message-unproduced`; two are
223
- * `asyncapi.message-contested`, where every consumer's join picks one
224
- * arbitrarily.
225
- *
226
- * The two answers rest on different evidence, and only one of them survives an
227
- * unreadable contract. Finding two producers is POSITIVE evidence and stays
228
- * true whatever else in the fleet fails to parse. Finding none is an argument
229
- * from absence, and one broken file makes it worthless — skipping that service
230
- * silently would turn its outage into one `spine.message-unproduced` per
231
- * consuming edge across the whole fleet, every one of them pointing at the
232
- * wrong repository. So the unreadable services are reported rather than
233
- * skipped, and the caller suspends the negative answer while any exist.
234
- *
235
- * The cost is N small YAML parses, not N LikeC4 workspace spins — the latter is
236
- * what makes `validate --all` expensive (SCHEMA.md, "Operating at fleet scale"),
237
- * and a context memoizes these reads across the run.
238
- */
239
- export async function producersByMessage(docsDir, services, context) {
240
- const byMessage = new Map();
241
- const unreadable = [];
242
- for (const service of services) {
243
- const doc = await readAsyncapi(servicePaths(docsDir, service).asyncapi, context);
244
- if (doc.unreadable) {
245
- unreadable.push(service);
246
- continue;
247
- }
248
- for (const name of doc.sent)
249
- byMessage.set(name, [...(byMessage.get(name) ?? []), service]);
250
- }
251
- return { byMessage, unreadable };
252
- }
253
- //# sourceMappingURL=asyncapi.js.map
239
+ //# sourceMappingURL=read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/core/asyncapi/read.ts"],"names":[],"mappings":"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","sourcesContent":["import { isUtf8 } from \"node:buffer\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { parse } from \"yaml\";\nimport { danglingRefs, deref, payloadUndeclared } from \"./depth.js\";\nimport { isSlotRemoval, removalMarkerPaths } from \"./digest.js\";\nimport type { AsyncapiDoc, EventMessage } from \"./model.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\n\n/**\n * The async contract axis: AsyncAPI 3.0, read the way `core/openapi/doc.ts` reads\n * OpenAPI — a shallow structural walk over the `yaml` parse, never a real\n * AsyncAPI parser. `@asyncapi/parser` would be a fourth runtime dependency\n * (AGENTS.md: adding one is a product decision), and loam needs a slice of the\n * document so thin that the parser's whole model would be dead weight.\n *\n * 3.0 only, deliberately. Its operations are named top-level objects carrying\n * `action: send|receive`, which is the exact analog of an `operationId`; 2.x\n * spells the same thing as `publish`/`subscribe` nested under a channel, where\n * the two words are notoriously ambiguous about whose perspective they take.\n * Supporting one dialect is cheaper than supporting two, and a 2.x document\n * declares no `operations` at all — so it reads as a contract with no messages\n * rather than as a silently mis-parsed one.\n *\n * WHAT THIS READER MUST NEVER DO: join on anything inside a message's `payload`.\n * The payload is JSON Schema today and may be Avro later, and that switch is\n * meant to be a line in the document (`schemaFormat`) rather than a branch in\n * loam. Every check on this axis joins on a message NAME; nothing joins on a\n * field, and nothing under `payload` may ever contribute one. The day\n * something here reads a `required` array or a `fields` list INTO A JOIN, the\n * Avro migration stops being free. The one look the reader takes inside is\n * `payloadUndeclared` (depth.ts) — a presence probe that checks whether any\n * shape was declared at all, reads key existence and never a value, and skips\n * any payload declaring a non-JSON `schemaFormat`, so the stance holds. The\n * slot digests (./digest.ts) are COMPATIBLE with it, not an exception: they\n * hash payload bytes as content equality — a changed payload moves the slot's\n * identity — and content equality is not a join; nothing a digest reads ever\n * contributes a name to the spine.\n */\n\n/*\n * The `EventMessage`/`AsyncapiDoc` read model lives in `./model.ts` — split\n * there when the `asyncapiFromText` extraction pushed this module past the\n * 300-line ceiling. This module keeps the walk; that one keeps what the walk\n * answers.\n */\n\n/**\n * A message's join token: its `name`, or the key it is declared under.\n * Exported for the merge (./merge/merge.ts), whose removal exactness compares\n * this same spelling — a second definition of the fallback rule is how a\n * marker would delete a message the reader joins under a different name.\n */\nexport function messageName(node: unknown, key: string): string {\n if (node !== null && typeof node === \"object\" && !Array.isArray(node)) {\n const name = (node as Record<string, unknown>)[\"name\"];\n if (typeof name === \"string\" && name.trim().length > 0) return name.trim();\n }\n return key;\n}\n\n/** Entries of a mapping node, or nothing — every structural read here goes through it. */\nfunction entriesOf(node: unknown): [string, unknown][] {\n if (node === null || typeof node !== \"object\" || Array.isArray(node)) return [];\n return Object.entries(node as Record<string, unknown>);\n}\n\n/**\n * Read an AsyncAPI 3.0 document into the slice loam joins on: the messages it\n * declares, and which of them it sends and receives.\n *\n * The send/receive sets are what make the spine directional, and the direction\n * is not decoration: on the HTTP axis the PROVIDER owns the contract and a\n * consumer's edge is checked against it, while here the PRODUCER owns the\n * message and a consumer joins to it from another repository entirely. That\n * inversion is why `spine.message-unproduced` has no OpenAPI analog.\n *\n * An unreadable document yields empty sets PLUS the `unreadable` flag, the\n * policy every reader here follows: parsers never diagnose. Swallowing the\n * failure into empty sets would make a broken contract indistinguishable from\n * one that declares nothing, and every inbound edge would be graded\n * `spine.message-undefined` — a false diagnosis pointing at the landscape when\n * the truth is this file.\n */\nexport async function readAsyncapi(asyncapiPath: string, context?: FleetContext): Promise<AsyncapiDoc> {\n if (context !== undefined) return context.readAsyncapi(asyncapiPath);\n if (!existsSync(asyncapiPath)) return empty();\n const bytes = await readFile(asyncapiPath);\n // Bytes that are not UTF-8 are as unreadable as broken YAML and for a worse\n // reason: `toString(\"utf8\")` substitutes U+FFFD and hands the parser a\n // document nobody wrote. The openapi axis learned this the same way.\n if (!isUtf8(bytes)) return { ...empty(), unreadable: true, error: \"file is not valid UTF-8\" };\n return asyncapiFromText(bytes.toString(\"utf8\"));\n}\n\n/**\n * The same read over text already in hand — the parse half of `readAsyncapi`,\n * split out so `loam diff` can read a contract fetched from a base git ref\n * (core/diff/base-state.ts) without writing it to disk. The YAML-throw catch\n * lives here and nowhere else; `asyncapiDocOf` below owns everything after\n * the parse, and the byte concerns (existence, UTF-8) stay with the reader\n * that holds the bytes.\n */\nexport function asyncapiFromText(text: string): AsyncapiDoc {\n let doc: unknown;\n try {\n doc = parse(text);\n } catch (e) {\n return { ...empty(), unreadable: true, error: e instanceof Error ? e.message : String(e) };\n }\n return asyncapiDocOf(doc);\n}\n\n/**\n * The same read over an already-parsed root — what the coherence gate's\n * merge simulation grades (core/coherence/events/), where the \"file\" is a\n * document the merge computed and never wrote. One spelling of the walk for\n * both entries, so a simulated contract can never read differently from the\n * living file the archive would produce from it.\n */\nexport function asyncapiDocOf(doc: unknown): AsyncapiDoc {\n // A scalar or sequence document has no mapping to look `channels` up in, so\n // nothing can be concluded from it. null (an empty file) stays readable — it\n // declares nothing, and says so honestly.\n if (doc !== null && (typeof doc !== \"object\" || Array.isArray(doc))) {\n return { ...empty(), unreadable: true, error: \"document is not a YAML mapping\" };\n }\n if (doc === null) return empty();\n\n const root = doc as Record<string, unknown>;\n const messages: EventMessage[] = [];\n const seen = new Map<string, string[]>();\n const declare = (name: string, slot: string, node: unknown): void => {\n // A declaration carrying the removal marker asserts a slot rather than\n // declaring a message: it is listed (with `remove`) so the gate can see\n // it, but it joins nothing — not sent/received, not the duplicate count.\n if (isSlotRemoval(node)) {\n messages.push({ name, slot, remove: true as const });\n return;\n }\n messages.push({ name, slot, ...(payloadUndeclared(root, node) ? { payloadEmpty: true as const } : {}) });\n seen.set(name, [...(seen.get(name) ?? []), slot]);\n };\n\n // `components.messages` — the ordinary place a message is declared.\n for (const [key, node] of entriesOf((root[\"components\"] as Record<string, unknown> | undefined)?.[\"messages\"])) {\n declare(messageName(node, key), `components.messages.${key}`, node);\n }\n\n // `channels.<ck>.messages.<mk>` — an entry here is either an ALIAS of a\n // components declaration (a `$ref`) or an inline declaration of its own. Only\n // the second is a new slot: counting an alias would report every properly\n // factored document as declaring each message twice, which is the shape the\n // spec's own examples use.\n const channelMessages = new Map<string, string[]>();\n for (const [ck, channel] of entriesOf(root[\"channels\"])) {\n // A channel-slot removal retires the whole channel, inline interior\n // included: nothing under it declares or joins anything any more.\n if (isSlotRemoval(channel)) {\n channelMessages.set(ck, []);\n continue;\n }\n const names: string[] = [];\n for (const [mk, entry] of entriesOf((channel as Record<string, unknown> | null)?.[\"messages\"])) {\n const isAlias =\n entry !== null && typeof entry === \"object\" && !Array.isArray(entry) && \"$ref\" in (entry as object);\n const { node, key } = deref(root, entry, mk);\n const name = messageName(node, key);\n // A name whose declaration is being retired stays off the channel's\n // list, whether the marker sits on the aliased components entry or on\n // the inline declaration itself — the operation fallback below must\n // not join through a message the feature is removing.\n if (!isSlotRemoval(node)) names.push(name);\n if (!isAlias) declare(name, `channels.${ck}.messages.${mk}`, node);\n }\n channelMessages.set(ck, names);\n }\n\n const sent = new Set<string>();\n const received = new Set<string>();\n for (const [, operation] of entriesOf(root[\"operations\"])) {\n const op = operation as Record<string, unknown> | null;\n // An operation-slot removal retires the operation: it contributes no\n // send/receive whatever its `action` says.\n if (isSlotRemoval(op)) continue;\n const action = op?.[\"action\"];\n if (action !== \"send\" && action !== \"receive\") continue;\n const into = action === \"send\" ? sent : received;\n // The channel this operation acts on, by pointer — its key is what the\n // fallback below indexes.\n const channelRef = (op?.[\"channel\"] as Record<string, unknown> | undefined)?.[\"$ref\"];\n const channelKey = typeof channelRef === \"string\" ? channelRef.slice(channelRef.lastIndexOf(\"/\") + 1) : undefined;\n const listed = op?.[\"messages\"];\n if (Array.isArray(listed) && listed.length > 0) {\n for (const entry of listed) {\n const { node, key } = deref(root, entry, \"\");\n // A pointer that resolves nowhere contributes no name rather than an\n // empty one: a phantom \"\" would join to nothing and read as a message\n // the service produces.\n if (node === undefined && key === \"\") continue;\n // A pointer into a declaration being retired joins nothing either —\n // the marker means the message is leaving the contract.\n if (isSlotRemoval(node)) continue;\n const name = messageName(node, key);\n if (name.length > 0) into.add(name);\n }\n continue;\n }\n // AsyncAPI 3: an operation that lists no messages applies to every message\n // of its channel. Omitting the list is the normal shape of a minimal\n // hand-written contract — exactly what a fleet with no registry writes — so\n // reading it as \"produces nothing\" would report the common case broken.\n if (channelKey !== undefined) for (const name of channelMessages.get(channelKey) ?? []) into.add(name);\n }\n\n const duplicateNames = [...seen].filter(([, slots]) => slots.length > 1).map(([name]) => name);\n return {\n messages,\n sent: [...sent],\n received: [...received],\n duplicateNames,\n unreadable: false,\n danglingRefs: danglingRefs(root),\n // One deep scan rather than pushes scattered through the walk above: the\n // walk only visits the depths that JOIN, and a marker leaked anywhere\n // else (the root, `info`) was invisible to the living sweep while the\n // strip still owed its removal.\n markers: removalMarkerPaths(root, \"\"),\n };\n}\n\nfunction empty(): AsyncapiDoc {\n return { messages: [], sent: [], received: [], duplicateNames: [], unreadable: false, danglingRefs: [], markers: [] };\n}\n\n/** The slots one message name is declared in — what `asyncapi.duplicate-message` names. */\nexport function slotsOf(doc: AsyncapiDoc, name: string): string[] {\n return doc.messages.filter((m) => m.name === name).map((m) => m.slot);\n}\n\n"]}