@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":"facts.js","sourceRoot":"","sources":["../../../src/core/dependencies/facts.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What one feature ADDS and what it NEEDS, read out of its own delta.\n *\n * The whole graph is built from these five lists and nothing else, which is why\n * they are computed once per feature and indexed rather than re-derived per\n * edge: a feature is a node here only because some other feature's requirement\n * or operation resolves into it, and answering that per pair would be a fleet\n * walk per pair.\n *\n * `reqKeys` returns BOTH spellings of a requirement's identity — the stable\n * `Requirement-ID` and the exact heading — because a legacy requirement has only\n * the second, and an edge that existed under one spelling and not the other\n * would make the graph depend on when the corpus was migrated.\n */\nimport { existsSync } from \"node:fs\";\nimport type { PathableService } from \"../kernel/ids/service.js\";\nimport { FleetContext } from \"../fleet-context.js\";\nimport { serviceResolver } from \"../c4/resolve/service.js\";\nimport { operations } from \"../openapi/doc.js\";\nimport { type FeatureEntry } from \"../repo/entries.js\";\nimport { SPEC_AXES, featurePaths, featureSpecPaths, type SpecAxis } from \"../repo/paths.js\";\nimport { locateServicePaths } from \"../repo/service-target.js\";\nimport { enumeratedServiceIds, enumeratedServiceIndex } from \"../repo/service-target.js\";\nimport type { Requirement } from \"../document/spec.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\n\nexport type DependencyReason =\n | {\n kind: \"requirement\";\n service: string;\n axis: SpecAxis[\"file\"];\n identity: string;\n }\n | { kind: \"operation\"; service: string; operationId: string };\n\nexport interface DependencyEdge {\n /** The feature that consumes/modifies something. */\n from: string;\n /** The feature that introduces it and therefore has to land first. */\n to: string;\n reasons: DependencyReason[];\n}\n\nexport interface FeatureConflict {\n kind: \"requirement\" | \"operation\";\n /**\n * How the owners collide.\n *\n * `added` — two features ADD the same identity (or define the same\n * operationId): whichever archives second replaces the first outright.\n *\n * `changed` — two features MODIFY or REMOVE the same living requirement.\n * That collision was invisible until now, and it is the more common one on a\n * fleet: nobody adds \"Cancel an order\" twice, but two teams editing its text\n * in the same week is a Tuesday. A MODIFIED requirement carries its FULL new\n * text, so the second archive does not merge the first one's wording — it\n * overwrites it, silently and completely.\n */\n change: \"added\" | \"changed\";\n service: string;\n axis?: SpecAxis[\"file\"];\n identity: string;\n features: string[];\n}\n\nexport interface DependencyNode {\n id: string;\n dirName: string;\n services: string[];\n dependsOn: string[];\n}\n\nexport interface DependencyGraph {\n nodes: DependencyNode[];\n edges: DependencyEdge[];\n conflicts: FeatureConflict[];\n /** Dependencies precede their consumers; cyclic members remain deterministic. */\n order: string[];\n /** Strongly connected components with more than one node (or a self-loop). */\n cycles: string[][];\n}\n\nexport interface FeatureFacts {\n feature: FeatureEntry;\n addedRequirements: Array<{\n service: string;\n axis: SpecAxis[\"file\"];\n requirement: Requirement;\n }>;\n changedRequirements: Array<{\n service: string;\n axis: SpecAxis[\"file\"];\n requirement: Requirement;\n }>;\n introducedOperations: Array<{ service: string; operationId: string }>;\n requiredOperations: Array<{ service: string; operationId: string }>;\n}\n\nexport function reqKeys(requirement: Pick<Requirement, \"id\" | \"name\">): string[] {\n return [\n ...(requirement.id === undefined ? [] : [`id:${requirement.id}`]),\n `name:${requirement.name}`,\n ];\n}\n\n/**\n * WHERE a collision happens, kept as fields rather than as a string.\n *\n * An index needs one scalar per entry to hash on, so the fields get NUL-joined\n * into a key — but the conflict records want those fields back, and splitting\n * the key apart again means asserting the pieces back into their types. That\n * assertion is a claim about data loam does not own: a service directory or a\n * requirement name containing a NUL would hand `axis` a fragment of an identity\n * with nothing to notice. Carrying the structured value beside the owner set\n * means the key is only ever a key, and the record is read, not reconstructed.\n */\nexport interface ReqAt {\n service: string;\n axis: SpecAxis[\"file\"];\n identity: string;\n}\n\nexport interface OpAt {\n service: string;\n operationId: string;\n}\n\nexport interface Owners<T> {\n readonly at: T;\n readonly features: Set<string>;\n}\n\nexport function reqIndexKey(at: ReqAt): string {\n return `${at.service}\\0${at.axis}\\0${at.identity}`;\n}\n\nexport function opIndexKey(at: OpAt): string {\n return `${at.service}\\0${at.operationId}`;\n}\n\nexport function addOwner<T>(index: Map<string, Owners<T>>, key: string, at: T, feature: string): void {\n const owners = index.get(key) ?? { at, features: new Set<string>() };\n owners.features.add(feature);\n index.set(key, owners);\n}\n\nexport async function readFacts(\n docsDir: DocsDir,\n feature: FeatureEntry,\n context: FleetContext,\n): Promise<FeatureFacts> {\n const addedRequirements: FeatureFacts[\"addedRequirements\"] = [];\n const changedRequirements: FeatureFacts[\"changedRequirements\"] = [];\n const introducedOperations: FeatureFacts[\"introducedOperations\"] = [];\n const requiredOperations: FeatureFacts[\"requiredOperations\"] = [];\n\n /**\n * The operationIds a service ALREADY has, per service.\n *\n * This is the whole difference between a dependency graph and a rumour mill.\n * A feature's `openapi.yaml` is a COMPLETE document, not a patch — authors\n * restate the living API around the slot they are changing — so every feature\n * that so much as mentions `authorizePayment` used to be recorded as\n * INTRODUCING it, and every other feature governing it as REQUIRING it. Two\n * features quoting the same living operation therefore depended on each other\n * in both directions: an invented cycle, an invented conflict, and an ordering\n * for work that had none. `loam validate`'s coherence pass already subtracts\n * the living contract this way (core/coherence/coherence.ts); this is the\n * same subtraction, so the two cannot disagree about what \"new\" means.\n *\n * Cached per service inside the call and, through the FleetContext, across\n * features: a fleet-wide graph asks about the same ten services N times.\n */\n const livingByService = new Map<string, Set<string>>();\n const living = async (service: PathableService): Promise<Set<string>> => {\n let ids = livingByService.get(service);\n if (ids === undefined) {\n ids = new Set(\n (await operations((await locateServicePaths(docsDir, service, context)).openapi, context))\n .filter((op) => !op.remove)\n .map((op) => op.id),\n );\n livingByService.set(service, ids);\n }\n return ids;\n };\n\n for (const service of feature.services) {\n const paths = featureSpecPaths(feature.dir, service);\n const livingIds = await living(service);\n for (const axis of SPEC_AXES) {\n const path = paths[axis.key];\n if (!existsSync(path)) continue;\n const requirements = await context.readRequirements(path);\n for (const requirement of requirements) {\n const fact = { service, axis: axis.file, requirement };\n if (requirement.kind === \"ADDED\") addedRequirements.push(fact);\n if (requirement.kind === \"MODIFIED\" || requirement.kind === \"REMOVED\") {\n changedRequirements.push(fact);\n }\n for (const operationId of requirement.operations) {\n // Governing an operation the service already provides is not a\n // dependency on anybody: the contract it needs is already merged.\n if (livingIds.has(operationId)) continue;\n requiredOperations.push({ service, operationId });\n }\n }\n }\n\n if (existsSync(paths.openapi)) {\n const featureOperations = await operations(paths.openapi, context);\n for (const operation of featureOperations) {\n if (livingIds.has(operation.id)) continue;\n if (operation.remove) requiredOperations.push({ service, operationId: operation.id });\n else introducedOperations.push({ service, operationId: operation.id });\n }\n }\n }\n\n // The C4 delta is the FOURTH place a feature names an operation, and it was\n // the one the graph could not see: an edge carrying `metadata { op 'x' }` is\n // a call this feature builds on `x`, which is exactly the \"must land first\"\n // relation this module exists to compute. Validate already says so — it\n // reports `c4-api.op-pending` when the op is defined by another feature in\n // flight — so the graph disagreeing with the validator about the same pair of\n // features was the graph being wrong, not quiet.\n //\n // Endpoints resolve through `serviceResolver` — the element's\n // `metadata { service }` binding, title as fallback — the same join every\n // other check uses, so renaming a box in a diagram cannot silently unhook it\n // here either.\n const deltaPath = featurePaths(feature.dir).delta;\n if (existsSync(deltaPath)) {\n const doc = await context.loadLikeC4(deltaPath);\n // A delta that does not parse proves nothing about who depends on whom.\n // `loam validate` owns that diagnosis (`delta.invalid`); inventing edges out\n // of a half-read document would be worse than the silence.\n if (doc.errors.length === 0) {\n // One resolver for the whole delta: `serviceOf` rebuilds its id map on\n // every call, and this loop asks once per edge. The enumerated fleet —\n // `services/` plus this feature's own `specs/` directories, the same\n // union `enumeratedTarget` probes below — rides into the resolver so a\n // delta that models CONTAINERS keeps its edges attached: without it, an\n // edge into `payment.api` resolves to a service called \"api\" that has\n // never existed, the op lookup misses the living contract, and the graph\n // invents a dependency (or orders two features that share nothing). An\n // unenumerable services/ falls back to the feature's own names — every\n // living probe would have found nothing there anyway.\n const fleetIds = await enumeratedServiceIds(docsDir, context);\n const svcOf = serviceResolver(doc.elements, new Set([...fleetIds, ...feature.services]));\n // The resolver answers with document text and `living` builds a path, so\n // the name crosses through the enumeration — coherence.ts grades its\n // edges through the same bridge. A name no enumeration vouches for has\n // no living contract anywhere: the op is required, exactly what the\n // probe answered for an absent service.\n const enumeratedTarget = enumeratedServiceIndex(docsDir, feature.services, context);\n for (const rel of doc.relationships) {\n if (rel.op === undefined) continue;\n const service = svcOf(rel.target);\n const pathable = await enumeratedTarget(service);\n if (pathable !== undefined && (await living(pathable)).has(rel.op)) continue;\n requiredOperations.push({ service, operationId: rel.op });\n }\n }\n }\n\n return {\n feature,\n addedRequirements,\n changedRequirements,\n introducedOperations,\n requiredOperations,\n };\n}\n"]}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Fleet fan-in: for each service, how many DISTINCT other known services
3
+ * depend on it — the blast radius behind `loam list --needs-work
4
+ * --review-order`. Reviewing the most-depended-on service first is the one
5
+ * ordering a campaign lead cannot derive by eye from the worklist.
6
+ *
7
+ * Pure derivation, derived-never-stored, in the package that already owns
8
+ * who-depends-on-whom: `core/dependencies/` derives the feature ordering from
9
+ * artifact identities, and this module derives the service-level analog. The
10
+ * command layer (commands/list/review.ts) gathers the inputs from reads the
11
+ * repository already pays for and hands them in as data, so the module itself
12
+ * imports nothing — no IO, no parser import, never prints. The edge slice is
13
+ * structural for the same reason `core/vocabulary/maturity.ts`'s EdgeSource
14
+ * is: `core/c4/likec4.ts`'s `Rel` satisfies it without an import edge into
15
+ * the parser.
16
+ */
17
+ /**
18
+ * Distinct known consumers per service, as a count for every id in
19
+ * `req.services` (0 when nothing depends on it — a proven zero, since only
20
+ * positive evidence ever increments it).
21
+ *
22
+ * Three joins, unioned by DISTINCT consumer so overlapping evidence for one
23
+ * caller counts once:
24
+ * 1. a drawn edge WITHOUT `consumes` into a service — its source is a
25
+ * caller, whether or not the edge carries an `op` (an op edge and a plain
26
+ * edge are one claim of dependence each);
27
+ * 2. a drawn edge carrying `consumes` — the rule of
28
+ * commands/validate/service/events/events.ts: `consumes` binds the edge's
29
+ * TARGET as the consumer and its SOURCE as the producer, so an edge drawn
30
+ * producer→consumer is fan-in on the SOURCE. Such an edge contributes
31
+ * join 2 ONLY: on the event spine THE ARROW FOLLOWS THE MESSAGE (the
32
+ * scaffolded landscape's own doctrine, examples/docs' landscape spells
33
+ * it), so the arrow of a delivery edge is not a call into its target —
34
+ * reading it as one would rank a pure event sink above a real dependency
35
+ * and hand a bound broker service one phantom dependant per consumer;
36
+ * 3. the landscape-independent requirement join — a service consumes a
37
+ * message some other service declares `action: send` for.
38
+ * Self-dependence proves nothing, and an endpoint outside the known-service
39
+ * set (an actor, an `#external` system, an unresolved id) is not a fleet
40
+ * caller — review order ranks work the FLEET depends on.
41
+ */
42
+ export function fleetFanIn(req) {
43
+ const known = new Set(req.services);
44
+ const consumers = new Map();
45
+ const depend = (producer, consumer) => {
46
+ if (producer === consumer)
47
+ return;
48
+ if (!known.has(producer) || !known.has(consumer))
49
+ return;
50
+ const set = consumers.get(producer) ?? new Set();
51
+ set.add(consumer);
52
+ consumers.set(producer, set);
53
+ };
54
+ if (req.landscape.parses) {
55
+ const { relationships, svcOf } = req.landscape;
56
+ for (const r of relationships) {
57
+ const source = svcOf(r.source);
58
+ const target = svcOf(r.target);
59
+ // The variants of the join comment above: a delivery edge (consumes)
60
+ // claims producer→consumer, never a call into its target.
61
+ if (r.consumes === undefined)
62
+ depend(target, source);
63
+ else
64
+ depend(source, target);
65
+ }
66
+ }
67
+ // Join 3. Producer index first: message name → every service declaring it
68
+ // sent. A message more than one service declares lands its subscribers on
69
+ // every declarer — the derivation never guesses which declaration wins.
70
+ const producers = new Map();
71
+ for (const [id, slice] of req.contracts) {
72
+ if (!known.has(id))
73
+ continue;
74
+ for (const message of slice.sent) {
75
+ producers.set(message, [...(producers.get(message) ?? []), id]);
76
+ }
77
+ }
78
+ for (const [id, slice] of req.contracts) {
79
+ if (!known.has(id))
80
+ continue;
81
+ for (const message of slice.consumed) {
82
+ for (const producer of producers.get(message) ?? [])
83
+ depend(producer, id);
84
+ }
85
+ }
86
+ return new Map(req.services.map((id) => [id, consumers.get(id)?.size ?? 0]));
87
+ }
88
+ //# sourceMappingURL=fanin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fanin.js","sourceRoot":"","sources":["../../../src/core/dependencies/fanin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AA2CH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,UAAU,CAAC,GAAiB;IAC1C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuB,CAAC;IACjD,MAAM,MAAM,GAAG,CAAC,QAAgB,EAAE,QAAgB,EAAQ,EAAE;QAC1D,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO;QAClC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO;QACzD,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;QACzD,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClB,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC/B,CAAC,CAAC;IAEF,IAAI,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC;QAC/C,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAC/B,qEAAqE;YACrE,0DAA0D;YAC1D,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS;gBAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;;gBAChD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,0EAA0E;IAC1E,wEAAwE;IACxE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC9C,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QACxC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC7B,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YACjC,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QACxC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC7B,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACrC,KAAK,MAAM,QAAQ,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE;gBAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC","sourcesContent":["/**\n * Fleet fan-in: for each service, how many DISTINCT other known services\n * depend on it — the blast radius behind `loam list --needs-work\n * --review-order`. Reviewing the most-depended-on service first is the one\n * ordering a campaign lead cannot derive by eye from the worklist.\n *\n * Pure derivation, derived-never-stored, in the package that already owns\n * who-depends-on-whom: `core/dependencies/` derives the feature ordering from\n * artifact identities, and this module derives the service-level analog. The\n * command layer (commands/list/review.ts) gathers the inputs from reads the\n * repository already pays for and hands them in as data, so the module itself\n * imports nothing — no IO, no parser import, never prints. The edge slice is\n * structural for the same reason `core/vocabulary/maturity.ts`'s EdgeSource\n * is: `core/c4/likec4.ts`'s `Rel` satisfies it without an import edge into\n * the parser.\n */\n\n/** The slice of a drawn relationship the joins read. */\nexport interface FanInEdge {\n source: string;\n target: string;\n /** AsyncAPI message this edge CONSUMES — binds the TARGET as the consumer. */\n consumes?: string;\n}\n\n/** One service's contract slice: what it declares it sends, and what its living requirements consume. */\nexport interface FanInContracts {\n /** Message names this service's asyncapi.yaml reaches from an `action: send` operation. */\n sent: readonly string[];\n /** Message names the service's living (non-REMOVED) spec/arch requirements carry on `Consumes:` lines. */\n consumed: readonly string[];\n}\n\n/**\n * The fleet map's contribution, as a variant rather than optional fields: a\n * landscape either parses — and then it has relationships and a resolver — or\n * it proves nothing, and there is no half-state in which `parses: false`\n * arrives carrying edges anyway. Positive evidence only, the rule\n * `landscapeEvidence` (core/vocabulary/maturity.ts) spells for the same map:\n * an absent or unparseable landscape contributes NOTHING to the edge joins,\n * while the requirement join below still counts.\n */\nexport type FanInLandscape =\n | {\n parses: true;\n relationships: readonly FanInEdge[];\n /** The shared container-aware resolver (`core/c4/resolve/service.ts` serviceResolver), widened to plain strings. */\n svcOf: (id: string) => string;\n }\n | { parses: false };\n\nexport interface FanInRequest {\n /** Every known service id — the universe both ends of every join are filtered to. */\n services: readonly string[];\n landscape: FanInLandscape;\n contracts: ReadonlyMap<string, FanInContracts>;\n}\n\n/**\n * Distinct known consumers per service, as a count for every id in\n * `req.services` (0 when nothing depends on it — a proven zero, since only\n * positive evidence ever increments it).\n *\n * Three joins, unioned by DISTINCT consumer so overlapping evidence for one\n * caller counts once:\n * 1. a drawn edge WITHOUT `consumes` into a service — its source is a\n * caller, whether or not the edge carries an `op` (an op edge and a plain\n * edge are one claim of dependence each);\n * 2. a drawn edge carrying `consumes` — the rule of\n * commands/validate/service/events/events.ts: `consumes` binds the edge's\n * TARGET as the consumer and its SOURCE as the producer, so an edge drawn\n * producer→consumer is fan-in on the SOURCE. Such an edge contributes\n * join 2 ONLY: on the event spine THE ARROW FOLLOWS THE MESSAGE (the\n * scaffolded landscape's own doctrine, examples/docs' landscape spells\n * it), so the arrow of a delivery edge is not a call into its target —\n * reading it as one would rank a pure event sink above a real dependency\n * and hand a bound broker service one phantom dependant per consumer;\n * 3. the landscape-independent requirement join — a service consumes a\n * message some other service declares `action: send` for.\n * Self-dependence proves nothing, and an endpoint outside the known-service\n * set (an actor, an `#external` system, an unresolved id) is not a fleet\n * caller — review order ranks work the FLEET depends on.\n */\nexport function fleetFanIn(req: FanInRequest): Map<string, number> {\n const known = new Set(req.services);\n const consumers = new Map<string, Set<string>>();\n const depend = (producer: string, consumer: string): void => {\n if (producer === consumer) return;\n if (!known.has(producer) || !known.has(consumer)) return;\n const set = consumers.get(producer) ?? new Set<string>();\n set.add(consumer);\n consumers.set(producer, set);\n };\n\n if (req.landscape.parses) {\n const { relationships, svcOf } = req.landscape;\n for (const r of relationships) {\n const source = svcOf(r.source);\n const target = svcOf(r.target);\n // The variants of the join comment above: a delivery edge (consumes)\n // claims producer→consumer, never a call into its target.\n if (r.consumes === undefined) depend(target, source);\n else depend(source, target);\n }\n }\n\n // Join 3. Producer index first: message name → every service declaring it\n // sent. A message more than one service declares lands its subscribers on\n // every declarer — the derivation never guesses which declaration wins.\n const producers = new Map<string, string[]>();\n for (const [id, slice] of req.contracts) {\n if (!known.has(id)) continue;\n for (const message of slice.sent) {\n producers.set(message, [...(producers.get(message) ?? []), id]);\n }\n }\n for (const [id, slice] of req.contracts) {\n if (!known.has(id)) continue;\n for (const message of slice.consumed) {\n for (const producer of producers.get(message) ?? []) depend(producer, id);\n }\n }\n\n return new Map(req.services.map((id) => [id, consumers.get(id)?.size ?? 0]));\n}\n"]}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * The graph arithmetic: which edges exist, which of them form a cycle, and what
3
+ * order the features can be archived in.
4
+ *
5
+ * Kept apart from `./facts.ts` because it knows nothing about requirements or
6
+ * operations — it takes ids and edges. That is what makes the cycle detection
7
+ * and the ordering testable against a graph nobody had to build a fleet for,
8
+ * and it is why `compareIds` sorts every adjacency list: the answer has to be
9
+ * the same on two machines that enumerated the docs tree in different orders.
10
+ */
11
+ import { compareIds } from "../repo/entries.js";
12
+ import {} from "./facts.js";
13
+ export function compareReasons(a, b) {
14
+ const ak = a.kind === "requirement"
15
+ ? `${a.kind}\0${a.service}\0${a.axis}\0${a.identity}`
16
+ : `${a.kind}\0${a.service}\0${a.operationId}`;
17
+ const bk = b.kind === "requirement"
18
+ ? `${b.kind}\0${b.service}\0${b.axis}\0${b.identity}`
19
+ : `${b.kind}\0${b.service}\0${b.operationId}`;
20
+ return compareIds(ak, bk);
21
+ }
22
+ export function edgeKey(from, to) {
23
+ return `${from}\0${to}`;
24
+ }
25
+ export function appendReason(edges, from, to, reason) {
26
+ if (from === to)
27
+ return;
28
+ const key = edgeKey(from, to);
29
+ const edge = edges.get(key) ?? { from, to, reasons: [] };
30
+ const encoded = JSON.stringify(reason);
31
+ if (!edge.reasons.some((item) => JSON.stringify(item) === encoded))
32
+ edge.reasons.push(reason);
33
+ edges.set(key, edge);
34
+ }
35
+ export function stronglyConnected(ids, edges) {
36
+ const adjacency = new Map(ids.map((id) => [id, []]));
37
+ for (const edge of edges)
38
+ adjacency.get(edge.from)?.push(edge.to);
39
+ for (const targets of adjacency.values())
40
+ targets.sort(compareIds);
41
+ let nextIndex = 0;
42
+ const indices = new Map();
43
+ const low = new Map();
44
+ const stack = [];
45
+ const onStack = new Set();
46
+ const components = [];
47
+ const visit = (id) => {
48
+ indices.set(id, nextIndex);
49
+ low.set(id, nextIndex);
50
+ nextIndex += 1;
51
+ stack.push(id);
52
+ onStack.add(id);
53
+ for (const target of adjacency.get(id) ?? []) {
54
+ if (!indices.has(target)) {
55
+ visit(target);
56
+ low.set(id, Math.min(low.get(id), low.get(target)));
57
+ }
58
+ else if (onStack.has(target)) {
59
+ low.set(id, Math.min(low.get(id), indices.get(target)));
60
+ }
61
+ }
62
+ if (low.get(id) !== indices.get(id))
63
+ return;
64
+ const component = [];
65
+ while (stack.length > 0) {
66
+ const member = stack.pop();
67
+ onStack.delete(member);
68
+ component.push(member);
69
+ if (member === id)
70
+ break;
71
+ }
72
+ component.sort(compareIds);
73
+ const selfLoop = component.length === 1
74
+ && (adjacency.get(component[0]) ?? []).includes(component[0]);
75
+ if (component.length > 1 || selfLoop)
76
+ components.push(component);
77
+ };
78
+ for (const id of [...ids].sort(compareIds))
79
+ if (!indices.has(id))
80
+ visit(id);
81
+ return components.sort((a, b) => compareIds(a[0], b[0]));
82
+ }
83
+ export function dependencyFirstOrder(ids, edges) {
84
+ const deps = new Map(ids.map((id) => [id, []]));
85
+ for (const edge of edges)
86
+ deps.get(edge.from)?.push(edge.to);
87
+ for (const values of deps.values())
88
+ values.sort(compareIds);
89
+ const visited = new Set();
90
+ const visiting = new Set();
91
+ const order = [];
92
+ const visit = (id) => {
93
+ if (visited.has(id) || visiting.has(id))
94
+ return;
95
+ visiting.add(id);
96
+ for (const dependency of deps.get(id) ?? [])
97
+ visit(dependency);
98
+ visiting.delete(id);
99
+ visited.add(id);
100
+ order.push(id);
101
+ };
102
+ for (const id of [...ids].sort(compareIds))
103
+ visit(id);
104
+ return order;
105
+ }
106
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../../src/core/dependencies/graph.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The graph arithmetic: which edges exist, which of them form a cycle, and what\n * order the features can be archived in.\n *\n * Kept apart from `./facts.ts` because it knows nothing about requirements or\n * operations — it takes ids and edges. That is what makes the cycle detection\n * and the ordering testable against a graph nobody had to build a fleet for,\n * and it is why `compareIds` sorts every adjacency list: the answer has to be\n * the same on two machines that enumerated the docs tree in different orders.\n */\nimport { compareIds } from \"../repo/entries.js\";\nimport { type DependencyEdge, type DependencyReason } from \"./facts.js\";\n\nexport function compareReasons(a: DependencyReason, b: DependencyReason): number {\n const ak = a.kind === \"requirement\"\n ? `${a.kind}\\0${a.service}\\0${a.axis}\\0${a.identity}`\n : `${a.kind}\\0${a.service}\\0${a.operationId}`;\n const bk = b.kind === \"requirement\"\n ? `${b.kind}\\0${b.service}\\0${b.axis}\\0${b.identity}`\n : `${b.kind}\\0${b.service}\\0${b.operationId}`;\n return compareIds(ak, bk);\n}\n\nexport function edgeKey(from: string, to: string): string {\n return `${from}\\0${to}`;\n}\n\nexport function appendReason(\n edges: Map<string, DependencyEdge>,\n from: string,\n to: string,\n reason: DependencyReason,\n): void {\n if (from === to) return;\n const key = edgeKey(from, to);\n const edge = edges.get(key) ?? { from, to, reasons: [] };\n const encoded = JSON.stringify(reason);\n if (!edge.reasons.some((item) => JSON.stringify(item) === encoded)) edge.reasons.push(reason);\n edges.set(key, edge);\n}\n\nexport function stronglyConnected(ids: string[], edges: DependencyEdge[]): string[][] {\n const adjacency = new Map(ids.map((id) => [id, [] as string[]]));\n for (const edge of edges) adjacency.get(edge.from)?.push(edge.to);\n for (const targets of adjacency.values()) targets.sort(compareIds);\n\n let nextIndex = 0;\n const indices = new Map<string, number>();\n const low = new Map<string, number>();\n const stack: string[] = [];\n const onStack = new Set<string>();\n const components: string[][] = [];\n\n const visit = (id: string): void => {\n indices.set(id, nextIndex);\n low.set(id, nextIndex);\n nextIndex += 1;\n stack.push(id);\n onStack.add(id);\n\n for (const target of adjacency.get(id) ?? []) {\n if (!indices.has(target)) {\n visit(target);\n low.set(id, Math.min(low.get(id)!, low.get(target)!));\n } else if (onStack.has(target)) {\n low.set(id, Math.min(low.get(id)!, indices.get(target)!));\n }\n }\n if (low.get(id) !== indices.get(id)) return;\n const component: string[] = [];\n while (stack.length > 0) {\n const member = stack.pop()!;\n onStack.delete(member);\n component.push(member);\n if (member === id) break;\n }\n component.sort(compareIds);\n const selfLoop = component.length === 1\n && (adjacency.get(component[0]!) ?? []).includes(component[0]!);\n if (component.length > 1 || selfLoop) components.push(component);\n };\n\n for (const id of [...ids].sort(compareIds)) if (!indices.has(id)) visit(id);\n return components.sort((a, b) => compareIds(a[0]!, b[0]!));\n}\n\nexport function dependencyFirstOrder(ids: string[], edges: DependencyEdge[]): string[] {\n const deps = new Map(ids.map((id) => [id, [] as string[]]));\n for (const edge of edges) deps.get(edge.from)?.push(edge.to);\n for (const values of deps.values()) values.sort(compareIds);\n const visited = new Set<string>();\n const visiting = new Set<string>();\n const order: string[] = [];\n const visit = (id: string): void => {\n if (visited.has(id) || visiting.has(id)) return;\n visiting.add(id);\n for (const dependency of deps.get(id) ?? []) visit(dependency);\n visiting.delete(id);\n visited.add(id);\n order.push(id);\n };\n for (const id of [...ids].sort(compareIds)) visit(id);\n return order;\n}\n"]}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * A feature's own topology: `features/<FEAT>/deployment/<name>.likec4`.
3
+ *
4
+ * Until this slot existed a change that stood up a standby cluster had to be
5
+ * written in two places at once — the requirement in the feature, the topology
6
+ * edited straight into `architecture/` — because `delta.likec4` refuses a
7
+ * `deployment { }` block and always will: that document re-declares the
8
+ * landscape's own identifiers and carries its own `specification`, so it cannot
9
+ * be staged beside the map in one LikeC4 project. A document that declares
10
+ * NEITHER can, which is exactly why the use-case axis put its flows in files of
11
+ * their own, and why this mirrors it rather than inventing a shape.
12
+ *
13
+ * WHAT MAKES IT WORK, and it was measured before the axis was written: LikeC4
14
+ * `extend` resolves across documents of one project. A feature writes
15
+ *
16
+ * deployment {
17
+ * extend eu {
18
+ * dcC = datacenter 'DC-C' { k8sC = cluster 'cluster-c' { … } }
19
+ * }
20
+ * eu.dcA.k8sA -> eu.dcC.k8sC 'async replication'
21
+ * }
22
+ *
23
+ * and the living region gains a datacenter with the living file untouched. So
24
+ * the merge is a copy, not a splice, and `unarchive` needs nothing new — a
25
+ * create is undone by deleting, which the snapshot manifest already records for
26
+ * every write in the plan.
27
+ *
28
+ * CREATE-ONLY, for `core/usecases/delta/flows.ts`'s reasons rather than a
29
+ * weaker version of them. A requirement delta merges INTO a living document and
30
+ * two features editing one requirement would overwrite each other silently; a
31
+ * topology document has no such algebra — the file is one block, the merge is a
32
+ * whole-file copy, and there is nothing to merge partially. Rewriting a living
33
+ * one through a feature would be a silent whole-file replacement with no pin to
34
+ * collide on, where editing `architecture/<name>.likec4` directly in the same
35
+ * pull request produces an ordinary git conflict a human resolves.
36
+ *
37
+ * ## Graded against the map its own merge would leave behind
38
+ *
39
+ * `ARCH-LOAM-FEATURE-CORPUS`, and this axis needs it more literally than the
40
+ * use-case one does: a feature that stands a service up in a new cluster
41
+ * declares that service in its `delta.likec4` and instances it here, so the
42
+ * element the topology names exists ONLY post-merge. Read against the living
43
+ * landscape it is unresolved, LikeC4 refuses the whole project, and loam would
44
+ * report a hole against a file whose only fault is arriving with the change
45
+ * that makes it true.
46
+ *
47
+ * The staging is `core/c4/project/staged.ts`, shared with the use-case slot
48
+ * rather than copied — the two would have disagreed first about the merge
49
+ * preview, which is the one thing both refusals rest on.
50
+ */
51
+ import { existsSync } from "node:fs";
52
+ import { basename, join, relative, resolve } from "node:path";
53
+ import { architectureDir } from "../c4/project/architecture.js";
54
+ import { stageMergedProject } from "../c4/project/staged.js";
55
+ import {} from "../c4/likec4.js";
56
+ import { architectureDocuments } from "../c4/project/documents.js";
57
+ import { featureDeploymentDir } from "../repo/authored/paths.js";
58
+ import { reservedArchitectureName } from "../repo/paths.js";
59
+ import {} from "../vocabulary/issue.js";
60
+ /**
61
+ * The topology documents one feature carries, ordered by path.
62
+ *
63
+ * Zero readdirs when the feature has no `deployment/` directory, which is every
64
+ * feature in a fleet that has not adopted the axis: `architectureDocuments`
65
+ * answers an absent directory with an empty list rather than a throw. That
66
+ * directory's existence is the whole per-feature opt-in.
67
+ */
68
+ export async function featureDeployments(featureDir) {
69
+ const dir = featureDeploymentDir(featureDir);
70
+ const paths = await architectureDocuments(dir);
71
+ const base = resolve(dir);
72
+ return paths.map((path) => ({ rel: relative(base, path).split(/[\\/]/).join("/"), path }));
73
+ }
74
+ /**
75
+ * The LIVING path a feature-local topology document addresses.
76
+ *
77
+ * Straight into `architecture/`, with no subdirectory of its own — unlike
78
+ * `architecture/usecases/`, and the difference is the model rather than taste.
79
+ * A `deployment { }` block is part of the fleet's ONE architecture project and
80
+ * is read as such by every loader; filing it under a subdirectory would suggest
81
+ * a second project, which is exactly the reading `subsystems.likec4` and
82
+ * `landscape.likec4` already refuse by sitting at the top level together.
83
+ *
84
+ * `rel` is joined un-split, which `node:path` normalizes. What holds the join is
85
+ * PROVENANCE: every `rel` here came out of an `architectureDocuments` walk, so
86
+ * each component is a directory entry that exists. No caller takes one from argv.
87
+ */
88
+ export function livingDeploymentPath(docsDir, rel) {
89
+ return join(architectureDir(docsDir), rel);
90
+ }
91
+ /**
92
+ * The two things that can go wrong about a topology document's NAME, before
93
+ * anything about its contents is asked.
94
+ *
95
+ * `deployment.doc-reserved` — the name is one loam owns inside `architecture/`.
96
+ * The merge writes straight into that directory, unlike a flow, which lands
97
+ * under `usecases/`, so `<name>` is free to collide with the living map, the
98
+ * generated subsystem views, or the flow tree. `reservedArchitectureName`
99
+ * carries which and why. It is asked FIRST and WITHOUT an existence test,
100
+ * because two of the three fail silently when the target does not exist yet.
101
+ *
102
+ * `deployment.doc-exists` — a topology document this feature introduces that
103
+ * the living `architecture/` already holds.
104
+ *
105
+ * An ERROR and never a warning-that-gates, for `usecase.flow-exists`'s reason:
106
+ * there is no legal reading of it. The merge would replace an authored topology
107
+ * wholesale, and no `--approve` makes that a different act than it is. Two
108
+ * features introducing the same file is the case that makes it load-bearing
109
+ * rather than pedantic — whichever archives first creates the living document,
110
+ * and the second is told before it merges that its own file is the one to
111
+ * delete.
112
+ *
113
+ * The collision is on the FILE, not on what is inside it. Two features may both
114
+ * extend the same living region from two documents of their own and both
115
+ * archive; that is the shape `extend` exists for, and refusing it would make the
116
+ * slot useless for the fleet-wide change it was built for.
117
+ */
118
+ export async function deploymentDeltaIssues(docsDir, featureDir) {
119
+ const docs = await featureDeployments(featureDir);
120
+ const issues = [];
121
+ // The reservation runs FIRST and independently of existence, because two of
122
+ // the three names it refuses need not exist for the merge to be wrong. A
123
+ // topology copied over `subsystems.likec4` is destroyed by the next
124
+ // `loam subsystem sync` and is invisible to every project load until then —
125
+ // the merge would report `created architecture/subsystems.likec4` and nothing
126
+ // downstream would ever say another word about it.
127
+ for (const doc of docs) {
128
+ const reason = reservedArchitectureName(doc.rel);
129
+ if (reason === null)
130
+ continue;
131
+ issues.push({
132
+ severity: "error",
133
+ code: "deployment.doc-reserved",
134
+ subject: doc.rel,
135
+ message: `features/<FEAT>/deployment/${doc.rel} would merge to architecture/${doc.rel}, and that name is loam's: ` +
136
+ `${reason}. Rename the feature's document — its name is yours to choose, and \`extend\` is how it adds to ` +
137
+ "what a living document already declares.",
138
+ });
139
+ }
140
+ return issues.concat(docs
141
+ .filter((doc) => reservedArchitectureName(doc.rel) === null)
142
+ .filter((doc) => existsSync(livingDeploymentPath(docsDir, doc.rel)))
143
+ .map((doc) => ({
144
+ severity: "error",
145
+ code: "deployment.doc-exists",
146
+ subject: doc.rel,
147
+ message: `architecture/${doc.rel} already exists, so this feature's topology would replace an authored one wholesale — ` +
148
+ "a feature-local deployment document INTRODUCES topology, it does not rewrite it. " +
149
+ `Delete features/<FEAT>/deployment/${doc.rel} and edit architecture/${doc.rel} directly in this same change, ` +
150
+ "where git produces an ordinary conflict if somebody else is editing it too. " +
151
+ `To ADD to what that file declares, write a document of another name that says \`extend\` — ` +
152
+ `\`${suggest(doc.rel)}\` — which is what lets two features grow one region without touching each other.`,
153
+ })));
154
+ }
155
+ /**
156
+ * Parse this feature's topology documents over the post-merge map.
157
+ *
158
+ * A feature with no `deployment/` directory is `read` at the cost of one walk
159
+ * over a directory that is not there — the axis's per-feature opt-in, and the
160
+ * whole price a fleet that has not adopted it pays. Nothing is staged, nothing
161
+ * is parsed, and no temp tree is made.
162
+ *
163
+ * The verdict is deliberately BINARY. The use-case overlay hands its caller the
164
+ * views it read because the axis has questions about their content; this one
165
+ * has none — a topology document is checked by being parseable against the map
166
+ * the merge will write, and everything else about it is graded by
167
+ * `loam validate --all` once it is living, exactly as the landscape is.
168
+ */
169
+ export async function readFeatureDeployments(req) {
170
+ const docs = await featureDeployments(req.featureDir);
171
+ if (docs.length === 0)
172
+ return { kind: "read" };
173
+ const staged = await stageMergedProject({
174
+ docsDir: req.docsDir,
175
+ featureDir: req.featureDir,
176
+ featureId: req.featureId,
177
+ documents: docs.map((doc) => ({ rel: doc.rel, path: doc.path })),
178
+ ...(req.load === undefined ? {} : { load: req.load }),
179
+ });
180
+ return staged.kind === "unreadable" ? { kind: "unreadable", errors: staged.errors } : { kind: "read" };
181
+ }
182
+ /** A free name near the colliding one, so the fix is a rename the author can copy. */
183
+ function suggest(rel) {
184
+ const name = basename(rel).replace(/\.likec4$/, "");
185
+ const dir = rel.slice(0, rel.length - basename(rel).length);
186
+ return `${dir}${name}-extend.likec4`;
187
+ }
188
+ //# sourceMappingURL=delta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delta.js","sourceRoot":"","sources":["../../../src/core/deployment/delta.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A feature's own topology: `features/<FEAT>/deployment/<name>.likec4`.\n *\n * Until this slot existed a change that stood up a standby cluster had to be\n * written in two places at once — the requirement in the feature, the topology\n * edited straight into `architecture/` — because `delta.likec4` refuses a\n * `deployment { }` block and always will: that document re-declares the\n * landscape's own identifiers and carries its own `specification`, so it cannot\n * be staged beside the map in one LikeC4 project. A document that declares\n * NEITHER can, which is exactly why the use-case axis put its flows in files of\n * their own, and why this mirrors it rather than inventing a shape.\n *\n * WHAT MAKES IT WORK, and it was measured before the axis was written: LikeC4\n * `extend` resolves across documents of one project. A feature writes\n *\n * deployment {\n * extend eu {\n * dcC = datacenter 'DC-C' { k8sC = cluster 'cluster-c' { … } }\n * }\n * eu.dcA.k8sA -> eu.dcC.k8sC 'async replication'\n * }\n *\n * and the living region gains a datacenter with the living file untouched. So\n * the merge is a copy, not a splice, and `unarchive` needs nothing new — a\n * create is undone by deleting, which the snapshot manifest already records for\n * every write in the plan.\n *\n * CREATE-ONLY, for `core/usecases/delta/flows.ts`'s reasons rather than a\n * weaker version of them. A requirement delta merges INTO a living document and\n * two features editing one requirement would overwrite each other silently; a\n * topology document has no such algebra — the file is one block, the merge is a\n * whole-file copy, and there is nothing to merge partially. Rewriting a living\n * one through a feature would be a silent whole-file replacement with no pin to\n * collide on, where editing `architecture/<name>.likec4` directly in the same\n * pull request produces an ordinary git conflict a human resolves.\n *\n * ## Graded against the map its own merge would leave behind\n *\n * `ARCH-LOAM-FEATURE-CORPUS`, and this axis needs it more literally than the\n * use-case one does: a feature that stands a service up in a new cluster\n * declares that service in its `delta.likec4` and instances it here, so the\n * element the topology names exists ONLY post-merge. Read against the living\n * landscape it is unresolved, LikeC4 refuses the whole project, and loam would\n * report a hole against a file whose only fault is arriving with the change\n * that makes it true.\n *\n * The staging is `core/c4/project/staged.ts`, shared with the use-case slot\n * rather than copied — the two would have disagreed first about the merge\n * preview, which is the one thing both refusals rest on.\n */\nimport { existsSync } from \"node:fs\";\nimport { basename, join, relative, resolve } from \"node:path\";\nimport { architectureDir } from \"../c4/project/architecture.js\";\nimport { stageMergedProject } from \"../c4/project/staged.js\";\nimport { type LoadedDoc } from \"../c4/likec4.js\";\nimport { architectureDocuments } from \"../c4/project/documents.js\";\nimport { featureDeploymentDir } from \"../repo/authored/paths.js\";\nimport { reservedArchitectureName } from \"../repo/paths.js\";\nimport type { DocsDir, FeatureDir } from \"../kernel/ids/dirs.js\";\nimport { type Issue } from \"../vocabulary/issue.js\";\n\n/** One topology document a feature carries. */\nexport interface FeatureDeployment {\n /**\n * The path INSIDE the feature's `deployment/` directory, `/`-separated — the\n * id this axis has. Nesting is spelled by the tree, as it is for every other\n * authored tree in the repo.\n */\n rel: string;\n /** The absolute path of the authored file. */\n path: string;\n}\n\n/**\n * The topology documents one feature carries, ordered by path.\n *\n * Zero readdirs when the feature has no `deployment/` directory, which is every\n * feature in a fleet that has not adopted the axis: `architectureDocuments`\n * answers an absent directory with an empty list rather than a throw. That\n * directory's existence is the whole per-feature opt-in.\n */\nexport async function featureDeployments(featureDir: FeatureDir): Promise<FeatureDeployment[]> {\n const dir = featureDeploymentDir(featureDir);\n const paths = await architectureDocuments(dir);\n const base = resolve(dir);\n return paths.map((path) => ({ rel: relative(base, path).split(/[\\\\/]/).join(\"/\"), path }));\n}\n\n/**\n * The LIVING path a feature-local topology document addresses.\n *\n * Straight into `architecture/`, with no subdirectory of its own — unlike\n * `architecture/usecases/`, and the difference is the model rather than taste.\n * A `deployment { }` block is part of the fleet's ONE architecture project and\n * is read as such by every loader; filing it under a subdirectory would suggest\n * a second project, which is exactly the reading `subsystems.likec4` and\n * `landscape.likec4` already refuse by sitting at the top level together.\n *\n * `rel` is joined un-split, which `node:path` normalizes. What holds the join is\n * PROVENANCE: every `rel` here came out of an `architectureDocuments` walk, so\n * each component is a directory entry that exists. No caller takes one from argv.\n */\nexport function livingDeploymentPath(docsDir: DocsDir, rel: string): string {\n return join(architectureDir(docsDir), rel);\n}\n\n/**\n * The two things that can go wrong about a topology document's NAME, before\n * anything about its contents is asked.\n *\n * `deployment.doc-reserved` — the name is one loam owns inside `architecture/`.\n * The merge writes straight into that directory, unlike a flow, which lands\n * under `usecases/`, so `<name>` is free to collide with the living map, the\n * generated subsystem views, or the flow tree. `reservedArchitectureName`\n * carries which and why. It is asked FIRST and WITHOUT an existence test,\n * because two of the three fail silently when the target does not exist yet.\n *\n * `deployment.doc-exists` — a topology document this feature introduces that\n * the living `architecture/` already holds.\n *\n * An ERROR and never a warning-that-gates, for `usecase.flow-exists`'s reason:\n * there is no legal reading of it. The merge would replace an authored topology\n * wholesale, and no `--approve` makes that a different act than it is. Two\n * features introducing the same file is the case that makes it load-bearing\n * rather than pedantic — whichever archives first creates the living document,\n * and the second is told before it merges that its own file is the one to\n * delete.\n *\n * The collision is on the FILE, not on what is inside it. Two features may both\n * extend the same living region from two documents of their own and both\n * archive; that is the shape `extend` exists for, and refusing it would make the\n * slot useless for the fleet-wide change it was built for.\n */\nexport async function deploymentDeltaIssues(docsDir: DocsDir, featureDir: FeatureDir): Promise<Issue[]> {\n const docs = await featureDeployments(featureDir);\n const issues: Issue[] = [];\n // The reservation runs FIRST and independently of existence, because two of\n // the three names it refuses need not exist for the merge to be wrong. A\n // topology copied over `subsystems.likec4` is destroyed by the next\n // `loam subsystem sync` and is invisible to every project load until then —\n // the merge would report `created architecture/subsystems.likec4` and nothing\n // downstream would ever say another word about it.\n for (const doc of docs) {\n const reason = reservedArchitectureName(doc.rel);\n if (reason === null) continue;\n issues.push({\n severity: \"error\",\n code: \"deployment.doc-reserved\",\n subject: doc.rel,\n message:\n `features/<FEAT>/deployment/${doc.rel} would merge to architecture/${doc.rel}, and that name is loam's: ` +\n `${reason}. Rename the feature's document — its name is yours to choose, and \\`extend\\` is how it adds to ` +\n \"what a living document already declares.\",\n });\n }\n return issues.concat(\n docs\n .filter((doc) => reservedArchitectureName(doc.rel) === null)\n .filter((doc) => existsSync(livingDeploymentPath(docsDir, doc.rel)))\n .map((doc) => ({\n severity: \"error\" as const,\n code: \"deployment.doc-exists\" as const,\n subject: doc.rel,\n message:\n `architecture/${doc.rel} already exists, so this feature's topology would replace an authored one wholesale — ` +\n \"a feature-local deployment document INTRODUCES topology, it does not rewrite it. \" +\n `Delete features/<FEAT>/deployment/${doc.rel} and edit architecture/${doc.rel} directly in this same change, ` +\n \"where git produces an ordinary conflict if somebody else is editing it too. \" +\n `To ADD to what that file declares, write a document of another name that says \\`extend\\` — ` +\n `\\`${suggest(doc.rel)}\\` — which is what lets two features grow one region without touching each other.`,\n })),\n );\n}\n\n/** What the caller needs to grade this feature's topology against the merge preview. */\nexport interface DeploymentOverlayRequest {\n docsDir: DocsDir;\n featureDir: FeatureDir;\n /** The feature's id — the tag that selects the delta's own additions. */\n featureId: string;\n /**\n * The caller's memoised LikeC4 read, when it has one. A FUNCTION rather than\n * the `FleetContext` itself, for the reason the use-case overlay states: one\n * memoised read does not justify an edge from this package to\n * `core/fleet-context.ts`, and the edge would push it up a DAG level for\n * nothing.\n */\n load?: (path: string) => Promise<LoadedDoc>;\n}\n\n/** Whether this feature's topology could be read at all, against the map its merge would leave. */\nexport type DeploymentOverlay = { kind: \"read\" } | { kind: \"unreadable\"; errors: string[] };\n\n/**\n * Parse this feature's topology documents over the post-merge map.\n *\n * A feature with no `deployment/` directory is `read` at the cost of one walk\n * over a directory that is not there — the axis's per-feature opt-in, and the\n * whole price a fleet that has not adopted it pays. Nothing is staged, nothing\n * is parsed, and no temp tree is made.\n *\n * The verdict is deliberately BINARY. The use-case overlay hands its caller the\n * views it read because the axis has questions about their content; this one\n * has none — a topology document is checked by being parseable against the map\n * the merge will write, and everything else about it is graded by\n * `loam validate --all` once it is living, exactly as the landscape is.\n */\nexport async function readFeatureDeployments(req: DeploymentOverlayRequest): Promise<DeploymentOverlay> {\n const docs = await featureDeployments(req.featureDir);\n if (docs.length === 0) return { kind: \"read\" };\n const staged = await stageMergedProject({\n docsDir: req.docsDir,\n featureDir: req.featureDir,\n featureId: req.featureId,\n documents: docs.map((doc) => ({ rel: doc.rel, path: doc.path })),\n ...(req.load === undefined ? {} : { load: req.load }),\n });\n return staged.kind === \"unreadable\" ? { kind: \"unreadable\", errors: staged.errors } : { kind: \"read\" };\n}\n\n/** A free name near the colliding one, so the fix is a rename the author can copy. */\nfunction suggest(rel: string): string {\n const name = basename(rel).replace(/\\.likec4$/, \"\");\n const dir = rel.slice(0, rel.length - basename(rel).length);\n return `${dir}${name}-extend.likec4`;\n}\n"]}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * The deployment axis: which objects on the fleet's TOPOLOGY carry a rule, and
3
+ * who owns each of them.
4
+ *
5
+ * A `#obl-` tag is a claim about the object it sits on, and the object's model
6
+ * is not a property any reader can see. Before this module the same undeclared
7
+ * tag was `obligation.unknown` on a container and SILENCE on a datacenter,
8
+ * because `validate/fleet/obligations.ts` walked the logical model only — the
9
+ * fail-open case where a rule an architect placed does not exist for any check,
10
+ * and a reviewer has no way to tell that from a rule that passed. This is the
11
+ * derivation that closes it (FEAT-1's ARCH-LOAM-DEPLOY-TAGGED).
12
+ *
13
+ * ## The `where` string is the `Covers:` line
14
+ *
15
+ * Every finding about a tagged object tells its reader to write
16
+ * `Covers: <where>`, so `where` is spelled as the grammar reads it —
17
+ * `node:eu.dcA`, `node:a.db -> node:b.db` — and never as a bare id. A message
18
+ * that names an object one way and asks for a line spelled another way sends
19
+ * the reader round the loop twice.
20
+ *
21
+ * ## Who owns a datacenter
22
+ *
23
+ * Nobody, and the answer is `undefined` rather than a guess. An INSTANCE is
24
+ * owned by the service its logical element belongs to, which is a real join
25
+ * through the landscape's own binding; an edge between two instances of one
26
+ * service is owned by that service; a region, a datacenter or a cluster is
27
+ * owned by whoever runs the platform, and loam has no such concept. The finding
28
+ * changes its sentence rather than naming a service that did not ask for the
29
+ * work — "write it in payment-service's arch.spec.md" is actionable, and
30
+ * "write it in <the wrong team>'s" is worse than no attribution at all.
31
+ *
32
+ * This package is one module today and gains its second with the feature-local
33
+ * `features/<FEAT>/deployment/` slot, which is the step of the axis that needs
34
+ * `repo` and `kernel`. Nothing here reads a path.
35
+ */
36
+ import {} from "../c4/likec4.js";
37
+ import {} from "../c4/parsed/deployment.js";
38
+ import { serviceResolver } from "../c4/resolve/service.js";
39
+ /**
40
+ * Every `#obl-` tag on the deployment model, one entry per (obligation, object)
41
+ * pair — the same shape, and the same bare-prefix tolerance, the logical walk
42
+ * has: a bare `#obl-` slugs to the empty string and is KEPT, because the prefix
43
+ * is the author's opt-in however little follows it, and dropping it would leave
44
+ * an object that asked to be graded silently ungraded.
45
+ */
46
+ export function taggedDeployment(deployment, elements, known, prefix) {
47
+ const owner = instanceOwners(deployment, elements, known);
48
+ const out = [];
49
+ const push = (tags, rest) => {
50
+ for (const tag of tags.filter((t) => t.startsWith(prefix))) {
51
+ out.push({ obligation: tag.slice(prefix.length), ...rest });
52
+ }
53
+ };
54
+ // Nodes first, then instances, then edges — the order the model declares them
55
+ // in, so a fleet report reads top-down the way the document does.
56
+ for (const node of deployment.nodes)
57
+ push(node.tags, { where: `node:${node.id}`, id: node.id });
58
+ for (const instance of deployment.instances) {
59
+ const service = owner.get(instance.id);
60
+ push(instance.tags, {
61
+ where: `node:${instance.id}`,
62
+ id: instance.id,
63
+ ...(service === undefined ? {} : { service }),
64
+ });
65
+ }
66
+ for (const edge of deployment.relationships) {
67
+ // An edge is owned only when BOTH ends agree. A replication edge between
68
+ // two instances of one service belongs to that service; one crossing
69
+ // services belongs to neither, and picking the target — the rule the
70
+ // logical walk uses, where the arrow means "calls" — says nothing here,
71
+ // because a deployment edge is as often symmetric as directed.
72
+ const from = owner.get(edge.source);
73
+ const to = owner.get(edge.target);
74
+ const service = from !== undefined && from === to ? from : undefined;
75
+ push(edge.tags, {
76
+ where: `node:${edge.source} -> node:${edge.target}`,
77
+ edge,
78
+ ...(service === undefined ? {} : { service }),
79
+ });
80
+ }
81
+ return out;
82
+ }
83
+ /**
84
+ * The topology one service is part of.
85
+ *
86
+ * Built for the CONTEXT PACK, which is the surface whose reader is an agent
87
+ * about to write the implementation. Before this, that pack described a
88
+ * service's calls and contracts and said nothing whatever about where it runs —
89
+ * so a failover was implemented against a map nobody had read, which is the
90
+ * gap FEAT-1's ARCH-LOAM-DEPLOY-UNCHECKED names alongside the sentence about
91
+ * what a green axis does not mean.
92
+ *
93
+ * BOTH ENDS, not only the outbound one. A replication edge is as often read
94
+ * from the standby's side as from the primary's, and a pack that showed only
95
+ * what this service points at would hide the stream it receives.
96
+ */
97
+ export function serviceTopology(deployment, elements, known, service) {
98
+ const owner = instanceOwners(deployment, elements, known);
99
+ const mine = deployment.instances.filter((i) => owner.get(i.id) === service);
100
+ const ids = new Set(mine.map((i) => i.id));
101
+ return {
102
+ instances: mine.map((i) => ({ id: i.id, element: i.element })),
103
+ edges: deployment.relationships
104
+ .filter((r) => ids.has(r.source) || ids.has(r.target))
105
+ .map((r) => ({ source: r.source, target: r.target, ...(r.title === undefined ? {} : { title: r.title }) })),
106
+ };
107
+ }
108
+ /**
109
+ * instance id → the service its logical element belongs to.
110
+ *
111
+ * Through `serviceResolver` and NOT `elementService`, and the difference is a
112
+ * defect this axis shipped once. A deployment instances a CONTAINER far more
113
+ * often than a whole system — `instanceOf orders.cache` is the ordinary way to
114
+ * say where the Redis a service owns actually runs — and `elementService` reads
115
+ * the binding or the TITLE of the element handed to it. A nested container
116
+ * carries no `metadata { service }` of its own, so that read answered "order
117
+ * cache", and `obligation.uncovered` told an author to write the requirement in
118
+ * "order cache's arch.spec.md" — a service that has never existed. The
119
+ * resolver's whole job is the ancestor walk that finds the bound system above
120
+ * it, which is the same join every other check makes about a container.
121
+ *
122
+ * `known` rides in for the reason `coversEdge` takes it: without the enumerated
123
+ * fleet the resolver's second tier — the nearest ancestor whose title names a
124
+ * real `services/<id>/` — cannot run, and a fleet that binds by title rather
125
+ * than by `metadata { service }` resolves to the title alone. It must be the
126
+ * SAME set the caller's own findings resolve with, or the message names one
127
+ * service and the check counts another.
128
+ *
129
+ * An instance of an element the landscape does not declare is left UNOWNED
130
+ * rather than filed under a fabricated name. LikeC4 refuses an unresolved
131
+ * `instanceOf` outright, so that state is reachable only when the caller hands
132
+ * in elements from a narrower document than the one the topology was parsed
133
+ * with.
134
+ */
135
+ function instanceOwners(deployment, elements, known) {
136
+ const ids = new Set(elements.map((e) => e.id));
137
+ const resolve = serviceResolver([...elements], known);
138
+ const out = new Map();
139
+ for (const instance of deployment.instances) {
140
+ if (ids.has(instance.element))
141
+ out.set(instance.id, resolve(instance.element));
142
+ }
143
+ return out;
144
+ }
145
+ //# sourceMappingURL=objects.js.map