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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1036) hide show
  1. package/CHANGELOG.md +2635 -86
  2. package/COMPARISON.md +80 -63
  3. package/CONTRIBUTING.md +84 -0
  4. package/MIGRATING-from-OpenSpec.md +213 -54
  5. package/QUICKSTART.md +125 -0
  6. package/README.md +450 -150
  7. package/ROADMAP.md +599 -0
  8. package/SCHEMA.md +2355 -256
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +701 -0
  11. package/dist/cli.js +113 -19
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +209 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +268 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +77 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/openapi.js +159 -0
  22. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  23. package/dist/commands/archive/plan/gate.js +323 -0
  24. package/dist/commands/archive/plan/gate.js.map +1 -0
  25. package/dist/commands/archive/plan/landscape.js +180 -0
  26. package/dist/commands/archive/plan/landscape.js.map +1 -0
  27. package/dist/commands/archive/plan/refusal.js +111 -0
  28. package/dist/commands/archive/plan/refusal.js.map +1 -0
  29. package/dist/commands/archive/plan/specs.js +237 -0
  30. package/dist/commands/archive/plan/specs.js.map +1 -0
  31. package/dist/commands/archive/plan/state.js +27 -0
  32. package/dist/commands/archive/plan/state.js.map +1 -0
  33. package/dist/commands/archive/run.js +252 -0
  34. package/dist/commands/archive/run.js.map +1 -0
  35. package/dist/commands/context/context.js +99 -0
  36. package/dist/commands/context/context.js.map +1 -0
  37. package/dist/commands/context/print.js +283 -0
  38. package/dist/commands/context/print.js.map +1 -0
  39. package/dist/commands/delta/delta.js +279 -0
  40. package/dist/commands/delta/delta.js.map +1 -0
  41. package/dist/commands/delta/print.js +205 -0
  42. package/dist/commands/delta/print.js.map +1 -0
  43. package/dist/commands/dependencies.js +9 -7
  44. package/dist/commands/dependencies.js.map +1 -1
  45. package/dist/commands/diff/diff.js +93 -0
  46. package/dist/commands/diff/diff.js.map +1 -0
  47. package/dist/commands/diff/print.js +38 -0
  48. package/dist/commands/diff/print.js.map +1 -0
  49. package/dist/commands/doctor.js +5 -4
  50. package/dist/commands/doctor.js.map +1 -1
  51. package/dist/commands/explain/explain.js +151 -0
  52. package/dist/commands/explain/explain.js.map +1 -0
  53. package/dist/commands/explore.js +29 -24
  54. package/dist/commands/explore.js.map +1 -1
  55. package/dist/commands/gate/gate.js +115 -0
  56. package/dist/commands/gate/gate.js.map +1 -0
  57. package/dist/commands/gate/print.js +54 -0
  58. package/dist/commands/gate/print.js.map +1 -0
  59. package/dist/commands/gherkin/commit.js +146 -0
  60. package/dist/commands/gherkin/commit.js.map +1 -0
  61. package/dist/commands/gherkin/gherkin.js +246 -0
  62. package/dist/commands/gherkin/gherkin.js.map +1 -0
  63. package/dist/commands/gherkin/reconcile.js +149 -0
  64. package/dist/commands/gherkin/reconcile.js.map +1 -0
  65. package/dist/commands/gherkin/render.js +77 -0
  66. package/dist/commands/gherkin/render.js.map +1 -0
  67. package/dist/commands/init/example.js +204 -0
  68. package/dist/commands/init/example.js.map +1 -0
  69. package/dist/commands/init/first-hour.js +28 -0
  70. package/dist/commands/init/first-hour.js.map +1 -0
  71. package/dist/commands/{init.js → init/init.js} +146 -71
  72. package/dist/commands/init/init.js.map +1 -0
  73. package/dist/commands/init/mcp.js +131 -0
  74. package/dist/commands/init/mcp.js.map +1 -0
  75. package/dist/commands/init/options.js +78 -0
  76. package/dist/commands/init/options.js.map +1 -0
  77. package/dist/commands/instructions.js +72 -14
  78. package/dist/commands/instructions.js.map +1 -1
  79. package/dist/commands/list/campaign/campaign.js +65 -0
  80. package/dist/commands/list/campaign/campaign.js.map +1 -0
  81. package/dist/commands/list/campaign/owners.js +65 -0
  82. package/dist/commands/list/campaign/owners.js.map +1 -0
  83. package/dist/commands/list/json.js +157 -0
  84. package/dist/commands/list/json.js.map +1 -0
  85. package/dist/commands/list/list.js +343 -0
  86. package/dist/commands/list/list.js.map +1 -0
  87. package/dist/commands/list/print.js +301 -0
  88. package/dist/commands/list/print.js.map +1 -0
  89. package/dist/commands/list/review.js +120 -0
  90. package/dist/commands/list/review.js.map +1 -0
  91. package/dist/commands/list/views.js +105 -0
  92. package/dist/commands/list/views.js.map +1 -0
  93. package/dist/commands/mcp/dispatch.js +183 -0
  94. package/dist/commands/mcp/dispatch.js.map +1 -0
  95. package/dist/commands/mcp/mcp.js +34 -0
  96. package/dist/commands/mcp/mcp.js.map +1 -0
  97. package/dist/commands/mcp/serve.js +55 -0
  98. package/dist/commands/mcp/serve.js.map +1 -0
  99. package/dist/commands/migrate-openspec/materialize/active.js +170 -0
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  101. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  102. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  103. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  104. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  105. package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
  106. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  107. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  108. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  109. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  110. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  111. package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
  112. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  113. package/dist/commands/migrate-openspec/openspec/error.js +19 -0
  114. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  115. package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
  116. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  117. package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
  118. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  119. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  120. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  121. package/dist/commands/migrate-openspec/print.js +89 -0
  122. package/dist/commands/migrate-openspec/print.js.map +1 -0
  123. package/dist/commands/new/commit.js +76 -0
  124. package/dist/commands/new/commit.js.map +1 -0
  125. package/dist/commands/new/new.js +283 -0
  126. package/dist/commands/new/new.js.map +1 -0
  127. package/dist/commands/new/templates.js +355 -0
  128. package/dist/commands/new/templates.js.map +1 -0
  129. package/dist/commands/open.js +203 -0
  130. package/dist/commands/open.js.map +1 -0
  131. package/dist/commands/policy/format.js +152 -0
  132. package/dist/commands/policy/format.js.map +1 -0
  133. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
  134. package/dist/commands/policy/gate.js.map +1 -0
  135. package/dist/commands/rebase/edit.js +106 -0
  136. package/dist/commands/rebase/edit.js.map +1 -0
  137. package/dist/commands/rebase/living.js +185 -0
  138. package/dist/commands/rebase/living.js.map +1 -0
  139. package/dist/commands/rebase/plan.js +245 -0
  140. package/dist/commands/rebase/plan.js.map +1 -0
  141. package/dist/commands/rebase/rebase.js +275 -0
  142. package/dist/commands/rebase/rebase.js.map +1 -0
  143. package/dist/commands/seed/commit.js +192 -0
  144. package/dist/commands/seed/commit.js.map +1 -0
  145. package/dist/commands/seed/plan.js +133 -0
  146. package/dist/commands/seed/plan.js.map +1 -0
  147. package/dist/commands/seed/seed.js +172 -0
  148. package/dist/commands/seed/seed.js.map +1 -0
  149. package/dist/commands/show/feature.js +178 -0
  150. package/dist/commands/show/feature.js.map +1 -0
  151. package/dist/commands/show/marks.js +24 -0
  152. package/dist/commands/show/marks.js.map +1 -0
  153. package/dist/commands/{show.js → show/service.js} +63 -152
  154. package/dist/commands/show/service.js.map +1 -0
  155. package/dist/commands/show/show.js +77 -0
  156. package/dist/commands/show/show.js.map +1 -0
  157. package/dist/commands/status/json.js +45 -0
  158. package/dist/commands/status/json.js.map +1 -0
  159. package/dist/commands/status/print.js +157 -0
  160. package/dist/commands/status/print.js.map +1 -0
  161. package/dist/commands/status/status.js +119 -0
  162. package/dist/commands/status/status.js.map +1 -0
  163. package/dist/commands/steps/steps.js +189 -0
  164. package/dist/commands/steps/steps.js.map +1 -0
  165. package/dist/commands/subsystem/edit.js +192 -0
  166. package/dist/commands/subsystem/edit.js.map +1 -0
  167. package/dist/commands/subsystem/move.js +265 -0
  168. package/dist/commands/subsystem/move.js.map +1 -0
  169. package/dist/commands/subsystem/query.js +115 -0
  170. package/dist/commands/subsystem/query.js.map +1 -0
  171. package/dist/commands/subsystem/subsystem.js +101 -0
  172. package/dist/commands/subsystem/subsystem.js.map +1 -0
  173. package/dist/commands/subsystem/sync.js +103 -0
  174. package/dist/commands/subsystem/sync.js.map +1 -0
  175. package/dist/commands/subsystem/txn/txn.js +94 -0
  176. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  177. package/dist/commands/subsystem/txn/views.js +70 -0
  178. package/dist/commands/subsystem/txn/views.js.map +1 -0
  179. package/dist/commands/unarchive/manifest.js +160 -0
  180. package/dist/commands/unarchive/manifest.js.map +1 -0
  181. package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
  182. package/dist/commands/unarchive/restore.js.map +1 -0
  183. package/dist/commands/unarchive/unarchive.js +67 -0
  184. package/dist/commands/unarchive/unarchive.js.map +1 -0
  185. package/dist/commands/validate/arch-coverage.js +204 -0
  186. package/dist/commands/validate/arch-coverage.js.map +1 -0
  187. package/dist/commands/validate/checks/fleet-shape.js +296 -0
  188. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  189. package/dist/commands/validate/checks/health-deps.js +55 -0
  190. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  191. package/dist/commands/validate/checks/requirements.js +254 -0
  192. package/dist/commands/validate/checks/requirements.js.map +1 -0
  193. package/dist/commands/validate/checks/sources.js +76 -0
  194. package/dist/commands/validate/checks/sources.js.map +1 -0
  195. package/dist/commands/validate/checks/vocabulary.js +31 -0
  196. package/dist/commands/validate/checks/vocabulary.js.map +1 -0
  197. package/dist/commands/validate/feature.js +216 -0
  198. package/dist/commands/validate/feature.js.map +1 -0
  199. package/dist/commands/validate/fleet/census.js +69 -0
  200. package/dist/commands/validate/fleet/census.js.map +1 -0
  201. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  202. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  203. package/dist/commands/validate/fleet/landscape.js +353 -0
  204. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  205. package/dist/commands/validate/fleet/load.js +52 -0
  206. package/dist/commands/validate/fleet/load.js.map +1 -0
  207. package/dist/commands/validate/fleet/obligations.js +270 -0
  208. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  209. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  210. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  211. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  212. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  213. package/dist/commands/validate/fleet/scorecard/print.js +63 -0
  214. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  215. package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
  216. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  217. package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
  218. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
  219. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  220. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  221. package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
  222. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
  223. package/dist/commands/validate/fleet/usecases/steps.js +197 -0
  224. package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
  225. package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
  226. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
  227. package/dist/commands/validate/fleet/views/ids.js +40 -0
  228. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  229. package/dist/commands/validate/fleet/views/stale.js +59 -0
  230. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  231. package/dist/commands/validate/links/corpus.js +92 -0
  232. package/dist/commands/validate/links/corpus.js.map +1 -0
  233. package/dist/commands/validate/links/glossary.js +75 -0
  234. package/dist/commands/validate/links/glossary.js.map +1 -0
  235. package/dist/commands/validate/report.js +269 -0
  236. package/dist/commands/validate/report.js.map +1 -0
  237. package/dist/commands/validate/service/api.js +338 -0
  238. package/dist/commands/validate/service/api.js.map +1 -0
  239. package/dist/commands/validate/service/events/events.js +219 -0
  240. package/dist/commands/validate/service/events/events.js.map +1 -0
  241. package/dist/commands/validate/service/events/message-producers.js +77 -0
  242. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  243. package/dist/commands/validate/service/evidence-pins.js +131 -0
  244. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  245. package/dist/commands/validate/service/service.js +251 -0
  246. package/dist/commands/validate/service/service.js.map +1 -0
  247. package/dist/commands/validate/service/specs.js +251 -0
  248. package/dist/commands/validate/service/specs.js.map +1 -0
  249. package/dist/commands/validate/service/spine.js +113 -0
  250. package/dist/commands/validate/service/spine.js.map +1 -0
  251. package/dist/commands/validate/validate.js +338 -0
  252. package/dist/commands/validate/validate.js.map +1 -0
  253. package/dist/commands/verify/cross/diff.js +182 -0
  254. package/dist/commands/verify/cross/diff.js.map +1 -0
  255. package/dist/commands/verify/evidence/contract.js +32 -0
  256. package/dist/commands/verify/evidence/contract.js.map +1 -0
  257. package/dist/commands/verify/evidence/pins.js +52 -0
  258. package/dist/commands/verify/evidence/pins.js.map +1 -0
  259. package/dist/commands/verify/evidence/read.js +72 -0
  260. package/dist/commands/verify/evidence/read.js.map +1 -0
  261. package/dist/commands/verify/frozen.js +241 -0
  262. package/dist/commands/verify/frozen.js.map +1 -0
  263. package/dist/commands/verify/record.js +226 -0
  264. package/dist/commands/verify/record.js.map +1 -0
  265. package/dist/commands/verify/report.js +223 -0
  266. package/dist/commands/verify/report.js.map +1 -0
  267. package/dist/commands/verify/results.js +246 -0
  268. package/dist/commands/verify/results.js.map +1 -0
  269. package/dist/commands/verify/verify.js +217 -0
  270. package/dist/commands/verify/verify.js.map +1 -0
  271. package/dist/commands/vouch/contract.js +11 -0
  272. package/dist/commands/vouch/contract.js.map +1 -0
  273. package/dist/commands/vouch/pack/contract.js +2 -0
  274. package/dist/commands/vouch/pack/contract.js.map +1 -0
  275. package/dist/commands/vouch/pack/pack.js +266 -0
  276. package/dist/commands/vouch/pack/pack.js.map +1 -0
  277. package/dist/commands/vouch/pack/print.js +271 -0
  278. package/dist/commands/vouch/pack/print.js.map +1 -0
  279. package/dist/commands/vouch/pack/sections.js +142 -0
  280. package/dist/commands/vouch/pack/sections.js.map +1 -0
  281. package/dist/commands/vouch/prompt/confirm.js +46 -0
  282. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  283. package/dist/commands/vouch/report.js +101 -0
  284. package/dist/commands/vouch/report.js.map +1 -0
  285. package/dist/commands/vouch/run.js +285 -0
  286. package/dist/commands/vouch/run.js.map +1 -0
  287. package/dist/commands/vouch/sample/plan.js +125 -0
  288. package/dist/commands/vouch/sample/plan.js.map +1 -0
  289. package/dist/commands/vouch/sample/print.js +109 -0
  290. package/dist/commands/vouch/sample/print.js.map +1 -0
  291. package/dist/commands/vouch/vet/verify.js +123 -0
  292. package/dist/commands/vouch/vet/verify.js.map +1 -0
  293. package/dist/commands/vouch/vouch.js +176 -0
  294. package/dist/commands/vouch/vouch.js.map +1 -0
  295. package/dist/core/agent/agents-md/artifacts.js +220 -0
  296. package/dist/core/agent/agents-md/artifacts.js.map +1 -0
  297. package/dist/core/agent/agents-md/command-map.js +324 -0
  298. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  299. package/dist/core/agent/agents-md/cycle.js +165 -0
  300. package/dist/core/agent/agents-md/cycle.js.map +1 -0
  301. package/dist/core/agent/agents-md/map/explain.js +34 -0
  302. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  303. package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
  304. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  305. package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
  306. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  307. package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
  308. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  309. package/dist/core/agent/agents-md/map/mcp.js +41 -0
  310. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  311. package/dist/core/agent/agents-md/map/status.js +62 -0
  312. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  313. package/dist/core/agent/agents-md/map/subsystem.js +32 -0
  314. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  315. package/dist/core/agent/agents-md/map/usecases.js +60 -0
  316. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  317. package/dist/core/agent/agents-md/refusals.js +246 -0
  318. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  319. package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
  320. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
  321. package/dist/core/agent/agents-md/spine.js +40 -0
  322. package/dist/core/agent/agents-md/spine.js.map +1 -0
  323. package/dist/core/agent/agents-md.js +170 -0
  324. package/dist/core/agent/agents-md.js.map +1 -0
  325. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +50 -0
  326. package/dist/core/agent/agents-stamp.js.map +1 -0
  327. package/dist/core/agent/contract.js +2 -0
  328. package/dist/core/agent/contract.js.map +1 -0
  329. package/dist/core/agent/protocol.js +193 -0
  330. package/dist/core/agent/protocol.js.map +1 -0
  331. package/dist/core/agent/scaffold.js +259 -0
  332. package/dist/core/agent/scaffold.js.map +1 -0
  333. package/dist/core/agent/support/report.js +103 -0
  334. package/dist/core/agent/support/report.js.map +1 -0
  335. package/dist/core/agent/tools/dialects.js +150 -0
  336. package/dist/core/agent/tools/dialects.js.map +1 -0
  337. package/dist/core/agent/tools/registry.js +228 -0
  338. package/dist/core/agent/tools/registry.js.map +1 -0
  339. package/dist/core/agent/workflows/adopt.js +133 -0
  340. package/dist/core/agent/workflows/adopt.js.map +1 -0
  341. package/dist/core/agent/workflows/check.js +337 -0
  342. package/dist/core/agent/workflows/check.js.map +1 -0
  343. package/dist/core/agent/workflows/closing.js +262 -0
  344. package/dist/core/agent/workflows/closing.js.map +1 -0
  345. package/dist/core/agent/workflows/feature.js +105 -0
  346. package/dist/core/agent/workflows/feature.js.map +1 -0
  347. package/dist/core/agent/workflows/implement.js +105 -0
  348. package/dist/core/agent/workflows/implement.js.map +1 -0
  349. package/dist/core/agent/workflows/reference/authoring.js +209 -0
  350. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  351. package/dist/core/agent/workflows/reference/codes.js +65 -0
  352. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  353. package/dist/core/agent/workflows/reference/done-check.js +188 -0
  354. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  355. package/dist/core/agent/workflows/reference/reference.js +16 -0
  356. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  357. package/dist/core/agent/workflows/reference/spine.js +297 -0
  358. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  359. package/dist/core/asyncapi/baseline/plan.js +110 -0
  360. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  361. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  362. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  363. package/dist/core/asyncapi/depth.js +164 -0
  364. package/dist/core/asyncapi/depth.js.map +1 -0
  365. package/dist/core/asyncapi/digest.js +141 -0
  366. package/dist/core/asyncapi/digest.js.map +1 -0
  367. package/dist/core/asyncapi/merge/components.js +91 -0
  368. package/dist/core/asyncapi/merge/components.js.map +1 -0
  369. package/dist/core/asyncapi/merge/error.js +33 -0
  370. package/dist/core/asyncapi/merge/error.js.map +1 -0
  371. package/dist/core/asyncapi/merge/markers.js +308 -0
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  373. package/dist/core/asyncapi/merge/merge.js +215 -0
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  375. package/dist/core/asyncapi/merge/pin.js +107 -0
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  377. package/dist/core/asyncapi/model.js +11 -0
  378. package/dist/core/asyncapi/model.js.map +1 -0
  379. package/dist/core/asyncapi/producers.js +50 -0
  380. package/dist/core/asyncapi/producers.js.map +1 -0
  381. package/dist/core/{asyncapi.js → asyncapi/read.js} +95 -109
  382. package/dist/core/asyncapi/read.js.map +1 -0
  383. package/dist/core/brief/brief.js +225 -0
  384. package/dist/core/brief/brief.js.map +1 -0
  385. package/dist/core/brief/checks.js +250 -0
  386. package/dist/core/brief/checks.js.map +1 -0
  387. package/dist/core/brief/landscape.js +194 -0
  388. package/dist/core/brief/landscape.js.map +1 -0
  389. package/dist/core/brief/targets.js +226 -0
  390. package/dist/core/brief/targets.js.map +1 -0
  391. package/dist/core/brief/unchecked.js +48 -0
  392. package/dist/core/brief/unchecked.js.map +1 -0
  393. package/dist/core/c4/arch.js +174 -0
  394. package/dist/core/c4/arch.js.map +1 -0
  395. package/dist/core/c4/likec4.js +90 -0
  396. package/dist/core/c4/likec4.js.map +1 -0
  397. package/dist/core/c4/parsed/deployment.js +158 -0
  398. package/dist/core/c4/parsed/deployment.js.map +1 -0
  399. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  400. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  401. package/dist/core/c4/parsed/specification.js +78 -0
  402. package/dist/core/c4/parsed/specification.js.map +1 -0
  403. package/dist/core/c4/parsed/values.js +57 -0
  404. package/dist/core/c4/parsed/values.js.map +1 -0
  405. package/dist/core/c4/parsed/view-ids.js +75 -0
  406. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  407. package/dist/core/c4/project/architecture.js +45 -0
  408. package/dist/core/c4/project/architecture.js.map +1 -0
  409. package/dist/core/c4/project/documents.js +58 -0
  410. package/dist/core/c4/project/documents.js.map +1 -0
  411. package/dist/core/c4/project/load.js +187 -0
  412. package/dist/core/c4/project/load.js.map +1 -0
  413. package/dist/core/c4/project/staged.js +220 -0
  414. package/dist/core/c4/project/staged.js.map +1 -0
  415. package/dist/core/c4/resolve/service.js +159 -0
  416. package/dist/core/c4/resolve/service.js.map +1 -0
  417. package/dist/core/c4/resolve/steps.js +144 -0
  418. package/dist/core/c4/resolve/steps.js.map +1 -0
  419. package/dist/core/c4/seed/fleet-file.js +201 -0
  420. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  421. package/dist/core/c4/seed/items.js +91 -0
  422. package/dist/core/c4/seed/items.js.map +1 -0
  423. package/dist/core/c4/seed/stamp.js +48 -0
  424. package/dist/core/c4/seed/stamp.js.map +1 -0
  425. package/dist/core/c4/seed/template.js +109 -0
  426. package/dist/core/c4/seed/template.js.map +1 -0
  427. package/dist/core/c4/source-mask.js +82 -0
  428. package/dist/core/c4/source-mask.js.map +1 -0
  429. package/dist/core/c4/source-scan.js +227 -0
  430. package/dist/core/c4/source-scan.js.map +1 -0
  431. package/dist/core/c4/splice/authored-source.js +101 -0
  432. package/dist/core/c4/splice/authored-source.js.map +1 -0
  433. package/dist/core/c4/splice/contract.js +10 -0
  434. package/dist/core/c4/splice/contract.js.map +1 -0
  435. package/dist/core/c4/splice/delta-blocks.js +139 -0
  436. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  437. package/dist/core/c4/splice/identity/edges.js +36 -0
  438. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  439. package/dist/core/c4/splice/landscape-merge.js +269 -0
  440. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  441. package/dist/core/c4/splice/placement.js +194 -0
  442. package/dist/core/c4/splice/placement.js.map +1 -0
  443. package/dist/core/c4/workspace.js +174 -0
  444. package/dist/core/c4/workspace.js.map +1 -0
  445. package/dist/core/capabilities/authoring/notes.js +141 -0
  446. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  447. package/dist/core/capabilities/capabilities.js +124 -0
  448. package/dist/core/capabilities/capabilities.js.map +1 -0
  449. package/dist/core/capabilities/delta/doc.js +50 -0
  450. package/dist/core/capabilities/delta/doc.js.map +1 -0
  451. package/dist/core/capabilities/delta/overlay.js +129 -0
  452. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  453. package/dist/core/capabilities/delta/summary.js +57 -0
  454. package/dist/core/capabilities/delta/summary.js.map +1 -0
  455. package/dist/core/capabilities/delta/tree.js +43 -0
  456. package/dist/core/capabilities/delta/tree.js.map +1 -0
  457. package/dist/core/capabilities/delta/uncovered.js +222 -0
  458. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  459. package/dist/core/capabilities/findings.js +342 -0
  460. package/dist/core/capabilities/findings.js.map +1 -0
  461. package/dist/core/capabilities/realizes/findings.js +181 -0
  462. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  463. package/dist/core/capabilities/realizes/join.js +143 -0
  464. package/dist/core/capabilities/realizes/join.js.map +1 -0
  465. package/dist/core/capabilities/rollup.js +199 -0
  466. package/dist/core/capabilities/rollup.js.map +1 -0
  467. package/dist/core/capabilities/tree.js +126 -0
  468. package/dist/core/capabilities/tree.js.map +1 -0
  469. package/dist/core/capabilities/usecase-join.js +277 -0
  470. package/dist/core/capabilities/usecase-join.js.map +1 -0
  471. package/dist/core/coherence/authoring/scaffold.js +177 -0
  472. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  473. package/dist/core/coherence/authoring/sentinels.js +74 -0
  474. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  475. package/dist/core/coherence/coherence.js +287 -0
  476. package/dist/core/coherence/coherence.js.map +1 -0
  477. package/dist/core/coherence/declared.js +269 -0
  478. package/dist/core/coherence/declared.js.map +1 -0
  479. package/dist/core/coherence/events/declared.js +206 -0
  480. package/dist/core/coherence/events/declared.js.map +1 -0
  481. package/dist/core/coherence/events/events.js +204 -0
  482. package/dist/core/coherence/events/events.js.map +1 -0
  483. package/dist/core/coherence/events/grades.js +166 -0
  484. package/dist/core/coherence/events/grades.js.map +1 -0
  485. package/dist/core/coherence/events/lookups.js +122 -0
  486. package/dist/core/coherence/events/lookups.js.map +1 -0
  487. package/dist/core/coherence/events/merged.js +40 -0
  488. package/dist/core/coherence/events/merged.js.map +1 -0
  489. package/dist/core/coherence/living.js +198 -0
  490. package/dist/core/coherence/living.js.map +1 -0
  491. package/dist/core/coherence/lookups.js +155 -0
  492. package/dist/core/coherence/lookups.js.map +1 -0
  493. package/dist/core/coherence/pending.js +39 -0
  494. package/dist/core/coherence/pending.js.map +1 -0
  495. package/dist/core/conflict-markers.js +60 -0
  496. package/dist/core/conflict-markers.js.map +1 -0
  497. package/dist/core/delta/claims.js +73 -0
  498. package/dist/core/delta/claims.js.map +1 -0
  499. package/dist/core/delta/delta.js +296 -0
  500. package/dist/core/delta/delta.js.map +1 -0
  501. package/dist/core/delta/document.js +177 -0
  502. package/dist/core/delta/document.js.map +1 -0
  503. package/dist/core/delta/scope.js +48 -0
  504. package/dist/core/delta/scope.js.map +1 -0
  505. package/dist/core/delta/select.js +237 -0
  506. package/dist/core/delta/select.js.map +1 -0
  507. package/dist/core/dependencies/dependencies.js +141 -0
  508. package/dist/core/dependencies/dependencies.js.map +1 -0
  509. package/dist/core/dependencies/facts.js +165 -0
  510. package/dist/core/dependencies/facts.js.map +1 -0
  511. package/dist/core/dependencies/fanin.js +88 -0
  512. package/dist/core/dependencies/fanin.js.map +1 -0
  513. package/dist/core/dependencies/graph.js +106 -0
  514. package/dist/core/dependencies/graph.js.map +1 -0
  515. package/dist/core/deployment/delta.js +188 -0
  516. package/dist/core/deployment/delta.js.map +1 -0
  517. package/dist/core/deployment/objects.js +145 -0
  518. package/dist/core/deployment/objects.js.map +1 -0
  519. package/dist/core/diff/base-git.js +148 -0
  520. package/dist/core/diff/base-git.js.map +1 -0
  521. package/dist/core/diff/base-state.js +209 -0
  522. package/dist/core/diff/base-state.js.map +1 -0
  523. package/dist/core/diff/current-state.js +96 -0
  524. package/dist/core/diff/current-state.js.map +1 -0
  525. package/dist/core/diff/scope/changed-paths.js +188 -0
  526. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  527. package/dist/core/diff/semantic.js +243 -0
  528. package/dist/core/diff/semantic.js.map +1 -0
  529. package/dist/core/diff/victims.js +247 -0
  530. package/dist/core/diff/victims.js.map +1 -0
  531. package/dist/core/docs.js +7 -64
  532. package/dist/core/docs.js.map +1 -1
  533. package/dist/core/doctor/agents.js +222 -0
  534. package/dist/core/doctor/agents.js.map +1 -0
  535. package/dist/core/doctor/config.js +135 -0
  536. package/dist/core/doctor/config.js.map +1 -0
  537. package/dist/core/doctor/doctor.js +275 -0
  538. package/dist/core/doctor/doctor.js.map +1 -0
  539. package/dist/core/doctor/report.js +13 -0
  540. package/dist/core/doctor/report.js.map +1 -0
  541. package/dist/core/doctor/residue.js +110 -0
  542. package/dist/core/doctor/residue.js.map +1 -0
  543. package/dist/core/document/apply.js +77 -0
  544. package/dist/core/document/apply.js.map +1 -0
  545. package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
  546. package/dist/core/document/frontmatter.js.map +1 -0
  547. package/dist/core/document/grammar/directives.js +143 -0
  548. package/dist/core/document/grammar/directives.js.map +1 -0
  549. package/dist/core/document/parse.js +263 -0
  550. package/dist/core/document/parse.js.map +1 -0
  551. package/dist/core/document/scenarios.js +221 -0
  552. package/dist/core/document/scenarios.js.map +1 -0
  553. package/dist/core/document/spec.js +241 -0
  554. package/dist/core/document/spec.js.map +1 -0
  555. package/dist/core/{config.js → envelope/config.js} +79 -18
  556. package/dist/core/envelope/config.js.map +1 -0
  557. package/dist/core/envelope/json.js +175 -0
  558. package/dist/core/envelope/json.js.map +1 -0
  559. package/dist/core/{version.js → envelope/version.js} +3 -3
  560. package/dist/core/envelope/version.js.map +1 -0
  561. package/dist/core/explain/families.js +175 -0
  562. package/dist/core/explain/families.js.map +1 -0
  563. package/dist/core/explain/fix-tables.js +178 -0
  564. package/dist/core/explain/fix-tables.js.map +1 -0
  565. package/dist/core/explain/lookup.js +181 -0
  566. package/dist/core/explain/lookup.js.map +1 -0
  567. package/dist/core/explain/refusals.js +49 -0
  568. package/dist/core/explain/refusals.js.map +1 -0
  569. package/dist/core/explain/terms.js +144 -0
  570. package/dist/core/explain/terms.js.map +1 -0
  571. package/dist/core/explore/describe.js +105 -0
  572. package/dist/core/explore/describe.js.map +1 -0
  573. package/dist/core/{explore.js → explore/explore.js} +50 -101
  574. package/dist/core/explore/explore.js.map +1 -0
  575. package/dist/core/fleet-context.js +120 -78
  576. package/dist/core/fleet-context.js.map +1 -1
  577. package/dist/core/gate/checks.js +201 -0
  578. package/dist/core/gate/checks.js.map +1 -0
  579. package/dist/core/gate/partners.js +205 -0
  580. package/dist/core/gate/partners.js.map +1 -0
  581. package/dist/core/gate/report.js +47 -0
  582. package/dist/core/gate/report.js.map +1 -0
  583. package/dist/core/gate/verification.js +113 -0
  584. package/dist/core/gate/verification.js.map +1 -0
  585. package/dist/core/gherkin/digest.js +60 -0
  586. package/dist/core/gherkin/digest.js.map +1 -0
  587. package/dist/core/gherkin/emit.js +177 -0
  588. package/dist/core/gherkin/emit.js.map +1 -0
  589. package/dist/core/gherkin/read.js +76 -0
  590. package/dist/core/gherkin/read.js.map +1 -0
  591. package/dist/core/gherkin/stale.js +234 -0
  592. package/dist/core/gherkin/stale.js.map +1 -0
  593. package/dist/core/gherkin/stamp.js +77 -0
  594. package/dist/core/gherkin/stamp.js.map +1 -0
  595. package/dist/core/gherkin/steps/catalogue.js +154 -0
  596. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  597. package/dist/core/gherkin/steps/inventory.js +98 -0
  598. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  599. package/dist/core/gherkin/steps/phrase.js +72 -0
  600. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  601. package/dist/core/glossary/delta.js +106 -0
  602. package/dist/core/glossary/delta.js.map +1 -0
  603. package/dist/core/glossary/tree.js +86 -0
  604. package/dist/core/glossary/tree.js.map +1 -0
  605. package/dist/core/kernel/concurrency.js.map +1 -0
  606. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  607. package/dist/core/kernel/document-bytes.js.map +1 -0
  608. package/dist/core/kernel/fences.js +42 -0
  609. package/dist/core/kernel/fences.js.map +1 -0
  610. package/dist/core/kernel/ids/capability.js +72 -0
  611. package/dist/core/kernel/ids/capability.js.map +1 -0
  612. package/dist/core/kernel/ids/dirs.js +33 -0
  613. package/dist/core/kernel/ids/dirs.js.map +1 -0
  614. package/dist/core/kernel/ids/feature.js +75 -0
  615. package/dist/core/kernel/ids/feature.js.map +1 -0
  616. package/dist/core/kernel/ids/service.js +156 -0
  617. package/dist/core/kernel/ids/service.js.map +1 -0
  618. package/dist/core/kernel/ids/subsystem.js +63 -0
  619. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  620. package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
  621. package/dist/core/kernel/path-safety.js.map +1 -0
  622. package/dist/core/kernel/records.js.map +1 -0
  623. package/dist/core/links/backlinks.js +68 -0
  624. package/dist/core/links/backlinks.js.map +1 -0
  625. package/dist/core/links/case.js +74 -0
  626. package/dist/core/links/case.js.map +1 -0
  627. package/dist/core/links/corpus.js +104 -0
  628. package/dist/core/links/corpus.js.map +1 -0
  629. package/dist/core/links/findings.js +110 -0
  630. package/dist/core/links/findings.js.map +1 -0
  631. package/dist/core/links/parse.js +236 -0
  632. package/dist/core/links/parse.js.map +1 -0
  633. package/dist/core/mcp/argv.js +111 -0
  634. package/dist/core/mcp/argv.js.map +1 -0
  635. package/dist/core/mcp/author-tools.js +72 -0
  636. package/dist/core/mcp/author-tools.js.map +1 -0
  637. package/dist/core/mcp/framing.js +46 -0
  638. package/dist/core/mcp/framing.js.map +1 -0
  639. package/dist/core/mcp/protocol.js +280 -0
  640. package/dist/core/mcp/protocol.js.map +1 -0
  641. package/dist/core/mcp/tools.js +314 -0
  642. package/dist/core/mcp/tools.js.map +1 -0
  643. package/dist/core/obligations/obligations.js +106 -0
  644. package/dist/core/obligations/obligations.js.map +1 -0
  645. package/dist/core/openapi/baseline/gate.js +166 -0
  646. package/dist/core/openapi/baseline/gate.js.map +1 -0
  647. package/dist/core/openapi/baseline/plan.js +112 -0
  648. package/dist/core/openapi/baseline/plan.js.map +1 -0
  649. package/dist/core/openapi/baseline/record.js +175 -0
  650. package/dist/core/openapi/baseline/record.js.map +1 -0
  651. package/dist/core/openapi/depth.js +122 -0
  652. package/dist/core/openapi/depth.js.map +1 -0
  653. package/dist/core/openapi/digest.js +189 -0
  654. package/dist/core/openapi/digest.js.map +1 -0
  655. package/dist/core/{openapi.js → openapi/doc.js} +44 -106
  656. package/dist/core/openapi/doc.js.map +1 -0
  657. package/dist/core/openapi/merge/components.js +234 -0
  658. package/dist/core/openapi/merge/components.js.map +1 -0
  659. package/dist/core/openapi/merge/error.js +26 -0
  660. package/dist/core/openapi/merge/error.js.map +1 -0
  661. package/dist/core/openapi/merge/markers.js +208 -0
  662. package/dist/core/openapi/merge/markers.js.map +1 -0
  663. package/dist/core/openapi/merge/merge.js +256 -0
  664. package/dist/core/openapi/merge/merge.js.map +1 -0
  665. package/dist/core/openapi/merge/pin.js +128 -0
  666. package/dist/core/openapi/merge/pin.js.map +1 -0
  667. package/dist/core/openspec/decide/capabilities.js +244 -0
  668. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  669. package/dist/core/openspec/decide/dispositions.js +63 -0
  670. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  671. package/dist/core/openspec/decide/renames.js +179 -0
  672. package/dist/core/openspec/decide/renames.js.map +1 -0
  673. package/dist/core/openspec/decide/verdict.js +84 -0
  674. package/dist/core/openspec/decide/verdict.js.map +1 -0
  675. package/dist/core/openspec/inventory.js +221 -0
  676. package/dist/core/openspec/inventory.js.map +1 -0
  677. package/dist/core/openspec/model/mapping.js +76 -0
  678. package/dist/core/openspec/model/mapping.js.map +1 -0
  679. package/dist/core/openspec/model/model.js +65 -0
  680. package/dist/core/openspec/model/model.js.map +1 -0
  681. package/dist/core/openspec/scan/changes.js +235 -0
  682. package/dist/core/openspec/scan/changes.js.map +1 -0
  683. package/dist/core/openspec/scan/config.js +200 -0
  684. package/dist/core/openspec/scan/config.js.map +1 -0
  685. package/dist/core/openspec/scan/shape.js +260 -0
  686. package/dist/core/openspec/scan/shape.js.map +1 -0
  687. package/dist/core/openspec/scan/walk.js +133 -0
  688. package/dist/core/openspec/scan/walk.js.map +1 -0
  689. package/dist/core/openspec/scan/workspace.js +71 -0
  690. package/dist/core/openspec/scan/workspace.js.map +1 -0
  691. package/dist/core/owners/codeowners.js +141 -0
  692. package/dist/core/owners/codeowners.js.map +1 -0
  693. package/dist/core/pack/features.js +120 -0
  694. package/dist/core/pack/features.js.map +1 -0
  695. package/dist/core/pack/joins.js +112 -0
  696. package/dist/core/pack/joins.js.map +1 -0
  697. package/dist/core/pack/living.js +137 -0
  698. package/dist/core/pack/living.js.map +1 -0
  699. package/dist/core/pack/pack.js +76 -0
  700. package/dist/core/pack/pack.js.map +1 -0
  701. package/dist/core/permissions/permissions.js +87 -0
  702. package/dist/core/permissions/permissions.js.map +1 -0
  703. package/dist/core/projection/api.js +84 -0
  704. package/dist/core/projection/api.js.map +1 -0
  705. package/dist/core/projection/arch-slice.js +63 -0
  706. package/dist/core/projection/arch-slice.js.map +1 -0
  707. package/dist/core/projection/events.js +34 -0
  708. package/dist/core/projection/events.js.map +1 -0
  709. package/dist/core/provenance/findings.js +208 -0
  710. package/dist/core/provenance/findings.js.map +1 -0
  711. package/dist/core/provenance/git.js +225 -0
  712. package/dist/core/provenance/git.js.map +1 -0
  713. package/dist/core/provenance/gitq/moves.js +182 -0
  714. package/dist/core/provenance/gitq/moves.js.map +1 -0
  715. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  716. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  717. package/dist/core/provenance/sample/scope.js +238 -0
  718. package/dist/core/provenance/sample/scope.js.map +1 -0
  719. package/dist/core/provenance/sample/sections.js +61 -0
  720. package/dist/core/provenance/sample/sections.js.map +1 -0
  721. package/dist/core/provenance/sources.js +263 -0
  722. package/dist/core/provenance/sources.js.map +1 -0
  723. package/dist/core/provenance/stamp.js +232 -0
  724. package/dist/core/provenance/stamp.js.map +1 -0
  725. package/dist/core/provenance/walk.js +157 -0
  726. package/dist/core/provenance/walk.js.map +1 -0
  727. package/dist/core/repo/authored/paths.js +210 -0
  728. package/dist/core/repo/authored/paths.js.map +1 -0
  729. package/dist/core/repo/entries.js +126 -0
  730. package/dist/core/repo/entries.js.map +1 -0
  731. package/dist/core/repo/paths.js +277 -0
  732. package/dist/core/repo/paths.js.map +1 -0
  733. package/dist/core/repo/repo.js +248 -0
  734. package/dist/core/repo/repo.js.map +1 -0
  735. package/dist/core/repo/service-target.js +153 -0
  736. package/dist/core/repo/service-target.js.map +1 -0
  737. package/dist/core/repo/state.js +58 -0
  738. package/dist/core/repo/state.js.map +1 -0
  739. package/dist/core/repo/tree/find.js +52 -0
  740. package/dist/core/repo/tree/find.js.map +1 -0
  741. package/dist/core/repo/tree/fs.js +64 -0
  742. package/dist/core/repo/tree/fs.js.map +1 -0
  743. package/dist/core/repo/tree/marker.js +61 -0
  744. package/dist/core/repo/tree/marker.js.map +1 -0
  745. package/dist/core/repo/tree/views.js +172 -0
  746. package/dist/core/repo/tree/views.js.map +1 -0
  747. package/dist/core/repo/tree/walk.js +234 -0
  748. package/dist/core/repo/tree/walk.js.map +1 -0
  749. package/dist/core/results.js +99 -2
  750. package/dist/core/results.js.map +1 -1
  751. package/dist/core/scaffold/landscape.js +131 -0
  752. package/dist/core/scaffold/landscape.js.map +1 -0
  753. package/dist/core/scaffold/readme.js +84 -0
  754. package/dist/core/scaffold/readme.js.map +1 -0
  755. package/dist/core/staging/commit.js +241 -0
  756. package/dist/core/staging/commit.js.map +1 -0
  757. package/dist/core/staging/interrupted.js +96 -0
  758. package/dist/core/staging/interrupted.js.map +1 -0
  759. package/dist/core/staging/lock.js +206 -0
  760. package/dist/core/staging/lock.js.map +1 -0
  761. package/dist/core/staging/recovery/finding.js +35 -0
  762. package/dist/core/staging/recovery/finding.js.map +1 -0
  763. package/dist/core/staging/recovery/intent.js +98 -0
  764. package/dist/core/staging/recovery/intent.js.map +1 -0
  765. package/dist/core/staging/recovery/recover.js +126 -0
  766. package/dist/core/staging/recovery/recover.js.map +1 -0
  767. package/dist/core/staging/recovery/residue.js +62 -0
  768. package/dist/core/staging/recovery/residue.js.map +1 -0
  769. package/dist/core/staging/snapshot.js +202 -0
  770. package/dist/core/staging/snapshot.js.map +1 -0
  771. package/dist/core/staging/txn/forward.js +171 -0
  772. package/dist/core/staging/txn/forward.js.map +1 -0
  773. package/dist/core/staging/txn/journal.js +139 -0
  774. package/dist/core/staging/txn/journal.js.map +1 -0
  775. package/dist/core/staging/txn/transaction.js +75 -0
  776. package/dist/core/staging/txn/transaction.js.map +1 -0
  777. package/dist/core/staging/writes.js +113 -0
  778. package/dist/core/staging/writes.js.map +1 -0
  779. package/dist/core/status/actions/execution.js +49 -0
  780. package/dist/core/status/actions/execution.js.map +1 -0
  781. package/dist/core/status/contracts.js +102 -0
  782. package/dist/core/status/contracts.js.map +1 -0
  783. package/dist/core/status/feature/artifacts.js +196 -0
  784. package/dist/core/status/feature/artifacts.js.map +1 -0
  785. package/dist/core/status/feature/feature.js +207 -0
  786. package/dist/core/status/feature/feature.js.map +1 -0
  787. package/dist/core/status/feature/next.js +150 -0
  788. package/dist/core/status/feature/next.js.map +1 -0
  789. package/dist/core/status/feature/state.js +21 -0
  790. package/dist/core/status/feature/state.js.map +1 -0
  791. package/dist/core/status/fleet/fleet.js +197 -0
  792. package/dist/core/status/fleet/fleet.js.map +1 -0
  793. package/dist/core/status/fleet/next.js +207 -0
  794. package/dist/core/status/fleet/next.js.map +1 -0
  795. package/dist/core/status/interrupted.js +97 -0
  796. package/dist/core/status/interrupted.js.map +1 -0
  797. package/dist/core/status/report.js +31 -0
  798. package/dist/core/status/report.js.map +1 -0
  799. package/dist/core/status/scan.js +41 -0
  800. package/dist/core/status/scan.js.map +1 -0
  801. package/dist/core/status/verification.js +201 -0
  802. package/dist/core/status/verification.js.map +1 -0
  803. package/dist/core/usecases/capability.js +169 -0
  804. package/dist/core/usecases/capability.js.map +1 -0
  805. package/dist/core/usecases/delta/claims.js +116 -0
  806. package/dist/core/usecases/delta/claims.js.map +1 -0
  807. package/dist/core/usecases/delta/flows.js +103 -0
  808. package/dist/core/usecases/delta/flows.js.map +1 -0
  809. package/dist/core/usecases/delta/overlay.js +72 -0
  810. package/dist/core/usecases/delta/overlay.js.map +1 -0
  811. package/dist/core/usecases/fleet.js +137 -0
  812. package/dist/core/usecases/fleet.js.map +1 -0
  813. package/dist/core/usecases/operations.js +111 -0
  814. package/dist/core/usecases/operations.js.map +1 -0
  815. package/dist/core/usecases/place.js +44 -0
  816. package/dist/core/usecases/place.js.map +1 -0
  817. package/dist/core/usecases/touch.js +101 -0
  818. package/dist/core/usecases/touch.js.map +1 -0
  819. package/dist/core/verify/answers.js +173 -0
  820. package/dist/core/verify/answers.js.map +1 -0
  821. package/dist/core/verify/build.js +150 -0
  822. package/dist/core/verify/build.js.map +1 -0
  823. package/dist/core/verify/checklist.js +201 -0
  824. package/dist/core/verify/checklist.js.map +1 -0
  825. package/dist/core/verify/claims/identity.js +61 -0
  826. package/dist/core/verify/claims/identity.js.map +1 -0
  827. package/dist/core/verify/cross/diff.js +97 -0
  828. package/dist/core/verify/cross/diff.js.map +1 -0
  829. package/dist/core/verify/evidence/contract.js +169 -0
  830. package/dist/core/verify/evidence/contract.js.map +1 -0
  831. package/dist/core/verify/file.js +257 -0
  832. package/dist/core/verify/file.js.map +1 -0
  833. package/dist/core/verify/pins/lint.js +157 -0
  834. package/dist/core/verify/pins/lint.js.map +1 -0
  835. package/dist/core/verify/pins/pin.js +95 -0
  836. package/dist/core/verify/pins/pin.js.map +1 -0
  837. package/dist/core/verify/record.js +142 -0
  838. package/dist/core/verify/record.js.map +1 -0
  839. package/dist/core/verify/store/commit.js +89 -0
  840. package/dist/core/verify/store/commit.js.map +1 -0
  841. package/dist/core/verify/store/render.js +57 -0
  842. package/dist/core/verify/store/render.js.map +1 -0
  843. package/dist/core/vocabulary/health.js +91 -0
  844. package/dist/core/vocabulary/health.js.map +1 -0
  845. package/dist/core/vocabulary/issue.js +58 -0
  846. package/dist/core/vocabulary/issue.js.map +1 -0
  847. package/dist/core/vocabulary/maturity.js +145 -0
  848. package/dist/core/vocabulary/maturity.js.map +1 -0
  849. package/dist/core/{report.js → vocabulary/report.js} +30 -2
  850. package/dist/core/vocabulary/report.js.map +1 -0
  851. package/dist/core/vocabulary/steps.js +266 -0
  852. package/dist/core/vocabulary/steps.js.map +1 -0
  853. package/dist/core/workspace/discover.js +239 -0
  854. package/dist/core/workspace/discover.js.map +1 -0
  855. package/dist/core/workspace/render.js +52 -0
  856. package/dist/core/workspace/render.js.map +1 -0
  857. package/examples/README.md +189 -0
  858. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  859. package/examples/docs/architecture/capabilities.yaml +31 -0
  860. package/examples/docs/architecture/landscape.likec4 +280 -0
  861. package/examples/docs/architecture/obligations.yaml +23 -0
  862. package/examples/docs/architecture/permissions.yaml +50 -0
  863. package/examples/docs/architecture/subsystems.likec4 +11 -0
  864. package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
  865. package/examples/docs/capabilities/checkout/spec.md +55 -0
  866. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  867. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  868. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  869. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  870. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  871. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  872. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
  873. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  874. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  875. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  876. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  877. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  878. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
  879. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  880. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  881. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  882. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  883. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  884. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  885. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  886. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  887. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  888. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  889. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
  890. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  891. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  892. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  893. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  894. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  895. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  896. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  897. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  898. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  899. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  900. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  901. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  902. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  903. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  904. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  905. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  906. package/examples/docs/glossary/order.md +15 -0
  907. package/examples/docs/glossary/payments/authorization.md +14 -0
  908. package/examples/docs/likec4.config.json +9 -0
  909. package/examples/docs/loam.json +3 -0
  910. package/examples/docs/services/checkout-web/model.likec4 +109 -0
  911. package/examples/docs/services/checkout-web/spec.md +91 -0
  912. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  913. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  914. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  915. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  916. package/examples/docs/services/order-service/arch.spec.md +127 -0
  917. package/examples/docs/services/order-service/asyncapi.yaml +108 -0
  918. package/examples/docs/services/order-service/health.yaml +57 -0
  919. package/examples/docs/services/order-service/model.likec4 +138 -0
  920. package/examples/docs/services/order-service/openapi.yaml +257 -0
  921. package/examples/docs/services/order-service/runbook.md +62 -0
  922. package/examples/docs/services/order-service/spec.md +134 -0
  923. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  924. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  925. package/examples/docs/services/payment-service/arch.spec.md +73 -0
  926. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  927. package/examples/docs/services/payment-service/health.yaml +39 -0
  928. package/examples/docs/services/payment-service/model.likec4 +67 -0
  929. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  930. package/examples/docs/services/payment-service/runbook.md +37 -0
  931. package/examples/docs/services/payment-service/spec.md +88 -0
  932. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  933. package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
  934. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  935. package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
  936. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  937. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  938. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  939. package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
  940. package/examples/docs/services/platform/notification-service/health.yaml +35 -0
  941. package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
  942. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  943. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  944. package/examples/docs/services/platform/subsystem.yaml +2 -0
  945. package/examples/fleet.yaml +57 -0
  946. package/package.json +19 -6
  947. package/dist/commands/adopt.js +0 -240
  948. package/dist/commands/adopt.js.map +0 -1
  949. package/dist/commands/archive.js +0 -1313
  950. package/dist/commands/archive.js.map +0 -1
  951. package/dist/commands/delta.js +0 -388
  952. package/dist/commands/delta.js.map +0 -1
  953. package/dist/commands/docs-repo-gate.js.map +0 -1
  954. package/dist/commands/format.js +0 -17
  955. package/dist/commands/format.js.map +0 -1
  956. package/dist/commands/gherkin.js +0 -309
  957. package/dist/commands/gherkin.js.map +0 -1
  958. package/dist/commands/init.js.map +0 -1
  959. package/dist/commands/list.js +0 -295
  960. package/dist/commands/list.js.map +0 -1
  961. package/dist/commands/migrate-openspec.js +0 -950
  962. package/dist/commands/migrate-openspec.js.map +0 -1
  963. package/dist/commands/new.js +0 -413
  964. package/dist/commands/new.js.map +0 -1
  965. package/dist/commands/rebase.js +0 -356
  966. package/dist/commands/rebase.js.map +0 -1
  967. package/dist/commands/show.js.map +0 -1
  968. package/dist/commands/status.js +0 -262
  969. package/dist/commands/status.js.map +0 -1
  970. package/dist/commands/unarchive.js.map +0 -1
  971. package/dist/commands/validate.js +0 -1773
  972. package/dist/commands/validate.js.map +0 -1
  973. package/dist/commands/verify.js +0 -775
  974. package/dist/commands/verify.js.map +0 -1
  975. package/dist/commands/vouch.js +0 -421
  976. package/dist/commands/vouch.js.map +0 -1
  977. package/dist/core/agent.js +0 -2173
  978. package/dist/core/agent.js.map +0 -1
  979. package/dist/core/agents-stamp.js.map +0 -1
  980. package/dist/core/arch.js +0 -130
  981. package/dist/core/arch.js.map +0 -1
  982. package/dist/core/asyncapi.js.map +0 -1
  983. package/dist/core/brief.js +0 -755
  984. package/dist/core/brief.js.map +0 -1
  985. package/dist/core/coherence.js +0 -577
  986. package/dist/core/coherence.js.map +0 -1
  987. package/dist/core/concurrency.js.map +0 -1
  988. package/dist/core/config.js.map +0 -1
  989. package/dist/core/delta.js +0 -476
  990. package/dist/core/delta.js.map +0 -1
  991. package/dist/core/dependencies.js +0 -356
  992. package/dist/core/dependencies.js.map +0 -1
  993. package/dist/core/doctor.js +0 -596
  994. package/dist/core/doctor.js.map +0 -1
  995. package/dist/core/document-bytes.js.map +0 -1
  996. package/dist/core/explore.js.map +0 -1
  997. package/dist/core/frontmatter.js.map +0 -1
  998. package/dist/core/gherkin.js +0 -463
  999. package/dist/core/gherkin.js.map +0 -1
  1000. package/dist/core/health.js +0 -67
  1001. package/dist/core/health.js.map +0 -1
  1002. package/dist/core/ids.js +0 -122
  1003. package/dist/core/ids.js.map +0 -1
  1004. package/dist/core/issue.js +0 -9
  1005. package/dist/core/issue.js.map +0 -1
  1006. package/dist/core/json.js +0 -74
  1007. package/dist/core/json.js.map +0 -1
  1008. package/dist/core/likec4.js +0 -489
  1009. package/dist/core/likec4.js.map +0 -1
  1010. package/dist/core/maturity.js +0 -66
  1011. package/dist/core/maturity.js.map +0 -1
  1012. package/dist/core/openapi-merge.js +0 -552
  1013. package/dist/core/openapi-merge.js.map +0 -1
  1014. package/dist/core/openapi.js.map +0 -1
  1015. package/dist/core/openspec-inventory.js +0 -1440
  1016. package/dist/core/openspec-inventory.js.map +0 -1
  1017. package/dist/core/path-safety.js.map +0 -1
  1018. package/dist/core/provenance.js +0 -787
  1019. package/dist/core/provenance.js.map +0 -1
  1020. package/dist/core/records.js.map +0 -1
  1021. package/dist/core/repo.js +0 -438
  1022. package/dist/core/repo.js.map +0 -1
  1023. package/dist/core/report.js.map +0 -1
  1024. package/dist/core/spec.js +0 -505
  1025. package/dist/core/spec.js.map +0 -1
  1026. package/dist/core/staging.js +0 -890
  1027. package/dist/core/staging.js.map +0 -1
  1028. package/dist/core/status.js +0 -1132
  1029. package/dist/core/status.js.map +0 -1
  1030. package/dist/core/steps.js +0 -72
  1031. package/dist/core/steps.js.map +0 -1
  1032. package/dist/core/verify.js +0 -807
  1033. package/dist/core/verify.js.map +0 -1
  1034. package/dist/core/version.js.map +0 -1
  1035. /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
  1036. /package/dist/core/{records.js → kernel/records.js} +0 -0
