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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1256) hide show
  1. package/CHANGELOG.md +5992 -82
  2. package/COMPARISON.md +168 -63
  3. package/CONTRIBUTING.md +121 -0
  4. package/MIGRATING-from-OpenSpec.md +238 -55
  5. package/QUICKSTART.md +302 -0
  6. package/README.md +653 -144
  7. package/ROADMAP.md +1035 -0
  8. package/SCHEMA.md +3916 -263
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +927 -0
  11. package/dist/cli.js +133 -21
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +204 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +309 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +74 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/closing.js +42 -0
  20. package/dist/commands/archive/closing.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
  22. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  24. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  25. package/dist/commands/archive/plan/contracts/openapi.js +193 -0
  26. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  28. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  29. package/dist/commands/archive/plan/document/head.js +151 -0
  30. package/dist/commands/archive/plan/document/head.js.map +1 -0
  31. package/dist/commands/archive/plan/document/links.js +284 -0
  32. package/dist/commands/archive/plan/document/links.js.map +1 -0
  33. package/dist/commands/archive/plan/document/run.js +136 -0
  34. package/dist/commands/archive/plan/document/run.js.map +1 -0
  35. package/dist/commands/archive/plan/gate.js +319 -0
  36. package/dist/commands/archive/plan/gate.js.map +1 -0
  37. package/dist/commands/archive/plan/landscape.js +298 -0
  38. package/dist/commands/archive/plan/landscape.js.map +1 -0
  39. package/dist/commands/archive/plan/model/extending.js +85 -0
  40. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  41. package/dist/commands/archive/plan/refusal.js +106 -0
  42. package/dist/commands/archive/plan/refusal.js.map +1 -0
  43. package/dist/commands/archive/plan/specs.js +318 -0
  44. package/dist/commands/archive/plan/specs.js.map +1 -0
  45. package/dist/commands/archive/plan/state.js +30 -0
  46. package/dist/commands/archive/plan/state.js.map +1 -0
  47. package/dist/commands/archive/run.js +355 -0
  48. package/dist/commands/archive/run.js.map +1 -0
  49. package/dist/commands/archive/shipped.js +49 -0
  50. package/dist/commands/archive/shipped.js.map +1 -0
  51. package/dist/commands/context/context.js +166 -0
  52. package/dist/commands/context/context.js.map +1 -0
  53. package/dist/commands/context/print.js +305 -0
  54. package/dist/commands/context/print.js.map +1 -0
  55. package/dist/commands/delta/delta.js +367 -0
  56. package/dist/commands/delta/delta.js.map +1 -0
  57. package/dist/commands/delta/print.js +221 -0
  58. package/dist/commands/delta/print.js.map +1 -0
  59. package/dist/commands/dependencies.js +6 -8
  60. package/dist/commands/dependencies.js.map +1 -1
  61. package/dist/commands/diff/diff.js +86 -0
  62. package/dist/commands/diff/diff.js.map +1 -0
  63. package/dist/commands/diff/print.js +38 -0
  64. package/dist/commands/diff/print.js.map +1 -0
  65. package/dist/commands/doctor.js +65 -5
  66. package/dist/commands/doctor.js.map +1 -1
  67. package/dist/commands/explain/explain.js +227 -0
  68. package/dist/commands/explain/explain.js.map +1 -0
  69. package/dist/commands/explore.js +39 -28
  70. package/dist/commands/explore.js.map +1 -1
  71. package/dist/commands/gate/gate.js +152 -0
  72. package/dist/commands/gate/gate.js.map +1 -0
  73. package/dist/commands/gate/print.js +66 -0
  74. package/dist/commands/gate/print.js.map +1 -0
  75. package/dist/commands/gherkin/commit.js +105 -0
  76. package/dist/commands/gherkin/commit.js.map +1 -0
  77. package/dist/commands/gherkin/gherkin.js +262 -0
  78. package/dist/commands/gherkin/gherkin.js.map +1 -0
  79. package/dist/commands/gherkin/reconcile.js +146 -0
  80. package/dist/commands/gherkin/reconcile.js.map +1 -0
  81. package/dist/commands/gherkin/render.js +77 -0
  82. package/dist/commands/gherkin/render.js.map +1 -0
  83. package/dist/commands/init/example.js +204 -0
  84. package/dist/commands/init/example.js.map +1 -0
  85. package/dist/commands/init/first-hour.js +72 -0
  86. package/dist/commands/init/first-hour.js.map +1 -0
  87. package/dist/commands/{init.js → init/init.js} +142 -71
  88. package/dist/commands/init/init.js.map +1 -0
  89. package/dist/commands/init/mcp.js +131 -0
  90. package/dist/commands/init/mcp.js.map +1 -0
  91. package/dist/commands/init/options.js +78 -0
  92. package/dist/commands/init/options.js.map +1 -0
  93. package/dist/commands/instructions.js +72 -14
  94. package/dist/commands/instructions.js.map +1 -1
  95. package/dist/commands/list/campaign/campaign.js +63 -0
  96. package/dist/commands/list/campaign/campaign.js.map +1 -0
  97. package/dist/commands/list/campaign/owners.js +65 -0
  98. package/dist/commands/list/campaign/owners.js.map +1 -0
  99. package/dist/commands/list/json.js +155 -0
  100. package/dist/commands/list/json.js.map +1 -0
  101. package/dist/commands/list/list.js +358 -0
  102. package/dist/commands/list/list.js.map +1 -0
  103. package/dist/commands/list/print.js +344 -0
  104. package/dist/commands/list/print.js.map +1 -0
  105. package/dist/commands/list/review.js +120 -0
  106. package/dist/commands/list/review.js.map +1 -0
  107. package/dist/commands/list/suites/suites.js +140 -0
  108. package/dist/commands/list/suites/suites.js.map +1 -0
  109. package/dist/commands/list/views.js +108 -0
  110. package/dist/commands/list/views.js.map +1 -0
  111. package/dist/commands/mcp/dispatch.js +238 -0
  112. package/dist/commands/mcp/dispatch.js.map +1 -0
  113. package/dist/commands/mcp/mcp.js +75 -0
  114. package/dist/commands/mcp/mcp.js.map +1 -0
  115. package/dist/commands/mcp/serve.js +55 -0
  116. package/dist/commands/mcp/serve.js.map +1 -0
  117. package/dist/commands/migrate-openspec/materialize/active.js +175 -0
  118. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  119. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  120. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  121. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  122. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  123. package/dist/commands/migrate-openspec/materialize/stage.js +143 -0
  124. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  125. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  126. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  127. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  128. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  129. package/dist/commands/migrate-openspec/openspec/decisions.js +86 -0
  130. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  131. package/dist/commands/migrate-openspec/openspec/error.js +18 -0
  132. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  133. package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
  134. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  135. package/dist/commands/migrate-openspec/openspec/paths.js +40 -0
  136. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  137. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  138. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  139. package/dist/commands/migrate-openspec/print.js +89 -0
  140. package/dist/commands/migrate-openspec/print.js.map +1 -0
  141. package/dist/commands/new/capability-template.js +118 -0
  142. package/dist/commands/new/capability-template.js.map +1 -0
  143. package/dist/commands/new/commit.js +62 -0
  144. package/dist/commands/new/commit.js.map +1 -0
  145. package/dist/commands/new/modifies.js +206 -0
  146. package/dist/commands/new/modifies.js.map +1 -0
  147. package/dist/commands/new/new.js +328 -0
  148. package/dist/commands/new/new.js.map +1 -0
  149. package/dist/commands/new/templates.js +279 -0
  150. package/dist/commands/new/templates.js.map +1 -0
  151. package/dist/commands/open.js +199 -0
  152. package/dist/commands/open.js.map +1 -0
  153. package/dist/commands/policy/format.js +152 -0
  154. package/dist/commands/policy/format.js.map +1 -0
  155. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +38 -11
  156. package/dist/commands/policy/gate.js.map +1 -0
  157. package/dist/commands/rebase/edit.js +106 -0
  158. package/dist/commands/rebase/edit.js.map +1 -0
  159. package/dist/commands/rebase/living.js +185 -0
  160. package/dist/commands/rebase/living.js.map +1 -0
  161. package/dist/commands/rebase/plan.js +245 -0
  162. package/dist/commands/rebase/plan.js.map +1 -0
  163. package/dist/commands/rebase/rebase.js +300 -0
  164. package/dist/commands/rebase/rebase.js.map +1 -0
  165. package/dist/commands/seed/commit.js +221 -0
  166. package/dist/commands/seed/commit.js.map +1 -0
  167. package/dist/commands/seed/plan.js +278 -0
  168. package/dist/commands/seed/plan.js.map +1 -0
  169. package/dist/commands/seed/seed.js +174 -0
  170. package/dist/commands/seed/seed.js.map +1 -0
  171. package/dist/commands/show/feature.js +182 -0
  172. package/dist/commands/show/feature.js.map +1 -0
  173. package/dist/commands/show/introduced.js +157 -0
  174. package/dist/commands/show/introduced.js.map +1 -0
  175. package/dist/commands/show/marks.js +53 -0
  176. package/dist/commands/show/marks.js.map +1 -0
  177. package/dist/commands/show/service.js +239 -0
  178. package/dist/commands/show/service.js.map +1 -0
  179. package/dist/commands/show/show.js +87 -0
  180. package/dist/commands/show/show.js.map +1 -0
  181. package/dist/commands/status/fleet-next.js +90 -0
  182. package/dist/commands/status/fleet-next.js.map +1 -0
  183. package/dist/commands/status/json.js +47 -0
  184. package/dist/commands/status/json.js.map +1 -0
  185. package/dist/commands/status/print.js +209 -0
  186. package/dist/commands/status/print.js.map +1 -0
  187. package/dist/commands/status/status.js +115 -0
  188. package/dist/commands/status/status.js.map +1 -0
  189. package/dist/commands/steps/steps.js +269 -0
  190. package/dist/commands/steps/steps.js.map +1 -0
  191. package/dist/commands/subsystem/edit.js +192 -0
  192. package/dist/commands/subsystem/edit.js.map +1 -0
  193. package/dist/commands/subsystem/move.js +325 -0
  194. package/dist/commands/subsystem/move.js.map +1 -0
  195. package/dist/commands/subsystem/query.js +113 -0
  196. package/dist/commands/subsystem/query.js.map +1 -0
  197. package/dist/commands/subsystem/subsystem.js +98 -0
  198. package/dist/commands/subsystem/subsystem.js.map +1 -0
  199. package/dist/commands/subsystem/sync.js +318 -0
  200. package/dist/commands/subsystem/sync.js.map +1 -0
  201. package/dist/commands/subsystem/txn/exclude.js +132 -0
  202. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  203. package/dist/commands/subsystem/txn/links.js +128 -0
  204. package/dist/commands/subsystem/txn/links.js.map +1 -0
  205. package/dist/commands/subsystem/txn/report.js +174 -0
  206. package/dist/commands/subsystem/txn/report.js.map +1 -0
  207. package/dist/commands/subsystem/txn/txn.js +196 -0
  208. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  209. package/dist/commands/subsystem/txn/views.js +249 -0
  210. package/dist/commands/subsystem/txn/views.js.map +1 -0
  211. package/dist/commands/tasks/actions.js +107 -0
  212. package/dist/commands/tasks/actions.js.map +1 -0
  213. package/dist/commands/tasks/render.js +253 -0
  214. package/dist/commands/tasks/render.js.map +1 -0
  215. package/dist/commands/tasks/tasks.js +119 -0
  216. package/dist/commands/tasks/tasks.js.map +1 -0
  217. package/dist/commands/unarchive/manifest.js +176 -0
  218. package/dist/commands/unarchive/manifest.js.map +1 -0
  219. package/dist/commands/unarchive/restore.js +254 -0
  220. package/dist/commands/unarchive/restore.js.map +1 -0
  221. package/dist/commands/unarchive/unarchive.js +59 -0
  222. package/dist/commands/unarchive/unarchive.js.map +1 -0
  223. package/dist/commands/validate/arch-coverage.js +245 -0
  224. package/dist/commands/validate/arch-coverage.js.map +1 -0
  225. package/dist/commands/validate/checks/fleet-shape.js +204 -0
  226. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  227. package/dist/commands/validate/checks/health-deps.js +58 -0
  228. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  229. package/dist/commands/validate/checks/introduced.js +102 -0
  230. package/dist/commands/validate/checks/introduced.js.map +1 -0
  231. package/dist/commands/validate/checks/requirements.js +264 -0
  232. package/dist/commands/validate/checks/requirements.js.map +1 -0
  233. package/dist/commands/validate/checks/sources.js +85 -0
  234. package/dist/commands/validate/checks/sources.js.map +1 -0
  235. package/dist/commands/validate/coverage/covers-after.js +105 -0
  236. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  237. package/dist/commands/validate/feature.js +222 -0
  238. package/dist/commands/validate/feature.js.map +1 -0
  239. package/dist/commands/validate/fleet/census.js +93 -0
  240. package/dist/commands/validate/fleet/census.js.map +1 -0
  241. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  242. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  243. package/dist/commands/validate/fleet/landscape.js +371 -0
  244. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  245. package/dist/commands/validate/fleet/load.js +118 -0
  246. package/dist/commands/validate/fleet/load.js.map +1 -0
  247. package/dist/commands/validate/fleet/map/attest.js +98 -0
  248. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  249. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  250. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  251. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  252. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  253. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  254. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  255. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  256. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  257. package/dist/commands/validate/fleet/obligations.js +266 -0
  258. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  259. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  260. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  261. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  262. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  263. package/dist/commands/validate/fleet/scorecard/print.js +71 -0
  264. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  265. package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
  266. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  267. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  268. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  269. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  270. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  271. package/dist/commands/validate/fleet/views/ids.js +75 -0
  272. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  273. package/dist/commands/validate/fleet/views/projects.js +278 -0
  274. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  275. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  276. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  277. package/dist/commands/validate/fleet/views/stale.js +52 -0
  278. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  279. package/dist/commands/validate/links/corpus.js +89 -0
  280. package/dist/commands/validate/links/corpus.js.map +1 -0
  281. package/dist/commands/validate/links/glossary.js +75 -0
  282. package/dist/commands/validate/links/glossary.js.map +1 -0
  283. package/dist/commands/validate/render/repeats.js +63 -0
  284. package/dist/commands/validate/render/repeats.js.map +1 -0
  285. package/dist/commands/validate/render/rollups.js +115 -0
  286. package/dist/commands/validate/render/rollups.js.map +1 -0
  287. package/dist/commands/validate/render/text.js +199 -0
  288. package/dist/commands/validate/render/text.js.map +1 -0
  289. package/dist/commands/validate/report.js +145 -0
  290. package/dist/commands/validate/report.js.map +1 -0
  291. package/dist/commands/validate/scope.js +113 -0
  292. package/dist/commands/validate/scope.js.map +1 -0
  293. package/dist/commands/validate/service/api.js +252 -0
  294. package/dist/commands/validate/service/api.js.map +1 -0
  295. package/dist/commands/validate/service/contracts/generated.js +134 -0
  296. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  297. package/dist/commands/validate/service/events/events.js +241 -0
  298. package/dist/commands/validate/service/events/events.js.map +1 -0
  299. package/dist/commands/validate/service/events/message-producers.js +77 -0
  300. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  301. package/dist/commands/validate/service/evidence-pins.js +177 -0
  302. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  303. package/dist/commands/validate/service/model/diverged.js +226 -0
  304. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  305. package/dist/commands/validate/service/model/grade.js +163 -0
  306. package/dist/commands/validate/service/model/grade.js.map +1 -0
  307. package/dist/commands/validate/service/service.js +310 -0
  308. package/dist/commands/validate/service/service.js.map +1 -0
  309. package/dist/commands/validate/service/specs.js +279 -0
  310. package/dist/commands/validate/service/specs.js.map +1 -0
  311. package/dist/commands/validate/service/spine.js +148 -0
  312. package/dist/commands/validate/service/spine.js.map +1 -0
  313. package/dist/commands/validate/service/usecases/tags.js +113 -0
  314. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  315. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  316. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  317. package/dist/commands/validate/validate.js +363 -0
  318. package/dist/commands/validate/validate.js.map +1 -0
  319. package/dist/commands/verify/cross/diff.js +178 -0
  320. package/dist/commands/verify/cross/diff.js.map +1 -0
  321. package/dist/commands/verify/evidence/contract.js +32 -0
  322. package/dist/commands/verify/evidence/contract.js.map +1 -0
  323. package/dist/commands/verify/evidence/pins.js +52 -0
  324. package/dist/commands/verify/evidence/pins.js.map +1 -0
  325. package/dist/commands/verify/evidence/read.js +81 -0
  326. package/dist/commands/verify/evidence/read.js.map +1 -0
  327. package/dist/commands/verify/frozen.js +263 -0
  328. package/dist/commands/verify/frozen.js.map +1 -0
  329. package/dist/commands/verify/record.js +278 -0
  330. package/dist/commands/verify/record.js.map +1 -0
  331. package/dist/commands/verify/report.js +206 -0
  332. package/dist/commands/verify/report.js.map +1 -0
  333. package/dist/commands/verify/results.js +328 -0
  334. package/dist/commands/verify/results.js.map +1 -0
  335. package/dist/commands/verify/verify.js +220 -0
  336. package/dist/commands/verify/verify.js.map +1 -0
  337. package/dist/commands/vouch/contract.js +11 -0
  338. package/dist/commands/vouch/contract.js.map +1 -0
  339. package/dist/commands/vouch/pack/contract.js +2 -0
  340. package/dist/commands/vouch/pack/contract.js.map +1 -0
  341. package/dist/commands/vouch/pack/pack.js +266 -0
  342. package/dist/commands/vouch/pack/pack.js.map +1 -0
  343. package/dist/commands/vouch/pack/print.js +266 -0
  344. package/dist/commands/vouch/pack/print.js.map +1 -0
  345. package/dist/commands/vouch/pack/sections.js +141 -0
  346. package/dist/commands/vouch/pack/sections.js.map +1 -0
  347. package/dist/commands/vouch/prompt/confirm.js +46 -0
  348. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  349. package/dist/commands/vouch/report.js +101 -0
  350. package/dist/commands/vouch/report.js.map +1 -0
  351. package/dist/commands/vouch/run.js +230 -0
  352. package/dist/commands/vouch/run.js.map +1 -0
  353. package/dist/commands/vouch/sample/plan.js +111 -0
  354. package/dist/commands/vouch/sample/plan.js.map +1 -0
  355. package/dist/commands/vouch/sample/print.js +109 -0
  356. package/dist/commands/vouch/sample/print.js.map +1 -0
  357. package/dist/commands/vouch/vet/verify.js +155 -0
  358. package/dist/commands/vouch/vet/verify.js.map +1 -0
  359. package/dist/commands/vouch/vouch.js +169 -0
  360. package/dist/commands/vouch/vouch.js.map +1 -0
  361. package/dist/core/agent/agents-md/command-map.js +299 -0
  362. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  363. package/dist/core/agent/agents-md/map/explain.js +46 -0
  364. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  365. package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
  366. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  367. package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
  368. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  369. package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
  370. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  371. package/dist/core/agent/agents-md/map/mcp.js +44 -0
  372. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  373. package/dist/core/agent/agents-md/map/status.js +78 -0
  374. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  375. package/dist/core/agent/agents-md/map/subsystem.js +104 -0
  376. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  377. package/dist/core/agent/agents-md/map/usecases.js +138 -0
  378. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  379. package/dist/core/agent/agents-md/refusals.js +273 -0
  380. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  381. package/dist/core/agent/agents-md.js +203 -0
  382. package/dist/core/agent/agents-md.js.map +1 -0
  383. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -0
  384. package/dist/core/agent/agents-stamp.js.map +1 -0
  385. package/dist/core/agent/contract.js +2 -0
  386. package/dist/core/agent/contract.js.map +1 -0
  387. package/dist/core/agent/protocol.js +193 -0
  388. package/dist/core/agent/protocol.js.map +1 -0
  389. package/dist/core/agent/scaffold.js +254 -0
  390. package/dist/core/agent/scaffold.js.map +1 -0
  391. package/dist/core/agent/support/report.js +144 -0
  392. package/dist/core/agent/support/report.js.map +1 -0
  393. package/dist/core/agent/tools/dialects.js +151 -0
  394. package/dist/core/agent/tools/dialects.js.map +1 -0
  395. package/dist/core/agent/tools/registry.js +193 -0
  396. package/dist/core/agent/tools/registry.js.map +1 -0
  397. package/dist/core/agent/workflows/adopt.js +280 -0
  398. package/dist/core/agent/workflows/adopt.js.map +1 -0
  399. package/dist/core/agent/workflows/check.js +373 -0
  400. package/dist/core/agent/workflows/check.js.map +1 -0
  401. package/dist/core/agent/workflows/closing.js +323 -0
  402. package/dist/core/agent/workflows/closing.js.map +1 -0
  403. package/dist/core/agent/workflows/feature.js +220 -0
  404. package/dist/core/agent/workflows/feature.js.map +1 -0
  405. package/dist/core/agent/workflows/implement.js +188 -0
  406. package/dist/core/agent/workflows/implement.js.map +1 -0
  407. package/dist/core/agent/workflows/reference/authoring.js +311 -0
  408. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  409. package/dist/core/agent/workflows/reference/codes.js +67 -0
  410. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  411. package/dist/core/agent/workflows/reference/done-check.js +210 -0
  412. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  413. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  414. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  415. package/dist/core/agent/workflows/reference/reference.js +19 -0
  416. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  417. package/dist/core/agent/workflows/reference/spine.js +338 -0
  418. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  419. package/dist/core/asyncapi/baseline/plan.js +43 -0
  420. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  421. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  422. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  423. package/dist/core/asyncapi/depth.js +164 -0
  424. package/dist/core/asyncapi/depth.js.map +1 -0
  425. package/dist/core/asyncapi/digest.js +146 -0
  426. package/dist/core/asyncapi/digest.js.map +1 -0
  427. package/dist/core/asyncapi/merge/components.js +92 -0
  428. package/dist/core/asyncapi/merge/components.js.map +1 -0
  429. package/dist/core/asyncapi/merge/error.js +38 -0
  430. package/dist/core/asyncapi/merge/error.js.map +1 -0
  431. package/dist/core/asyncapi/merge/markers.js +290 -0
  432. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  433. package/dist/core/asyncapi/merge/merge.js +195 -0
  434. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  435. package/dist/core/asyncapi/merge/pin.js +83 -0
  436. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  437. package/dist/core/asyncapi/model.js +11 -0
  438. package/dist/core/asyncapi/model.js.map +1 -0
  439. package/dist/core/asyncapi/producers.js +50 -0
  440. package/dist/core/asyncapi/producers.js.map +1 -0
  441. package/dist/core/asyncapi/read.js +263 -0
  442. package/dist/core/asyncapi/read.js.map +1 -0
  443. package/dist/core/brief/brief.js +285 -0
  444. package/dist/core/brief/brief.js.map +1 -0
  445. package/dist/core/brief/checks.js +385 -0
  446. package/dist/core/brief/checks.js.map +1 -0
  447. package/dist/core/brief/landscape.js +273 -0
  448. package/dist/core/brief/landscape.js.map +1 -0
  449. package/dist/core/brief/map/extend.js +84 -0
  450. package/dist/core/brief/map/extend.js.map +1 -0
  451. package/dist/core/brief/map/owed.js +266 -0
  452. package/dist/core/brief/map/owed.js.map +1 -0
  453. package/dist/core/brief/targets.js +304 -0
  454. package/dist/core/brief/targets.js.map +1 -0
  455. package/dist/core/brief/unchecked.js +58 -0
  456. package/dist/core/brief/unchecked.js.map +1 -0
  457. package/dist/core/c4/arch.js +190 -0
  458. package/dist/core/c4/arch.js.map +1 -0
  459. package/dist/core/c4/direction/direction.js +114 -0
  460. package/dist/core/c4/direction/direction.js.map +1 -0
  461. package/dist/core/c4/likec4.js +243 -0
  462. package/dist/core/c4/likec4.js.map +1 -0
  463. package/dist/core/c4/locate/unlocated.js +150 -0
  464. package/dist/core/c4/locate/unlocated.js.map +1 -0
  465. package/dist/core/c4/parsed/deployment.js +160 -0
  466. package/dist/core/c4/parsed/deployment.js.map +1 -0
  467. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  468. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  469. package/dist/core/c4/parsed/specification.js +78 -0
  470. package/dist/core/c4/parsed/specification.js.map +1 -0
  471. package/dist/core/c4/parsed/values.js +110 -0
  472. package/dist/core/c4/parsed/values.js.map +1 -0
  473. package/dist/core/c4/parsed/view-ids.js +113 -0
  474. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  475. package/dist/core/c4/prefetch/fleet.js +134 -0
  476. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  477. package/dist/core/c4/project/architecture.js +161 -0
  478. package/dist/core/c4/project/architecture.js.map +1 -0
  479. package/dist/core/c4/project/batch.js +140 -0
  480. package/dist/core/c4/project/batch.js.map +1 -0
  481. package/dist/core/c4/project/documents.js +89 -0
  482. package/dist/core/c4/project/documents.js.map +1 -0
  483. package/dist/core/c4/project/load.js +219 -0
  484. package/dist/core/c4/project/load.js.map +1 -0
  485. package/dist/core/c4/project/staged.js +277 -0
  486. package/dist/core/c4/project/staged.js.map +1 -0
  487. package/dist/core/c4/resolve/attested.js +0 -0
  488. package/dist/core/c4/resolve/attested.js.map +1 -0
  489. package/dist/core/c4/resolve/external.js +51 -0
  490. package/dist/core/c4/resolve/external.js.map +1 -0
  491. package/dist/core/c4/resolve/service.js +174 -0
  492. package/dist/core/c4/resolve/service.js.map +1 -0
  493. package/dist/core/c4/resolve/steps.js +290 -0
  494. package/dist/core/c4/resolve/steps.js.map +1 -0
  495. package/dist/core/c4/resolve/systems.js +154 -0
  496. package/dist/core/c4/resolve/systems.js.map +1 -0
  497. package/dist/core/c4/root-project/exclude.js +352 -0
  498. package/dist/core/c4/root-project/exclude.js.map +1 -0
  499. package/dist/core/c4/seed/fleet-file.js +201 -0
  500. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  501. package/dist/core/c4/seed/items.js +91 -0
  502. package/dist/core/c4/seed/items.js.map +1 -0
  503. package/dist/core/c4/seed/stamp.js +48 -0
  504. package/dist/core/c4/seed/stamp.js.map +1 -0
  505. package/dist/core/c4/seed/template.js +173 -0
  506. package/dist/core/c4/seed/template.js.map +1 -0
  507. package/dist/core/c4/service-model/created/models.js +96 -0
  508. package/dist/core/c4/service-model/created/models.js.map +1 -0
  509. package/dist/core/c4/service-model/documents.js +47 -0
  510. package/dist/core/c4/service-model/documents.js.map +1 -0
  511. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  512. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  513. package/dist/core/c4/service-model/load.js +165 -0
  514. package/dist/core/c4/service-model/load.js.map +1 -0
  515. package/dist/core/c4/service-model/renderer.js +128 -0
  516. package/dist/core/c4/service-model/renderer.js.map +1 -0
  517. package/dist/core/c4/service-model/shape.js +106 -0
  518. package/dist/core/c4/service-model/shape.js.map +1 -0
  519. package/dist/core/c4/service-model/slice.js +188 -0
  520. package/dist/core/c4/service-model/slice.js.map +1 -0
  521. package/dist/core/c4/source-mask.js +369 -0
  522. package/dist/core/c4/source-mask.js.map +1 -0
  523. package/dist/core/c4/source-scan.js +308 -0
  524. package/dist/core/c4/source-scan.js.map +1 -0
  525. package/dist/core/c4/splice/authored-source.js +167 -0
  526. package/dist/core/c4/splice/authored-source.js.map +1 -0
  527. package/dist/core/c4/splice/contract.js +30 -0
  528. package/dist/core/c4/splice/contract.js.map +1 -0
  529. package/dist/core/c4/splice/delta-blocks.js +126 -0
  530. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  531. package/dist/core/c4/splice/identity/declared.js +87 -0
  532. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  533. package/dist/core/c4/splice/identity/edges.js +73 -0
  534. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  535. package/dist/core/c4/splice/identity/existing.js +80 -0
  536. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  537. package/dist/core/c4/splice/identity/interior.js +80 -0
  538. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  539. package/dist/core/c4/splice/identity/owner.js +50 -0
  540. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  541. package/dist/core/c4/splice/landscape-merge.js +337 -0
  542. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  543. package/dist/core/c4/splice/model/merge.js +151 -0
  544. package/dist/core/c4/splice/model/merge.js.map +1 -0
  545. package/dist/core/c4/splice/placement.js +298 -0
  546. package/dist/core/c4/splice/placement.js.map +1 -0
  547. package/dist/core/c4/splice/text/spot.js +131 -0
  548. package/dist/core/c4/splice/text/spot.js.map +1 -0
  549. package/dist/core/c4/workspace.js +166 -0
  550. package/dist/core/c4/workspace.js.map +1 -0
  551. package/dist/core/capabilities/authoring/notes.js +141 -0
  552. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  553. package/dist/core/capabilities/capabilities.js +124 -0
  554. package/dist/core/capabilities/capabilities.js.map +1 -0
  555. package/dist/core/capabilities/delta/doc.js +47 -0
  556. package/dist/core/capabilities/delta/doc.js.map +1 -0
  557. package/dist/core/capabilities/delta/overlay.js +129 -0
  558. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  559. package/dist/core/capabilities/delta/summary.js +57 -0
  560. package/dist/core/capabilities/delta/summary.js.map +1 -0
  561. package/dist/core/capabilities/delta/tree.js +43 -0
  562. package/dist/core/capabilities/delta/tree.js.map +1 -0
  563. package/dist/core/capabilities/delta/uncovered.js +222 -0
  564. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  565. package/dist/core/capabilities/findings.js +338 -0
  566. package/dist/core/capabilities/findings.js.map +1 -0
  567. package/dist/core/capabilities/realizes/findings.js +174 -0
  568. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  569. package/dist/core/capabilities/realizes/join.js +123 -0
  570. package/dist/core/capabilities/realizes/join.js.map +1 -0
  571. package/dist/core/capabilities/rollup.js +205 -0
  572. package/dist/core/capabilities/rollup.js.map +1 -0
  573. package/dist/core/capabilities/tree.js +104 -0
  574. package/dist/core/capabilities/tree.js.map +1 -0
  575. package/dist/core/capabilities/usecase-join.js +267 -0
  576. package/dist/core/capabilities/usecase-join.js.map +1 -0
  577. package/dist/core/coherence/authoring/scaffold.js +185 -0
  578. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  579. package/dist/core/coherence/authoring/sentinels.js +75 -0
  580. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  581. package/dist/core/coherence/calls/called.js +52 -0
  582. package/dist/core/coherence/calls/called.js.map +1 -0
  583. package/dist/core/coherence/coherence.js +332 -0
  584. package/dist/core/coherence/coherence.js.map +1 -0
  585. package/dist/core/coherence/consumed/operations.js +70 -0
  586. package/dist/core/coherence/consumed/operations.js.map +1 -0
  587. package/dist/core/coherence/consumed/refusal.js +38 -0
  588. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  589. package/dist/core/coherence/covers/health.js +85 -0
  590. package/dist/core/coherence/covers/health.js.map +1 -0
  591. package/dist/core/coherence/declared.js +295 -0
  592. package/dist/core/coherence/declared.js.map +1 -0
  593. package/dist/core/coherence/events/declared.js +191 -0
  594. package/dist/core/coherence/events/declared.js.map +1 -0
  595. package/dist/core/coherence/events/events.js +335 -0
  596. package/dist/core/coherence/events/events.js.map +1 -0
  597. package/dist/core/coherence/events/grades.js +189 -0
  598. package/dist/core/coherence/events/grades.js.map +1 -0
  599. package/dist/core/coherence/events/lookups.js +63 -0
  600. package/dist/core/coherence/events/lookups.js.map +1 -0
  601. package/dist/core/coherence/events/produced.js +100 -0
  602. package/dist/core/coherence/events/produced.js.map +1 -0
  603. package/dist/core/coherence/living.js +198 -0
  604. package/dist/core/coherence/living.js.map +1 -0
  605. package/dist/core/coherence/lookups.js +95 -0
  606. package/dist/core/coherence/lookups.js.map +1 -0
  607. package/dist/core/coherence/pending.js +39 -0
  608. package/dist/core/coherence/pending.js.map +1 -0
  609. package/dist/core/coherence/retired/archived.js +285 -0
  610. package/dist/core/coherence/retired/archived.js.map +1 -0
  611. package/dist/core/coherence/retired/event-pair.js +62 -0
  612. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  613. package/dist/core/coherence/retired/merged.js +79 -0
  614. package/dist/core/coherence/retired/merged.js.map +1 -0
  615. package/dist/core/coherence/retired/retirement.js +49 -0
  616. package/dist/core/coherence/retired/retirement.js.map +1 -0
  617. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  618. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  619. package/dist/core/coherence/retired/revival/revived.js +297 -0
  620. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  621. package/dist/core/conflict-markers.js +60 -0
  622. package/dist/core/conflict-markers.js.map +1 -0
  623. package/dist/core/consumers/after.js +113 -0
  624. package/dist/core/consumers/after.js.map +1 -0
  625. package/dist/core/consumers/consumers.js +296 -0
  626. package/dist/core/consumers/consumers.js.map +1 -0
  627. package/dist/core/consumers/current.js +211 -0
  628. package/dist/core/consumers/current.js.map +1 -0
  629. package/dist/core/consumers/scan.js +46 -0
  630. package/dist/core/consumers/scan.js.map +1 -0
  631. package/dist/core/consumers/state.js +27 -0
  632. package/dist/core/consumers/state.js.map +1 -0
  633. package/dist/core/delta/claims.js +73 -0
  634. package/dist/core/delta/claims.js.map +1 -0
  635. package/dist/core/delta/delta.js +341 -0
  636. package/dist/core/delta/delta.js.map +1 -0
  637. package/dist/core/delta/document.js +177 -0
  638. package/dist/core/delta/document.js.map +1 -0
  639. package/dist/core/delta/scope.js +48 -0
  640. package/dist/core/delta/scope.js.map +1 -0
  641. package/dist/core/delta/select.js +237 -0
  642. package/dist/core/delta/select.js.map +1 -0
  643. package/dist/core/dependencies/dependencies.js +141 -0
  644. package/dist/core/dependencies/dependencies.js.map +1 -0
  645. package/dist/core/dependencies/facts.js +165 -0
  646. package/dist/core/dependencies/facts.js.map +1 -0
  647. package/dist/core/dependencies/fanin.js +88 -0
  648. package/dist/core/dependencies/fanin.js.map +1 -0
  649. package/dist/core/dependencies/graph.js +106 -0
  650. package/dist/core/dependencies/graph.js.map +1 -0
  651. package/dist/core/deployment/delta.js +191 -0
  652. package/dist/core/deployment/delta.js.map +1 -0
  653. package/dist/core/deployment/objects.js +145 -0
  654. package/dist/core/deployment/objects.js.map +1 -0
  655. package/dist/core/diff/base-git.js +230 -0
  656. package/dist/core/diff/base-git.js.map +1 -0
  657. package/dist/core/diff/base-state.js +237 -0
  658. package/dist/core/diff/base-state.js.map +1 -0
  659. package/dist/core/diff/joins.js +136 -0
  660. package/dist/core/diff/joins.js.map +1 -0
  661. package/dist/core/diff/scope/changed-paths.js +204 -0
  662. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  663. package/dist/core/diff/scope/edges.js +82 -0
  664. package/dist/core/diff/scope/edges.js.map +1 -0
  665. package/dist/core/diff/semantic.js +312 -0
  666. package/dist/core/diff/semantic.js.map +1 -0
  667. package/dist/core/docs.js +37 -85
  668. package/dist/core/docs.js.map +1 -1
  669. package/dist/core/doctor/agents.js +238 -0
  670. package/dist/core/doctor/agents.js.map +1 -0
  671. package/dist/core/doctor/config.js +139 -0
  672. package/dist/core/doctor/config.js.map +1 -0
  673. package/dist/core/doctor/doctor.js +355 -0
  674. package/dist/core/doctor/doctor.js.map +1 -0
  675. package/dist/core/doctor/report.js +13 -0
  676. package/dist/core/doctor/report.js.map +1 -0
  677. package/dist/core/doctor/reports/scan.js +242 -0
  678. package/dist/core/doctor/reports/scan.js.map +1 -0
  679. package/dist/core/doctor/residue.js +110 -0
  680. package/dist/core/doctor/residue.js.map +1 -0
  681. package/dist/core/document/apply.js +224 -0
  682. package/dist/core/document/apply.js.map +1 -0
  683. package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -2
  684. package/dist/core/document/frontmatter.js.map +1 -0
  685. package/dist/core/document/grammar/directives.js +143 -0
  686. package/dist/core/document/grammar/directives.js.map +1 -0
  687. package/dist/core/document/parse.js +286 -0
  688. package/dist/core/document/parse.js.map +1 -0
  689. package/dist/core/document/scenarios.js +238 -0
  690. package/dist/core/document/scenarios.js.map +1 -0
  691. package/dist/core/document/spec.js +234 -0
  692. package/dist/core/document/spec.js.map +1 -0
  693. package/dist/core/{config.js → envelope/config.js} +89 -18
  694. package/dist/core/envelope/config.js.map +1 -0
  695. package/dist/core/envelope/json.js +209 -0
  696. package/dist/core/envelope/json.js.map +1 -0
  697. package/dist/core/{version.js → envelope/version.js} +3 -3
  698. package/dist/core/envelope/version.js.map +1 -0
  699. package/dist/core/explain/families.js +180 -0
  700. package/dist/core/explain/families.js.map +1 -0
  701. package/dist/core/explain/fix-tables.js +178 -0
  702. package/dist/core/explain/fix-tables.js.map +1 -0
  703. package/dist/core/explain/lookup.js +194 -0
  704. package/dist/core/explain/lookup.js.map +1 -0
  705. package/dist/core/explain/refusals.js +49 -0
  706. package/dist/core/explain/refusals.js.map +1 -0
  707. package/dist/core/explain/terms/documents.js +227 -0
  708. package/dist/core/explain/terms/documents.js.map +1 -0
  709. package/dist/core/explain/terms/done-check.js +144 -0
  710. package/dist/core/explain/terms/done-check.js.map +1 -0
  711. package/dist/core/explain/terms/entry.js +14 -0
  712. package/dist/core/explain/terms/entry.js.map +1 -0
  713. package/dist/core/explain/terms/stages.js +71 -0
  714. package/dist/core/explain/terms/stages.js.map +1 -0
  715. package/dist/core/explain/terms/tasks.js +97 -0
  716. package/dist/core/explain/terms/tasks.js.map +1 -0
  717. package/dist/core/explain/terms.js +103 -0
  718. package/dist/core/explain/terms.js.map +1 -0
  719. package/dist/core/explore/describe.js +105 -0
  720. package/dist/core/explore/describe.js.map +1 -0
  721. package/dist/core/explore/explore.js +204 -0
  722. package/dist/core/explore/explore.js.map +1 -0
  723. package/dist/core/fleet-context.js +174 -146
  724. package/dist/core/fleet-context.js.map +1 -1
  725. package/dist/core/gate/checks.js +208 -0
  726. package/dist/core/gate/checks.js.map +1 -0
  727. package/dist/core/gate/partners.js +246 -0
  728. package/dist/core/gate/partners.js.map +1 -0
  729. package/dist/core/gate/report.js +47 -0
  730. package/dist/core/gate/report.js.map +1 -0
  731. package/dist/core/gate/verification.js +176 -0
  732. package/dist/core/gate/verification.js.map +1 -0
  733. package/dist/core/gherkin/digest.js +60 -0
  734. package/dist/core/gherkin/digest.js.map +1 -0
  735. package/dist/core/gherkin/emit.js +177 -0
  736. package/dist/core/gherkin/emit.js.map +1 -0
  737. package/dist/core/gherkin/read.js +76 -0
  738. package/dist/core/gherkin/read.js.map +1 -0
  739. package/dist/core/gherkin/stale.js +210 -0
  740. package/dist/core/gherkin/stale.js.map +1 -0
  741. package/dist/core/gherkin/stamp.js +77 -0
  742. package/dist/core/gherkin/stamp.js.map +1 -0
  743. package/dist/core/gherkin/steps/catalogue.js +154 -0
  744. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  745. package/dist/core/gherkin/steps/inventory.js +98 -0
  746. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  747. package/dist/core/gherkin/steps/phrase.js +72 -0
  748. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  749. package/dist/core/glossary/delta.js +109 -0
  750. package/dist/core/glossary/delta.js.map +1 -0
  751. package/dist/core/glossary/tree.js +73 -0
  752. package/dist/core/glossary/tree.js.map +1 -0
  753. package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -0
  754. package/dist/core/kernel/concurrency.js.map +1 -0
  755. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  756. package/dist/core/kernel/document-bytes.js.map +1 -0
  757. package/dist/core/kernel/fences.js +42 -0
  758. package/dist/core/kernel/fences.js.map +1 -0
  759. package/dist/core/kernel/ids/capability.js +72 -0
  760. package/dist/core/kernel/ids/capability.js.map +1 -0
  761. package/dist/core/kernel/ids/dirs.js +33 -0
  762. package/dist/core/kernel/ids/dirs.js.map +1 -0
  763. package/dist/core/kernel/ids/feature.js +75 -0
  764. package/dist/core/kernel/ids/feature.js.map +1 -0
  765. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  766. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  767. package/dist/core/kernel/ids/service.js +156 -0
  768. package/dist/core/kernel/ids/service.js.map +1 -0
  769. package/dist/core/kernel/ids/subsystem.js +63 -0
  770. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  771. package/dist/core/{path-safety.js → kernel/path-safety.js} +56 -4
  772. package/dist/core/kernel/path-safety.js.map +1 -0
  773. package/dist/core/{records.js → kernel/records.js} +11 -0
  774. package/dist/core/kernel/records.js.map +1 -0
  775. package/dist/core/links/backlinks.js +66 -0
  776. package/dist/core/links/backlinks.js.map +1 -0
  777. package/dist/core/links/case.js +74 -0
  778. package/dist/core/links/case.js.map +1 -0
  779. package/dist/core/links/corpus.js +118 -0
  780. package/dist/core/links/corpus.js.map +1 -0
  781. package/dist/core/links/findings.js +110 -0
  782. package/dist/core/links/findings.js.map +1 -0
  783. package/dist/core/links/parse.js +265 -0
  784. package/dist/core/links/parse.js.map +1 -0
  785. package/dist/core/mcp/argv.js +212 -0
  786. package/dist/core/mcp/argv.js.map +1 -0
  787. package/dist/core/mcp/author-tools.js +73 -0
  788. package/dist/core/mcp/author-tools.js.map +1 -0
  789. package/dist/core/mcp/framing.js +46 -0
  790. package/dist/core/mcp/framing.js.map +1 -0
  791. package/dist/core/mcp/protocol.js +280 -0
  792. package/dist/core/mcp/protocol.js.map +1 -0
  793. package/dist/core/mcp/tools.js +324 -0
  794. package/dist/core/mcp/tools.js.map +1 -0
  795. package/dist/core/obligations/obligations.js +106 -0
  796. package/dist/core/obligations/obligations.js.map +1 -0
  797. package/dist/core/openapi/baseline/gate.js +207 -0
  798. package/dist/core/openapi/baseline/gate.js.map +1 -0
  799. package/dist/core/openapi/baseline/plan.js +142 -0
  800. package/dist/core/openapi/baseline/plan.js.map +1 -0
  801. package/dist/core/openapi/baseline/record.js +174 -0
  802. package/dist/core/openapi/baseline/record.js.map +1 -0
  803. package/dist/core/openapi/contract-text.js +33 -0
  804. package/dist/core/openapi/contract-text.js.map +1 -0
  805. package/dist/core/openapi/contract-tree.js +301 -0
  806. package/dist/core/openapi/contract-tree.js.map +1 -0
  807. package/dist/core/openapi/depth.js +136 -0
  808. package/dist/core/openapi/depth.js.map +1 -0
  809. package/dist/core/openapi/digest.js +239 -0
  810. package/dist/core/openapi/digest.js.map +1 -0
  811. package/dist/core/{openapi.js → openapi/doc.js} +54 -108
  812. package/dist/core/openapi/doc.js.map +1 -0
  813. package/dist/core/openapi/merge/components.js +199 -0
  814. package/dist/core/openapi/merge/components.js.map +1 -0
  815. package/dist/core/openapi/merge/error.js +16 -0
  816. package/dist/core/openapi/merge/error.js.map +1 -0
  817. package/dist/core/openapi/merge/markers.js +204 -0
  818. package/dist/core/openapi/merge/markers.js.map +1 -0
  819. package/dist/core/openapi/merge/merge.js +232 -0
  820. package/dist/core/openapi/merge/merge.js.map +1 -0
  821. package/dist/core/openapi/merge/pin.js +110 -0
  822. package/dist/core/openapi/merge/pin.js.map +1 -0
  823. package/dist/core/openspec/decide/capabilities.js +244 -0
  824. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  825. package/dist/core/openspec/decide/dispositions.js +63 -0
  826. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  827. package/dist/core/openspec/decide/renames.js +179 -0
  828. package/dist/core/openspec/decide/renames.js.map +1 -0
  829. package/dist/core/openspec/decide/verdict.js +84 -0
  830. package/dist/core/openspec/decide/verdict.js.map +1 -0
  831. package/dist/core/openspec/inventory.js +220 -0
  832. package/dist/core/openspec/inventory.js.map +1 -0
  833. package/dist/core/openspec/model/mapping.js +78 -0
  834. package/dist/core/openspec/model/mapping.js.map +1 -0
  835. package/dist/core/openspec/model/model.js +70 -0
  836. package/dist/core/openspec/model/model.js.map +1 -0
  837. package/dist/core/openspec/scan/changes.js +241 -0
  838. package/dist/core/openspec/scan/changes.js.map +1 -0
  839. package/dist/core/openspec/scan/config.js +191 -0
  840. package/dist/core/openspec/scan/config.js.map +1 -0
  841. package/dist/core/openspec/scan/shape.js +304 -0
  842. package/dist/core/openspec/scan/shape.js.map +1 -0
  843. package/dist/core/openspec/scan/walk.js +116 -0
  844. package/dist/core/openspec/scan/walk.js.map +1 -0
  845. package/dist/core/openspec/scan/workspace.js +71 -0
  846. package/dist/core/openspec/scan/workspace.js.map +1 -0
  847. package/dist/core/owners/codeowners.js +141 -0
  848. package/dist/core/owners/codeowners.js.map +1 -0
  849. package/dist/core/pack/features.js +120 -0
  850. package/dist/core/pack/features.js.map +1 -0
  851. package/dist/core/pack/joins.js +112 -0
  852. package/dist/core/pack/joins.js.map +1 -0
  853. package/dist/core/pack/living.js +157 -0
  854. package/dist/core/pack/living.js.map +1 -0
  855. package/dist/core/pack/pack.js +120 -0
  856. package/dist/core/pack/pack.js.map +1 -0
  857. package/dist/core/permissions/permissions.js +87 -0
  858. package/dist/core/permissions/permissions.js.map +1 -0
  859. package/dist/core/projection/api.js +84 -0
  860. package/dist/core/projection/api.js.map +1 -0
  861. package/dist/core/projection/arch-slice.js +63 -0
  862. package/dist/core/projection/arch-slice.js.map +1 -0
  863. package/dist/core/projection/events.js +34 -0
  864. package/dist/core/projection/events.js.map +1 -0
  865. package/dist/core/projection/introduced.js +14 -0
  866. package/dist/core/projection/introduced.js.map +1 -0
  867. package/dist/core/provenance/findings.js +244 -0
  868. package/dist/core/provenance/findings.js.map +1 -0
  869. package/dist/core/provenance/git.js +201 -0
  870. package/dist/core/provenance/git.js.map +1 -0
  871. package/dist/core/provenance/gitq/moves.js +139 -0
  872. package/dist/core/provenance/gitq/moves.js.map +1 -0
  873. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  874. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  875. package/dist/core/provenance/sample/scope.js +238 -0
  876. package/dist/core/provenance/sample/scope.js.map +1 -0
  877. package/dist/core/provenance/sample/sections.js +61 -0
  878. package/dist/core/provenance/sample/sections.js.map +1 -0
  879. package/dist/core/provenance/sources.js +280 -0
  880. package/dist/core/provenance/sources.js.map +1 -0
  881. package/dist/core/provenance/stamp.js +220 -0
  882. package/dist/core/provenance/stamp.js.map +1 -0
  883. package/dist/core/provenance/walk.js +157 -0
  884. package/dist/core/provenance/walk.js.map +1 -0
  885. package/dist/core/repo/authored/paths.js +210 -0
  886. package/dist/core/repo/authored/paths.js.map +1 -0
  887. package/dist/core/repo/entries.js +126 -0
  888. package/dist/core/repo/entries.js.map +1 -0
  889. package/dist/core/repo/paths.js +322 -0
  890. package/dist/core/repo/paths.js.map +1 -0
  891. package/dist/core/repo/repo.js +308 -0
  892. package/dist/core/repo/repo.js.map +1 -0
  893. package/dist/core/repo/service-target.js +153 -0
  894. package/dist/core/repo/service-target.js.map +1 -0
  895. package/dist/core/repo/state.js +58 -0
  896. package/dist/core/repo/state.js.map +1 -0
  897. package/dist/core/repo/tree/find.js +61 -0
  898. package/dist/core/repo/tree/find.js.map +1 -0
  899. package/dist/core/repo/tree/fs.js +90 -0
  900. package/dist/core/repo/tree/fs.js.map +1 -0
  901. package/dist/core/repo/tree/marker.js +61 -0
  902. package/dist/core/repo/tree/marker.js.map +1 -0
  903. package/dist/core/repo/tree/render/body.js +258 -0
  904. package/dist/core/repo/tree/render/body.js.map +1 -0
  905. package/dist/core/repo/tree/render/projects.js +182 -0
  906. package/dist/core/repo/tree/render/projects.js.map +1 -0
  907. package/dist/core/repo/tree/render/service/header.js +125 -0
  908. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  909. package/dist/core/repo/tree/render/service/peers.js +28 -0
  910. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  911. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  912. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  913. package/dist/core/repo/tree/render/service/views.js +78 -0
  914. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  915. package/dist/core/repo/tree/render/stale.js +42 -0
  916. package/dist/core/repo/tree/render/stale.js.map +1 -0
  917. package/dist/core/repo/tree/render/text.js +84 -0
  918. package/dist/core/repo/tree/render/text.js.map +1 -0
  919. package/dist/core/repo/tree/render/views.js +293 -0
  920. package/dist/core/repo/tree/render/views.js.map +1 -0
  921. package/dist/core/repo/tree/walk.js +255 -0
  922. package/dist/core/repo/tree/walk.js.map +1 -0
  923. package/dist/core/results.js +146 -14
  924. package/dist/core/results.js.map +1 -1
  925. package/dist/core/scaffold/landscape.js +239 -0
  926. package/dist/core/scaffold/landscape.js.map +1 -0
  927. package/dist/core/scaffold/legacy.js +271 -0
  928. package/dist/core/scaffold/legacy.js.map +1 -0
  929. package/dist/core/scaffold/readme.js +84 -0
  930. package/dist/core/scaffold/readme.js.map +1 -0
  931. package/dist/core/staging/commit.js +252 -0
  932. package/dist/core/staging/commit.js.map +1 -0
  933. package/dist/core/staging/interrupted.js +96 -0
  934. package/dist/core/staging/interrupted.js.map +1 -0
  935. package/dist/core/staging/lock.js +268 -0
  936. package/dist/core/staging/lock.js.map +1 -0
  937. package/dist/core/staging/recovery/finding.js +35 -0
  938. package/dist/core/staging/recovery/finding.js.map +1 -0
  939. package/dist/core/staging/recovery/intent.js +95 -0
  940. package/dist/core/staging/recovery/intent.js.map +1 -0
  941. package/dist/core/staging/recovery/recover.js +204 -0
  942. package/dist/core/staging/recovery/recover.js.map +1 -0
  943. package/dist/core/staging/recovery/residue.js +62 -0
  944. package/dist/core/staging/recovery/residue.js.map +1 -0
  945. package/dist/core/staging/snapshot/manifest.js +188 -0
  946. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  947. package/dist/core/staging/snapshot/snapshot.js +196 -0
  948. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  949. package/dist/core/staging/txn/forward.js +181 -0
  950. package/dist/core/staging/txn/forward.js.map +1 -0
  951. package/dist/core/staging/txn/journal.js +139 -0
  952. package/dist/core/staging/txn/journal.js.map +1 -0
  953. package/dist/core/staging/txn/transaction.js +75 -0
  954. package/dist/core/staging/txn/transaction.js.map +1 -0
  955. package/dist/core/staging/writes.js +113 -0
  956. package/dist/core/staging/writes.js.map +1 -0
  957. package/dist/core/status/actions/execution.js +60 -0
  958. package/dist/core/status/actions/execution.js.map +1 -0
  959. package/dist/core/status/contracts.js +126 -0
  960. package/dist/core/status/contracts.js.map +1 -0
  961. package/dist/core/status/feature/artifacts.js +196 -0
  962. package/dist/core/status/feature/artifacts.js.map +1 -0
  963. package/dist/core/status/feature/feature.js +214 -0
  964. package/dist/core/status/feature/feature.js.map +1 -0
  965. package/dist/core/status/feature/next.js +163 -0
  966. package/dist/core/status/feature/next.js.map +1 -0
  967. package/dist/core/status/feature/state.js +21 -0
  968. package/dist/core/status/feature/state.js.map +1 -0
  969. package/dist/core/status/feature/words.js +96 -0
  970. package/dist/core/status/feature/words.js.map +1 -0
  971. package/dist/core/status/fleet/fleet.js +216 -0
  972. package/dist/core/status/fleet/fleet.js.map +1 -0
  973. package/dist/core/status/fleet/next.js +302 -0
  974. package/dist/core/status/fleet/next.js.map +1 -0
  975. package/dist/core/status/interrupted.js +97 -0
  976. package/dist/core/status/interrupted.js.map +1 -0
  977. package/dist/core/status/report.js +31 -0
  978. package/dist/core/status/report.js.map +1 -0
  979. package/dist/core/status/scan.js +41 -0
  980. package/dist/core/status/scan.js.map +1 -0
  981. package/dist/core/status/verification.js +216 -0
  982. package/dist/core/status/verification.js.map +1 -0
  983. package/dist/core/tasks/packet.js +199 -0
  984. package/dist/core/tasks/packet.js.map +1 -0
  985. package/dist/core/tasks/record.js +43 -0
  986. package/dist/core/tasks/record.js.map +1 -0
  987. package/dist/core/tasks/sources.js +181 -0
  988. package/dist/core/tasks/sources.js.map +1 -0
  989. package/dist/core/tasks/stamps.js +76 -0
  990. package/dist/core/tasks/stamps.js.map +1 -0
  991. package/dist/core/tasks/unit.js +0 -0
  992. package/dist/core/tasks/unit.js.map +1 -0
  993. package/dist/core/usecases/capability.js +166 -0
  994. package/dist/core/usecases/capability.js.map +1 -0
  995. package/dist/core/usecases/delta/claims.js +140 -0
  996. package/dist/core/usecases/delta/claims.js.map +1 -0
  997. package/dist/core/usecases/delta/flows.js +101 -0
  998. package/dist/core/usecases/delta/flows.js.map +1 -0
  999. package/dist/core/usecases/delta/modified.js +315 -0
  1000. package/dist/core/usecases/delta/modified.js.map +1 -0
  1001. package/dist/core/usecases/delta/overlay.js +76 -0
  1002. package/dist/core/usecases/delta/overlay.js.map +1 -0
  1003. package/dist/core/usecases/fleet.js +296 -0
  1004. package/dist/core/usecases/fleet.js.map +1 -0
  1005. package/dist/core/usecases/grade/capability-tag.js +93 -0
  1006. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  1007. package/dist/core/usecases/grade/feature.js +88 -0
  1008. package/dist/core/usecases/grade/feature.js.map +1 -0
  1009. package/dist/core/usecases/grade/requirement-tag.js +94 -0
  1010. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  1011. package/dist/core/usecases/grade/steps.js +266 -0
  1012. package/dist/core/usecases/grade/steps.js.map +1 -0
  1013. package/dist/core/usecases/grade/usecases.js +112 -0
  1014. package/dist/core/usecases/grade/usecases.js.map +1 -0
  1015. package/dist/core/usecases/operations.js +123 -0
  1016. package/dist/core/usecases/operations.js.map +1 -0
  1017. package/dist/core/usecases/place.js +44 -0
  1018. package/dist/core/usecases/place.js.map +1 -0
  1019. package/dist/core/usecases/service/exclude.js +119 -0
  1020. package/dist/core/usecases/service/exclude.js.map +1 -0
  1021. package/dist/core/usecases/service/flows.js +164 -0
  1022. package/dist/core/usecases/service/flows.js.map +1 -0
  1023. package/dist/core/usecases/suites/participants.js +83 -0
  1024. package/dist/core/usecases/suites/participants.js.map +1 -0
  1025. package/dist/core/usecases/suites/suites.js +45 -0
  1026. package/dist/core/usecases/suites/suites.js.map +1 -0
  1027. package/dist/core/usecases/touch.js +101 -0
  1028. package/dist/core/usecases/touch.js.map +1 -0
  1029. package/dist/core/verify/answers.js +180 -0
  1030. package/dist/core/verify/answers.js.map +1 -0
  1031. package/dist/core/verify/build.js +170 -0
  1032. package/dist/core/verify/build.js.map +1 -0
  1033. package/dist/core/verify/checklist.js +259 -0
  1034. package/dist/core/verify/checklist.js.map +1 -0
  1035. package/dist/core/verify/claims/identity.js +61 -0
  1036. package/dist/core/verify/claims/identity.js.map +1 -0
  1037. package/dist/core/verify/cross/diff.js +97 -0
  1038. package/dist/core/verify/cross/diff.js.map +1 -0
  1039. package/dist/core/verify/evidence/contract.js +169 -0
  1040. package/dist/core/verify/evidence/contract.js.map +1 -0
  1041. package/dist/core/verify/location.js +67 -0
  1042. package/dist/core/verify/location.js.map +1 -0
  1043. package/dist/core/verify/pins/lint.js +158 -0
  1044. package/dist/core/verify/pins/lint.js.map +1 -0
  1045. package/dist/core/verify/pins/pin.js +95 -0
  1046. package/dist/core/verify/pins/pin.js.map +1 -0
  1047. package/dist/core/verify/read/file.js +224 -0
  1048. package/dist/core/verify/read/file.js.map +1 -0
  1049. package/dist/core/verify/read/shape.js +169 -0
  1050. package/dist/core/verify/read/shape.js.map +1 -0
  1051. package/dist/core/verify/read/union.js +105 -0
  1052. package/dist/core/verify/read/union.js.map +1 -0
  1053. package/dist/core/verify/record.js +165 -0
  1054. package/dist/core/verify/record.js.map +1 -0
  1055. package/dist/core/verify/store/commit.js +99 -0
  1056. package/dist/core/verify/store/commit.js.map +1 -0
  1057. package/dist/core/verify/store/render.js +61 -0
  1058. package/dist/core/verify/store/render.js.map +1 -0
  1059. package/dist/core/vocabulary/health.js +91 -0
  1060. package/dist/core/vocabulary/health.js.map +1 -0
  1061. package/dist/core/vocabulary/issue.js +59 -0
  1062. package/dist/core/vocabulary/issue.js.map +1 -0
  1063. package/dist/core/vocabulary/maturity.js +216 -0
  1064. package/dist/core/vocabulary/maturity.js.map +1 -0
  1065. package/dist/core/vocabulary/report.js +90 -0
  1066. package/dist/core/vocabulary/report.js.map +1 -0
  1067. package/dist/core/vocabulary/steps.js +266 -0
  1068. package/dist/core/vocabulary/steps.js.map +1 -0
  1069. package/dist/core/workspace/discover.js +239 -0
  1070. package/dist/core/workspace/discover.js.map +1 -0
  1071. package/dist/core/workspace/render.js +52 -0
  1072. package/dist/core/workspace/render.js.map +1 -0
  1073. package/examples/README.md +232 -0
  1074. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  1075. package/examples/docs/architecture/capabilities.yaml +31 -0
  1076. package/examples/docs/architecture/landscape.likec4 +336 -0
  1077. package/examples/docs/architecture/obligations.yaml +23 -0
  1078. package/examples/docs/architecture/permissions.yaml +50 -0
  1079. package/examples/docs/architecture/services.likec4 +70 -0
  1080. package/examples/docs/architecture/subsystems.likec4 +18 -0
  1081. package/examples/docs/architecture/usecases/order-notification.likec4 +74 -0
  1082. package/examples/docs/capabilities/checkout/spec.md +55 -0
  1083. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  1084. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  1085. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  1086. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  1087. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  1088. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  1089. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +132 -0
  1090. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  1091. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  1092. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  1093. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  1094. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  1095. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +31 -0
  1096. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  1097. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  1098. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  1099. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  1100. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  1101. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  1102. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  1103. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  1104. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  1105. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  1106. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +73 -0
  1107. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  1108. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  1109. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  1110. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  1111. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  1112. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  1113. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  1114. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  1115. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  1116. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  1117. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  1118. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  1119. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  1120. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  1121. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  1122. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  1123. package/examples/docs/glossary/order.md +15 -0
  1124. package/examples/docs/glossary/payments/authorization.md +14 -0
  1125. package/examples/docs/likec4.config.json +8 -0
  1126. package/examples/docs/loam.json +3 -0
  1127. package/examples/docs/services/checkout-web/model.likec4 +92 -0
  1128. package/examples/docs/services/checkout-web/spec.md +91 -0
  1129. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  1130. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  1131. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  1132. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  1133. package/examples/docs/services/order-service/arch.spec.md +134 -0
  1134. package/examples/docs/services/order-service/asyncapi.yaml +109 -0
  1135. package/examples/docs/services/order-service/health.yaml +57 -0
  1136. package/examples/docs/services/order-service/model.likec4 +126 -0
  1137. package/examples/docs/services/order-service/openapi.yaml +257 -0
  1138. package/examples/docs/services/order-service/runbook.md +62 -0
  1139. package/examples/docs/services/order-service/spec.md +134 -0
  1140. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  1141. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  1142. package/examples/docs/services/payment-service/arch.spec.md +76 -0
  1143. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  1144. package/examples/docs/services/payment-service/health.yaml +39 -0
  1145. package/examples/docs/services/payment-service/model.likec4 +68 -0
  1146. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  1147. package/examples/docs/services/payment-service/runbook.md +37 -0
  1148. package/examples/docs/services/payment-service/spec.md +88 -0
  1149. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  1150. package/examples/docs/services/platform/identity-service/arch.spec.md +120 -0
  1151. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  1152. package/examples/docs/services/platform/identity-service/model.likec4 +81 -0
  1153. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  1154. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  1155. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  1156. package/examples/docs/services/platform/notification-service/asyncapi.yaml +200 -0
  1157. package/examples/docs/services/platform/notification-service/health.yaml +40 -0
  1158. package/examples/docs/services/platform/notification-service/model.likec4 +97 -0
  1159. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  1160. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  1161. package/examples/docs/services/platform/subsystem.yaml +2 -0
  1162. package/examples/fleet.yaml +57 -0
  1163. package/package.json +19 -6
  1164. package/dist/commands/adopt.js +0 -240
  1165. package/dist/commands/adopt.js.map +0 -1
  1166. package/dist/commands/archive.js +0 -1313
  1167. package/dist/commands/archive.js.map +0 -1
  1168. package/dist/commands/delta.js +0 -388
  1169. package/dist/commands/delta.js.map +0 -1
  1170. package/dist/commands/docs-repo-gate.js.map +0 -1
  1171. package/dist/commands/format.js +0 -17
  1172. package/dist/commands/format.js.map +0 -1
  1173. package/dist/commands/gherkin.js +0 -309
  1174. package/dist/commands/gherkin.js.map +0 -1
  1175. package/dist/commands/init.js.map +0 -1
  1176. package/dist/commands/list.js +0 -295
  1177. package/dist/commands/list.js.map +0 -1
  1178. package/dist/commands/migrate-openspec.js +0 -950
  1179. package/dist/commands/migrate-openspec.js.map +0 -1
  1180. package/dist/commands/new.js +0 -413
  1181. package/dist/commands/new.js.map +0 -1
  1182. package/dist/commands/rebase.js +0 -356
  1183. package/dist/commands/rebase.js.map +0 -1
  1184. package/dist/commands/show.js +0 -320
  1185. package/dist/commands/show.js.map +0 -1
  1186. package/dist/commands/status.js +0 -262
  1187. package/dist/commands/status.js.map +0 -1
  1188. package/dist/commands/unarchive.js +0 -317
  1189. package/dist/commands/unarchive.js.map +0 -1
  1190. package/dist/commands/validate.js +0 -1773
  1191. package/dist/commands/validate.js.map +0 -1
  1192. package/dist/commands/verify.js +0 -775
  1193. package/dist/commands/verify.js.map +0 -1
  1194. package/dist/commands/vouch.js +0 -421
  1195. package/dist/commands/vouch.js.map +0 -1
  1196. package/dist/core/agent.js +0 -2173
  1197. package/dist/core/agent.js.map +0 -1
  1198. package/dist/core/agents-stamp.js.map +0 -1
  1199. package/dist/core/arch.js +0 -130
  1200. package/dist/core/arch.js.map +0 -1
  1201. package/dist/core/asyncapi.js +0 -253
  1202. package/dist/core/asyncapi.js.map +0 -1
  1203. package/dist/core/brief.js +0 -755
  1204. package/dist/core/brief.js.map +0 -1
  1205. package/dist/core/coherence.js +0 -577
  1206. package/dist/core/coherence.js.map +0 -1
  1207. package/dist/core/concurrency.js.map +0 -1
  1208. package/dist/core/config.js.map +0 -1
  1209. package/dist/core/delta.js +0 -476
  1210. package/dist/core/delta.js.map +0 -1
  1211. package/dist/core/dependencies.js +0 -356
  1212. package/dist/core/dependencies.js.map +0 -1
  1213. package/dist/core/doctor.js +0 -596
  1214. package/dist/core/doctor.js.map +0 -1
  1215. package/dist/core/document-bytes.js.map +0 -1
  1216. package/dist/core/explore.js +0 -225
  1217. package/dist/core/explore.js.map +0 -1
  1218. package/dist/core/frontmatter.js.map +0 -1
  1219. package/dist/core/gherkin.js +0 -463
  1220. package/dist/core/gherkin.js.map +0 -1
  1221. package/dist/core/health.js +0 -67
  1222. package/dist/core/health.js.map +0 -1
  1223. package/dist/core/ids.js +0 -122
  1224. package/dist/core/ids.js.map +0 -1
  1225. package/dist/core/issue.js +0 -9
  1226. package/dist/core/issue.js.map +0 -1
  1227. package/dist/core/json.js +0 -74
  1228. package/dist/core/json.js.map +0 -1
  1229. package/dist/core/likec4.js +0 -489
  1230. package/dist/core/likec4.js.map +0 -1
  1231. package/dist/core/maturity.js +0 -66
  1232. package/dist/core/maturity.js.map +0 -1
  1233. package/dist/core/openapi-merge.js +0 -552
  1234. package/dist/core/openapi-merge.js.map +0 -1
  1235. package/dist/core/openapi.js.map +0 -1
  1236. package/dist/core/openspec-inventory.js +0 -1440
  1237. package/dist/core/openspec-inventory.js.map +0 -1
  1238. package/dist/core/path-safety.js.map +0 -1
  1239. package/dist/core/provenance.js +0 -787
  1240. package/dist/core/provenance.js.map +0 -1
  1241. package/dist/core/records.js.map +0 -1
  1242. package/dist/core/repo.js +0 -438
  1243. package/dist/core/repo.js.map +0 -1
  1244. package/dist/core/report.js +0 -47
  1245. package/dist/core/report.js.map +0 -1
  1246. package/dist/core/spec.js +0 -505
  1247. package/dist/core/spec.js.map +0 -1
  1248. package/dist/core/staging.js +0 -890
  1249. package/dist/core/staging.js.map +0 -1
  1250. package/dist/core/status.js +0 -1132
  1251. package/dist/core/status.js.map +0 -1
  1252. package/dist/core/steps.js +0 -72
  1253. package/dist/core/steps.js.map +0 -1
  1254. package/dist/core/verify.js +0 -807
  1255. package/dist/core/verify.js.map +0 -1
  1256. package/dist/core/version.js.map +0 -1