@@ -0,0 +1,222 @@
1
+ import { splitRealizesEntry } from "../realizes/join.js";
2
+ import { tagSlug } from "../usecase-join.js";
3
+ /**
4
+ * The `(capability, requirement)` pair, keyed for a Set.
5
+ *
6
+ * NUL — the separator `core/delta/scope.ts`'s claim key already uses — rather
7
+ * than `#`, because a key's separator must be one its halves cannot contain and
8
+ * a capability id is a YAML key and a directory name, constrained nowhere.
9
+ * Re-joining with `#` would make `a#b` + `C` and `a` + `b#C` one key, and the
10
+ * second is unreachable only because the requirement grammar happens to exclude
11
+ * `#` today.
12
+ */
13
+ function pairKey(capability, requirement) {
14
+ return `${capability}\0${requirement}`;
15
+ }
16
+ /**
17
+ * The pairs one requirement's `Realizes:` lines name.
18
+ *
19
+ * Through `splitRealizesEntry`, never a local split, and the LAST `#` is what
20
+ * makes it right: the requirement half has a grammar that excludes `#` and the
21
+ * capability half has none, so a first-`#` split mis-parses every id containing
22
+ * one — silently, which is the failure this axis exists to refuse.
23
+ */
24
+ function realizedPairs(r) {
25
+ return r.realizes.flatMap((entry) => {
26
+ const target = splitRealizesEntry(entry);
27
+ return target === null ? [] : [pairKey(target.capability, target.requirement)];
28
+ });
29
+ }
30
+ /** How a service document is named in a message — the axis only where it is not the default one. */
31
+ function docLabel(doc) {
32
+ return doc.file === "spec.md" ? doc.service : `${doc.service} (${doc.file})`;
33
+ }
34
+ /**
35
+ * `capability.uncovered` — a capability requirement this feature ADDS that no
36
+ * `Realizes:` line in the same feature's service deltas names.
37
+ *
38
+ * ADDED ONLY. A MODIFIED changes a promise the living fleet may already
39
+ * realize, so demanding a re-declaration would force an edit with nothing to
40
+ * change — the same exemption `c4.uncovered` takes one axis over. A requirement
41
+ * with no `Requirement-ID:` is SKIPPED rather than reported: it is already
42
+ * `capability.requirement-unidentified`, and there is nothing for a `Realizes:`
43
+ * line to address, so two findings for one mistake is the failure to avoid.
44
+ *
45
+ * The covering side is ADDED or MODIFIED, never BASE and never REMOVED. A BASE
46
+ * requirement in a delta quotes living context and the merge never writes it,
47
+ * so a `Realizes:` line there lands nowhere; a REMOVED one is on its way out and
48
+ * cannot keep a promise after it is gone.
49
+ *
50
+ * Feature scope, deliberately. The fleet-scope version already ships as
51
+ * `capability.requirement-unrealized`, and grading a feature-ADDED requirement
52
+ * against the LIVING fleet is vacuous — no living `Realizes:` can name it
53
+ * without being `capability.realizes-unknown` today.
54
+ */
55
+ export function uncoveredIssues(capabilities, services,
56
+ // REQUIRED, with no default. A default would have to be one of the two arms,
57
+ // and either choice is wrong for a caller that forgot: `graded: true` with an
58
+ // empty list makes the message assert a negative, and `graded: false` makes it
59
+ // quietly stop checking a corpus the caller does have. The compiler asking is
60
+ // cheaper than either.
61
+ flows) {
62
+ if (capabilities.length === 0)
63
+ return [];
64
+ const kept = new Set();
65
+ for (const doc of services) {
66
+ for (const r of doc.reqs) {
67
+ if (r.kind !== "ADDED" && r.kind !== "MODIFIED")
68
+ continue;
69
+ for (const pair of realizedPairs(r))
70
+ kept.add(pair);
71
+ }
72
+ }
73
+ // The other carrier, through the SAME `pairKey` as the `Realizes:` side: two
74
+ // corpora answering one question must not be able to disagree about which
75
+ // promise a claim addresses. The caller resolved these; a claim whose tags did
76
+ // not both resolve never reaches here, which is what stops a typo from
77
+ // silencing the gate.
78
+ if (flows.graded)
79
+ for (const flow of flows.kept)
80
+ kept.add(pairKey(flow.capability, flow.requirement));
81
+ // What the message may CLAIM about the flow half. Ungraded, it claims nothing
82
+ // and says so — the `Realizes:` half was still checked and is still worth
83
+ // gating on, so the finding stands; what must not stand is a sentence
84
+ // convicting a flow nobody resolved.
85
+ const flowClause = flows.graded
86
+ ? "and no `dynamic view` under this feature's usecases/ resolves a `#req-` tag to it. "
87
+ : `and the flow half of the join was NOT checked — ${flows.why}, so a \`#req-\` claim could not be resolved either way. `;
88
+ const issues = [];
89
+ for (const doc of capabilities) {
90
+ for (const r of doc.reqs) {
91
+ if (r.kind !== "ADDED" || r.id === undefined)
92
+ continue;
93
+ if (kept.has(pairKey(doc.id, r.id)))
94
+ continue;
95
+ const entry = `${doc.id}#${r.id}`;
96
+ issues.push({
97
+ severity: "warn",
98
+ gates: true,
99
+ code: "capability.uncovered",
100
+ subject: doc.id,
101
+ message: `capability ${doc.id}: ADDED requirement '${r.name}' (${r.id}) is realized by nothing this feature changes — ` +
102
+ `no ADDED or MODIFIED requirement in its specs/ deltas carries \`Realizes: ${entry}\`, ` +
103
+ flowClause +
104
+ "The document is legal; the MERGE is what is unsafe: once it lands, the only thing that will ever mention " +
105
+ "this promise again is a fleet-scope warning (capability.requirement-unrealized) nobody reads. " +
106
+ `Three ways on: add \`Realizes: ${entry}\` to the service requirement that carries part of it; ` +
107
+ `if the promise CROSSES services, write the flow that keeps it as features/<FEAT>/usecases/<name>.likec4 and ` +
108
+ `tag its \`dynamic view\` \`#cap-${tagSlug(doc.id)}\` and \`#req-${tagSlug(r.id)}\` — the archive merges it into ` +
109
+ "architecture/usecases/ with everything else this feature lands; or archive with --approve to land the promise " +
110
+ "ahead of the fleet and let capability.requirement-unrealized carry it.",
111
+ });
112
+ }
113
+ }
114
+ return issues;
115
+ }
116
+ /** The living requirements a delta document supersedes — MODIFIED and REMOVED both restate or delete. */
117
+ function supersedes(delta, living) {
118
+ if (delta === undefined)
119
+ return false;
120
+ return delta.reqs.some((r) => {
121
+ if (r.kind !== "MODIFIED" && r.kind !== "REMOVED")
122
+ return false;
123
+ return r.id === undefined ? r.name === living.name : r.id === living.id;
124
+ });
125
+ }
126
+ /**
127
+ * `capability.remove-requirement-realized` — this feature retires a capability
128
+ * requirement that something the merge LEAVES BEHIND still realizes.
129
+ *
130
+ * The hole the forward direction does not close, and the one this whole module
131
+ * exists to make impossible: a feature that REMOVES a capability requirement a
132
+ * living service requirement realizes used to archive at exit 0, and the next
133
+ * `loam validate --all` then failed with `capability.realizes-unknown` against a
134
+ * service document nobody had touched. An archive that leaves the fleet red
135
+ * against an untouched document is the exact class of silent damage the product
136
+ * exists to refuse.
137
+ *
138
+ * GRADED AGAINST THE POST-MERGE FLEET, which is the only reading under which
139
+ * the two escape hatches fall out instead of being special-cased. A living
140
+ * requirement that this feature's own delta MODIFIES or REMOVES is gone as
141
+ * written — a MODIFIED carries its FULL new text, so restating the requirement
142
+ * without its `Realizes:` line IS how an author drops the join — and the delta's
143
+ * own ADDED/MODIFIED requirements are what stands in its place. So: retire the
144
+ * realizer in the same change and there is no breach; keep the line and there
145
+ * is.
146
+ *
147
+ * A `#req-` tagged flow realizing the promise is NOT consulted, and that is the
148
+ * other subject rather than a gap: the tag names the requirement directly, so a
149
+ * removal turns it into `usecase.requirement-unresolved` on the living view —
150
+ * loud, in the document that has to change, and nothing here would make it
151
+ * louder.
152
+ *
153
+ * A REMOVED spelled by heading resolves through the living document, so it
154
+ * grades exactly what the merge would delete. One that selects nothing is
155
+ * already `delta.removed-unknown` and retires nothing, so it is skipped here —
156
+ * two findings for one mistake, again.
157
+ */
158
+ export async function removedRealizedIssues(join) {
159
+ const retired = new Map();
160
+ for (const doc of join.capabilities) {
161
+ for (const r of doc.reqs) {
162
+ if (r.kind !== "REMOVED")
163
+ continue;
164
+ const selected = doc.living.filter((l) => (r.id === undefined ? l.name === r.name : l.id === r.id));
165
+ for (const l of selected) {
166
+ if (l.id === undefined)
167
+ continue;
168
+ retired.set(pairKey(doc.id, l.id), { capability: doc.id, id: l.id, name: l.name });
169
+ }
170
+ }
171
+ }
172
+ if (retired.size === 0)
173
+ return [];
174
+ // Who still realizes each retired pair after the merge: the living
175
+ // requirements this feature does not supersede, plus the requirements its own
176
+ // deltas add or restate.
177
+ const realizers = new Map();
178
+ const record = (pair, who) => {
179
+ if (!retired.has(pair))
180
+ return;
181
+ const found = realizers.get(pair) ?? [];
182
+ found.push(who);
183
+ realizers.set(pair, found);
184
+ };
185
+ for (const doc of await join.living()) {
186
+ const delta = join.deltas.find((d) => d.service === doc.service && d.file === doc.file);
187
+ for (const r of doc.reqs) {
188
+ if (supersedes(delta, r))
189
+ continue;
190
+ for (const pair of realizedPairs(r))
191
+ record(pair, `${docLabel(doc)}'s living requirement '${r.name}'`);
192
+ }
193
+ }
194
+ for (const doc of join.deltas) {
195
+ for (const r of doc.reqs) {
196
+ if (r.kind !== "ADDED" && r.kind !== "MODIFIED")
197
+ continue;
198
+ for (const pair of realizedPairs(r))
199
+ record(pair, `this feature's ${docLabel(doc)} delta requirement '${r.name}'`);
200
+ }
201
+ }
202
+ const issues = [];
203
+ for (const [pair, promise] of retired) {
204
+ const who = realizers.get(pair);
205
+ if (who === undefined)
206
+ continue;
207
+ const entry = `${promise.capability}#${promise.id}`;
208
+ issues.push({
209
+ severity: "error",
210
+ code: "capability.remove-requirement-realized",
211
+ subject: promise.capability,
212
+ message: `capability ${promise.capability}: this feature REMOVES '${promise.name}' (${promise.id}), but ${who.join("; ")} ` +
213
+ `still carries \`Realizes: ${entry}\`. After the merge that line points at a promise no document declares, and ` +
214
+ "the very next `loam validate --all` reports capability.realizes-unknown against whatever carries it — for a " +
215
+ "LIVING realizer, a service document this feature never touched. Retire the realizing requirement in the same " +
216
+ "feature, or drop its `Realizes:` line (a MODIFIED does that by restating the requirement without it), or " +
217
+ "archive with --approve to break the join deliberately.",
218
+ });
219
+ }
220
+ return issues;
221
+ }
222
+ //# sourceMappingURL=uncovered.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uncovered.js","sourceRoot":"","sources":["../../../../src/core/capabilities/delta/uncovered.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The `Realizes:` join taken INSIDE ONE FEATURE, in both directions: a promise\n * this feature makes that nothing in it keeps, and a promise it retires that\n * something outside it still keeps.\n *\n * `../realizes/findings.ts` grades the same join at the two places it can be\n * WRONG — an entry that resolves to nothing, a living requirement nothing\n * realizes. This module grades it at the one place it can silently COME APART:\n * the merge. Both directions are about a change, both are answered from\n * documents the archive gate already has parsed, and neither has any meaning\n * outside a feature — which is why they live together here and not beside their\n * fleet-scope siblings.\n *\n * TWO CODES, NOT ONE, and the decision is worth the paragraph because the shape\n * invites the opposite:\n *\n * - The FIXES are different. `capability.uncovered` is fixed by writing the\n * `Realizes:` line the promise is missing; `capability.remove-requirement-realized`\n * is fixed by retiring the requirement that carries the line, or by dropping\n * the line from it. A code is what a machine branches on and the branch is\n * the fix, so a single code covering both would be a code neither caller can\n * act on.\n * - The SEVERITIES are different, and they are different for the reason\n * `../../vocabulary/issue.ts` draws the distinction at all. `capability.uncovered`\n * is a warning that GATES: the document is legal — writing a business promise\n * ahead of the fleet is the recorded intended use, which is exactly why\n * `capability.requirement-unrealized` warns and never gates — while the MERGE\n * is what is unsafe, because once it lands the only thing that will ever\n * mention the promise again is a fleet-scope warning nobody reads. The\n * removal direction has no such legal reading: after that merge a LIVING\n * service document nobody in the feature touched carries a pointer at\n * nothing, and `capability.realizes-unknown` is already an ERROR there. So it\n * is an error here, exactly as `openapi.remove-op-consumed` is one axis over\n * for the identical shape — this feature retires a thing the living fleet\n * still uses. One code carrying two severities is a code that says nothing.\n * - The family already spells every direction of every join as its own code:\n * `capability.unknown` / `capability.realizes-unknown` name the entry that\n * resolves to nothing, `capability.unrealized` /\n * `capability.requirement-unrealized` name the promise nobody keeps. A pair\n * here is the shape a reader of that list already expects.\n *\n * A `#req-` TAGGED FLOW COUNTS AS COVER, and the reason it did not is worth\n * recording because it was a consequence rather than a policy. A `dynamic view`\n * used to be a fleet document with no feature-delta path, so a `#req-` tag\n * naming a capability requirement that was not living yet was ALREADY\n * `usecase.requirement-unresolved` — an error on `validate --all` — for the\n * whole window before the archive. At the moment this ran, a legal flow claim on\n * a newly-ADDED requirement could not exist, and the message said so: archive\n * with `--approve` first, tag the flow afterwards. That advice lands a promise\n * kept by nothing and relies on somebody coming back.\n *\n * `features/<FEAT>/usecases/` closed that (`core/usecases/delta/flows.ts`), so\n * the claim can now be legal at the moment it is graded, and the third arm of\n * `flows` below is it. What has NOT changed is which claims count: both tags\n * must resolve, against the vocabulary and requirement index this feature's own\n * merge would leave behind. A broken tag of either kind is an error in its own\n * right and must never also mark a promise kept — a typo that silenced this gate\n * would turn a mistake into a green archive.\n *\n * NO FILESYSTEM, deliberately, exactly as `../realizes/join.ts` has none — and\n * that is why the flows arrive as resolved pairs rather than as a docsDir. The\n * living side of the removal direction arrives as a thunk the caller supplies,\n * so the fleet-wide read happens only when this feature retires something, and\n * this module stays testable without a tree.\n */\nimport type { Requirement } from \"../../document/spec.js\";\nimport type { Issue } from \"../../vocabulary/issue.js\";\nimport { splitRealizesEntry } from \"../realizes/join.js\";\nimport { tagSlug } from \"../usecase-join.js\";\n\n/**\n * One requirements document on the SERVICE side of the join, and the two facts\n * that address it: whose it is, and which axis. Both halves of the key are\n * needed because a feature's delta of `payment-service`'s `arch.spec.md`\n * supersedes the living `arch.spec.md` and says nothing at all about the living\n * `spec.md` beside it.\n */\nexport interface RealizingDoc {\n /** The service id. */\n service: string;\n /** The axis's filename — `spec.md` or `arch.spec.md`, as `SPEC_AXES` spells it. */\n file: string;\n reqs: readonly Requirement[];\n}\n\n/**\n * One capability document a feature's delta changes, with the living text that\n * delta applies to.\n *\n * `living` is here rather than derived because a REMOVED requirement is exempt\n * from `capability.requirement-unidentified` and so may be spelled by heading\n * alone — the id it retires is then a fact about the LIVING document, and\n * without it the removal direction would silently grade nothing for the\n * commonest way a removal is written. Requirements rather than the delta\n * package's `LivingIndex`: `core/delta` imports this package, so importing it\n * back would be a package cycle the file-level cycle check cannot see.\n */\nexport interface CapabilityDeltaDoc {\n /** The capability id — the directory chain under `features/<FEAT>/capabilities/`. */\n id: string;\n reqs: readonly Requirement[];\n /** The LIVING `capabilities/<id>/spec.md` requirements, or `[]` when this feature creates it. */\n living: readonly Requirement[];\n}\n\n/**\n * The `(capability, requirement)` pair, keyed for a Set.\n *\n * NUL — the separator `core/delta/scope.ts`'s claim key already uses — rather\n * than `#`, because a key's separator must be one its halves cannot contain and\n * a capability id is a YAML key and a directory name, constrained nowhere.\n * Re-joining with `#` would make `a#b` + `C` and `a` + `b#C` one key, and the\n * second is unreachable only because the requirement grammar happens to exclude\n * `#` today.\n */\nfunction pairKey(capability: string, requirement: string): string {\n return `${capability}\\0${requirement}`;\n}\n\n/**\n * The pairs one requirement's `Realizes:` lines name.\n *\n * Through `splitRealizesEntry`, never a local split, and the LAST `#` is what\n * makes it right: the requirement half has a grammar that excludes `#` and the\n * capability half has none, so a first-`#` split mis-parses every id containing\n * one — silently, which is the failure this axis exists to refuse.\n */\nfunction realizedPairs(r: Requirement): string[] {\n return r.realizes.flatMap((entry) => {\n const target = splitRealizesEntry(entry);\n return target === null ? [] : [pairKey(target.capability, target.requirement)];\n });\n}\n\n/** How a service document is named in a message — the axis only where it is not the default one. */\nfunction docLabel(doc: RealizingDoc): string {\n return doc.file === \"spec.md\" ? doc.service : `${doc.service} (${doc.file})`;\n}\n\n/**\n * One promise a `#req-` tagged flow in the SAME feature keeps.\n *\n * Structurally typed rather than imported from `core/usecases/delta/claims.ts`,\n * where the caller builds it, and the reason is the package graph rather than\n * taste: `core/usecases/` already imports this package, so importing it back\n * would be a cycle that `import/no-cycle` cannot see — the acyclicity obligation\n * `scripts/package-graph.mjs` exists to hold. The shape is three fields; the\n * RULE that produced them (both tags resolved, or the claim does not count) is\n * that module's, and this one grades what it is handed.\n */\nexport interface KeptByFlow {\n capability: string;\n requirement: string;\n /** The view ids keeping it. Carried for a caller's report; nothing here reads it. */\n flows: readonly string[];\n}\n\n/**\n * The flow corpus, or the honest statement that there was not one to read.\n *\n * A TRI-STATE and not a possibly-empty list, because the message says what was\n * checked and an empty list would make it say something loam never looked at.\n * \"No flow keeps this\" and \"the flows were not graded\" are different sentences\n * and only one of them is an accusation — the standing rule this axis states\n * everywhere else, applied to the message rather than to a severity.\n *\n * `why` is printed, so it names the cause an author can act on: an\n * `architecture/` that did not parse is one thing, a `capabilities.yaml` that\n * does not read as a vocabulary is another, and inside a feature gate NOTHING\n * ELSE reports the second — `core/coherence/declared.ts` keeps\n * `capability.invalid` for `validate --all`. Without the sentence the run\n * refuses, names the wrong cause, and points at nothing.\n */\nexport type FlowCorpus =\n | { graded: true; kept: readonly KeptByFlow[] }\n | { graded: false; why: string };\n\n/**\n * `capability.uncovered` — a capability requirement this feature ADDS that no\n * `Realizes:` line in the same feature's service deltas names.\n *\n * ADDED ONLY. A MODIFIED changes a promise the living fleet may already\n * realize, so demanding a re-declaration would force an edit with nothing to\n * change — the same exemption `c4.uncovered` takes one axis over. A requirement\n * with no `Requirement-ID:` is SKIPPED rather than reported: it is already\n * `capability.requirement-unidentified`, and there is nothing for a `Realizes:`\n * line to address, so two findings for one mistake is the failure to avoid.\n *\n * The covering side is ADDED or MODIFIED, never BASE and never REMOVED. A BASE\n * requirement in a delta quotes living context and the merge never writes it,\n * so a `Realizes:` line there lands nowhere; a REMOVED one is on its way out and\n * cannot keep a promise after it is gone.\n *\n * Feature scope, deliberately. The fleet-scope version already ships as\n * `capability.requirement-unrealized`, and grading a feature-ADDED requirement\n * against the LIVING fleet is vacuous — no living `Realizes:` can name it\n * without being `capability.realizes-unknown` today.\n */\nexport function uncoveredIssues(\n capabilities: readonly CapabilityDeltaDoc[],\n services: readonly RealizingDoc[],\n // REQUIRED, with no default. A default would have to be one of the two arms,\n // and either choice is wrong for a caller that forgot: `graded: true` with an\n // empty list makes the message assert a negative, and `graded: false` makes it\n // quietly stop checking a corpus the caller does have. The compiler asking is\n // cheaper than either.\n flows: FlowCorpus,\n): Issue[] {\n if (capabilities.length === 0) return [];\n const kept = new Set<string>();\n for (const doc of services) {\n for (const r of doc.reqs) {\n if (r.kind !== \"ADDED\" && r.kind !== \"MODIFIED\") continue;\n for (const pair of realizedPairs(r)) kept.add(pair);\n }\n }\n // The other carrier, through the SAME `pairKey` as the `Realizes:` side: two\n // corpora answering one question must not be able to disagree about which\n // promise a claim addresses. The caller resolved these; a claim whose tags did\n // not both resolve never reaches here, which is what stops a typo from\n // silencing the gate.\n if (flows.graded) for (const flow of flows.kept) kept.add(pairKey(flow.capability, flow.requirement));\n // What the message may CLAIM about the flow half. Ungraded, it claims nothing\n // and says so — the `Realizes:` half was still checked and is still worth\n // gating on, so the finding stands; what must not stand is a sentence\n // convicting a flow nobody resolved.\n const flowClause = flows.graded\n ? \"and no `dynamic view` under this feature's usecases/ resolves a `#req-` tag to it. \"\n : `and the flow half of the join was NOT checked — ${flows.why}, so a \\`#req-\\` claim could not be resolved either way. `;\n const issues: Issue[] = [];\n for (const doc of capabilities) {\n for (const r of doc.reqs) {\n if (r.kind !== \"ADDED\" || r.id === undefined) continue;\n if (kept.has(pairKey(doc.id, r.id))) continue;\n const entry = `${doc.id}#${r.id}`;\n issues.push({\n severity: \"warn\",\n gates: true,\n code: \"capability.uncovered\",\n subject: doc.id,\n message:\n `capability ${doc.id}: ADDED requirement '${r.name}' (${r.id}) is realized by nothing this feature changes — ` +\n `no ADDED or MODIFIED requirement in its specs/ deltas carries \\`Realizes: ${entry}\\`, ` +\n flowClause +\n \"The document is legal; the MERGE is what is unsafe: once it lands, the only thing that will ever mention \" +\n \"this promise again is a fleet-scope warning (capability.requirement-unrealized) nobody reads. \" +\n `Three ways on: add \\`Realizes: ${entry}\\` to the service requirement that carries part of it; ` +\n `if the promise CROSSES services, write the flow that keeps it as features/<FEAT>/usecases/<name>.likec4 and ` +\n `tag its \\`dynamic view\\` \\`#cap-${tagSlug(doc.id)}\\` and \\`#req-${tagSlug(r.id)}\\` — the archive merges it into ` +\n \"architecture/usecases/ with everything else this feature lands; or archive with --approve to land the promise \" +\n \"ahead of the fleet and let capability.requirement-unrealized carry it.\",\n });\n }\n }\n return issues;\n}\n\n/** Everything the removal direction needs, and nothing it would have to read twice. */\nexport interface RemovalJoin {\n /** This feature's capability deltas, each with the living document it applies to. */\n capabilities: readonly CapabilityDeltaDoc[];\n /** This feature's own service delta documents, already parsed by the same walk. */\n deltas: readonly RealizingDoc[];\n /**\n * Every LIVING service requirements document in the fleet. A thunk, called at\n * most once and only when this feature actually retires a capability\n * requirement — the overwhelming majority of features retire none, and this\n * read is the whole fleet's `spec.md` and `arch.spec.md`.\n */\n living: () => Promise<readonly RealizingDoc[]>;\n}\n\n/** The living requirements a delta document supersedes — MODIFIED and REMOVED both restate or delete. */\nfunction supersedes(delta: RealizingDoc | undefined, living: Requirement): boolean {\n if (delta === undefined) return false;\n return delta.reqs.some((r) => {\n if (r.kind !== \"MODIFIED\" && r.kind !== \"REMOVED\") return false;\n return r.id === undefined ? r.name === living.name : r.id === living.id;\n });\n}\n\n/**\n * `capability.remove-requirement-realized` — this feature retires a capability\n * requirement that something the merge LEAVES BEHIND still realizes.\n *\n * The hole the forward direction does not close, and the one this whole module\n * exists to make impossible: a feature that REMOVES a capability requirement a\n * living service requirement realizes used to archive at exit 0, and the next\n * `loam validate --all` then failed with `capability.realizes-unknown` against a\n * service document nobody had touched. An archive that leaves the fleet red\n * against an untouched document is the exact class of silent damage the product\n * exists to refuse.\n *\n * GRADED AGAINST THE POST-MERGE FLEET, which is the only reading under which\n * the two escape hatches fall out instead of being special-cased. A living\n * requirement that this feature's own delta MODIFIES or REMOVES is gone as\n * written — a MODIFIED carries its FULL new text, so restating the requirement\n * without its `Realizes:` line IS how an author drops the join — and the delta's\n * own ADDED/MODIFIED requirements are what stands in its place. So: retire the\n * realizer in the same change and there is no breach; keep the line and there\n * is.\n *\n * A `#req-` tagged flow realizing the promise is NOT consulted, and that is the\n * other subject rather than a gap: the tag names the requirement directly, so a\n * removal turns it into `usecase.requirement-unresolved` on the living view —\n * loud, in the document that has to change, and nothing here would make it\n * louder.\n *\n * A REMOVED spelled by heading resolves through the living document, so it\n * grades exactly what the merge would delete. One that selects nothing is\n * already `delta.removed-unknown` and retires nothing, so it is skipped here —\n * two findings for one mistake, again.\n */\nexport async function removedRealizedIssues(join: RemovalJoin): Promise<Issue[]> {\n const retired = new Map<string, { capability: string; id: string; name: string }>();\n for (const doc of join.capabilities) {\n for (const r of doc.reqs) {\n if (r.kind !== \"REMOVED\") continue;\n const selected = doc.living.filter((l) => (r.id === undefined ? l.name === r.name : l.id === r.id));\n for (const l of selected) {\n if (l.id === undefined) continue;\n retired.set(pairKey(doc.id, l.id), { capability: doc.id, id: l.id, name: l.name });\n }\n }\n }\n if (retired.size === 0) return [];\n\n // Who still realizes each retired pair after the merge: the living\n // requirements this feature does not supersede, plus the requirements its own\n // deltas add or restate.\n const realizers = new Map<string, string[]>();\n const record = (pair: string, who: string): void => {\n if (!retired.has(pair)) return;\n const found = realizers.get(pair) ?? [];\n found.push(who);\n realizers.set(pair, found);\n };\n for (const doc of await join.living()) {\n const delta = join.deltas.find((d) => d.service === doc.service && d.file === doc.file);\n for (const r of doc.reqs) {\n if (supersedes(delta, r)) continue;\n for (const pair of realizedPairs(r)) record(pair, `${docLabel(doc)}'s living requirement '${r.name}'`);\n }\n }\n for (const doc of join.deltas) {\n for (const r of doc.reqs) {\n if (r.kind !== \"ADDED\" && r.kind !== \"MODIFIED\") continue;\n for (const pair of realizedPairs(r)) record(pair, `this feature's ${docLabel(doc)} delta requirement '${r.name}'`);\n }\n }\n\n const issues: Issue[] = [];\n for (const [pair, promise] of retired) {\n const who = realizers.get(pair);\n if (who === undefined) continue;\n const entry = `${promise.capability}#${promise.id}`;\n issues.push({\n severity: \"error\",\n code: \"capability.remove-requirement-realized\",\n subject: promise.capability,\n message:\n `capability ${promise.capability}: this feature REMOVES '${promise.name}' (${promise.id}), but ${who.join(\"; \")} ` +\n `still carries \\`Realizes: ${entry}\\`. After the merge that line points at a promise no document declares, and ` +\n \"the very next `loam validate --all` reports capability.realizes-unknown against whatever carries it — for a \" +\n \"LIVING realizer, a service document this feature never touched. Retire the realizing requirement in the same \" +\n \"feature, or drop its `Realizes:` line (a MODIFIED does that by restating the requirement without it), or \" +\n \"archive with --approve to break the join deliberately.\",\n });\n }\n return issues;\n}\n"]}
@@ -0,0 +1,342 @@
1
+ /**
2
+ * The capability grades, in every direction the axis is graded: a `Capability:`
3
+ * entry the vocabulary does not declare, a vocabulary nobody can read, a
4
+ * declared capability no living requirement realizes, a directory that declares
5
+ * nothing, and the two rules an authored capability document itself must keep.
6
+ * Values only — core never prints — and the join rule shaped twice (Finding for
7
+ * validate, Issue for coherence), both spelled with literal codes so
8
+ * test/codes-drift.test.ts can collect them.
9
+ *
10
+ * The opt-in rule lives here, and it deliberately DIVERGES from `Requires:`.
11
+ * There the LINE is the opt-in: a `Requires:` entry against a missing
12
+ * permissions.yaml errors, because an authorization join that resolves against
13
+ * nothing is the failure that axis exists to prevent. Here the FLEET'S OWN
14
+ * FILES are the opt-in — `architecture/capabilities.yaml`, the `capabilities/`
15
+ * tree, or both — so a fleet holding neither stays finding-free however many
16
+ * `Capability:` lines its requirements already carry. (The roadmap's exit
17
+ * criterion was written when the YAML was the only side and says 'a fleet with
18
+ * no architecture/capabilities.yaml produces no capability findings at all';
19
+ * the authored tree is the second way to opt in, and `CapabilityVocabulary.present`
20
+ * is where the two are combined.) An INVALID vocabulary is also silence for the
21
+ * per-entry grades — `capability.invalid` is the honest finding there, and
22
+ * grading a hundred entries against a file nobody can read is the cascade that
23
+ * suppression exists to stop.
24
+ */
25
+ import { closeIds } from "../c4/arch.js";
26
+ import { compareIds } from "../repo/entries.js";
27
+ import { requirementDigest } from "../document/spec.js";
28
+ /**
29
+ * THE LADDER, and the only place it is applied: the declared capability ids when
30
+ * the vocabulary can be graded against at all, `null` when it cannot.
31
+ *
32
+ * Exported because the suppression is not this module's private business — the
33
+ * use-case axis asks the same question about the same file
34
+ * (`commands/validate/fleet/landscape.ts` hands the answer to
35
+ * `usecases/capability-tag.ts`), and a hand-rolled
36
+ * `present && invalid === undefined ? [...byId.keys()] : null` at each site is
37
+ * three copies of one rule. The failure that costs is not hypothetical: the next
38
+ * un-gradable state added to `CapabilityVocabulary` — "present but partially
39
+ * readable" is the obvious one, since `readCapabilities` already treats a
40
+ * non-mapping declaration body as `{}` — gets fixed wherever the greps land, and
41
+ * any copy left behind answers with the whole key set. A half-read vocabulary
42
+ * then reads as a complete one, and every `#cap-` tag whose capability lived in
43
+ * the unreadable half becomes one `usecase.capability-unresolved` ERROR per
44
+ * view: the cascade this ladder exists to prevent, arriving through the ladder.
45
+ *
46
+ * `null` rather than `[]`, and the two are never interchangeable: an empty list
47
+ * is the real verdict "this fleet declares no capabilities" and every entry
48
+ * fails against it, while `null` says there is nothing to grade against and
49
+ * suspends the family. Callers that only need the boolean read `=== null`.
50
+ */
51
+ export function gradableCapabilityIds(vocab) {
52
+ if (!vocab.present || vocab.invalid !== undefined)
53
+ return null;
54
+ return [...vocab.byId.keys()];
55
+ }
56
+ /** Non-REMOVED requirements' entries the vocabulary does not declare — or nothing, per the opt-in rule above. */
57
+ function unknownEntries(reqs, vocab) {
58
+ const known = gradableCapabilityIds(vocab);
59
+ if (known === null)
60
+ return [];
61
+ const out = [];
62
+ for (const r of reqs) {
63
+ if (r.kind === "REMOVED")
64
+ continue;
65
+ for (const entry of r.capabilities) {
66
+ if (vocab.byId.has(entry))
67
+ continue;
68
+ out.push({ requirement: r.name, entry, close: closeIds(entry, known) });
69
+ }
70
+ }
71
+ return out;
72
+ }
73
+ function unknownMessage(where, u) {
74
+ return (`${where}: requirement '${u.requirement}' — Capability: '${u.entry}' is declared neither in architecture/capabilities.yaml nor as capabilities/${u.entry}/spec.md` +
75
+ (u.close.length > 0
76
+ ? `. Did you mean: ${u.close.join(", ")}?`
77
+ : ". Declare it in either — a name alone is a `capabilities: {<id>: {description, owner}}` entry, a name with prose behind it is the document — or fix the spelling"));
78
+ }
79
+ /**
80
+ * `capability.unknown` as validate sees it — an ERROR, the same grade as
81
+ * `Requires:` and for its reason: an invented capability reads exactly like a
82
+ * real one in the requirement and in every rollup built over it.
83
+ */
84
+ export function capabilityUnknownFindings(reqs, target, vocab) {
85
+ return unknownEntries(reqs, vocab).map((u) => ({
86
+ severity: "error",
87
+ code: "capability.unknown",
88
+ subject: target.subject,
89
+ message: unknownMessage(target.where, u),
90
+ }));
91
+ }
92
+ /**
93
+ * The same rule shaped as coherence Issues, for a feature's delta documents: a
94
+ * delta requirement naming an undeclared capability would merge a join that
95
+ * resolves to nothing, so it gates `loam archive` like other errors and stays
96
+ * `--approve`-overridable. The one new archive gate of this axis.
97
+ */
98
+ export function capabilityUnknownIssues(reqs, target, vocab) {
99
+ return unknownEntries(reqs, vocab).map((u) => ({
100
+ severity: "error",
101
+ code: "capability.unknown",
102
+ subject: target.subject,
103
+ message: unknownMessage(target.where, u),
104
+ }));
105
+ }
106
+ /**
107
+ * `capability.invalid` — the whole run's ONE finding about an unreadable
108
+ * vocabulary, spelling the expected shape. Every grade that RESOLVES AGAINST
109
+ * the vocabulary stays suspended behind it (see the module comment); the
110
+ * authored tree's own grades do not, because none of them consults it — a
111
+ * directory holding no document, a requirement without a stable id and a
112
+ * requirement carrying a service-level join are facts about files that a broken
113
+ * YAML does not make untrue, and hiding them until an unrelated file parses is
114
+ * suppression without the cascade that justifies it.
115
+ */
116
+ export function invalidVocabularyFinding(vocab) {
117
+ if (vocab.invalid === undefined)
118
+ return null;
119
+ return {
120
+ severity: "error",
121
+ code: "capability.invalid",
122
+ message: `landscape: architecture/capabilities.yaml does not read as a vocabulary — ${vocab.invalid}. ` +
123
+ "Every `Capability:` line in the fleet resolves against this file, so the whole capability family is suspended until it parses — fix the YAML first. " +
124
+ "The shape is `capabilities: {<id>: {description, owner}}`, ids flat keys with `/` allowed for nesting.",
125
+ };
126
+ }
127
+ /**
128
+ * `capability.unrealized` — ONE warn per declared capability no living
129
+ * non-REMOVED requirement names, subject = the id, sorted with compareIds.
130
+ * Per capability rather than one rollup finding with details[] (the
131
+ * permissions.unenforced shape) because the roadmap's own exit criterion is
132
+ * 'one warning per capability, not one per service' — each is a distinct
133
+ * promise nobody implemented, or a distinct word nobody adopted.
134
+ */
135
+ export function unrealizedFindings(vocab, used) {
136
+ const declared = gradableCapabilityIds(vocab);
137
+ if (declared === null)
138
+ return [];
139
+ return declared
140
+ .filter((id) => !used.has(id))
141
+ .sort(compareIds)
142
+ .map((id) => ({
143
+ severity: "warn",
144
+ code: "capability.unrealized",
145
+ subject: id,
146
+ message: `landscape: capability '${id}' is declared in ${declaredIn(vocab, id)} and nothing in the fleet realizes it — ` +
147
+ "no living requirement names it with `Capability:` or `Realizes:`, and no `#cap-`/`#req-` tagged flow keeps one of its promises. " +
148
+ "Either a promise nobody implemented or a word nobody adopted; write the requirement that realizes it, draw the flow that keeps it, or drop the declaration",
149
+ }));
150
+ }
151
+ /**
152
+ * Where an id was declared, spelled for a message. The fix differs by side —
153
+ * a YAML line is deleted, a document is deleted with its directory — and a
154
+ * message naming the wrong file sends its reader to edit something that is not
155
+ * there. `both` names both because either alone would leave the id declared.
156
+ */
157
+ function declaredIn(vocab, id) {
158
+ const source = vocab.byId.get(id)?.source;
159
+ if (source === "tree")
160
+ return `capabilities/${id}/spec.md`;
161
+ if (source === "both")
162
+ return `architecture/capabilities.yaml and capabilities/${id}/spec.md`;
163
+ return "architecture/capabilities.yaml";
164
+ }
165
+ /* ------------------------------------------------------------------ */
166
+ /* The authored tree — the documents themselves, graded on their own */
167
+ /* terms rather than on the join any requirement makes to them. */
168
+ /* ------------------------------------------------------------------ */
169
+ /**
170
+ * `capability.doc-missing` — a directory in a `capabilities/` tree that holds no
171
+ * `spec.md` and has no capability beneath it.
172
+ *
173
+ * WARN, not error, and the severity is the whole judgement: the state it names
174
+ * is what `mkdir` leaves behind halfway through creating a capability, and a
175
+ * half-finished authoring step must not fail somebody else's `loam validate`
176
+ * on the same tree. What makes it worth a finding at all is that the directory
177
+ * LOOKS declared — a reader browsing `capabilities/` counts it, and a
178
+ * `Capability:` line naming it still reports `capability.unknown`, which is the
179
+ * confusing pair this warning exists to join up.
180
+ *
181
+ * BOTH TREES EARN IT, and `featureDirName` is which one. The same walk reads
182
+ * `features/<dir>/capabilities/`, so the same `mkdir` leaves the same shape
183
+ * there — quieter, not louder: an empty directory is not a delta, so the delta
184
+ * algebra, the merge and `loam show` alike do not see it and the business change
185
+ * ships as nothing at exit 0. One code, one mistake; two messages, because the
186
+ * path and the fix differ. It is the DIRECTORY name and not the feature id
187
+ * (`FEAT-1-split` is where the directory is), and `undocumented` is spelled from
188
+ * the WALK'S root — literally `capabilities/…` on both sides — so a feature's
189
+ * entry is re-rooted here or the message names a path nobody can open.
190
+ */
191
+ export function docMissingFindings(tree, featureDirName) {
192
+ return tree.undocumented.map((walked) => {
193
+ const path = featureDirName === undefined ? walked : `features/${featureDirName}/${walked}`;
194
+ const rest = featureDirName === undefined
195
+ ? "so this one declares nothing and a requirement naming it still reports capability.unknown. " +
196
+ `Write ${path}/spec.md (the narrative, then \`## Requirements\`), or remove the directory.`
197
+ : "so this one changes nothing — the archive merges the capability deltas the walk FINDS, and an empty directory is not one. " +
198
+ `Write ${path}/spec.md (a \`## ADDED Requirements\` section), or remove the directory.`;
199
+ return {
200
+ severity: "warn",
201
+ code: "capability.doc-missing",
202
+ subject: path,
203
+ message: `${path}/ holds no spec.md and no capability beneath it — a directory under capabilities/ is a capability only when it holds the document, ${rest}`,
204
+ };
205
+ });
206
+ }
207
+ /**
208
+ * The service-level joins, and the whole of what "names no service" is checked
209
+ * as. Each entry is a `Requirement` field that is non-empty exactly when the
210
+ * requirement wrote the line and named something in it.
211
+ *
212
+ * THE PROSE RULE IS NOT CHECKED AND MUST NOT BE FAKED. "A capability
213
+ * requirement names no service" is an authoring rule about wording, and the
214
+ * only mechanical reading of it — scanning the text for a declared service id —
215
+ * is a heuristic that convicts a payments capability for the word "payments".
216
+ * loam refuses that class of check everywhere else and refuses it here; PR
217
+ * review holds the prose. What IS exact is the structural half: these four
218
+ * lines resolve against a SERVICE's contract and model, so a requirement
219
+ * carrying one has already left the business altitude whatever its wording
220
+ * says. `Requires:` is deliberately absent — a permission is a domain fact
221
+ * ("who may see a profile"), observable outside the fleet, and gating a
222
+ * capability requirement on one is legitimate.
223
+ */
224
+ const SERVICE_JOINS = [
225
+ { field: "operations", line: "Operations:", names: "an operationId in a service's openapi.yaml" },
226
+ { field: "covers", line: "Covers:", names: "a C4 element, edge or health signal" },
227
+ { field: "publishes", line: "Publishes:", names: "an AsyncAPI message a service produces" },
228
+ { field: "consumes", line: "Consumes:", names: "an AsyncAPI message a service consumes" },
229
+ ];
230
+ /**
231
+ * The two joins that point INTO the capability tree, and are therefore inert
232
+ * written inside it.
233
+ *
234
+ * Not "wrong at this altitude" like the four above — these are the axis's own
235
+ * lines. They are refused here because nothing reads them: `capabilityRollup`
236
+ * joins SERVICE requirements to capabilities, so a `Capability:` line in a
237
+ * capability document is a requirement claiming the document it is already in,
238
+ * and a `Realizes:` line there points at a promise loam will never see anybody
239
+ * keep. Both parse, both look exactly like the working joins one directory
240
+ * over, and both would sit in a reviewed document meaning nothing.
241
+ *
242
+ * A capability realizing ANOTHER capability's requirement — a nested
243
+ * `payments/refunds` serving a promise made by `payments` — is a real idea and
244
+ * is deliberately not being smuggled in as a line that happens to parse. It
245
+ * would need a design: a second corpus of joins, its own cycle rule, and an
246
+ * answer for what `capability.requirement-unrealized` means when the realizer
247
+ * is itself unrealized. Refusing the line now is what keeps that decision open.
248
+ */
249
+ const INTERNAL_JOINS = [
250
+ {
251
+ field: "capabilities",
252
+ line: "Capability:",
253
+ why: "the rollup joins SERVICE requirements to capabilities, so written here it claims the document it is already in",
254
+ },
255
+ {
256
+ field: "realizes",
257
+ line: "Realizes:",
258
+ why: "a capability requirement is what gets realized, not what realizes — nothing reads this line inside the tree",
259
+ },
260
+ ];
261
+ export function capabilityDocFindings(reqs, id, where = `capabilities/${id}/spec.md`) {
262
+ const findings = [];
263
+ for (const r of reqs) {
264
+ if (r.id === undefined) {
265
+ findings.push({
266
+ severity: "error",
267
+ code: "capability.requirement-unidentified",
268
+ subject: id,
269
+ message: `${where}: requirement '${r.name}' has no \`Requirement-ID:\` line. ` +
270
+ "A capability document outlives every service that realizes it, so its requirements are identified by a stable id rather than by their heading — " +
271
+ "without one, rewording the heading is a removal and an addition, and every join made to it breaks silently. " +
272
+ "Add `Requirement-ID: <id>` as the first body line.",
273
+ });
274
+ }
275
+ for (const join of SERVICE_JOINS) {
276
+ if (r[join.field].length === 0)
277
+ continue;
278
+ findings.push({
279
+ severity: "error",
280
+ code: "capability.requirement-service-scoped",
281
+ subject: id,
282
+ message: `${where}: requirement '${r.name}' carries \`${join.line}\`, which names ${join.names}. ` +
283
+ "A capability requirement must be observable outside the fleet — a promise a customer could check — and these lines resolve against one service's own contract, " +
284
+ "so a requirement carrying one is a service requirement filed at the wrong altitude. " +
285
+ "Move it into that service's spec.md, where the line resolves; what belongs here is the promise, not the mechanism.",
286
+ });
287
+ }
288
+ for (const join of INTERNAL_JOINS) {
289
+ if (r[join.field].length === 0)
290
+ continue;
291
+ findings.push({
292
+ severity: "error",
293
+ code: "capability.requirement-inert-join",
294
+ subject: id,
295
+ message: `${where}: requirement '${r.name}' carries \`${join.line}\`, which does nothing in a capability document — ` +
296
+ `${join.why}. It parses and reads exactly like the working join one directory over, which is why it is refused ` +
297
+ "rather than ignored. Delete the line; the join that matters is written on the SERVICE requirement, as " +
298
+ `\`Realizes: ${id}#${r.id ?? "<Requirement-ID>"}\`.`,
299
+ });
300
+ }
301
+ }
302
+ return findings;
303
+ }
304
+ /**
305
+ * The requirement ids each capability document declares, with THE LADDER
306
+ * already applied — the one shape `Realizes:` is ever resolved against.
307
+ *
308
+ * Built here rather than at the three call sites for the reason
309
+ * `gradableCapabilityIds` above is exported: the suppression rule and the index
310
+ * it guards belong together. A caller that composed them itself would be a
311
+ * fourth place where "can this be graded at all" is decided, and the first one
312
+ * to be forgotten when a fifth un-gradable vocabulary state arrives.
313
+ *
314
+ * A requirement with no `Requirement-ID:` is absent from the index, so a
315
+ * `Realizes:` entry naming its heading does not resolve. That is deliberate and
316
+ * not a gap: an unidentified capability requirement is already an ERROR
317
+ * (`capability.requirement-unidentified`), and letting a heading work as an
318
+ * address would quietly reintroduce the identity-by-heading the tree exists to
319
+ * refuse. REMOVED is skipped for the reason every other reader skips it.
320
+ *
321
+ * The reads are NOT wrapped: a `capabilities/<id>/spec.md` that cannot be
322
+ * decoded takes the run down exactly as a service spec does — the rule
323
+ * `capabilityFleetFindings` already states one directory over.
324
+ */
325
+ export async function capabilityRequirementIndex(vocab, read) {
326
+ const declared = gradableCapabilityIds(vocab);
327
+ const byCapability = new Map();
328
+ const digests = new Map();
329
+ if (declared === null)
330
+ return { declared, byCapability, digests };
331
+ for (const doc of vocab.tree.docs) {
332
+ const reqs = await read(doc.spec);
333
+ // ONE pass fills both, which is what keeps them from disagreeing: an id
334
+ // reaches the set and the digest map in the same iteration or reaches
335
+ // neither. The skip rule is stated once, above the loop body it guards.
336
+ const kept = reqs.filter((r) => r.kind !== "REMOVED" && r.id !== undefined);
337
+ byCapability.set(doc.id, new Set(kept.map((r) => r.id)));
338
+ digests.set(doc.id, new Map(kept.map((r) => [r.id, requirementDigest(r)])));
339
+ }
340
+ return { declared, byCapability, digests };
341
+ }
342
+ //# sourceMappingURL=findings.js.map