@@ -0,0 +1,123 @@
1
+ /**
2
+ * The join from a service requirement INTO the authored business tree:
3
+ * `Realizes: <capability-id>#<Requirement-ID>`.
4
+ *
5
+ * This is the axis's load-bearing edge. `Capability:` beside it answers a
6
+ * different question and neither replaces the other — `Capability: checkout`
7
+ * claims a theme, `Realizes: checkout#CHECKOUT-CHARGE-ONCE` claims that this
8
+ * requirement is part of what makes one named promise true. Only the second can
9
+ * be graded in both directions, and both directions are the point: an entry
10
+ * that resolves to nothing, and a capability requirement nothing realizes.
11
+ *
12
+ * WHO WRITES IT. Not the analyst. The analyst writes the capability and its
13
+ * requirements and names no service; whoever implements a service requirement
14
+ * writes the line that says which promise it serves. That is why the line lives
15
+ * on the SERVICE requirement and not as a back-reference in the capability
16
+ * document: a business document must not have to be edited every time a fleet
17
+ * rearranges which service carries which part.
18
+ *
19
+ * WHY NO SEPARATE LINE FOR THE API HOP. A capability requirement reaches its
20
+ * operations by composing this join with the `Operations:` lines that already
21
+ * exist on the requirements realizing it. A third place to keep in sync would
22
+ * buy nothing and could disagree with the two.
23
+ *
24
+ * DELIBERATELY THE NARROWEST LAYER THAT CAN MEAN IT, exactly as
25
+ * `../usecase-join.ts` is: no file is read, no finding is emitted, nothing is
26
+ * thrown, and — the load-bearing part — this package does NOT import
27
+ * `../capabilities.js`. It takes ids somebody else supplies. That keeps the
28
+ * package edge one-way (`capabilities` → `capabilities/realizes`), and it keeps
29
+ * the resolution testable without a filesystem.
30
+ *
31
+ * WHAT THE CALLER STILL OWES. The vocabulary ladder in `../findings.ts` — an
32
+ * absent or unreadable `architecture/capabilities.yaml` means silence, not a
33
+ * fleet full of unresolved joins — is applied BEFORE calling here, and travels
34
+ * as `declared: null`.
35
+ */
36
+ import { closeIds } from "../../c4/arch.js";
37
+ import { splitRealizesPin } from "../../document/spec.js";
38
+ import { compareIds } from "../../repo/entries.js";
39
+ /**
40
+ * The separator between the two halves of an entry.
41
+ *
42
+ * A composite entry rather than two lines because a `Requirement-ID` is unique
43
+ * only inside its own document: the capability half is not decoration, it is
44
+ * what makes the target addressable. Two lines would let one requirement name
45
+ * three capabilities and four ids with nothing saying which belongs to which.
46
+ */
47
+ export const REALIZES_SEPARATOR = "#";
48
+ /**
49
+ * Split one entry, or `null` when it has no two halves.
50
+ *
51
+ * THE LAST SEPARATOR, NOT THE FIRST, and the asymmetry is the reason: the
52
+ * requirement half has a strict grammar (`REQUIREMENT_ID_RE` in
53
+ * `core/document/spec.ts`) that excludes `#`, while the capability half is a
54
+ * YAML key and a directory name and is constrained nowhere. Splitting at the
55
+ * last `#` is therefore unambiguous for every capability id there is;
56
+ * splitting at the first would mis-parse any id containing one, and would do it
57
+ * silently — the failure mode this whole axis exists to refuse.
58
+ *
59
+ * Both halves must be non-empty. `checkout#`, `#CHK-1` and a bare `checkout`
60
+ * are all one answer — `null` — because the fix for all three is the same
61
+ * sentence, and inventing three refusals for one mistake helps nobody.
62
+ */
63
+ export function splitRealizesEntry(entry) {
64
+ // The pin comes off FIRST. It is a suffix of the whole entry, and leaving it
65
+ // on would put `@<digest>` inside the requirement half, where it would fail
66
+ // to resolve against an id that never contained one.
67
+ const { target, pin } = splitRealizesPin(entry);
68
+ const at = target.lastIndexOf(REALIZES_SEPARATOR);
69
+ if (at <= 0 || at === target.length - 1)
70
+ return null;
71
+ return { capability: target.slice(0, at), requirement: target.slice(at + 1), pin };
72
+ }
73
+ /**
74
+ * Resolve every entry, in the order the author wrote them.
75
+ *
76
+ * Order preserved and repeats NOT collapsed, matching the `Capability:` line's
77
+ * behaviour in `../findings.ts` rather than the `#cap-` tag's in
78
+ * `../usecase-join.ts`. The two siblings differ because a tag set is a set —
79
+ * LikeC4 hands it over with no authored order to preserve — while a body line
80
+ * is text somebody typed, and a reader chasing a finding is looking at that
81
+ * text. Consistency with the line beside it is worth more here than a
82
+ * deduplication nobody asked for.
83
+ *
84
+ * An empty result when `declared` is `null` is the ladder, not an answer: there
85
+ * is nothing to grade against, so nothing is graded.
86
+ */
87
+ export function resolveRealizes(entries, index) {
88
+ const { declared, byCapability, digests } = index;
89
+ if (declared === null)
90
+ return [];
91
+ const known = new Set(declared);
92
+ return entries.map((entry) => {
93
+ const target = splitRealizesEntry(entry);
94
+ if (target === null)
95
+ return { entry, kind: "malformed" };
96
+ const { capability, requirement, pin } = target;
97
+ if (!known.has(capability)) {
98
+ return { entry, kind: "unknown-capability", capability, close: closeIds(capability, declared) };
99
+ }
100
+ const ids = byCapability.get(capability);
101
+ if (ids === undefined)
102
+ return { entry, kind: "undocumented-capability", capability };
103
+ if (ids.size === 0)
104
+ return { entry, kind: "empty-capability", capability };
105
+ if (ids.has(requirement)) {
106
+ // An index with no digest for a resolved id leaves the verdict UNKNOWN
107
+ // rather than STALE. The two are not the same claim, and a reader who is
108
+ // told a pin went stale because the grader could not compute the other
109
+ // side would be told something false.
110
+ const current = digests.get(capability)?.get(requirement) ?? null;
111
+ const stale = pin === null || current === null ? null : pin !== current;
112
+ return { entry, kind: "resolved", capability, requirement, pin, current, stale };
113
+ }
114
+ return {
115
+ entry,
116
+ kind: "unknown-requirement",
117
+ capability,
118
+ requirement,
119
+ close: closeIds(requirement, [...ids].sort(compareIds)),
120
+ };
121
+ });
122
+ }
123
+ //# sourceMappingURL=join.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"join.js","sourceRoot":"","sources":["../../../../src/core/capabilities/realizes/join.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The join from a service requirement INTO the authored business tree:\n * `Realizes: <capability-id>#<Requirement-ID>`.\n *\n * This is the axis's load-bearing edge. `Capability:` beside it answers a\n * different question and neither replaces the other — `Capability: checkout`\n * claims a theme, `Realizes: checkout#CHECKOUT-CHARGE-ONCE` claims that this\n * requirement is part of what makes one named promise true. Only the second can\n * be graded in both directions, and both directions are the point: an entry\n * that resolves to nothing, and a capability requirement nothing realizes.\n *\n * WHO WRITES IT. Not the analyst. The analyst writes the capability and its\n * requirements and names no service; whoever implements a service requirement\n * writes the line that says which promise it serves. That is why the line lives\n * on the SERVICE requirement and not as a back-reference in the capability\n * document: a business document must not have to be edited every time a fleet\n * rearranges which service carries which part.\n *\n * WHY NO SEPARATE LINE FOR THE API HOP. A capability requirement reaches its\n * operations by composing this join with the `Operations:` lines that already\n * exist on the requirements realizing it. A third place to keep in sync would\n * buy nothing and could disagree with the two.\n *\n * DELIBERATELY THE NARROWEST LAYER THAT CAN MEAN IT, exactly as\n * `../usecase-join.ts` is: no file is read, no finding is emitted, nothing is\n * thrown, and — the load-bearing part — this package does NOT import\n * `../capabilities.js`. It takes ids somebody else supplies. That keeps the\n * package edge one-way (`capabilities` → `capabilities/realizes`), and it keeps\n * the resolution testable without a filesystem.\n *\n * WHAT THE CALLER STILL OWES. The vocabulary ladder in `../findings.ts` — an\n * absent or unreadable `architecture/capabilities.yaml` means silence, not a\n * fleet full of unresolved joins — is applied BEFORE calling here, and travels\n * as `declared: null`.\n */\nimport { closeIds } from \"../../c4/arch.js\";\nimport { splitRealizesPin } from \"../../document/spec.js\";\nimport { compareIds } from \"../../repo/entries.js\";\n\n/**\n * The separator between the two halves of an entry.\n *\n * A composite entry rather than two lines because a `Requirement-ID` is unique\n * only inside its own document: the capability half is not decoration, it is\n * what makes the target addressable. Two lines would let one requirement name\n * three capabilities and four ids with nothing saying which belongs to which.\n */\nexport const REALIZES_SEPARATOR = \"#\";\n\n/** The two halves of one entry, plus the version it was written against. */\nexport interface RealizesTarget {\n capability: string;\n requirement: string;\n /**\n * The digest of the capability requirement this claim was last pinned to, or\n * `null` for an unpinned entry. Written by `loam rebase --living`, never by\n * hand; `null` is the normal state of a corpus that has not been pinned and\n * grades exactly as it did before pins existed.\n */\n pin: string | null;\n}\n\n/**\n * Split one entry, or `null` when it has no two halves.\n *\n * THE LAST SEPARATOR, NOT THE FIRST, and the asymmetry is the reason: the\n * requirement half has a strict grammar (`REQUIREMENT_ID_RE` in\n * `core/document/spec.ts`) that excludes `#`, while the capability half is a\n * YAML key and a directory name and is constrained nowhere. Splitting at the\n * last `#` is therefore unambiguous for every capability id there is;\n * splitting at the first would mis-parse any id containing one, and would do it\n * silently — the failure mode this whole axis exists to refuse.\n *\n * Both halves must be non-empty. `checkout#`, `#CHK-1` and a bare `checkout`\n * are all one answer — `null` — because the fix for all three is the same\n * sentence, and inventing three refusals for one mistake helps nobody.\n */\nexport function splitRealizesEntry(entry: string): RealizesTarget | null {\n // The pin comes off FIRST. It is a suffix of the whole entry, and leaving it\n // on would put `@<digest>` inside the requirement half, where it would fail\n // to resolve against an id that never contained one.\n const { target, pin } = splitRealizesPin(entry);\n const at = target.lastIndexOf(REALIZES_SEPARATOR);\n if (at <= 0 || at === target.length - 1) return null;\n return { capability: target.slice(0, at), requirement: target.slice(at + 1), pin };\n}\n\n/**\n * What the tree declares, as the resolution needs it.\n *\n * The two fields answer different questions and both are needed to tell the\n * failures apart: `declared` is every capability id the fleet knows — the union\n * of the YAML and the tree — while `byCapability` holds only those with a\n * document, since only a document can carry requirements. A capability in\n * `declared` and absent from `byCapability` is declared-but-undocumented, which\n * is a real and common mid-adoption state with a fix of its own.\n */\nexport interface CapabilityRequirementIndex {\n /**\n * Every declared capability id, or `null` when the vocabulary cannot be\n * graded against at all. `null` and `[]` are never interchangeable — the same\n * distinction `gradableCapabilityIds` draws, for the same reason.\n */\n declared: readonly string[] | null;\n /** Requirement ids per capability that HAS a document. Present-and-empty is a real answer. */\n byCapability: ReadonlyMap<string, ReadonlySet<string>>;\n /**\n * The current `requirementDigest` of each id in `byCapability`, for the pin\n * comparison and nothing else.\n *\n * A second collection over the same keys, which is a shape this codebase\n * otherwise refuses — the justification is that the alternative is worse.\n * Widening `byCapability`'s values to a Map would change what `[...ids]`\n * iterates at four call sites that legitimately want the ids alone, and a\n * silent change of meaning in an existing iteration is a far more expensive\n * mistake than a redundant map built in the same loop. The invariant — same\n * capabilities, same ids, both sides — is asserted by\n * `test/capability-realizes-pin.test.ts` rather than left to a comment.\n */\n digests: ReadonlyMap<string, ReadonlyMap<string, string>>;\n}\n\n/**\n * What one `Realizes:` entry joins to. Branch on `kind`; every arm carries the\n * entry it is about, so a message can name it without re-deriving it.\n *\n * Five arms because there are five different fixes. Collapsing them would be\n * cheaper to write and worse to read: \"does not resolve\" tells an author\n * nothing about whether to declare a capability, write a document, add a\n * requirements section, or correct four characters.\n */\nexport type RealizesClaim =\n /**\n * Both halves resolve. `stale` is the pin verdict, and it is a THIRD state\n * rather than a boolean: `null` means the entry carries no pin, which is not\n * the same answer as a pin that still matches. Only `true` is a finding.\n */\n | {\n entry: string;\n kind: \"resolved\";\n capability: string;\n requirement: string;\n pin: string | null;\n /** The target's digest now, or `null` when the index could not supply one. */\n current: string | null;\n stale: boolean | null;\n }\n /** No usable separator — the fix is the spelling of the entry itself. */\n | { entry: string; kind: \"malformed\" }\n /** Nothing declares the capability half. `close` holds real declared ids. */\n | { entry: string; kind: \"unknown-capability\"; capability: string; close: string[] }\n /** Declared, but with no `capabilities/<id>/spec.md` — so it has no requirements at all. */\n | { entry: string; kind: \"undocumented-capability\"; capability: string }\n /** The document exists and declares no requirements yet. */\n | { entry: string; kind: \"empty-capability\"; capability: string }\n /** The document exists and declares requirements, but not this one. */\n | { entry: string; kind: \"unknown-requirement\"; capability: string; requirement: string; close: string[] };\n\n/**\n * Resolve every entry, in the order the author wrote them.\n *\n * Order preserved and repeats NOT collapsed, matching the `Capability:` line's\n * behaviour in `../findings.ts` rather than the `#cap-` tag's in\n * `../usecase-join.ts`. The two siblings differ because a tag set is a set —\n * LikeC4 hands it over with no authored order to preserve — while a body line\n * is text somebody typed, and a reader chasing a finding is looking at that\n * text. Consistency with the line beside it is worth more here than a\n * deduplication nobody asked for.\n *\n * An empty result when `declared` is `null` is the ladder, not an answer: there\n * is nothing to grade against, so nothing is graded.\n */\nexport function resolveRealizes(\n entries: readonly string[],\n index: CapabilityRequirementIndex,\n): RealizesClaim[] {\n const { declared, byCapability, digests } = index;\n if (declared === null) return [];\n const known = new Set(declared);\n\n return entries.map((entry): RealizesClaim => {\n const target = splitRealizesEntry(entry);\n if (target === null) return { entry, kind: \"malformed\" };\n const { capability, requirement, pin } = target;\n if (!known.has(capability)) {\n return { entry, kind: \"unknown-capability\", capability, close: closeIds(capability, declared) };\n }\n const ids = byCapability.get(capability);\n if (ids === undefined) return { entry, kind: \"undocumented-capability\", capability };\n if (ids.size === 0) return { entry, kind: \"empty-capability\", capability };\n if (ids.has(requirement)) {\n // An index with no digest for a resolved id leaves the verdict UNKNOWN\n // rather than STALE. The two are not the same claim, and a reader who is\n // told a pin went stale because the grader could not compute the other\n // side would be told something false.\n const current = digests.get(capability)?.get(requirement) ?? null;\n const stale = pin === null || current === null ? null : pin !== current;\n return { entry, kind: \"resolved\", capability, requirement, pin, current, stale };\n }\n return {\n entry,\n kind: \"unknown-requirement\",\n capability,\n requirement,\n close: closeIds(requirement, [...ids].sort(compareIds)),\n };\n });\n}\n"]}
@@ -0,0 +1,205 @@
1
+ /**
2
+ * The fleet total over the capability join, built once and reused by the fleet
3
+ * grade, `loam list capabilities` and `loam explore --capability` — one walk,
4
+ * so the unrealized warning and the rollup a reader diffs can never disagree
5
+ * about what "realized" means.
6
+ *
7
+ * Deterministic and diff-stable by construction: rows sorted with compareIds,
8
+ * realizedBy sorted by (service, file, requirement), statuses' keys sorted —
9
+ * no timestamps, no absolute paths, no readdir-order dependence. The reader is
10
+ * INJECTED (`read`) rather than a FleetContext, because fleet-context.ts
11
+ * imports this package for its memo and an import back would be a package
12
+ * cycle (see the memo's comment); callers pass `fleet.readRequirements` bound,
13
+ * so under `validate --all` every parse is already cached from the service
14
+ * targets and the rollup costs no additional per-service read.
15
+ *
16
+ * TWO CORPORA MEET HERE, and neither is derived from the other. A promise is
17
+ * kept by a service requirement's `Realizes:` line (walked below) or by a
18
+ * `#cap-`/`#req-` tagged flow (injected as `keptByFlows`, because the module
19
+ * that computes it imports this one). The rollup carries both on one row for the
20
+ * reason it carries both `Capability:` joins on one row: `loam list capabilities`
21
+ * and `capability.requirement-unrealized` must not be able to give different
22
+ * answers to "is this business promise kept", and they can only give one answer
23
+ * if they read one row.
24
+ */
25
+ import { existsSync } from "node:fs";
26
+ import { compareIds } from "../repo/entries.js";
27
+ import { SPEC_AXES, servicePathsAt } from "../repo/paths.js";
28
+ import { splitRealizesEntry } from "./realizes/join.js";
29
+ /**
30
+ * Walk every service's spec.md and arch.spec.md (existsSync-guarded, exactly
31
+ * like permissionFindings: an absent OPTIONAL artifact must never take a whole
32
+ * `--all` run down) and join non-REMOVED requirements' `Capability:` entries to
33
+ * the declared vocabulary. Rows exist for every DECLARED id — an unrealized
34
+ * declaration is a row with empty realizedBy, which is what the unrealized
35
+ * grade and the list's `0 — unrealized` marker both read.
36
+ */
37
+ export async function capabilityRollup(input) {
38
+ const { services, vocab, read, keptByFlows } = input;
39
+ // Rows exist only for DECLARED ids, so an empty vocabulary (absent file, or
40
+ // present with nothing declared) can build nothing — walking every service's
41
+ // two spec files to produce zero rows is what a vocabless 120-service fleet
42
+ // would otherwise pay on every `list`/`explore` that asks.
43
+ if (vocab.byId.size === 0)
44
+ return [];
45
+ const rows = new Map();
46
+ for (const id of [...vocab.byId.keys()].sort(compareIds)) {
47
+ const decl = vocab.byId.get(id);
48
+ rows.set(id, {
49
+ id,
50
+ ...(decl.description !== undefined ? { description: decl.description } : {}),
51
+ ...(decl.owner !== undefined ? { owner: decl.owner } : {}),
52
+ realizedBy: [],
53
+ services: [],
54
+ statuses: {},
55
+ });
56
+ }
57
+ // The documents, before the services, because a `Realizes:` entry can only
58
+ // land on a requirement row that already exists.
59
+ for (const doc of vocab.tree.docs) {
60
+ const row = rows.get(doc.id);
61
+ if (row === undefined)
62
+ continue; // unreachable: the tree is one half of byId
63
+ row.requirements = capabilityRequirementRows(await read(doc.spec));
64
+ }
65
+ // Realizations are collected as a SET per row before they become a list, so
66
+ // the two joins cannot count one requirement twice — see `CapabilityRow.realizedBy`.
67
+ const claimed = new Map();
68
+ for (const entry of services) {
69
+ const paths = servicePathsAt(entry.dir);
70
+ for (const axis of SPEC_AXES) {
71
+ const path = paths[axis.key];
72
+ if (!existsSync(path))
73
+ continue;
74
+ for (const r of await read(path)) {
75
+ if (r.kind === "REMOVED")
76
+ continue;
77
+ const where = { service: entry.id, file: axis.file, requirement: r.name };
78
+ for (const capability of r.capabilities)
79
+ claim(rows, claimed, capability, where);
80
+ for (const target of r.realizes.map(splitRealizesEntry)) {
81
+ if (target === null)
82
+ continue; // malformed — capability.realizes-unknown's business
83
+ // The capability is claimed BEFORE asking whether the requirement id
84
+ // resolves, and that is deliberate: an entry naming an undeclared id
85
+ // already earns `capability.realizes-unknown`, and letting it also
86
+ // leave its capability `capability.unrealized` would be two findings
87
+ // for one mistake — the second pointing at the analyst's document
88
+ // rather than at the typo.
89
+ claim(rows, claimed, target.capability, where);
90
+ // The requirement-level half. An entry naming an id the document does
91
+ // not declare lands nowhere, which is exactly right: it is already
92
+ // `capability.realizes-unknown`, and inventing a row for it here would
93
+ // make a typo look like a promise somebody wrote.
94
+ rows
95
+ .get(target.capability)
96
+ ?.requirements?.find((req) => req.id === target.requirement)
97
+ ?.realizedBy.push(where);
98
+ }
99
+ }
100
+ }
101
+ }
102
+ for (const row of rows.values()) {
103
+ row.realizedBy = [...(claimed.get(row)?.values() ?? [])].sort(compareRealizations);
104
+ row.services = [...new Set(row.realizedBy.map((r) => r.service))].sort(compareIds);
105
+ const byStatus = {};
106
+ for (const r of row.realizedBy) {
107
+ const status = statusOf(services, r.service);
108
+ byStatus[status] = (byStatus[status] ?? 0) + 1;
109
+ }
110
+ row.statuses = Object.fromEntries(Object.entries(byStatus).sort(([a], [b]) => compareIds(a, b)));
111
+ for (const req of row.requirements ?? []) {
112
+ req.realizedBy.sort(compareRealizations);
113
+ // Copied out of the injected map rather than aliased into the row: the row
114
+ // is a mutable value a caller may sort or splice, and handing it the
115
+ // caller's own array would let one consumer's edit rewrite the answer the
116
+ // next one reads. Already sorted upstream — copied, never re-sorted, so
117
+ // there is exactly one statement of the order.
118
+ if (keptByFlows !== undefined)
119
+ req.keptBy = [...(keptByFlows.get(`${row.id}#${req.id}`) ?? [])];
120
+ }
121
+ }
122
+ return [...rows.values()];
123
+ }
124
+ /** Deterministic realization order — the diff-stable rule this module states for its rows. */
125
+ function compareRealizations(a, b) {
126
+ return (compareIds(a.service, b.service) ||
127
+ a.file.localeCompare(b.file) ||
128
+ compareIds(a.requirement, b.requirement));
129
+ }
130
+ /** The service's declared frontmatter status, or `unset` for one nobody has marked. */
131
+ function statusOf(services, id) {
132
+ return services.find((s) => s.id === id)?.status ?? "unset";
133
+ }
134
+ /** Record one realization of one capability, deduplicated on where it came from. */
135
+ function claim(rows, claimed, capability, where) {
136
+ const row = rows.get(capability);
137
+ if (row === undefined)
138
+ return; // undeclared — capability.unknown's business, not the rollup's
139
+ const seen = claimed.get(row) ?? new Map();
140
+ seen.set(`${where.service}\0${where.file}\0${where.requirement}`, where);
141
+ claimed.set(row, seen);
142
+ }
143
+ /**
144
+ * A capability document's requirements as rows, keyed by their stable id.
145
+ *
146
+ * A requirement WITHOUT a `Requirement-ID:` is dropped rather than keyed by its
147
+ * heading, and the drop is the honest answer rather than a shortcut: nothing
148
+ * can address it — `Realizes:` names an id — so a row for it would be a promise
149
+ * reported as unrealized that no author could ever mark realized.
150
+ * `capability.requirement-unidentified` is the finding that names it, and it is
151
+ * an ERROR, so the state does not persist quietly.
152
+ *
153
+ * A duplicate id keeps the FIRST, matching `requirementIdProblems`' own
154
+ * `duplicate` grade: the document already earns an error for it, and picking a
155
+ * winner here is only about not producing two identical rows.
156
+ */
157
+ export function capabilityRequirementRows(reqs) {
158
+ const rows = new Map();
159
+ for (const r of reqs) {
160
+ if (r.kind === "REMOVED" || r.id === undefined || rows.has(r.id))
161
+ continue;
162
+ rows.set(r.id, { id: r.id, name: r.name, realizedBy: [] });
163
+ }
164
+ return [...rows.values()].sort((a, b) => compareIds(a.id, b.id));
165
+ }
166
+ /** The declared ids something realizes — the set the unrealized grade is taken against. */
167
+ export function usedCapabilities(rows) {
168
+ return new Set(rows.filter(isRealized).map((row) => row.id));
169
+ }
170
+ /**
171
+ * Does anything in the fleet realize this capability — by EITHER corpus?
172
+ *
173
+ * A flow keeping one of a capability's promises realizes part of that
174
+ * capability as surely as a `Capability:` line does, and the case is not
175
+ * hypothetical: a capability whose promises are all cross-service can be kept
176
+ * perfectly by `#cap-`/`#req-` tagged flows and named by no service requirement
177
+ * at all. Counting only the service corpus told such a fleet its capability was
178
+ * "a promise nobody implemented or a word nobody adopted" while the fleet's own
179
+ * use cases said otherwise — one warning, contradicted by loam's own answer two
180
+ * lines further down the same report.
181
+ *
182
+ * ASYMMETRIC WITH `capability.requirement-unrealized`, on purpose. That grade
183
+ * suspends entirely when the flows cannot be read, because a promise crossing
184
+ * services often has NO possible realizer but a flow — unreadable flows remove
185
+ * the only evidence there was. A capability has independent primary evidence in
186
+ * the `Capability:`/`Realizes:` lines, so unreadable flows leave it answering
187
+ * from less rather than from nothing, and going silent would lose the warning
188
+ * for a fleet that has a vocabulary and no fleet map at all — a real and legal
189
+ * shape, and one where the whole point of the code is to be heard.
190
+ */
191
+ function isRealized(row) {
192
+ if (row.realizedBy.length > 0)
193
+ return true;
194
+ return (row.requirements ?? []).some((req) => (req.keptBy?.length ?? 0) > 0);
195
+ }
196
+ /**
197
+ * The requested ids the rollup cannot seed from: undeclared, or declared but
198
+ * realized by nothing. One list on purpose — explore's contract is 'every miss
199
+ * is a field', and splitting the two miss kinds waits for a consumer to ask.
200
+ */
201
+ export function unresolvedCapabilities(rows, requested) {
202
+ const realized = usedCapabilities(rows);
203
+ return requested.filter((id) => !realized.has(id));
204
+ }
205
+ //# sourceMappingURL=rollup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rollup.js","sourceRoot":"","sources":["../../../src/core/capabilities/rollup.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The fleet total over the capability join, built once and reused by the fleet\n * grade, `loam list capabilities` and `loam explore --capability` — one walk,\n * so the unrealized warning and the rollup a reader diffs can never disagree\n * about what \"realized\" means.\n *\n * Deterministic and diff-stable by construction: rows sorted with compareIds,\n * realizedBy sorted by (service, file, requirement), statuses' keys sorted —\n * no timestamps, no absolute paths, no readdir-order dependence. The reader is\n * INJECTED (`read`) rather than a FleetContext, because fleet-context.ts\n * imports this package for its memo and an import back would be a package\n * cycle (see the memo's comment); callers pass `fleet.readRequirements` bound,\n * so under `validate --all` every parse is already cached from the service\n * targets and the rollup costs no additional per-service read.\n *\n * TWO CORPORA MEET HERE, and neither is derived from the other. A promise is\n * kept by a service requirement's `Realizes:` line (walked below) or by a\n * `#cap-`/`#req-` tagged flow (injected as `keptByFlows`, because the module\n * that computes it imports this one). The rollup carries both on one row for the\n * reason it carries both `Capability:` joins on one row: `loam list capabilities`\n * and `capability.requirement-unrealized` must not be able to give different\n * answers to \"is this business promise kept\", and they can only give one answer\n * if they read one row.\n */\nimport { existsSync } from \"node:fs\";\nimport type { Requirement } from \"../document/spec.js\";\nimport { compareIds, type ServiceEntry } from \"../repo/entries.js\";\nimport { SPEC_AXES, servicePathsAt } from \"../repo/paths.js\";\nimport type { CapabilityVocabulary } from \"./capabilities.js\";\nimport { splitRealizesEntry } from \"./realizes/join.js\";\n\n/** One requirement realizing one capability, located exactly. */\nexport interface CapabilityRealization {\n service: string;\n file: \"spec.md\" | \"arch.spec.md\";\n /** The requirement's `### Requirement:` name. */\n requirement: string;\n}\n\n/** One requirement OF a capability document, and what realizes it. */\nexport interface CapabilityRequirementRow {\n /** Its `Requirement-ID:`. A requirement without one is absent here — see `capabilityRequirementRows`. */\n id: string;\n /** Its `### Requirement:` heading. */\n name: string;\n /** Service requirements whose `Realizes:` line names `<capability>#<id>`. */\n realizedBy: CapabilityRealization[];\n /**\n * The ids of the declared flows that keep this promise — a `#cap-`/`#req-`\n * tagged `dynamic view` whose BOTH tags resolve. THE SECOND CORPUS, and the\n * only carrier a cross-service promise has: \"I enter a login and a password\n * and I am in\" belongs to no single service's spec, so a fleet can keep it\n * perfectly through a flow and realize it by no `Realizes:` line at all.\n *\n * Three states, all of them different answers, exactly as `requirements`\n * itself has three:\n * present and non-empty — these flows keep it;\n * present and empty — loam read the flows and none of them keeps it;\n * ABSENT — nobody looked. Either the caller did not ask\n * (`CapabilityRollupInput.keptByFlows` omitted) or\n * it asked and `architecture/` could not be read.\n * The third must never collapse into the second. \"Kept by no flow\" over a\n * project that did not parse is the vacuously-green claim the whole use-case\n * axis exists to refuse, and it is the claim a `[]` default would make.\n */\n keptBy?: string[];\n}\n\n/** One declared capability with everything the fleet says about it. */\nexport interface CapabilityRow {\n id: string;\n description?: string;\n owner?: string;\n /**\n * Service requirements realizing this capability BY EITHER JOIN, deduplicated\n * on (service, file, requirement).\n *\n * Both joins land here on purpose. `Realizes: checkout#CHK-1` realizes part of\n * `checkout` as surely as `Capability: checkout` does, and a rollup that\n * counted only the second would report a capability as realized by nobody\n * while the fleet pointed at its individual promises — which would then be\n * one spurious `capability.unrealized` per capability an author had documented\n * carefully enough to join at requirement level. The deduplication is what\n * lets a requirement carry both lines, which is the normal shape: the theme\n * and the promise are different claims.\n */\n realizedBy: CapabilityRealization[];\n /** Distinct realizing services, sorted. */\n services: string[];\n /**\n * Realizing requirements counted by their service's frontmatter status\n * (`unset` for a service nobody has marked) — the draft/verified split the\n * roadmap asks the total to answer. Counted over the DEDUPLICATED set above,\n * so a requirement writing both joins is one requirement.\n */\n statuses: Record<string, number>;\n /**\n * The capability document's own requirements, each with what realizes it.\n * Present only for a capability that HAS a document — absent and empty are\n * different answers, and only the second means \"the document declares none\".\n */\n requirements?: CapabilityRequirementRow[];\n}\n\nexport interface CapabilityRollupInput {\n services: ServiceEntry[];\n vocab: CapabilityVocabulary;\n /** The requirement reader — pass a FleetContext's readRequirements, bound. */\n read: (path: string) => Promise<Requirement[]>;\n /**\n * `<capability>#<Requirement-ID>` → the ids of the flows that keep it, from\n * `core/usecases`' `useCaseRequirementClaims`. Injected as PLAIN DATA, exactly\n * as `read` is, and for a harder reason than the memo: `core/usecases` imports\n * this package, so an import back would be a package cycle and\n * `npm run arch:check` refuses it. What travels is a Map of strings, which\n * carries no dependency in either direction.\n *\n * OMIT IT to answer \"nobody looked\": every `keptBy` above is then absent\n * rather than empty, which is what keeps a caller that never asked about\n * flows — `explore`, the context pack, `validate`'s own rollup — from\n * publishing a `[]` that reads as \"no flow keeps this\". A caller that DID look\n * and found nothing passes an empty Map; a caller that looked and could not\n * see must omit it and say so in its own words (`loam list` prints the note\n * and carries `useCases.unreadable`).\n */\n keptByFlows?: ReadonlyMap<string, readonly string[]>;\n}\n\n/**\n * Walk every service's spec.md and arch.spec.md (existsSync-guarded, exactly\n * like permissionFindings: an absent OPTIONAL artifact must never take a whole\n * `--all` run down) and join non-REMOVED requirements' `Capability:` entries to\n * the declared vocabulary. Rows exist for every DECLARED id — an unrealized\n * declaration is a row with empty realizedBy, which is what the unrealized\n * grade and the list's `0 — unrealized` marker both read.\n */\nexport async function capabilityRollup(input: CapabilityRollupInput): Promise<CapabilityRow[]> {\n const { services, vocab, read, keptByFlows } = input;\n // Rows exist only for DECLARED ids, so an empty vocabulary (absent file, or\n // present with nothing declared) can build nothing — walking every service's\n // two spec files to produce zero rows is what a vocabless 120-service fleet\n // would otherwise pay on every `list`/`explore` that asks.\n if (vocab.byId.size === 0) return [];\n const rows = new Map<string, CapabilityRow>();\n for (const id of [...vocab.byId.keys()].sort(compareIds)) {\n const decl = vocab.byId.get(id)!;\n rows.set(id, {\n id,\n ...(decl.description !== undefined ? { description: decl.description } : {}),\n ...(decl.owner !== undefined ? { owner: decl.owner } : {}),\n realizedBy: [],\n services: [],\n statuses: {},\n });\n }\n // The documents, before the services, because a `Realizes:` entry can only\n // land on a requirement row that already exists.\n for (const doc of vocab.tree.docs) {\n const row = rows.get(doc.id);\n if (row === undefined) continue; // unreachable: the tree is one half of byId\n row.requirements = capabilityRequirementRows(await read(doc.spec));\n }\n\n // Realizations are collected as a SET per row before they become a list, so\n // the two joins cannot count one requirement twice — see `CapabilityRow.realizedBy`.\n const claimed = new Map<CapabilityRow, Map<string, CapabilityRealization>>();\n for (const entry of services) {\n const paths = servicePathsAt(entry.dir);\n for (const axis of SPEC_AXES) {\n const path = paths[axis.key];\n if (!existsSync(path)) continue;\n for (const r of await read(path)) {\n if (r.kind === \"REMOVED\") continue;\n const where: CapabilityRealization = { service: entry.id, file: axis.file, requirement: r.name };\n for (const capability of r.capabilities) claim(rows, claimed, capability, where);\n for (const target of r.realizes.map(splitRealizesEntry)) {\n if (target === null) continue; // malformed — capability.realizes-unknown's business\n // The capability is claimed BEFORE asking whether the requirement id\n // resolves, and that is deliberate: an entry naming an undeclared id\n // already earns `capability.realizes-unknown`, and letting it also\n // leave its capability `capability.unrealized` would be two findings\n // for one mistake — the second pointing at the analyst's document\n // rather than at the typo.\n claim(rows, claimed, target.capability, where);\n // The requirement-level half. An entry naming an id the document does\n // not declare lands nowhere, which is exactly right: it is already\n // `capability.realizes-unknown`, and inventing a row for it here would\n // make a typo look like a promise somebody wrote.\n rows\n .get(target.capability)\n ?.requirements?.find((req) => req.id === target.requirement)\n ?.realizedBy.push(where);\n }\n }\n }\n }\n\n for (const row of rows.values()) {\n row.realizedBy = [...(claimed.get(row)?.values() ?? [])].sort(compareRealizations);\n row.services = [...new Set(row.realizedBy.map((r) => r.service))].sort(compareIds);\n const byStatus: Record<string, number> = {};\n for (const r of row.realizedBy) {\n const status = statusOf(services, r.service);\n byStatus[status] = (byStatus[status] ?? 0) + 1;\n }\n row.statuses = Object.fromEntries(Object.entries(byStatus).sort(([a], [b]) => compareIds(a, b)));\n for (const req of row.requirements ?? []) {\n req.realizedBy.sort(compareRealizations);\n // Copied out of the injected map rather than aliased into the row: the row\n // is a mutable value a caller may sort or splice, and handing it the\n // caller's own array would let one consumer's edit rewrite the answer the\n // next one reads. Already sorted upstream — copied, never re-sorted, so\n // there is exactly one statement of the order.\n if (keptByFlows !== undefined) req.keptBy = [...(keptByFlows.get(`${row.id}#${req.id}`) ?? [])];\n }\n }\n return [...rows.values()];\n}\n\n/** Deterministic realization order — the diff-stable rule this module states for its rows. */\nfunction compareRealizations(a: CapabilityRealization, b: CapabilityRealization): number {\n return (\n compareIds(a.service, b.service) ||\n a.file.localeCompare(b.file) ||\n compareIds(a.requirement, b.requirement)\n );\n}\n\n/** The service's declared frontmatter status, or `unset` for one nobody has marked. */\nfunction statusOf(services: ServiceEntry[], id: string): string {\n return services.find((s) => s.id === id)?.status ?? \"unset\";\n}\n\n/** Record one realization of one capability, deduplicated on where it came from. */\nfunction claim(\n rows: Map<string, CapabilityRow>,\n claimed: Map<CapabilityRow, Map<string, CapabilityRealization>>,\n capability: string,\n where: CapabilityRealization,\n): void {\n const row = rows.get(capability);\n if (row === undefined) return; // undeclared — capability.unknown's business, not the rollup's\n const seen = claimed.get(row) ?? new Map<string, CapabilityRealization>();\n seen.set(`${where.service}\\0${where.file}\\0${where.requirement}`, where);\n claimed.set(row, seen);\n}\n\n/**\n * A capability document's requirements as rows, keyed by their stable id.\n *\n * A requirement WITHOUT a `Requirement-ID:` is dropped rather than keyed by its\n * heading, and the drop is the honest answer rather than a shortcut: nothing\n * can address it — `Realizes:` names an id — so a row for it would be a promise\n * reported as unrealized that no author could ever mark realized.\n * `capability.requirement-unidentified` is the finding that names it, and it is\n * an ERROR, so the state does not persist quietly.\n *\n * A duplicate id keeps the FIRST, matching `requirementIdProblems`' own\n * `duplicate` grade: the document already earns an error for it, and picking a\n * winner here is only about not producing two identical rows.\n */\nexport function capabilityRequirementRows(reqs: Requirement[]): CapabilityRequirementRow[] {\n const rows = new Map<string, CapabilityRequirementRow>();\n for (const r of reqs) {\n if (r.kind === \"REMOVED\" || r.id === undefined || rows.has(r.id)) continue;\n rows.set(r.id, { id: r.id, name: r.name, realizedBy: [] });\n }\n return [...rows.values()].sort((a, b) => compareIds(a.id, b.id));\n}\n\n/** The declared ids something realizes — the set the unrealized grade is taken against. */\nexport function usedCapabilities(rows: CapabilityRow[]): Set<string> {\n return new Set(rows.filter(isRealized).map((row) => row.id));\n}\n\n/**\n * Does anything in the fleet realize this capability — by EITHER corpus?\n *\n * A flow keeping one of a capability's promises realizes part of that\n * capability as surely as a `Capability:` line does, and the case is not\n * hypothetical: a capability whose promises are all cross-service can be kept\n * perfectly by `#cap-`/`#req-` tagged flows and named by no service requirement\n * at all. Counting only the service corpus told such a fleet its capability was\n * \"a promise nobody implemented or a word nobody adopted\" while the fleet's own\n * use cases said otherwise — one warning, contradicted by loam's own answer two\n * lines further down the same report.\n *\n * ASYMMETRIC WITH `capability.requirement-unrealized`, on purpose. That grade\n * suspends entirely when the flows cannot be read, because a promise crossing\n * services often has NO possible realizer but a flow — unreadable flows remove\n * the only evidence there was. A capability has independent primary evidence in\n * the `Capability:`/`Realizes:` lines, so unreadable flows leave it answering\n * from less rather than from nothing, and going silent would lose the warning\n * for a fleet that has a vocabulary and no fleet map at all — a real and legal\n * shape, and one where the whole point of the code is to be heard.\n */\nfunction isRealized(row: CapabilityRow): boolean {\n if (row.realizedBy.length > 0) return true;\n return (row.requirements ?? []).some((req) => (req.keptBy?.length ?? 0) > 0);\n}\n\n/**\n * The requested ids the rollup cannot seed from: undeclared, or declared but\n * realized by nothing. One list on purpose — explore's contract is 'every miss\n * is a field', and splitting the two miss kinds waits for a consumer to ask.\n */\nexport function unresolvedCapabilities(rows: CapabilityRow[], requested: string[]): string[] {\n const realized = usedCapabilities(rows);\n return requested.filter((id) => !realized.has(id));\n}\n"]}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * The capability tree: `capabilities/<id>/spec.md`, and the rule that a
3
+ * directory holding one IS a declared capability.
4
+ *
5
+ * WHY A TREE AND NOT A SECOND LIST IN YAML. `architecture/capabilities.yaml`
6
+ * declares names; it cannot carry prose, and a capability a business analyst
7
+ * actually wrote is mostly prose. The alternative — a single vocabulary file
8
+ * grown to hold paragraphs — is the exact drift `loam init`'s removed
9
+ * `loam.docs.json` was removed for: a second list nothing keeps current. So the
10
+ * DIRECTORY is the list, and the general rule it settles is that an entry with
11
+ * prose gets a file while an entry without prose stays a line in YAML
12
+ * (`architecture/permissions.yaml` is the principled exception — a
13
+ * `user/profile:read` pair has no prose, and a document per pair is ceremony).
14
+ *
15
+ * THE VOCABULARY IS THE UNION of this tree and the YAML, and the YAML is not
16
+ * deprecated by it. A fleet that declared twenty names and has written four
17
+ * documents is the normal state of an adoption, and a tree that refused to
18
+ * grade the other sixteen would make adopting the axis a cliff.
19
+ * `./capabilities.ts` merges the two and records which side declared each id.
20
+ *
21
+ * PRESENCE CLASSIFIES, one tree over from `isServiceArtifactName`: a directory
22
+ * holding the document is a capability, and one holding only other directories
23
+ * is a group the walk descends through. Both at once is legal and normal —
24
+ * `payments` may be a capability with `payments/refunds` nested inside it —
25
+ * because a capability id spells its own nesting wherever it is written and the
26
+ * tree only mirrors that. What is NOT legal is a directory that is neither:
27
+ * `capability.doc-missing` names it, rather than letting a half-created
28
+ * capability sit in the tree looking declared.
29
+ *
30
+ * The walk reads directories only. It never parses a document — the requirement
31
+ * reader is injected by whoever grades (`./findings.ts` takes parsed
32
+ * requirements, `commands/validate/` supplies the fleet's cached reader), for
33
+ * the reason `./rollup.ts` states: this package is imported by
34
+ * `core/fleet-context.ts` and may never import it back.
35
+ */
36
+ import { existsSync } from "node:fs";
37
+ import { readdir } from "node:fs/promises";
38
+ import { join } from "node:path";
39
+ import { compareIds } from "../repo/entries.js";
40
+ import { capabilityDocPathsAt } from "../repo/authored/paths.js";
41
+ import { entryIs, markDescended, subdirNames } from "../repo/tree/fs.js";
42
+ /**
43
+ * Read the tree under `root` (`capabilityDocsDir(docsDir)`).
44
+ *
45
+ * Cost is one readdir per directory, capability directories included: their own
46
+ * listing is what classifies them, and it is the same listing that finds the
47
+ * capabilities nested inside. A fleet is expected to hold tens of these
48
+ * documents rather than hundreds — the corpus is sized like the landscape, not
49
+ * like the service tree — which is what keeps a second requirement corpus
50
+ * reviewable at all, and what makes the walk's cost a non-question.
51
+ */
52
+ export async function readCapabilityTree(root) {
53
+ const tree = { present: existsSync(root), docs: [], undocumented: [] };
54
+ if (!tree.present)
55
+ return tree;
56
+ const state = { tree, visited: new Set() };
57
+ // The same guard `core/repo/tree/walk.ts` carries (`markDescended`), for
58
+ // the same reason: `entryIs` follows symlinks on purpose.
59
+ if (markDescended(root, state.visited)) {
60
+ for (const name of await subdirNames(root)) {
61
+ await visit({ dir: join(root, name), chain: [name] }, state);
62
+ }
63
+ }
64
+ tree.docs.sort((a, b) => compareIds(a.id, b.id));
65
+ tree.undocumented.sort(compareIds);
66
+ return tree;
67
+ }
68
+ /**
69
+ * Classify one directory and walk what is inside it. Returns whether a
70
+ * capability was found at or beneath it — the only thing a caller needs, since
71
+ * a group directory earns no finding for being a group.
72
+ *
73
+ * A directory reached a SECOND time through a symlink answers `true` rather
74
+ * than `false`, and the distinction is a quiet enumeration against a spurious
75
+ * finding: it was already walked under its first name, so everything in it is
76
+ * already recorded, and reporting it undocumented would name a directory whose
77
+ * document loam has in fact already read.
78
+ */
79
+ async function visit(spot, state) {
80
+ const entries = (await readdir(spot.dir, { withFileTypes: true })).filter((e) => !e.name.startsWith("."));
81
+ const paths = capabilityDocPathsAt(spot.dir);
82
+ const documented = entries.some((e) => join(spot.dir, e.name) === paths.spec && entryIs(spot.dir, e, "file"));
83
+ if (documented)
84
+ state.tree.docs.push({ id: spot.chain.join("/"), dir: spot.dir, spec: paths.spec });
85
+ let beneath = false;
86
+ if (markDescended(spot.dir, state.visited)) {
87
+ const dirs = entries.filter((e) => entryIs(spot.dir, e, "dir")).map((e) => e.name).sort();
88
+ for (const child of dirs) {
89
+ // Sequential, not Promise.all: the visited set is shared mutable state and
90
+ // the walk's correctness under symlinks rests on a child being marked
91
+ // before its sibling asks. These trees are tens of directories at most, so
92
+ // there is nothing to win by racing them.
93
+ if (await visit({ dir: join(spot.dir, child), chain: [...spot.chain, child] }, state))
94
+ beneath = true;
95
+ }
96
+ }
97
+ else {
98
+ beneath = true;
99
+ }
100
+ if (!documented && !beneath)
101
+ state.tree.undocumented.push(["capabilities", ...spot.chain].join("/"));
102
+ return documented || beneath;
103
+ }
104
+ //# sourceMappingURL=tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.js","sourceRoot":"","sources":["../../../src/core/capabilities/tree.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The capability tree: `capabilities/<id>/spec.md`, and the rule that a\n * directory holding one IS a declared capability.\n *\n * WHY A TREE AND NOT A SECOND LIST IN YAML. `architecture/capabilities.yaml`\n * declares names; it cannot carry prose, and a capability a business analyst\n * actually wrote is mostly prose. The alternative — a single vocabulary file\n * grown to hold paragraphs — is the exact drift `loam init`'s removed\n * `loam.docs.json` was removed for: a second list nothing keeps current. So the\n * DIRECTORY is the list, and the general rule it settles is that an entry with\n * prose gets a file while an entry without prose stays a line in YAML\n * (`architecture/permissions.yaml` is the principled exception — a\n * `user/profile:read` pair has no prose, and a document per pair is ceremony).\n *\n * THE VOCABULARY IS THE UNION of this tree and the YAML, and the YAML is not\n * deprecated by it. A fleet that declared twenty names and has written four\n * documents is the normal state of an adoption, and a tree that refused to\n * grade the other sixteen would make adopting the axis a cliff.\n * `./capabilities.ts` merges the two and records which side declared each id.\n *\n * PRESENCE CLASSIFIES, one tree over from `isServiceArtifactName`: a directory\n * holding the document is a capability, and one holding only other directories\n * is a group the walk descends through. Both at once is legal and normal —\n * `payments` may be a capability with `payments/refunds` nested inside it —\n * because a capability id spells its own nesting wherever it is written and the\n * tree only mirrors that. What is NOT legal is a directory that is neither:\n * `capability.doc-missing` names it, rather than letting a half-created\n * capability sit in the tree looking declared.\n *\n * The walk reads directories only. It never parses a document — the requirement\n * reader is injected by whoever grades (`./findings.ts` takes parsed\n * requirements, `commands/validate/` supplies the fleet's cached reader), for\n * the reason `./rollup.ts` states: this package is imported by\n * `core/fleet-context.ts` and may never import it back.\n */\nimport { existsSync } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { compareIds } from \"../repo/entries.js\";\nimport { capabilityDocPathsAt } from \"../repo/authored/paths.js\";\nimport { entryIs, markDescended, subdirNames } from \"../repo/tree/fs.js\";\n\n/** One authored capability: where its directory is, and where its document is. */\nexport interface CapabilityDoc {\n /** The id — the directory names between `capabilities/` and this one, joined with `/`. */\n id: string;\n dir: string;\n /** `<dir>/spec.md`. Its existence is what made this a capability. */\n spec: string;\n}\n\nexport interface CapabilityTree {\n /**\n * False when `capabilities/` does not exist. The directory's existence is\n * this half of the axis's opt-in, so a fleet without one produces nothing\n * here — not an empty tree that then reads as \"the capabilities went\n * missing\" to anything counting.\n */\n present: boolean;\n /** Every capability found, at any depth, ordered by id. */\n docs: CapabilityDoc[];\n /**\n * Repo-relative paths of directories under `capabilities/` that hold no\n * document and have no capability beneath them — the half-created capability\n * `capability.doc-missing` names. Ordered, for a diff-stable finding list.\n */\n undocumented: string[];\n}\n\n/** One directory the walk is looking at: where it is, and how it was reached. */\ninterface Spot {\n dir: string;\n /** Directory names between `capabilities/` and this one, outermost first, including it. */\n chain: string[];\n}\n\ninterface WalkState {\n tree: CapabilityTree;\n /** Realpaths already DESCENDED into — the symlink-cycle guard. */\n visited: Set<string>;\n}\n\n/**\n * Read the tree under `root` (`capabilityDocsDir(docsDir)`).\n *\n * Cost is one readdir per directory, capability directories included: their own\n * listing is what classifies them, and it is the same listing that finds the\n * capabilities nested inside. A fleet is expected to hold tens of these\n * documents rather than hundreds — the corpus is sized like the landscape, not\n * like the service tree — which is what keeps a second requirement corpus\n * reviewable at all, and what makes the walk's cost a non-question.\n */\nexport async function readCapabilityTree(root: string): Promise<CapabilityTree> {\n const tree: CapabilityTree = { present: existsSync(root), docs: [], undocumented: [] };\n if (!tree.present) return tree;\n const state: WalkState = { tree, visited: new Set() };\n // The same guard `core/repo/tree/walk.ts` carries (`markDescended`), for\n // the same reason: `entryIs` follows symlinks on purpose.\n if (markDescended(root, state.visited)) {\n for (const name of await subdirNames(root)) {\n await visit({ dir: join(root, name), chain: [name] }, state);\n }\n }\n tree.docs.sort((a, b) => compareIds(a.id, b.id));\n tree.undocumented.sort(compareIds);\n return tree;\n}\n\n/**\n * Classify one directory and walk what is inside it. Returns whether a\n * capability was found at or beneath it — the only thing a caller needs, since\n * a group directory earns no finding for being a group.\n *\n * A directory reached a SECOND time through a symlink answers `true` rather\n * than `false`, and the distinction is a quiet enumeration against a spurious\n * finding: it was already walked under its first name, so everything in it is\n * already recorded, and reporting it undocumented would name a directory whose\n * document loam has in fact already read.\n */\nasync function visit(spot: Spot, state: WalkState): Promise<boolean> {\n const entries = (await readdir(spot.dir, { withFileTypes: true })).filter((e) => !e.name.startsWith(\".\"));\n const paths = capabilityDocPathsAt(spot.dir);\n const documented = entries.some((e) => join(spot.dir, e.name) === paths.spec && entryIs(spot.dir, e, \"file\"));\n if (documented) state.tree.docs.push({ id: spot.chain.join(\"/\"), dir: spot.dir, spec: paths.spec });\n\n let beneath = false;\n if (markDescended(spot.dir, state.visited)) {\n const dirs = entries.filter((e) => entryIs(spot.dir, e, \"dir\")).map((e) => e.name).sort();\n for (const child of dirs) {\n // Sequential, not Promise.all: the visited set is shared mutable state and\n // the walk's correctness under symlinks rests on a child being marked\n // before its sibling asks. These trees are tens of directories at most, so\n // there is nothing to win by racing them.\n if (await visit({ dir: join(spot.dir, child), chain: [...spot.chain, child] }, state)) beneath = true;\n }\n } else {\n beneath = true;\n }\n\n if (!documented && !beneath) state.tree.undocumented.push([\"capabilities\", ...spot.chain].join(\"/\"));\n return documented || beneath;\n}\n"]}