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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (901) hide show
  1. package/CHANGELOG.md +3448 -0
  2. package/COMPARISON.md +91 -3
  3. package/CONTRIBUTING.md +37 -0
  4. package/MIGRATING-from-OpenSpec.md +47 -23
  5. package/QUICKSTART.md +189 -12
  6. package/README.md +274 -65
  7. package/ROADMAP.md +572 -31
  8. package/SCHEMA.md +1709 -155
  9. package/WORKFLOW.md +298 -72
  10. package/dist/cli.js +26 -8
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/adopt/adopt.js +5 -10
  13. package/dist/commands/adopt/adopt.js.map +1 -1
  14. package/dist/commands/adopt/render.js +50 -9
  15. package/dist/commands/adopt/render.js.map +1 -1
  16. package/dist/commands/archive/archive.js +16 -19
  17. package/dist/commands/archive/archive.js.map +1 -1
  18. package/dist/commands/archive/closing.js +42 -0
  19. package/dist/commands/archive/closing.js.map +1 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js +36 -42
  21. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
  22. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  24. package/dist/commands/archive/plan/contracts/openapi.js +77 -43
  25. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
  26. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  28. package/dist/commands/archive/plan/document/head.js +151 -0
  29. package/dist/commands/archive/plan/document/head.js.map +1 -0
  30. package/dist/commands/archive/plan/document/links.js +284 -0
  31. package/dist/commands/archive/plan/document/links.js.map +1 -0
  32. package/dist/commands/archive/plan/document/run.js +136 -0
  33. package/dist/commands/archive/plan/document/run.js.map +1 -0
  34. package/dist/commands/archive/plan/gate.js +21 -19
  35. package/dist/commands/archive/plan/gate.js.map +1 -1
  36. package/dist/commands/archive/plan/landscape.js +167 -30
  37. package/dist/commands/archive/plan/landscape.js.map +1 -1
  38. package/dist/commands/archive/plan/model/extending.js +85 -0
  39. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  40. package/dist/commands/archive/plan/refusal.js +14 -19
  41. package/dist/commands/archive/plan/refusal.js.map +1 -1
  42. package/dist/commands/archive/plan/specs.js +137 -56
  43. package/dist/commands/archive/plan/specs.js.map +1 -1
  44. package/dist/commands/archive/plan/state.js +3 -0
  45. package/dist/commands/archive/plan/state.js.map +1 -1
  46. package/dist/commands/archive/run.js +134 -30
  47. package/dist/commands/archive/run.js.map +1 -1
  48. package/dist/commands/archive/shipped.js +49 -0
  49. package/dist/commands/archive/shipped.js.map +1 -0
  50. package/dist/commands/context/context.js +85 -18
  51. package/dist/commands/context/context.js.map +1 -1
  52. package/dist/commands/context/print.js +29 -7
  53. package/dist/commands/context/print.js.map +1 -1
  54. package/dist/commands/delta/delta.js +102 -14
  55. package/dist/commands/delta/delta.js.map +1 -1
  56. package/dist/commands/delta/print.js +17 -1
  57. package/dist/commands/delta/print.js.map +1 -1
  58. package/dist/commands/dependencies.js +3 -7
  59. package/dist/commands/dependencies.js.map +1 -1
  60. package/dist/commands/diff/diff.js +20 -27
  61. package/dist/commands/diff/diff.js.map +1 -1
  62. package/dist/commands/doctor.js +60 -1
  63. package/dist/commands/doctor.js.map +1 -1
  64. package/dist/commands/explain/explain.js +89 -13
  65. package/dist/commands/explain/explain.js.map +1 -1
  66. package/dist/commands/explore.js +16 -10
  67. package/dist/commands/explore.js.map +1 -1
  68. package/dist/commands/gate/gate.js +45 -8
  69. package/dist/commands/gate/gate.js.map +1 -1
  70. package/dist/commands/gate/print.js +15 -3
  71. package/dist/commands/gate/print.js.map +1 -1
  72. package/dist/commands/gherkin/commit.js +13 -54
  73. package/dist/commands/gherkin/commit.js.map +1 -1
  74. package/dist/commands/gherkin/gherkin.js +36 -20
  75. package/dist/commands/gherkin/gherkin.js.map +1 -1
  76. package/dist/commands/gherkin/reconcile.js +10 -13
  77. package/dist/commands/gherkin/reconcile.js.map +1 -1
  78. package/dist/commands/init/first-hour.js +44 -0
  79. package/dist/commands/init/first-hour.js.map +1 -1
  80. package/dist/commands/init/init.js +18 -22
  81. package/dist/commands/init/init.js.map +1 -1
  82. package/dist/commands/list/campaign/campaign.js +4 -6
  83. package/dist/commands/list/campaign/campaign.js.map +1 -1
  84. package/dist/commands/list/json.js +5 -7
  85. package/dist/commands/list/json.js.map +1 -1
  86. package/dist/commands/list/list.js +44 -29
  87. package/dist/commands/list/list.js.map +1 -1
  88. package/dist/commands/list/print.js +52 -9
  89. package/dist/commands/list/print.js.map +1 -1
  90. package/dist/commands/list/suites/suites.js +140 -0
  91. package/dist/commands/list/suites/suites.js.map +1 -0
  92. package/dist/commands/list/views.js +37 -34
  93. package/dist/commands/list/views.js.map +1 -1
  94. package/dist/commands/mcp/dispatch.js +91 -36
  95. package/dist/commands/mcp/dispatch.js.map +1 -1
  96. package/dist/commands/mcp/mcp.js +56 -15
  97. package/dist/commands/mcp/mcp.js.map +1 -1
  98. package/dist/commands/mcp/serve.js.map +1 -1
  99. package/dist/commands/migrate-openspec/materialize/active.js +27 -22
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
  101. package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
  102. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
  103. package/dist/commands/migrate-openspec/materialize/target.js +2 -2
  104. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
  105. package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
  106. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
  107. package/dist/commands/migrate-openspec/openspec/error.js +7 -8
  108. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
  109. package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
  110. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
  111. package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
  112. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
  113. package/dist/commands/new/capability-template.js +118 -0
  114. package/dist/commands/new/capability-template.js.map +1 -0
  115. package/dist/commands/new/commit.js +8 -22
  116. package/dist/commands/new/commit.js.map +1 -1
  117. package/dist/commands/new/modifies.js +206 -0
  118. package/dist/commands/new/modifies.js.map +1 -0
  119. package/dist/commands/new/new.js +59 -14
  120. package/dist/commands/new/new.js.map +1 -1
  121. package/dist/commands/new/templates.js +48 -124
  122. package/dist/commands/new/templates.js.map +1 -1
  123. package/dist/commands/open.js +3 -7
  124. package/dist/commands/open.js.map +1 -1
  125. package/dist/commands/policy/gate.js +27 -0
  126. package/dist/commands/policy/gate.js.map +1 -1
  127. package/dist/commands/rebase/plan.js +2 -2
  128. package/dist/commands/rebase/plan.js.map +1 -1
  129. package/dist/commands/rebase/rebase.js +60 -35
  130. package/dist/commands/rebase/rebase.js.map +1 -1
  131. package/dist/commands/seed/commit.js +55 -26
  132. package/dist/commands/seed/commit.js.map +1 -1
  133. package/dist/commands/seed/plan.js +158 -13
  134. package/dist/commands/seed/plan.js.map +1 -1
  135. package/dist/commands/seed/seed.js +13 -11
  136. package/dist/commands/seed/seed.js.map +1 -1
  137. package/dist/commands/show/feature.js +9 -5
  138. package/dist/commands/show/feature.js.map +1 -1
  139. package/dist/commands/show/introduced.js +157 -0
  140. package/dist/commands/show/introduced.js.map +1 -0
  141. package/dist/commands/show/marks.js +35 -6
  142. package/dist/commands/show/marks.js.map +1 -1
  143. package/dist/commands/show/service.js +41 -33
  144. package/dist/commands/show/service.js.map +1 -1
  145. package/dist/commands/show/show.js +17 -7
  146. package/dist/commands/show/show.js.map +1 -1
  147. package/dist/commands/status/fleet-next.js +90 -0
  148. package/dist/commands/status/fleet-next.js.map +1 -0
  149. package/dist/commands/status/json.js +2 -0
  150. package/dist/commands/status/json.js.map +1 -1
  151. package/dist/commands/status/print.js +89 -37
  152. package/dist/commands/status/print.js.map +1 -1
  153. package/dist/commands/status/status.js +3 -7
  154. package/dist/commands/status/status.js.map +1 -1
  155. package/dist/commands/steps/steps.js +103 -23
  156. package/dist/commands/steps/steps.js.map +1 -1
  157. package/dist/commands/subsystem/edit.js +7 -7
  158. package/dist/commands/subsystem/edit.js.map +1 -1
  159. package/dist/commands/subsystem/move.js +106 -46
  160. package/dist/commands/subsystem/move.js.map +1 -1
  161. package/dist/commands/subsystem/query.js +2 -4
  162. package/dist/commands/subsystem/query.js.map +1 -1
  163. package/dist/commands/subsystem/subsystem.js +4 -7
  164. package/dist/commands/subsystem/subsystem.js.map +1 -1
  165. package/dist/commands/subsystem/sync.js +289 -74
  166. package/dist/commands/subsystem/sync.js.map +1 -1
  167. package/dist/commands/subsystem/txn/exclude.js +132 -0
  168. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  169. package/dist/commands/subsystem/txn/links.js +128 -0
  170. package/dist/commands/subsystem/txn/links.js.map +1 -0
  171. package/dist/commands/subsystem/txn/report.js +174 -0
  172. package/dist/commands/subsystem/txn/report.js.map +1 -0
  173. package/dist/commands/subsystem/txn/txn.js +147 -45
  174. package/dist/commands/subsystem/txn/txn.js.map +1 -1
  175. package/dist/commands/subsystem/txn/views.js +200 -21
  176. package/dist/commands/subsystem/txn/views.js.map +1 -1
  177. package/dist/commands/tasks/actions.js +107 -0
  178. package/dist/commands/tasks/actions.js.map +1 -0
  179. package/dist/commands/tasks/render.js +253 -0
  180. package/dist/commands/tasks/render.js.map +1 -0
  181. package/dist/commands/tasks/tasks.js +119 -0
  182. package/dist/commands/tasks/tasks.js.map +1 -0
  183. package/dist/commands/unarchive/manifest.js +42 -26
  184. package/dist/commands/unarchive/manifest.js.map +1 -1
  185. package/dist/commands/unarchive/restore.js +83 -33
  186. package/dist/commands/unarchive/restore.js.map +1 -1
  187. package/dist/commands/unarchive/unarchive.js +22 -30
  188. package/dist/commands/unarchive/unarchive.js.map +1 -1
  189. package/dist/commands/validate/arch-coverage.js +78 -27
  190. package/dist/commands/validate/arch-coverage.js.map +1 -1
  191. package/dist/commands/validate/checks/fleet-shape.js +34 -126
  192. package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
  193. package/dist/commands/validate/checks/health-deps.js +9 -6
  194. package/dist/commands/validate/checks/health-deps.js.map +1 -1
  195. package/dist/commands/validate/checks/introduced.js +102 -0
  196. package/dist/commands/validate/checks/introduced.js.map +1 -0
  197. package/dist/commands/validate/checks/requirements.js +18 -8
  198. package/dist/commands/validate/checks/requirements.js.map +1 -1
  199. package/dist/commands/validate/checks/sources.js +11 -2
  200. package/dist/commands/validate/checks/sources.js.map +1 -1
  201. package/dist/commands/validate/coverage/covers-after.js +105 -0
  202. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  203. package/dist/commands/validate/feature.js +26 -20
  204. package/dist/commands/validate/feature.js.map +1 -1
  205. package/dist/commands/validate/fleet/census.js +37 -13
  206. package/dist/commands/validate/fleet/census.js.map +1 -1
  207. package/dist/commands/validate/fleet/landscape.js +144 -126
  208. package/dist/commands/validate/fleet/landscape.js.map +1 -1
  209. package/dist/commands/validate/fleet/load.js +66 -0
  210. package/dist/commands/validate/fleet/load.js.map +1 -1
  211. package/dist/commands/validate/fleet/map/attest.js +98 -0
  212. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  213. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  214. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  215. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  216. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  217. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  218. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  219. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  220. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  221. package/dist/commands/validate/fleet/obligations.js +44 -14
  222. package/dist/commands/validate/fleet/obligations.js.map +1 -1
  223. package/dist/commands/validate/fleet/scorecard/print.js +10 -2
  224. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
  225. package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
  226. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
  227. package/dist/commands/validate/fleet/usecases/place.js.map +1 -1
  228. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  229. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  230. package/dist/commands/validate/fleet/views/ids.js +50 -15
  231. package/dist/commands/validate/fleet/views/ids.js.map +1 -1
  232. package/dist/commands/validate/fleet/views/projects.js +278 -0
  233. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  234. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  235. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  236. package/dist/commands/validate/fleet/views/stale.js +40 -47
  237. package/dist/commands/validate/fleet/views/stale.js.map +1 -1
  238. package/dist/commands/validate/links/corpus.js +1 -4
  239. package/dist/commands/validate/links/corpus.js.map +1 -1
  240. package/dist/commands/validate/links/glossary.js.map +1 -1
  241. package/dist/commands/validate/render/repeats.js +63 -0
  242. package/dist/commands/validate/render/repeats.js.map +1 -0
  243. package/dist/commands/validate/render/rollups.js +115 -0
  244. package/dist/commands/validate/render/rollups.js.map +1 -0
  245. package/dist/commands/validate/render/text.js +199 -0
  246. package/dist/commands/validate/render/text.js.map +1 -0
  247. package/dist/commands/validate/report.js +36 -160
  248. package/dist/commands/validate/report.js.map +1 -1
  249. package/dist/commands/validate/scope.js +113 -0
  250. package/dist/commands/validate/scope.js.map +1 -0
  251. package/dist/commands/validate/service/api.js +21 -107
  252. package/dist/commands/validate/service/api.js.map +1 -1
  253. package/dist/commands/validate/service/contracts/generated.js +134 -0
  254. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  255. package/dist/commands/validate/service/events/events.js +36 -14
  256. package/dist/commands/validate/service/events/events.js.map +1 -1
  257. package/dist/commands/validate/service/events/message-producers.js +1 -1
  258. package/dist/commands/validate/service/events/message-producers.js.map +1 -1
  259. package/dist/commands/validate/service/evidence-pins.js +56 -10
  260. package/dist/commands/validate/service/evidence-pins.js.map +1 -1
  261. package/dist/commands/validate/service/model/diverged.js +226 -0
  262. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  263. package/dist/commands/validate/service/model/grade.js +163 -0
  264. package/dist/commands/validate/service/model/grade.js.map +1 -0
  265. package/dist/commands/validate/service/service.js +121 -61
  266. package/dist/commands/validate/service/service.js.map +1 -1
  267. package/dist/commands/validate/service/specs.js +88 -28
  268. package/dist/commands/validate/service/specs.js.map +1 -1
  269. package/dist/commands/validate/service/spine.js +38 -3
  270. package/dist/commands/validate/service/spine.js.map +1 -1
  271. package/dist/commands/validate/service/usecases/tags.js +113 -0
  272. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  273. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  274. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  275. package/dist/commands/validate/validate.js +85 -60
  276. package/dist/commands/validate/validate.js.map +1 -1
  277. package/dist/commands/verify/cross/diff.js +2 -6
  278. package/dist/commands/verify/cross/diff.js.map +1 -1
  279. package/dist/commands/verify/evidence/contract.js +1 -1
  280. package/dist/commands/verify/evidence/contract.js.map +1 -1
  281. package/dist/commands/verify/evidence/read.js +12 -3
  282. package/dist/commands/verify/evidence/read.js.map +1 -1
  283. package/dist/commands/verify/frozen.js +45 -23
  284. package/dist/commands/verify/frozen.js.map +1 -1
  285. package/dist/commands/verify/record.js +69 -17
  286. package/dist/commands/verify/record.js.map +1 -1
  287. package/dist/commands/verify/report.js +27 -44
  288. package/dist/commands/verify/report.js.map +1 -1
  289. package/dist/commands/verify/results.js +112 -30
  290. package/dist/commands/verify/results.js.map +1 -1
  291. package/dist/commands/verify/verify.js +55 -52
  292. package/dist/commands/verify/verify.js.map +1 -1
  293. package/dist/commands/vouch/pack/pack.js +2 -2
  294. package/dist/commands/vouch/pack/pack.js.map +1 -1
  295. package/dist/commands/vouch/pack/print.js +1 -6
  296. package/dist/commands/vouch/pack/print.js.map +1 -1
  297. package/dist/commands/vouch/pack/sections.js +1 -2
  298. package/dist/commands/vouch/pack/sections.js.map +1 -1
  299. package/dist/commands/vouch/run.js +26 -81
  300. package/dist/commands/vouch/run.js.map +1 -1
  301. package/dist/commands/vouch/sample/plan.js +20 -34
  302. package/dist/commands/vouch/sample/plan.js.map +1 -1
  303. package/dist/commands/vouch/vet/verify.js +39 -7
  304. package/dist/commands/vouch/vet/verify.js.map +1 -1
  305. package/dist/commands/vouch/vouch.js +10 -17
  306. package/dist/commands/vouch/vouch.js.map +1 -1
  307. package/dist/core/agent/agents-md/command-map.js +81 -106
  308. package/dist/core/agent/agents-md/command-map.js.map +1 -1
  309. package/dist/core/agent/agents-md/map/explain.js +21 -9
  310. package/dist/core/agent/agents-md/map/explain.js.map +1 -1
  311. package/dist/core/agent/agents-md/map/lenses/context.js +17 -8
  312. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
  313. package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
  314. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
  315. package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
  316. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
  317. package/dist/core/agent/agents-md/map/mcp.js +10 -7
  318. package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
  319. package/dist/core/agent/agents-md/map/status.js +24 -8
  320. package/dist/core/agent/agents-md/map/status.js.map +1 -1
  321. package/dist/core/agent/agents-md/map/subsystem.js +80 -8
  322. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
  323. package/dist/core/agent/agents-md/map/usecases.js +88 -10
  324. package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
  325. package/dist/core/agent/agents-md/refusals.js +49 -22
  326. package/dist/core/agent/agents-md/refusals.js.map +1 -1
  327. package/dist/core/agent/agents-md.js +39 -6
  328. package/dist/core/agent/agents-md.js.map +1 -1
  329. package/dist/core/agent/agents-stamp.js +10 -0
  330. package/dist/core/agent/agents-stamp.js.map +1 -1
  331. package/dist/core/agent/protocol.js +1 -1
  332. package/dist/core/agent/protocol.js.map +1 -1
  333. package/dist/core/agent/scaffold.js +10 -15
  334. package/dist/core/agent/scaffold.js.map +1 -1
  335. package/dist/core/agent/support/report.js +46 -5
  336. package/dist/core/agent/support/report.js.map +1 -1
  337. package/dist/core/agent/tools/dialects.js +1 -0
  338. package/dist/core/agent/tools/dialects.js.map +1 -1
  339. package/dist/core/agent/tools/registry.js +41 -76
  340. package/dist/core/agent/tools/registry.js.map +1 -1
  341. package/dist/core/agent/workflows/adopt.js +158 -11
  342. package/dist/core/agent/workflows/adopt.js.map +1 -1
  343. package/dist/core/agent/workflows/check.js +78 -39
  344. package/dist/core/agent/workflows/check.js.map +1 -1
  345. package/dist/core/agent/workflows/closing.js +88 -27
  346. package/dist/core/agent/workflows/closing.js.map +1 -1
  347. package/dist/core/agent/workflows/feature.js +128 -13
  348. package/dist/core/agent/workflows/feature.js.map +1 -1
  349. package/dist/core/agent/workflows/implement.js +96 -13
  350. package/dist/core/agent/workflows/implement.js.map +1 -1
  351. package/dist/core/agent/workflows/reference/authoring.js +106 -4
  352. package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
  353. package/dist/core/agent/workflows/reference/codes.js +8 -6
  354. package/dist/core/agent/workflows/reference/codes.js.map +1 -1
  355. package/dist/core/agent/workflows/reference/done-check.js +37 -15
  356. package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
  357. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  358. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  359. package/dist/core/agent/workflows/reference/reference.js +6 -3
  360. package/dist/core/agent/workflows/reference/reference.js.map +1 -1
  361. package/dist/core/agent/workflows/reference/spine.js +68 -27
  362. package/dist/core/agent/workflows/reference/spine.js.map +1 -1
  363. package/dist/core/asyncapi/baseline/plan.js +14 -81
  364. package/dist/core/asyncapi/baseline/plan.js.map +1 -1
  365. package/dist/core/asyncapi/digest.js +30 -25
  366. package/dist/core/asyncapi/digest.js.map +1 -1
  367. package/dist/core/asyncapi/merge/components.js +5 -4
  368. package/dist/core/asyncapi/merge/components.js.map +1 -1
  369. package/dist/core/asyncapi/merge/error.js +7 -2
  370. package/dist/core/asyncapi/merge/error.js.map +1 -1
  371. package/dist/core/asyncapi/merge/markers.js +32 -50
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -1
  373. package/dist/core/asyncapi/merge/merge.js +33 -53
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -1
  375. package/dist/core/asyncapi/merge/pin.js +12 -36
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -1
  377. package/dist/core/asyncapi/model.js.map +1 -1
  378. package/dist/core/asyncapi/read.js +36 -12
  379. package/dist/core/asyncapi/read.js.map +1 -1
  380. package/dist/core/brief/brief.js +96 -36
  381. package/dist/core/brief/brief.js.map +1 -1
  382. package/dist/core/brief/checks.js +138 -3
  383. package/dist/core/brief/checks.js.map +1 -1
  384. package/dist/core/brief/landscape.js +209 -130
  385. package/dist/core/brief/landscape.js.map +1 -1
  386. package/dist/core/brief/map/extend.js +84 -0
  387. package/dist/core/brief/map/extend.js.map +1 -0
  388. package/dist/core/brief/map/owed.js +266 -0
  389. package/dist/core/brief/map/owed.js.map +1 -0
  390. package/dist/core/brief/targets.js +109 -31
  391. package/dist/core/brief/targets.js.map +1 -1
  392. package/dist/core/brief/unchecked.js +14 -3
  393. package/dist/core/brief/unchecked.js.map +1 -1
  394. package/dist/core/c4/arch.js +90 -182
  395. package/dist/core/c4/arch.js.map +1 -1
  396. package/dist/core/c4/direction/direction.js +114 -0
  397. package/dist/core/c4/direction/direction.js.map +1 -0
  398. package/dist/core/c4/likec4.js +169 -14
  399. package/dist/core/c4/likec4.js.map +1 -1
  400. package/dist/core/c4/locate/unlocated.js +150 -0
  401. package/dist/core/c4/locate/unlocated.js.map +1 -0
  402. package/dist/core/c4/parsed/deployment.js +160 -0
  403. package/dist/core/c4/parsed/deployment.js.map +1 -0
  404. package/dist/core/c4/parsed/dynamic-views.js.map +1 -1
  405. package/dist/core/c4/parsed/values.js +54 -1
  406. package/dist/core/c4/parsed/values.js.map +1 -1
  407. package/dist/core/c4/parsed/view-ids.js +39 -1
  408. package/dist/core/c4/parsed/view-ids.js.map +1 -1
  409. package/dist/core/c4/prefetch/fleet.js +134 -0
  410. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  411. package/dist/core/c4/project/architecture.js +123 -7
  412. package/dist/core/c4/project/architecture.js.map +1 -1
  413. package/dist/core/c4/project/batch.js +140 -0
  414. package/dist/core/c4/project/batch.js.map +1 -0
  415. package/dist/core/c4/project/documents.js +43 -12
  416. package/dist/core/c4/project/documents.js.map +1 -1
  417. package/dist/core/c4/project/load.js +79 -43
  418. package/dist/core/c4/project/load.js.map +1 -1
  419. package/dist/core/c4/project/staged.js +277 -0
  420. package/dist/core/c4/project/staged.js.map +1 -0
  421. package/dist/core/c4/resolve/attested.js +0 -0
  422. package/dist/core/c4/resolve/attested.js.map +1 -0
  423. package/dist/core/c4/resolve/external.js +51 -0
  424. package/dist/core/c4/resolve/external.js.map +1 -0
  425. package/dist/core/c4/resolve/service.js +78 -17
  426. package/dist/core/c4/resolve/service.js.map +1 -1
  427. package/dist/core/c4/resolve/steps.js +290 -0
  428. package/dist/core/c4/resolve/steps.js.map +1 -0
  429. package/dist/core/c4/resolve/systems.js +154 -0
  430. package/dist/core/c4/resolve/systems.js.map +1 -0
  431. package/dist/core/c4/root-project/exclude.js +352 -0
  432. package/dist/core/c4/root-project/exclude.js.map +1 -0
  433. package/dist/core/c4/seed/template.js +65 -1
  434. package/dist/core/c4/seed/template.js.map +1 -1
  435. package/dist/core/c4/service-model/created/models.js +96 -0
  436. package/dist/core/c4/service-model/created/models.js.map +1 -0
  437. package/dist/core/c4/service-model/documents.js +47 -0
  438. package/dist/core/c4/service-model/documents.js.map +1 -0
  439. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  440. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  441. package/dist/core/c4/service-model/load.js +165 -0
  442. package/dist/core/c4/service-model/load.js.map +1 -0
  443. package/dist/core/c4/service-model/renderer.js +128 -0
  444. package/dist/core/c4/service-model/renderer.js.map +1 -0
  445. package/dist/core/c4/service-model/shape.js +106 -0
  446. package/dist/core/c4/service-model/shape.js.map +1 -0
  447. package/dist/core/c4/service-model/slice.js +188 -0
  448. package/dist/core/c4/service-model/slice.js.map +1 -0
  449. package/dist/core/c4/source-mask.js +297 -10
  450. package/dist/core/c4/source-mask.js.map +1 -1
  451. package/dist/core/c4/source-scan.js +222 -141
  452. package/dist/core/c4/source-scan.js.map +1 -1
  453. package/dist/core/c4/splice/authored-source.js +79 -13
  454. package/dist/core/c4/splice/authored-source.js.map +1 -1
  455. package/dist/core/c4/splice/contract.js +20 -0
  456. package/dist/core/c4/splice/contract.js.map +1 -1
  457. package/dist/core/c4/splice/delta-blocks.js +20 -20
  458. package/dist/core/c4/splice/delta-blocks.js.map +1 -1
  459. package/dist/core/c4/splice/identity/declared.js +87 -0
  460. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  461. package/dist/core/c4/splice/identity/edges.js +37 -0
  462. package/dist/core/c4/splice/identity/edges.js.map +1 -1
  463. package/dist/core/c4/splice/identity/existing.js +80 -0
  464. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  465. package/dist/core/c4/splice/identity/interior.js +80 -0
  466. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  467. package/dist/core/c4/splice/identity/owner.js +50 -0
  468. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  469. package/dist/core/c4/splice/landscape-merge.js +182 -114
  470. package/dist/core/c4/splice/landscape-merge.js.map +1 -1
  471. package/dist/core/c4/splice/model/merge.js +151 -0
  472. package/dist/core/c4/splice/model/merge.js.map +1 -0
  473. package/dist/core/c4/splice/placement.js +160 -56
  474. package/dist/core/c4/splice/placement.js.map +1 -1
  475. package/dist/core/c4/splice/text/spot.js +131 -0
  476. package/dist/core/c4/splice/text/spot.js.map +1 -0
  477. package/dist/core/c4/workspace.js +13 -19
  478. package/dist/core/c4/workspace.js.map +1 -1
  479. package/dist/core/capabilities/capabilities.js +6 -6
  480. package/dist/core/capabilities/capabilities.js.map +1 -1
  481. package/dist/core/capabilities/delta/doc.js +7 -10
  482. package/dist/core/capabilities/delta/doc.js.map +1 -1
  483. package/dist/core/capabilities/delta/uncovered.js +2 -2
  484. package/dist/core/capabilities/delta/uncovered.js.map +1 -1
  485. package/dist/core/capabilities/findings.js +18 -22
  486. package/dist/core/capabilities/findings.js.map +1 -1
  487. package/dist/core/capabilities/realizes/findings.js +12 -19
  488. package/dist/core/capabilities/realizes/findings.js.map +1 -1
  489. package/dist/core/capabilities/realizes/join.js +0 -20
  490. package/dist/core/capabilities/realizes/join.js.map +1 -1
  491. package/dist/core/capabilities/rollup.js +6 -0
  492. package/dist/core/capabilities/rollup.js.map +1 -1
  493. package/dist/core/capabilities/tree.js +6 -28
  494. package/dist/core/capabilities/tree.js.map +1 -1
  495. package/dist/core/capabilities/usecase-join.js +3 -13
  496. package/dist/core/capabilities/usecase-join.js.map +1 -1
  497. package/dist/core/coherence/authoring/scaffold.js +11 -3
  498. package/dist/core/coherence/authoring/scaffold.js.map +1 -1
  499. package/dist/core/coherence/authoring/sentinels.js +2 -1
  500. package/dist/core/coherence/authoring/sentinels.js.map +1 -1
  501. package/dist/core/coherence/calls/called.js +52 -0
  502. package/dist/core/coherence/calls/called.js.map +1 -0
  503. package/dist/core/coherence/coherence.js +103 -22
  504. package/dist/core/coherence/coherence.js.map +1 -1
  505. package/dist/core/coherence/consumed/operations.js +70 -0
  506. package/dist/core/coherence/consumed/operations.js.map +1 -0
  507. package/dist/core/coherence/consumed/refusal.js +38 -0
  508. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  509. package/dist/core/coherence/covers/health.js +85 -0
  510. package/dist/core/coherence/covers/health.js.map +1 -0
  511. package/dist/core/coherence/declared.js +60 -34
  512. package/dist/core/coherence/declared.js.map +1 -1
  513. package/dist/core/coherence/events/declared.js +44 -59
  514. package/dist/core/coherence/events/declared.js.map +1 -1
  515. package/dist/core/coherence/events/events.js +147 -16
  516. package/dist/core/coherence/events/events.js.map +1 -1
  517. package/dist/core/coherence/events/grades.js +31 -8
  518. package/dist/core/coherence/events/grades.js.map +1 -1
  519. package/dist/core/coherence/events/lookups.js +28 -87
  520. package/dist/core/coherence/events/lookups.js.map +1 -1
  521. package/dist/core/coherence/events/produced.js +100 -0
  522. package/dist/core/coherence/events/produced.js.map +1 -0
  523. package/dist/core/coherence/lookups.js +18 -78
  524. package/dist/core/coherence/lookups.js.map +1 -1
  525. package/dist/core/coherence/retired/archived.js +285 -0
  526. package/dist/core/coherence/retired/archived.js.map +1 -0
  527. package/dist/core/coherence/retired/event-pair.js +62 -0
  528. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  529. package/dist/core/coherence/retired/merged.js +79 -0
  530. package/dist/core/coherence/retired/merged.js.map +1 -0
  531. package/dist/core/coherence/retired/retirement.js +49 -0
  532. package/dist/core/coherence/retired/retirement.js.map +1 -0
  533. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  534. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  535. package/dist/core/coherence/retired/revival/revived.js +297 -0
  536. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  537. package/dist/core/consumers/after.js +113 -0
  538. package/dist/core/consumers/after.js.map +1 -0
  539. package/dist/core/consumers/consumers.js +296 -0
  540. package/dist/core/consumers/consumers.js.map +1 -0
  541. package/dist/core/consumers/current.js +211 -0
  542. package/dist/core/consumers/current.js.map +1 -0
  543. package/dist/core/consumers/scan.js +46 -0
  544. package/dist/core/consumers/scan.js.map +1 -0
  545. package/dist/core/consumers/state.js +27 -0
  546. package/dist/core/consumers/state.js.map +1 -0
  547. package/dist/core/delta/delta.js +51 -6
  548. package/dist/core/delta/delta.js.map +1 -1
  549. package/dist/core/dependencies/fanin.js +2 -2
  550. package/dist/core/dependencies/fanin.js.map +1 -1
  551. package/dist/core/deployment/delta.js +191 -0
  552. package/dist/core/deployment/delta.js.map +1 -0
  553. package/dist/core/deployment/objects.js +145 -0
  554. package/dist/core/deployment/objects.js.map +1 -0
  555. package/dist/core/diff/base-git.js +94 -12
  556. package/dist/core/diff/base-git.js.map +1 -1
  557. package/dist/core/diff/base-state.js +49 -21
  558. package/dist/core/diff/base-state.js.map +1 -1
  559. package/dist/core/diff/joins.js +136 -0
  560. package/dist/core/diff/joins.js.map +1 -0
  561. package/dist/core/diff/scope/changed-paths.js +22 -6
  562. package/dist/core/diff/scope/changed-paths.js.map +1 -1
  563. package/dist/core/diff/scope/edges.js +82 -0
  564. package/dist/core/diff/scope/edges.js.map +1 -0
  565. package/dist/core/diff/semantic.js +100 -31
  566. package/dist/core/diff/semantic.js.map +1 -1
  567. package/dist/core/docs.js +31 -22
  568. package/dist/core/docs.js.map +1 -1
  569. package/dist/core/doctor/agents.js +34 -18
  570. package/dist/core/doctor/agents.js.map +1 -1
  571. package/dist/core/doctor/config.js +7 -3
  572. package/dist/core/doctor/config.js.map +1 -1
  573. package/dist/core/doctor/doctor.js +91 -11
  574. package/dist/core/doctor/doctor.js.map +1 -1
  575. package/dist/core/doctor/report.js.map +1 -1
  576. package/dist/core/doctor/reports/scan.js +242 -0
  577. package/dist/core/doctor/reports/scan.js.map +1 -0
  578. package/dist/core/document/apply.js +158 -11
  579. package/dist/core/document/apply.js.map +1 -1
  580. package/dist/core/document/frontmatter.js +55 -0
  581. package/dist/core/document/frontmatter.js.map +1 -1
  582. package/dist/core/document/parse.js +29 -6
  583. package/dist/core/document/parse.js.map +1 -1
  584. package/dist/core/document/scenarios.js +17 -0
  585. package/dist/core/document/scenarios.js.map +1 -1
  586. package/dist/core/document/spec.js +4 -11
  587. package/dist/core/document/spec.js.map +1 -1
  588. package/dist/core/envelope/config.js +10 -0
  589. package/dist/core/envelope/config.js.map +1 -1
  590. package/dist/core/envelope/json.js +34 -0
  591. package/dist/core/envelope/json.js.map +1 -1
  592. package/dist/core/explain/families.js +26 -21
  593. package/dist/core/explain/families.js.map +1 -1
  594. package/dist/core/explain/lookup.js +14 -1
  595. package/dist/core/explain/lookup.js.map +1 -1
  596. package/dist/core/explain/refusals.js +5 -5
  597. package/dist/core/explain/refusals.js.map +1 -1
  598. package/dist/core/explain/terms/documents.js +227 -0
  599. package/dist/core/explain/terms/documents.js.map +1 -0
  600. package/dist/core/explain/terms/done-check.js +144 -0
  601. package/dist/core/explain/terms/done-check.js.map +1 -0
  602. package/dist/core/explain/terms/entry.js +14 -0
  603. package/dist/core/explain/terms/entry.js.map +1 -0
  604. package/dist/core/explain/terms/stages.js +71 -0
  605. package/dist/core/explain/terms/stages.js.map +1 -0
  606. package/dist/core/explain/terms/tasks.js +97 -0
  607. package/dist/core/explain/terms/tasks.js.map +1 -0
  608. package/dist/core/explain/terms.js +68 -109
  609. package/dist/core/explain/terms.js.map +1 -1
  610. package/dist/core/explore/explore.js +40 -10
  611. package/dist/core/explore/explore.js.map +1 -1
  612. package/dist/core/fleet-context.js +81 -95
  613. package/dist/core/fleet-context.js.map +1 -1
  614. package/dist/core/gate/checks.js +11 -4
  615. package/dist/core/gate/checks.js.map +1 -1
  616. package/dist/core/gate/partners.js +69 -28
  617. package/dist/core/gate/partners.js.map +1 -1
  618. package/dist/core/gate/report.js.map +1 -1
  619. package/dist/core/gate/verification.js +75 -12
  620. package/dist/core/gate/verification.js.map +1 -1
  621. package/dist/core/gherkin/stale.js +13 -37
  622. package/dist/core/gherkin/stale.js.map +1 -1
  623. package/dist/core/glossary/delta.js +10 -7
  624. package/dist/core/glossary/delta.js.map +1 -1
  625. package/dist/core/glossary/tree.js +6 -19
  626. package/dist/core/glossary/tree.js.map +1 -1
  627. package/dist/core/kernel/concurrency.js +19 -0
  628. package/dist/core/kernel/concurrency.js.map +1 -1
  629. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  630. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  631. package/dist/core/kernel/path-safety.js +38 -0
  632. package/dist/core/kernel/path-safety.js.map +1 -1
  633. package/dist/core/kernel/records.js +11 -0
  634. package/dist/core/kernel/records.js.map +1 -1
  635. package/dist/core/links/backlinks.js +1 -3
  636. package/dist/core/links/backlinks.js.map +1 -1
  637. package/dist/core/links/corpus.js +51 -37
  638. package/dist/core/links/corpus.js.map +1 -1
  639. package/dist/core/links/findings.js.map +1 -1
  640. package/dist/core/links/parse.js +38 -9
  641. package/dist/core/links/parse.js.map +1 -1
  642. package/dist/core/mcp/argv.js +101 -0
  643. package/dist/core/mcp/argv.js.map +1 -1
  644. package/dist/core/mcp/author-tools.js +2 -1
  645. package/dist/core/mcp/author-tools.js.map +1 -1
  646. package/dist/core/mcp/protocol.js +2 -2
  647. package/dist/core/mcp/protocol.js.map +1 -1
  648. package/dist/core/mcp/tools.js +43 -33
  649. package/dist/core/mcp/tools.js.map +1 -1
  650. package/dist/core/openapi/baseline/gate.js +53 -12
  651. package/dist/core/openapi/baseline/gate.js.map +1 -1
  652. package/dist/core/openapi/baseline/plan.js +40 -10
  653. package/dist/core/openapi/baseline/plan.js.map +1 -1
  654. package/dist/core/openapi/baseline/record.js +0 -1
  655. package/dist/core/openapi/baseline/record.js.map +1 -1
  656. package/dist/core/openapi/contract-text.js +33 -0
  657. package/dist/core/openapi/contract-text.js.map +1 -0
  658. package/dist/core/openapi/contract-tree.js +301 -0
  659. package/dist/core/openapi/contract-tree.js.map +1 -0
  660. package/dist/core/openapi/depth.js +38 -24
  661. package/dist/core/openapi/depth.js.map +1 -1
  662. package/dist/core/openapi/digest.js +52 -2
  663. package/dist/core/openapi/digest.js.map +1 -1
  664. package/dist/core/openapi/doc.js +12 -4
  665. package/dist/core/openapi/doc.js.map +1 -1
  666. package/dist/core/openapi/merge/components.js +25 -60
  667. package/dist/core/openapi/merge/components.js.map +1 -1
  668. package/dist/core/openapi/merge/error.js +3 -13
  669. package/dist/core/openapi/merge/error.js.map +1 -1
  670. package/dist/core/openapi/merge/markers.js +26 -30
  671. package/dist/core/openapi/merge/markers.js.map +1 -1
  672. package/dist/core/openapi/merge/merge.js +28 -52
  673. package/dist/core/openapi/merge/merge.js.map +1 -1
  674. package/dist/core/openapi/merge/pin.js +17 -35
  675. package/dist/core/openapi/merge/pin.js.map +1 -1
  676. package/dist/core/openspec/decide/verdict.js.map +1 -1
  677. package/dist/core/openspec/inventory.js +4 -5
  678. package/dist/core/openspec/inventory.js.map +1 -1
  679. package/dist/core/openspec/model/mapping.js +30 -28
  680. package/dist/core/openspec/model/mapping.js.map +1 -1
  681. package/dist/core/openspec/model/model.js +12 -7
  682. package/dist/core/openspec/model/model.js.map +1 -1
  683. package/dist/core/openspec/scan/changes.js +10 -4
  684. package/dist/core/openspec/scan/changes.js.map +1 -1
  685. package/dist/core/openspec/scan/config.js +7 -16
  686. package/dist/core/openspec/scan/config.js.map +1 -1
  687. package/dist/core/openspec/scan/shape.js +63 -19
  688. package/dist/core/openspec/scan/shape.js.map +1 -1
  689. package/dist/core/openspec/scan/walk.js +21 -38
  690. package/dist/core/openspec/scan/walk.js.map +1 -1
  691. package/dist/core/pack/living.js +43 -4
  692. package/dist/core/pack/living.js.map +1 -1
  693. package/dist/core/pack/pack.js +50 -6
  694. package/dist/core/pack/pack.js.map +1 -1
  695. package/dist/core/projection/arch-slice.js +2 -2
  696. package/dist/core/projection/arch-slice.js.map +1 -1
  697. package/dist/core/projection/introduced.js +14 -0
  698. package/dist/core/projection/introduced.js.map +1 -0
  699. package/dist/core/provenance/findings.js +48 -12
  700. package/dist/core/provenance/findings.js.map +1 -1
  701. package/dist/core/provenance/git.js +33 -57
  702. package/dist/core/provenance/git.js.map +1 -1
  703. package/dist/core/provenance/gitq/moves.js +71 -114
  704. package/dist/core/provenance/gitq/moves.js.map +1 -1
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
  707. package/dist/core/provenance/sources.js +23 -6
  708. package/dist/core/provenance/sources.js.map +1 -1
  709. package/dist/core/provenance/stamp.js +5 -17
  710. package/dist/core/provenance/stamp.js.map +1 -1
  711. package/dist/core/repo/authored/paths.js +18 -0
  712. package/dist/core/repo/authored/paths.js.map +1 -1
  713. package/dist/core/repo/entries.js.map +1 -1
  714. package/dist/core/repo/paths.js +92 -6
  715. package/dist/core/repo/paths.js.map +1 -1
  716. package/dist/core/repo/repo.js +74 -14
  717. package/dist/core/repo/repo.js.map +1 -1
  718. package/dist/core/repo/tree/find.js +12 -3
  719. package/dist/core/repo/tree/find.js.map +1 -1
  720. package/dist/core/repo/tree/fs.js +27 -1
  721. package/dist/core/repo/tree/fs.js.map +1 -1
  722. package/dist/core/repo/tree/render/body.js +258 -0
  723. package/dist/core/repo/tree/render/body.js.map +1 -0
  724. package/dist/core/repo/tree/render/projects.js +182 -0
  725. package/dist/core/repo/tree/render/projects.js.map +1 -0
  726. package/dist/core/repo/tree/render/service/header.js +125 -0
  727. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  728. package/dist/core/repo/tree/render/service/peers.js +28 -0
  729. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  730. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  731. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  732. package/dist/core/repo/tree/render/service/views.js +78 -0
  733. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  734. package/dist/core/repo/tree/render/stale.js +42 -0
  735. package/dist/core/repo/tree/render/stale.js.map +1 -0
  736. package/dist/core/repo/tree/render/text.js +84 -0
  737. package/dist/core/repo/tree/render/text.js.map +1 -0
  738. package/dist/core/repo/tree/render/views.js +293 -0
  739. package/dist/core/repo/tree/render/views.js.map +1 -0
  740. package/dist/core/repo/tree/walk.js +53 -32
  741. package/dist/core/repo/tree/walk.js.map +1 -1
  742. package/dist/core/results.js +47 -12
  743. package/dist/core/results.js.map +1 -1
  744. package/dist/core/scaffold/landscape.js +121 -13
  745. package/dist/core/scaffold/landscape.js.map +1 -1
  746. package/dist/core/scaffold/legacy.js +271 -0
  747. package/dist/core/scaffold/legacy.js.map +1 -0
  748. package/dist/core/staging/commit.js +26 -15
  749. package/dist/core/staging/commit.js.map +1 -1
  750. package/dist/core/staging/lock.js +74 -12
  751. package/dist/core/staging/lock.js.map +1 -1
  752. package/dist/core/staging/recovery/intent.js +2 -5
  753. package/dist/core/staging/recovery/intent.js.map +1 -1
  754. package/dist/core/staging/recovery/recover.js +84 -6
  755. package/dist/core/staging/recovery/recover.js.map +1 -1
  756. package/dist/core/staging/snapshot/manifest.js +188 -0
  757. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  758. package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +39 -45
  759. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  760. package/dist/core/staging/txn/forward.js +24 -14
  761. package/dist/core/staging/txn/forward.js.map +1 -1
  762. package/dist/core/staging/writes.js.map +1 -1
  763. package/dist/core/status/actions/execution.js +11 -0
  764. package/dist/core/status/actions/execution.js.map +1 -1
  765. package/dist/core/status/contracts.js +39 -15
  766. package/dist/core/status/contracts.js.map +1 -1
  767. package/dist/core/status/feature/artifacts.js +33 -8
  768. package/dist/core/status/feature/artifacts.js.map +1 -1
  769. package/dist/core/status/feature/feature.js +24 -17
  770. package/dist/core/status/feature/feature.js.map +1 -1
  771. package/dist/core/status/feature/next.js +20 -7
  772. package/dist/core/status/feature/next.js.map +1 -1
  773. package/dist/core/status/feature/words.js +96 -0
  774. package/dist/core/status/feature/words.js.map +1 -0
  775. package/dist/core/status/fleet/fleet.js +43 -14
  776. package/dist/core/status/fleet/fleet.js.map +1 -1
  777. package/dist/core/status/fleet/next.js +153 -58
  778. package/dist/core/status/fleet/next.js.map +1 -1
  779. package/dist/core/status/report.js.map +1 -1
  780. package/dist/core/status/scan.js.map +1 -1
  781. package/dist/core/status/verification.js +30 -15
  782. package/dist/core/status/verification.js.map +1 -1
  783. package/dist/core/tasks/packet.js +199 -0
  784. package/dist/core/tasks/packet.js.map +1 -0
  785. package/dist/core/tasks/record.js +43 -0
  786. package/dist/core/tasks/record.js.map +1 -0
  787. package/dist/core/tasks/sources.js +181 -0
  788. package/dist/core/tasks/sources.js.map +1 -0
  789. package/dist/core/tasks/stamps.js +76 -0
  790. package/dist/core/tasks/stamps.js.map +1 -0
  791. package/dist/core/tasks/unit.js +0 -0
  792. package/dist/core/tasks/unit.js.map +1 -0
  793. package/dist/core/usecases/capability.js +11 -14
  794. package/dist/core/usecases/capability.js.map +1 -1
  795. package/dist/core/usecases/delta/claims.js +31 -7
  796. package/dist/core/usecases/delta/claims.js.map +1 -1
  797. package/dist/core/usecases/delta/flows.js +5 -7
  798. package/dist/core/usecases/delta/flows.js.map +1 -1
  799. package/dist/core/usecases/delta/modified.js +315 -0
  800. package/dist/core/usecases/delta/modified.js.map +1 -0
  801. package/dist/core/usecases/delta/overlay.js +32 -191
  802. package/dist/core/usecases/delta/overlay.js.map +1 -1
  803. package/dist/core/usecases/fleet.js +195 -36
  804. package/dist/core/usecases/fleet.js.map +1 -1
  805. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/capability-tag.js +8 -9
  806. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  807. package/dist/core/usecases/grade/feature.js +88 -0
  808. package/dist/core/usecases/grade/feature.js.map +1 -0
  809. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/requirement-tag.js +3 -4
  810. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  811. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/steps.js +102 -33
  812. package/dist/core/usecases/grade/steps.js.map +1 -0
  813. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/usecases.js +23 -10
  814. package/dist/core/usecases/grade/usecases.js.map +1 -0
  815. package/dist/core/usecases/operations.js +26 -14
  816. package/dist/core/usecases/operations.js.map +1 -1
  817. package/dist/core/usecases/place.js.map +1 -1
  818. package/dist/core/usecases/service/exclude.js +119 -0
  819. package/dist/core/usecases/service/exclude.js.map +1 -0
  820. package/dist/core/usecases/service/flows.js +164 -0
  821. package/dist/core/usecases/service/flows.js.map +1 -0
  822. package/dist/core/usecases/suites/participants.js +83 -0
  823. package/dist/core/usecases/suites/participants.js.map +1 -0
  824. package/dist/core/usecases/suites/suites.js +45 -0
  825. package/dist/core/usecases/suites/suites.js.map +1 -0
  826. package/dist/core/verify/answers.js +12 -5
  827. package/dist/core/verify/answers.js.map +1 -1
  828. package/dist/core/verify/build.js +102 -82
  829. package/dist/core/verify/build.js.map +1 -1
  830. package/dist/core/verify/checklist.js +70 -12
  831. package/dist/core/verify/checklist.js.map +1 -1
  832. package/dist/core/verify/location.js +67 -0
  833. package/dist/core/verify/location.js.map +1 -0
  834. package/dist/core/verify/pins/lint.js +3 -2
  835. package/dist/core/verify/pins/lint.js.map +1 -1
  836. package/dist/core/verify/pins/pin.js +1 -1
  837. package/dist/core/verify/pins/pin.js.map +1 -1
  838. package/dist/core/verify/read/file.js +224 -0
  839. package/dist/core/verify/read/file.js.map +1 -0
  840. package/dist/core/verify/{file.js → read/shape.js} +16 -104
  841. package/dist/core/verify/read/shape.js.map +1 -0
  842. package/dist/core/verify/read/union.js +105 -0
  843. package/dist/core/verify/read/union.js.map +1 -0
  844. package/dist/core/verify/record.js +35 -12
  845. package/dist/core/verify/record.js.map +1 -1
  846. package/dist/core/verify/store/commit.js +40 -30
  847. package/dist/core/verify/store/commit.js.map +1 -1
  848. package/dist/core/verify/store/render.js +8 -4
  849. package/dist/core/verify/store/render.js.map +1 -1
  850. package/dist/core/vocabulary/issue.js +4 -0
  851. package/dist/core/vocabulary/issue.js.map +1 -1
  852. package/dist/core/vocabulary/maturity.js +75 -4
  853. package/dist/core/vocabulary/maturity.js.map +1 -1
  854. package/dist/core/vocabulary/report.js +16 -1
  855. package/dist/core/vocabulary/report.js.map +1 -1
  856. package/examples/README.md +54 -11
  857. package/examples/docs/architecture/landscape.likec4 +62 -6
  858. package/examples/docs/architecture/services.likec4 +70 -0
  859. package/examples/docs/architecture/subsystems.likec4 +7 -0
  860. package/examples/docs/architecture/usecases/order-notification.likec4 +16 -7
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
  863. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +4 -1
  864. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
  865. package/examples/docs/likec4.config.json +0 -1
  866. package/examples/docs/services/checkout-web/model.likec4 +39 -56
  867. package/examples/docs/services/order-service/arch.spec.md +13 -6
  868. package/examples/docs/services/order-service/asyncapi.yaml +3 -2
  869. package/examples/docs/services/order-service/model.likec4 +58 -70
  870. package/examples/docs/services/payment-service/arch.spec.md +7 -4
  871. package/examples/docs/services/payment-service/model.likec4 +38 -37
  872. package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
  873. package/examples/docs/services/platform/identity-service/model.likec4 +35 -37
  874. package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
  875. package/examples/docs/services/platform/notification-service/health.yaml +8 -3
  876. package/examples/docs/services/platform/notification-service/model.likec4 +43 -64
  877. package/package.json +1 -1
  878. package/dist/commands/validate/checks/vocabulary.js +0 -31
  879. package/dist/commands/validate/checks/vocabulary.js.map +0 -1
  880. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +0 -1
  881. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +0 -1
  882. package/dist/commands/validate/fleet/usecases/steps.js.map +0 -1
  883. package/dist/commands/validate/fleet/usecases/usecases.js.map +0 -1
  884. package/dist/core/agent/agents-md/artifacts.js +0 -220
  885. package/dist/core/agent/agents-md/artifacts.js.map +0 -1
  886. package/dist/core/agent/agents-md/cycle.js +0 -165
  887. package/dist/core/agent/agents-md/cycle.js.map +0 -1
  888. package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
  889. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
  890. package/dist/core/agent/agents-md/spine.js +0 -40
  891. package/dist/core/agent/agents-md/spine.js.map +0 -1
  892. package/dist/core/coherence/events/merged.js +0 -40
  893. package/dist/core/coherence/events/merged.js.map +0 -1
  894. package/dist/core/diff/current-state.js +0 -96
  895. package/dist/core/diff/current-state.js.map +0 -1
  896. package/dist/core/diff/victims.js +0 -247
  897. package/dist/core/diff/victims.js.map +0 -1
  898. package/dist/core/repo/tree/views.js +0 -172
  899. package/dist/core/repo/tree/views.js.map +0 -1
  900. package/dist/core/staging/snapshot.js.map +0 -1
  901. package/dist/core/verify/file.js.map +0 -1
@@ -1,19 +1,20 @@
1
1
  /**
2
2
  * Everything that happens to a `TargetReport` around the checks themselves:
3
3
  * how one is built when a target could not be read at all, how a finding's
4
- * evidence is capped, how the set is summed, and how it prints.
4
+ * evidence is capped, and how the set is summed. How it PRINTS is
5
+ * `./render/text.ts`.
5
6
  *
6
7
  * A module rather than the tail of validate.ts because the rollup and the
7
8
  * renderer have to agree. The `--all` footer and the `--json` summary are the
8
- * same `summary()`, and the cap reaches both payloads from one place; a second
9
- * copy of either is how a footer starts printing a number its own findings
10
- * contradict.
9
+ * same `summary()` — computed here once and HANDED to the renderer, which
10
+ * never counts for itself — and the cap reaches both payloads from one place;
11
+ * a second copy of either is how a footer starts printing a number its own
12
+ * findings contradict.
11
13
  */
14
+ import { isAbsolute } from "node:path";
12
15
  import { DocsRepoUnavailableError } from "../../core/repo/state.js";
13
- import { listCodes } from "../../core/explain/lookup.js";
14
- import { countSeverity, subjectsWith, SEVERITY_MARK, } from "../../core/vocabulary/report.js";
15
- import { EXPLAIN_FOOTER, plural } from "../policy/format.js";
16
- import { ADOPTION_AXES, groupedWarnCodes, } from "./fleet/scorecard/adoption.js";
16
+ import { repoPath } from "../../core/envelope/json.js";
17
+ import { countSeverity, subjectsWith, } from "../../core/vocabulary/report.js";
17
18
  export function summary(targets) {
18
19
  return {
19
20
  services: targets.filter((t) => t.kind === "service").length,
@@ -32,10 +33,11 @@ export function summary(targets) {
32
33
  * arch.spec.md both name `sources` raises two findings and is one service) is
33
34
  * `subjectsWith`'s, spelled once for every findings-derived rollup — the
34
35
  * fleet scorecard counts through the same function on the same code, so its
35
- * number and this one are structurally the same number. The code is a LITERAL
36
- * rather than checks/vocabulary.ts's UNVERIFIABLE constant because the
37
- * stable-code collector reads counting sites too, and it refuses a slot it
38
- * cannot read — the collector is also what convicts a typo here.
36
+ * number and this one are structurally the same number. The code is a LITERAL,
37
+ * as it is at the emission site (checks/sources.ts), rather than a shared
38
+ * constant, because the stable-code collector reads counting sites too, and it
39
+ * refuses a slot it cannot read — the collector is also what convicts a typo
40
+ * here.
39
41
  */
40
42
  export function unverifiableSubjects(targets) {
41
43
  return subjectsWith(targets, "sources.unverifiable-from-here");
@@ -78,8 +80,9 @@ export function capDetails(t) {
78
80
  * trace. The failure is real and it is an error, so the run still exits 1; what
79
81
  * changes is that everything else is still graded, and the finding names the
80
82
  * service and the path instead of arriving as the `internal` catch-all.
83
+ * `docsDir` is how it names the path: see `shownPath`.
81
84
  */
82
- export async function guarded(target, run) {
85
+ export async function guarded(target, docsDir, run) {
83
86
  try {
84
87
  return await run();
85
88
  }
@@ -88,8 +91,13 @@ export async function guarded(target, run) {
88
91
  // whole run's, and the action's own catch reports it.
89
92
  if (err instanceof DocsRepoUnavailableError)
90
93
  throw err;
91
- const path = err.path;
92
- const reason = err instanceof Error ? err.message : String(err);
94
+ const abs = err.path;
95
+ const path = abs === undefined ? undefined : shownPath(docsDir, abs);
96
+ // Node spells the same absolute path inside its own message
97
+ // (`EACCES: permission denied, open '…'`), so the reason is respelled
98
+ // with it — otherwise the one finding would name the file twice, two ways.
99
+ const said = err instanceof Error ? err.message : String(err);
100
+ const reason = abs === undefined || path === undefined ? said : said.replaceAll(abs, path);
93
101
  return {
94
102
  kind: target.kind,
95
103
  id: target.id,
@@ -105,6 +113,19 @@ export async function guarded(target, run) {
105
113
  };
106
114
  }
107
115
  }
116
+ /**
117
+ * A path as a finding's message names it: repo-relative and `/`-separated when
118
+ * it is inside the docs repo, so the report reads the same on every machine
119
+ * and in every CI log — an absolute path names the checkout that ran the
120
+ * check, not the file in the repository. A path OUTSIDE the docs repo (a
121
+ * source file in the service repo loam is standing in) keeps its absolute
122
+ * spelling: the `../` route to it depends on where two checkouts happen to
123
+ * sit, which is exactly what a relative path was meant to stop mattering.
124
+ */
125
+ function shownPath(docsDir, abs) {
126
+ const rel = repoPath(docsDir, abs);
127
+ return rel === "" || rel === ".." || rel.startsWith("../") || isAbsolute(rel) ? abs : rel;
128
+ }
108
129
  /**
109
130
  * `target.ambiguous` — the positional named a service AND a feature. The tie is
110
131
  * still broken the way it always was (the feature wins), because changing which
@@ -121,149 +142,4 @@ export function ambiguousTarget(arg, chosen) {
121
142
  `Pass --${other} ${arg} for the other reading.`,
122
143
  };
123
144
  }
124
- /**
125
- * `--errors-only` is a RENDERING lever, the way `--strict` is an exit-code
126
- * lever: neither changes the report, and the `--json` payload is unaffected by
127
- * both. On a fleet of a hundred services the clean run prints several hundred
128
- * `ok` confirmations, and the two warnings that matter are somewhere inside it;
129
- * anyone reading a CI log wants the exceptions, and anyone auditing wants all
130
- * of it. Both are available, from the same run, and neither is the default.
131
- *
132
- * Axis grouping is the same kind of lever, one notch further: warnings whose
133
- * SOLE cause is a fleet-wide not-started axis (the mechanical, fail-closed
134
- * rule in fleet/scorecard/adoption.ts — warn severity, listed code, axis at
135
- * zero) are dropped from the per-target listing and re-stated as one banner
136
- * per axis after the footer. The report, the footer's counts, `--json` and
137
- * `--strict` are all computed from the UNFILTERED findings, so nothing a
138
- * machine or an exit code reads moves by a single bit.
139
- */
140
- export function renderText(targets, opts) {
141
- const { all, errorsOnly, unverifiable } = opts;
142
- // When the fleet-wide "not started" claim is measurable at all — each guard
143
- // fails closed to ungrouped rendering. `!all` is structural, not just the
144
- // call site's promise: the banners print after the footer that only `--all`
145
- // reaches, so grouping outside `--all` would DROP warnings instead of
146
- // moving them — the one thing this lever must never do. `services === 0`
147
- // is the vacuous fleet: with no services every axis is 0 "fleet-wide", and
148
- // a banner over "0 of 0 services" would hide the fleet-level warnings of a
149
- // repo that merely has no fleet yet. And an unreadable service proves
150
- // nothing about what it started: its all-false participation (contracts.ts)
151
- // could MANUFACTURE the very N=0 that licenses suppression — beside an
152
- // error saying that service could not be checked — so one
153
- // `service.unreadable` subject disables grouping for the whole run.
154
- const card = !all ||
155
- opts.scorecard === null ||
156
- opts.scorecard.services === 0 ||
157
- subjectsWith(targets, "service.unreadable") > 0
158
- ? null
159
- : opts.scorecard;
160
- const grouped = card === null ? new Map() : groupedWarnCodes(card.adoption);
161
- const isGrouped = (f) => f.severity === "warn" && grouped.has(f.code);
162
- // The explain pointer follows any report that printed work — a non-ok
163
- // finding, listed or folded under an axis banner. Gated on the UNFILTERED
164
- // findings like every other rollup, so `--errors-only` and grouping cannot
165
- // print codes the pointer then fails to follow. It is computed HERE rather
166
- // than beside the two places it prints because the code column below asks
167
- // the same question and must not walk the findings a second time to answer
168
- // it differently.
169
- const pointer = targets.some((t) => t.findings.some((f) => f.severity !== "ok"));
170
- // The lookup key on the line itself.
171
- //
172
- // Until now a text report printed messages and no codes, so the footer under
173
- // it could only say codes were somewhere else — in `--json`, which a reader
174
- // would have to re-run the whole command to see. The code is what `loam
175
- // explain` takes, what a CI branch tests and what a bug report quotes, and
176
- // withholding it from the one surface a person actually reads made the
177
- // footer's own offer unreachable.
178
- //
179
- // Only where a code is genuinely answerable, and that guard is not
180
- // decoration: a handful of emitted finding codes still have no fix-table row
181
- // (test/explain.test.ts names them), and printing one beside a footer
182
- // promising an explanation would send the reader to a refusal. The set is
183
- // built ONCE per render, and only when something non-ok will be printed:
184
- // `explainSubject` walks the shipped workflow bodies per code (the cost
185
- // `fixesFor` measured from the other side, where a handful of lookups is the
186
- // cheaper shape), while `listCodes()` walks them once for the whole
187
- // vocabulary — and a fleet report has far more finding lines than the fleet
188
- // has distinct codes. Measured: 2.7 ms for all 273 codes, once per report.
189
- const explainable = pointer ? new Set(listCodes().map((listing) => listing.code)) : new Set();
190
- for (const t of targets) {
191
- const shown = t.findings.filter((f) => !isGrouped(f) && (!errorsOnly || f.severity !== "ok"));
192
- if (shown.length === 0)
193
- continue;
194
- // A feature announces itself; a service's findings already carry its name.
195
- if (t.kind === "feature")
196
- console.log(t.id);
197
- let header;
198
- for (const f of shown) {
199
- const hint = f.text ?? {};
200
- if (hint.header && hint.header !== header) {
201
- header = hint.header;
202
- console.log(` ${header}`);
203
- }
204
- // The whole report goes to stdout, in document order. Splitting errors
205
- // onto stderr meant a piped stdout silently lost them from the middle of
206
- // the report and 2>&1 could reorder it; the exit code carries failure,
207
- // and stderr stays reserved for refusals (the fail() path).
208
- const marker = hint.marker === false ? "" : `${SEVERITY_MARK[f.severity]} `;
209
- // `ok` confirmations stay clean, deliberately. A clean fleet run is
210
- // several hundred ✓ lines and two warnings, and a code appended to every
211
- // one of them would cost exactly the signal the exceptions carry — there
212
- // is nothing to look up about a check that passed.
213
- const code = f.severity !== "ok" && explainable.has(f.code) ? ` (${f.code})` : "";
214
- console.log(`${" ".repeat(hint.indent ?? 0)}${marker}${f.message}${code}`);
215
- for (const d of f.details ?? [])
216
- console.log(` ${hint.detailPrefix ?? ""}${d}`);
217
- }
218
- }
219
- if (!all) {
220
- // Without the --all footer there would be nothing at all to print for a
221
- // clean single target under --errors-only — and silence is the one output
222
- // that must never mean "checked, fine".
223
- if (errorsOnly && targets.every((t) => t.findings.every((f) => f.severity === "ok"))) {
224
- console.log(`${targets.map((t) => t.id).join(", ")}: no errors or warnings`);
225
- }
226
- if (pointer)
227
- console.log(`\n${EXPLAIN_FOOTER}`);
228
- return;
229
- }
230
- const s = summary(targets);
231
- console.log(`\n${plural(s.services, "service")}, ${plural(s.features, "feature")} — ` +
232
- `${plural(s.errors, "error")}, ${plural(s.warnings, "warning")}`);
233
- // One line for the whole fleet, never one per service: honest about the blind
234
- // spot without drowning the report in a hundred copies of it.
235
- if (unverifiable > 0) {
236
- const whose = unverifiable === 1 ? "1 service's" : `${unverifiable} services'`;
237
- console.log(`⚠ sources.unverifiable-from-here: ${whose} sources can only be checked from their own repos`);
238
- }
239
- // The axis banners — one per not-started axis that actually grouped a
240
- // warning, in the axes' fixed order, each naming its dropped codes with
241
- // counts. Tallied off the UNFILTERED findings (the same walk the footer
242
- // counts), and printed under --errors-only too: like the footer and the
243
- // unverifiable line this is a rollup, not a finding.
244
- if (card !== null && grouped.size > 0) {
245
- const tally = new Map();
246
- for (const t of targets) {
247
- for (const f of t.findings) {
248
- if (isGrouped(f))
249
- tally.set(f.code, (tally.get(f.code) ?? 0) + 1);
250
- }
251
- }
252
- for (const axis of ADOPTION_AXES) {
253
- // Insertion order of `grouped` is the table's order, so the pairs render
254
- // deterministically across runs and machines.
255
- const pairs = [...grouped]
256
- .filter(([code, a]) => a === axis && (tally.get(code) ?? 0) > 0)
257
- .map(([code]) => [code, tally.get(code) ?? 0]);
258
- if (pairs.length === 0)
259
- continue;
260
- const total = pairs.reduce((n, [, k]) => n + k, 0);
261
- console.log(`⚠ ${axis} axis not started fleet-wide (0 of ${plural(card.services, "service")}), ` +
262
- `expected during staged adoption — ${total} warning(s) grouped: ` +
263
- `${pairs.map(([code, k]) => `${code}×${k}`).join(", ")}; every finding is unchanged in --json`);
264
- }
265
- }
266
- if (pointer)
267
- console.log(`\n${EXPLAIN_FOOTER}`);
268
- }
269
145
  //# sourceMappingURL=report.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/commands/validate/report.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Everything that happens to a `TargetReport` around the checks themselves:\n * how one is built when a target could not be read at all, how a finding's\n * evidence is capped, how the set is summed, and how it prints.\n *\n * A module rather than the tail of validate.ts because the rollup and the\n * renderer have to agree. The `--all` footer and the `--json` summary are the\n * same `summary()`, and the cap reaches both payloads from one place; a second\n * copy of either is how a footer starts printing a number its own findings\n * contradict.\n */\nimport { DocsRepoUnavailableError } from \"../../core/repo/state.js\";\nimport { listCodes } from \"../../core/explain/lookup.js\";\nimport {\n countSeverity,\n subjectsWith,\n SEVERITY_MARK,\n type Finding,\n type TargetReport,\n} from \"../../core/vocabulary/report.js\";\nimport { EXPLAIN_FOOTER, plural } from \"../policy/format.js\";\nimport {\n ADOPTION_AXES,\n groupedWarnCodes,\n type Adoption,\n type AdoptionAxis,\n} from \"./fleet/scorecard/adoption.js\";\n\n/**\n * The rollup `--json` carries and the `--all` footer prints.\n *\n * Four named fields rather than a `Record<string, number>`: the keys ARE the\n * contract, and under an index signature every read of them was an assertion\n * (`s.errors!`) that tsc could not check — rename one and the compiler stayed\n * quiet while the footer printed `undefined errors`.\n */\nexport interface ValidateSummary {\n services: number;\n features: number;\n errors: number;\n warnings: number;\n}\n\nexport function summary(targets: TargetReport[]): ValidateSummary {\n return {\n services: targets.filter((t) => t.kind === \"service\").length,\n features: targets.filter((t) => t.kind === \"feature\").length,\n errors: countSeverity(targets, \"error\"),\n warnings: countSeverity(targets, \"warn\"),\n };\n}\n\n/**\n * How many services this run could not check, for the rollup line and the\n * `--json` payload.\n *\n * Counted off the findings rather than alongside them, so the rollup line\n * and the per-service findings can never disagree about how many services\n * this run could not check. The by-SUBJECT rule (a service whose spec.md and\n * arch.spec.md both name `sources` raises two findings and is one service) is\n * `subjectsWith`'s, spelled once for every findings-derived rollup — the\n * fleet scorecard counts through the same function on the same code, so its\n * number and this one are structurally the same number. The code is a LITERAL\n * rather than checks/vocabulary.ts's UNVERIFIABLE constant because the\n * stable-code collector reads counting sites too, and it refuses a slot it\n * cannot read — the collector is also what convicts a typo here.\n */\nexport function unverifiableSubjects(targets: TargetReport[]): number {\n return subjectsWith(targets, \"sources.unverifiable-from-here\");\n}\n\n/**\n * How many `details` lines any one finding may print before the rest are\n * summarised away.\n *\n * A finding's details are evidence, not a log: LikeC4 reports one syntax error\n * as dozens of cascading diagnostics, and a fleet-sized repo multiplies that by\n * every target that mentions the file. The report is read by a person scrolling\n * a CI log and by an agent with a context window, and neither of them is helped\n * by the four-hundredth copy. The cap is applied to the JSON payload too, on\n * purpose: `--json` is the interface an agent pipes, and an unbounded array is\n * the same denial-of-attention there, just machine-readable.\n */\nconst DETAIL_LIMIT = 10;\n\n/** Truncate every finding's details, marking what was dropped so nothing looks complete when it is not. */\nexport function capDetails(t: TargetReport): TargetReport {\n return {\n ...t,\n findings: t.findings.map((f) => {\n const details = f.details ?? [];\n if (details.length <= DETAIL_LIMIT) return f;\n return {\n ...f,\n details: [...details.slice(0, DETAIL_LIMIT), `… (+${details.length - DETAIL_LIMIT} more)`],\n };\n }),\n };\n}\n\n/**\n * One target's checks, with an IO exception turned into a finding ON that\n * target instead of aborting the run.\n *\n * A fleet gate that dies on the first unreadable file reports nothing about the\n * other ninety-nine services — one bad permission bit, one file that is a\n * dangling symlink, and CI's answer to \"how is the fleet\" becomes a stack\n * trace. The failure is real and it is an error, so the run still exits 1; what\n * changes is that everything else is still graded, and the finding names the\n * service and the path instead of arriving as the `internal` catch-all.\n */\nexport async function guarded(\n target: { kind: \"service\" | \"feature\"; id: string },\n run: () => Promise<TargetReport>,\n): Promise<TargetReport> {\n try {\n return await run();\n } catch (err) {\n // A docs repo that vanished mid-run is not one target's problem — it is the\n // whole run's, and the action's own catch reports it.\n if (err instanceof DocsRepoUnavailableError) throw err;\n const path = (err as NodeJS.ErrnoException).path;\n const reason = err instanceof Error ? err.message : String(err);\n return {\n kind: target.kind,\n id: target.id,\n findings: [\n {\n severity: \"error\",\n code: target.kind === \"service\" ? \"service.unreadable\" : \"feature.unreadable\",\n subject: target.id,\n message:\n `${target.id}: ${path === undefined ? \"an artifact\" : path} could not be read — ` +\n `nothing about this ${target.kind} was checked. ${reason}`,\n },\n ],\n };\n }\n}\n\n/**\n * `target.ambiguous` — the positional named a service AND a feature. The tie is\n * still broken the way it always was (the feature wins), because changing which\n * one is picked would silently re-target every script that relies on it; what\n * is new is that the run says which reading it took and how to force the other.\n */\nexport function ambiguousTarget(arg: string, chosen: \"service\" | \"feature\"): Finding {\n const other = chosen === \"feature\" ? \"service\" : \"feature\";\n return {\n severity: \"warn\",\n code: \"target.ambiguous\",\n subject: arg,\n message:\n `'${arg}' names both a service and a feature — validated as the ${chosen}. ` +\n `Pass --${other} ${arg} for the other reading.`,\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Text renderer */\n/* ------------------------------------------------------------------ */\n\n/** What `renderText` needs of the run beyond the graded targets themselves. */\nexport interface RenderOptions {\n all: boolean;\n errorsOnly: boolean;\n /** The fleet's unverifiable-sources subject count, for the one-line rollup. */\n unverifiable: number;\n /**\n * The run's scorecard facts the renderer reads — ONE field, not a nullable\n * adoption beside a defaulted denominator, so \"adoption without its real\n * denominator\" is not constructible. Null on every single-target run and on\n * an `--all` run whose card failed closed, and null renders exactly as\n * before grouping existed: fail-open to today's behaviour, every warning\n * printed individually.\n */\n scorecard: { readonly adoption: Adoption; readonly services: number } | null;\n}\n\n/**\n * `--errors-only` is a RENDERING lever, the way `--strict` is an exit-code\n * lever: neither changes the report, and the `--json` payload is unaffected by\n * both. On a fleet of a hundred services the clean run prints several hundred\n * `ok` confirmations, and the two warnings that matter are somewhere inside it;\n * anyone reading a CI log wants the exceptions, and anyone auditing wants all\n * of it. Both are available, from the same run, and neither is the default.\n *\n * Axis grouping is the same kind of lever, one notch further: warnings whose\n * SOLE cause is a fleet-wide not-started axis (the mechanical, fail-closed\n * rule in fleet/scorecard/adoption.ts — warn severity, listed code, axis at\n * zero) are dropped from the per-target listing and re-stated as one banner\n * per axis after the footer. The report, the footer's counts, `--json` and\n * `--strict` are all computed from the UNFILTERED findings, so nothing a\n * machine or an exit code reads moves by a single bit.\n */\nexport function renderText(targets: TargetReport[], opts: RenderOptions): void {\n const { all, errorsOnly, unverifiable } = opts;\n // When the fleet-wide \"not started\" claim is measurable at all — each guard\n // fails closed to ungrouped rendering. `!all` is structural, not just the\n // call site's promise: the banners print after the footer that only `--all`\n // reaches, so grouping outside `--all` would DROP warnings instead of\n // moving them — the one thing this lever must never do. `services === 0`\n // is the vacuous fleet: with no services every axis is 0 \"fleet-wide\", and\n // a banner over \"0 of 0 services\" would hide the fleet-level warnings of a\n // repo that merely has no fleet yet. And an unreadable service proves\n // nothing about what it started: its all-false participation (contracts.ts)\n // could MANUFACTURE the very N=0 that licenses suppression — beside an\n // error saying that service could not be checked — so one\n // `service.unreadable` subject disables grouping for the whole run.\n const card =\n !all ||\n opts.scorecard === null ||\n opts.scorecard.services === 0 ||\n subjectsWith(targets, \"service.unreadable\") > 0\n ? null\n : opts.scorecard;\n const grouped = card === null ? new Map<string, AdoptionAxis>() : groupedWarnCodes(card.adoption);\n const isGrouped = (f: Finding): boolean => f.severity === \"warn\" && grouped.has(f.code);\n\n // The explain pointer follows any report that printed work — a non-ok\n // finding, listed or folded under an axis banner. Gated on the UNFILTERED\n // findings like every other rollup, so `--errors-only` and grouping cannot\n // print codes the pointer then fails to follow. It is computed HERE rather\n // than beside the two places it prints because the code column below asks\n // the same question and must not walk the findings a second time to answer\n // it differently.\n const pointer = targets.some((t) => t.findings.some((f) => f.severity !== \"ok\"));\n // The lookup key on the line itself.\n //\n // Until now a text report printed messages and no codes, so the footer under\n // it could only say codes were somewhere else — in `--json`, which a reader\n // would have to re-run the whole command to see. The code is what `loam\n // explain` takes, what a CI branch tests and what a bug report quotes, and\n // withholding it from the one surface a person actually reads made the\n // footer's own offer unreachable.\n //\n // Only where a code is genuinely answerable, and that guard is not\n // decoration: a handful of emitted finding codes still have no fix-table row\n // (test/explain.test.ts names them), and printing one beside a footer\n // promising an explanation would send the reader to a refusal. The set is\n // built ONCE per render, and only when something non-ok will be printed:\n // `explainSubject` walks the shipped workflow bodies per code (the cost\n // `fixesFor` measured from the other side, where a handful of lookups is the\n // cheaper shape), while `listCodes()` walks them once for the whole\n // vocabulary — and a fleet report has far more finding lines than the fleet\n // has distinct codes. Measured: 2.7 ms for all 273 codes, once per report.\n const explainable = pointer ? new Set(listCodes().map((listing) => listing.code)) : new Set<string>();\n for (const t of targets) {\n const shown = t.findings.filter(\n (f) => !isGrouped(f) && (!errorsOnly || f.severity !== \"ok\"),\n );\n if (shown.length === 0) continue;\n // A feature announces itself; a service's findings already carry its name.\n if (t.kind === \"feature\") console.log(t.id);\n let header: string | undefined;\n for (const f of shown) {\n const hint = f.text ?? {};\n if (hint.header && hint.header !== header) {\n header = hint.header;\n console.log(` ${header}`);\n }\n // The whole report goes to stdout, in document order. Splitting errors\n // onto stderr meant a piped stdout silently lost them from the middle of\n // the report and 2>&1 could reorder it; the exit code carries failure,\n // and stderr stays reserved for refusals (the fail() path).\n const marker = hint.marker === false ? \"\" : `${SEVERITY_MARK[f.severity]} `;\n // `ok` confirmations stay clean, deliberately. A clean fleet run is\n // several hundred ✓ lines and two warnings, and a code appended to every\n // one of them would cost exactly the signal the exceptions carry — there\n // is nothing to look up about a check that passed.\n const code = f.severity !== \"ok\" && explainable.has(f.code) ? ` (${f.code})` : \"\";\n console.log(`${\" \".repeat(hint.indent ?? 0)}${marker}${f.message}${code}`);\n for (const d of f.details ?? []) console.log(` ${hint.detailPrefix ?? \"\"}${d}`);\n }\n }\n\n if (!all) {\n // Without the --all footer there would be nothing at all to print for a\n // clean single target under --errors-only — and silence is the one output\n // that must never mean \"checked, fine\".\n if (errorsOnly && targets.every((t) => t.findings.every((f) => f.severity === \"ok\"))) {\n console.log(`${targets.map((t) => t.id).join(\", \")}: no errors or warnings`);\n }\n if (pointer) console.log(`\\n${EXPLAIN_FOOTER}`);\n return;\n }\n const s = summary(targets);\n console.log(\n `\\n${plural(s.services, \"service\")}, ${plural(s.features, \"feature\")} — ` +\n `${plural(s.errors, \"error\")}, ${plural(s.warnings, \"warning\")}`,\n );\n // One line for the whole fleet, never one per service: honest about the blind\n // spot without drowning the report in a hundred copies of it.\n if (unverifiable > 0) {\n const whose = unverifiable === 1 ? \"1 service's\" : `${unverifiable} services'`;\n console.log(\n `⚠ sources.unverifiable-from-here: ${whose} sources can only be checked from their own repos`,\n );\n }\n // The axis banners — one per not-started axis that actually grouped a\n // warning, in the axes' fixed order, each naming its dropped codes with\n // counts. Tallied off the UNFILTERED findings (the same walk the footer\n // counts), and printed under --errors-only too: like the footer and the\n // unverifiable line this is a rollup, not a finding.\n if (card !== null && grouped.size > 0) {\n const tally = new Map<string, number>();\n for (const t of targets) {\n for (const f of t.findings) {\n if (isGrouped(f)) tally.set(f.code, (tally.get(f.code) ?? 0) + 1);\n }\n }\n for (const axis of ADOPTION_AXES) {\n // Insertion order of `grouped` is the table's order, so the pairs render\n // deterministically across runs and machines.\n const pairs = [...grouped]\n .filter(([code, a]) => a === axis && (tally.get(code) ?? 0) > 0)\n .map(([code]) => [code, tally.get(code) ?? 0] as const);\n if (pairs.length === 0) continue;\n const total = pairs.reduce((n, [, k]) => n + k, 0);\n console.log(\n `⚠ ${axis} axis not started fleet-wide (0 of ${plural(card.services, \"service\")}), ` +\n `expected during staged adoption — ${total} warning(s) grouped: ` +\n `${pairs.map(([code, k]) => `${code}×${k}`).join(\", \")}; every finding is unchanged in --json`,\n );\n }\n }\n if (pointer) console.log(`\\n${EXPLAIN_FOOTER}`);\n}\n"]}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/commands/validate/report.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Everything that happens to a `TargetReport` around the checks themselves:\n * how one is built when a target could not be read at all, how a finding's\n * evidence is capped, and how the set is summed. How it PRINTS is\n * `./render/text.ts`.\n *\n * A module rather than the tail of validate.ts because the rollup and the\n * renderer have to agree. The `--all` footer and the `--json` summary are the\n * same `summary()` — computed here once and HANDED to the renderer, which\n * never counts for itself — and the cap reaches both payloads from one place;\n * a second copy of either is how a footer starts printing a number its own\n * findings contradict.\n */\nimport { isAbsolute } from \"node:path\";\nimport { DocsRepoUnavailableError } from \"../../core/repo/state.js\";\nimport { repoPath } from \"../../core/envelope/json.js\";\nimport {\n countSeverity,\n subjectsWith,\n type Finding,\n type TargetReport,\n} from \"../../core/vocabulary/report.js\";\n\n/**\n * The rollup `--json` carries and the `--all` footer prints.\n *\n * Four named fields rather than a `Record<string, number>`: the keys ARE the\n * contract, and under an index signature every read of them was an assertion\n * (`s.errors!`) that tsc could not check — rename one and the compiler stayed\n * quiet while the footer printed `undefined errors`.\n */\nexport interface ValidateSummary {\n services: number;\n features: number;\n errors: number;\n warnings: number;\n}\n\nexport function summary(targets: TargetReport[]): ValidateSummary {\n return {\n services: targets.filter((t) => t.kind === \"service\").length,\n features: targets.filter((t) => t.kind === \"feature\").length,\n errors: countSeverity(targets, \"error\"),\n warnings: countSeverity(targets, \"warn\"),\n };\n}\n\n/**\n * How many services this run could not check, for the rollup line and the\n * `--json` payload.\n *\n * Counted off the findings rather than alongside them, so the rollup line\n * and the per-service findings can never disagree about how many services\n * this run could not check. The by-SUBJECT rule (a service whose spec.md and\n * arch.spec.md both name `sources` raises two findings and is one service) is\n * `subjectsWith`'s, spelled once for every findings-derived rollup — the\n * fleet scorecard counts through the same function on the same code, so its\n * number and this one are structurally the same number. The code is a LITERAL,\n * as it is at the emission site (checks/sources.ts), rather than a shared\n * constant, because the stable-code collector reads counting sites too, and it\n * refuses a slot it cannot read — the collector is also what convicts a typo\n * here.\n */\nexport function unverifiableSubjects(targets: TargetReport[]): number {\n return subjectsWith(targets, \"sources.unverifiable-from-here\");\n}\n\n/**\n * How many `details` lines any one finding may print before the rest are\n * summarised away.\n *\n * A finding's details are evidence, not a log: LikeC4 reports one syntax error\n * as dozens of cascading diagnostics, and a fleet-sized repo multiplies that by\n * every target that mentions the file. The report is read by a person scrolling\n * a CI log and by an agent with a context window, and neither of them is helped\n * by the four-hundredth copy. The cap is applied to the JSON payload too, on\n * purpose: `--json` is the interface an agent pipes, and an unbounded array is\n * the same denial-of-attention there, just machine-readable.\n */\nconst DETAIL_LIMIT = 10;\n\n/** Truncate every finding's details, marking what was dropped so nothing looks complete when it is not. */\nexport function capDetails(t: TargetReport): TargetReport {\n return {\n ...t,\n findings: t.findings.map((f) => {\n const details = f.details ?? [];\n if (details.length <= DETAIL_LIMIT) return f;\n return {\n ...f,\n details: [...details.slice(0, DETAIL_LIMIT), `… (+${details.length - DETAIL_LIMIT} more)`],\n };\n }),\n };\n}\n\n/**\n * One target's checks, with an IO exception turned into a finding ON that\n * target instead of aborting the run.\n *\n * A fleet gate that dies on the first unreadable file reports nothing about the\n * other ninety-nine services — one bad permission bit, one file that is a\n * dangling symlink, and CI's answer to \"how is the fleet\" becomes a stack\n * trace. The failure is real and it is an error, so the run still exits 1; what\n * changes is that everything else is still graded, and the finding names the\n * service and the path instead of arriving as the `internal` catch-all.\n * `docsDir` is how it names the path: see `shownPath`.\n */\nexport async function guarded(\n target: { kind: \"service\" | \"feature\"; id: string },\n docsDir: string,\n run: () => Promise<TargetReport>,\n): Promise<TargetReport> {\n try {\n return await run();\n } catch (err) {\n // A docs repo that vanished mid-run is not one target's problem — it is the\n // whole run's, and the action's own catch reports it.\n if (err instanceof DocsRepoUnavailableError) throw err;\n const abs = (err as NodeJS.ErrnoException).path;\n const path = abs === undefined ? undefined : shownPath(docsDir, abs);\n // Node spells the same absolute path inside its own message\n // (`EACCES: permission denied, open '…'`), so the reason is respelled\n // with it — otherwise the one finding would name the file twice, two ways.\n const said = err instanceof Error ? err.message : String(err);\n const reason = abs === undefined || path === undefined ? said : said.replaceAll(abs, path);\n return {\n kind: target.kind,\n id: target.id,\n findings: [\n {\n severity: \"error\",\n code: target.kind === \"service\" ? \"service.unreadable\" : \"feature.unreadable\",\n subject: target.id,\n message:\n `${target.id}: ${path === undefined ? \"an artifact\" : path} could not be read — ` +\n `nothing about this ${target.kind} was checked. ${reason}`,\n },\n ],\n };\n }\n}\n\n/**\n * A path as a finding's message names it: repo-relative and `/`-separated when\n * it is inside the docs repo, so the report reads the same on every machine\n * and in every CI log — an absolute path names the checkout that ran the\n * check, not the file in the repository. A path OUTSIDE the docs repo (a\n * source file in the service repo loam is standing in) keeps its absolute\n * spelling: the `../` route to it depends on where two checkouts happen to\n * sit, which is exactly what a relative path was meant to stop mattering.\n */\nfunction shownPath(docsDir: string, abs: string): string {\n const rel = repoPath(docsDir, abs);\n return rel === \"\" || rel === \"..\" || rel.startsWith(\"../\") || isAbsolute(rel) ? abs : rel;\n}\n\n/**\n * `target.ambiguous` — the positional named a service AND a feature. The tie is\n * still broken the way it always was (the feature wins), because changing which\n * one is picked would silently re-target every script that relies on it; what\n * is new is that the run says which reading it took and how to force the other.\n */\nexport function ambiguousTarget(arg: string, chosen: \"service\" | \"feature\"): Finding {\n const other = chosen === \"feature\" ? \"service\" : \"feature\";\n return {\n severity: \"warn\",\n code: \"target.ambiguous\",\n subject: arg,\n message:\n `'${arg}' names both a service and a feature — validated as the ${chosen}. ` +\n `Pass --${other} ${arg} for the other reading.`,\n };\n}\n"]}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * What a `--base` run does to the landscape target, which is the one target
3
+ * whose subject is not a directory.
4
+ *
5
+ * Every other target is graded whole or not at all: a service or a feature the
6
+ * branch touched is graded by exactly the checks `--all` runs on it. The
7
+ * landscape cannot be, for two reasons that pull in opposite directions, and
8
+ * both are defects a docs-repo PR gate actually shipped with.
9
+ *
10
+ * IT GRADED TOO MUCH. The landscape target carries the fleet-wide
11
+ * vocabularies' warnings — a permission nobody requires, a capability nobody
12
+ * realizes, an obligation nobody applies, a glossary term nobody cites — and
13
+ * the AGENTS.md stamp. Every one of those grades a file other than the map, so
14
+ * any `architecture/` branch re-graded all of them, and under `--strict` a
15
+ * one-line map edit on the adopted example fleet went red on four warnings that
16
+ * were all there at the base. Those findings now ride a scoped run only when the
17
+ * file that carries them changed.
18
+ *
19
+ * IT GRADED TOO LITTLE. `spine.op-undefined` is graded on the PROVIDER's
20
+ * service target, so an edge the branch drew or re-spelled on the map was
21
+ * graded by no scoped run unless the provider happened to change too —
22
+ * README's own `authorisePayment` example merged green through both PR gates.
23
+ * Those edges are now graded here, against their providers' contracts, and
24
+ * ONLY those edges: pulling the provider into scope instead would grade every
25
+ * document it already has, which on a spine-first fleet means
26
+ * `service.no-model` reddening exactly the labour that path asks for.
27
+ */
28
+ import { existsSync } from "node:fs";
29
+ import { serviceResolver } from "../../core/c4/resolve/service.js";
30
+ import { edgeKey } from "../../core/diff/scope/edges.js";
31
+ import { touched } from "../../core/diff/scope/changed-paths.js";
32
+ import { repoPath } from "../../core/envelope/json.js";
33
+ import { inOrder } from "../../core/kernel/concurrency.js";
34
+ import { serviceTreePath } from "../../core/kernel/ids/dirs.js";
35
+ import { readOpenapi } from "../../core/openapi/doc.js";
36
+ import { capabilityDocsDir, glossaryDir } from "../../core/repo/authored/paths.js";
37
+ import { agentsPath, capabilitiesPath, obligationsPath, permissionsPath, servicePathsAt } from "../../core/repo/paths.js";
38
+ import { contractOf } from "./service/api.js";
39
+ import { spineFindings } from "./service/spine.js";
40
+ /**
41
+ * The landscape target's findings that grade a file other than the map, with
42
+ * the file — or directory — that carries each.
43
+ *
44
+ * Only the families that are a VERDICT ON THAT FILE are listed: the vocabulary
45
+ * that does not read, and the declaration nothing cites. The obligation codes
46
+ * the MAP causes stay off this table — `obligation.unknown` (a tag naming no
47
+ * rule) and `obligation.uncovered` (an applied rule no requirement covers) are
48
+ * written by an edit to `architecture/`, and a scoped run over that edit owes
49
+ * them. A code on no row rides the landscape target exactly as before.
50
+ *
51
+ * What this costs, said once: the "nothing cites it" grades also move when a
52
+ * CITATION goes away — a branch deleting the last `Requires:` line naming a
53
+ * permission. A branch that touches only a service never graded the landscape
54
+ * at all, so that is not a new blind spot; the unscoped `validate --all` keeps
55
+ * reporting every one of these.
56
+ */
57
+ const CARRIED = [
58
+ { carries: (code) => code.startsWith("permissions."), by: (d) => [permissionsPath(d)] },
59
+ { carries: (code) => code.startsWith("capability."), by: (d) => [capabilitiesPath(d), capabilityDocsDir(d)] },
60
+ { carries: (code) => code === "obligation.invalid" || code === "obligation.unapplied", by: (d) => [obligationsPath(d)] },
61
+ { carries: (code) => code.startsWith("glossary."), by: (d) => [glossaryDir(d)] },
62
+ // The stamp is a fact about which binary wrote the file, and a branch that
63
+ // did not edit the file did not move it — `loam doctor` is where a binary
64
+ // upgrade is noticed, not every map PR that happens to follow one.
65
+ { carries: (code) => code === "agents.stale" || code === "docs.binary-behind", by: (d) => [agentsPath(d)] },
66
+ ];
67
+ /** The landscape target's `findings` as a `--base` run reports them. */
68
+ export async function scopedLandscapeFindings(findings, scoped) {
69
+ const { docsDir, scope } = scoped;
70
+ const kept = findings.filter((f) => {
71
+ const carried = CARRIED.find((row) => row.carries(f.code));
72
+ return carried === undefined || carried.by(docsDir).some((abs) => touched(scope, repoPath(docsDir, abs)));
73
+ });
74
+ return [...kept, ...(await changedEdgeFindings(scoped))];
75
+ }
76
+ /**
77
+ * The spine of the edges this branch wrote, graded per provider by the
78
+ * service target's own `spineFindings` over just those edges — so a changed
79
+ * edge reads exactly as it would on the provider's target, and an unreadable
80
+ * or absent contract proves nothing here for the reason it proves nothing
81
+ * there.
82
+ *
83
+ * A provider the run already grades is skipped: its own target walks every
84
+ * inbound edge, these included, and grading them twice would report one broken
85
+ * join as two.
86
+ */
87
+ async function changedEdgeFindings(scoped) {
88
+ const { docsDir, scope, land, services, fleet } = scoped;
89
+ // A map that does not parse has no edges to read, and `landscape.invalid`
90
+ // on this same target already says so.
91
+ if (land === null || land.errors.length > 0 || scope.edges.size === 0)
92
+ return [];
93
+ const svcOf = serviceResolver(land.elements, new Set(services.map((s) => s.id)));
94
+ const providerOf = (target) => svcOf(target);
95
+ const edges = land.relationships.filter((r) => scope.edges.has(edgeKey(r)));
96
+ const graded = new Set(scope.services.map((s) => s.id));
97
+ const providers = services.filter((s) => !graded.has(s.id) && edges.some((r) => providerOf(r.target) === s.id));
98
+ const perProvider = await inOrder(providers, async (svc) => {
99
+ const paths = servicePathsAt(svc.dir);
100
+ return spineFindings({
101
+ service: svc.id,
102
+ docsDir,
103
+ treePath: serviceTreePath(svc),
104
+ me: svc.id,
105
+ land: { ...land, relationships: edges.filter((r) => providerOf(r.target) === svc.id) },
106
+ landSvcOf: svcOf,
107
+ contract: contractOf(await readOpenapi(paths.openapi, fleet), !existsSync(paths.openapi)),
108
+ landscapeReported: true,
109
+ });
110
+ });
111
+ return perProvider.flat();
112
+ }
113
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../../../src/commands/validate/scope.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What a `--base` run does to the landscape target, which is the one target\n * whose subject is not a directory.\n *\n * Every other target is graded whole or not at all: a service or a feature the\n * branch touched is graded by exactly the checks `--all` runs on it. The\n * landscape cannot be, for two reasons that pull in opposite directions, and\n * both are defects a docs-repo PR gate actually shipped with.\n *\n * IT GRADED TOO MUCH. The landscape target carries the fleet-wide\n * vocabularies' warnings — a permission nobody requires, a capability nobody\n * realizes, an obligation nobody applies, a glossary term nobody cites — and\n * the AGENTS.md stamp. Every one of those grades a file other than the map, so\n * any `architecture/` branch re-graded all of them, and under `--strict` a\n * one-line map edit on the adopted example fleet went red on four warnings that\n * were all there at the base. Those findings now ride a scoped run only when the\n * file that carries them changed.\n *\n * IT GRADED TOO LITTLE. `spine.op-undefined` is graded on the PROVIDER's\n * service target, so an edge the branch drew or re-spelled on the map was\n * graded by no scoped run unless the provider happened to change too —\n * README's own `authorisePayment` example merged green through both PR gates.\n * Those edges are now graded here, against their providers' contracts, and\n * ONLY those edges: pulling the provider into scope instead would grade every\n * document it already has, which on a spine-first fleet means\n * `service.no-model` reddening exactly the labour that path asks for.\n */\nimport { existsSync } from \"node:fs\";\nimport { serviceResolver } from \"../../core/c4/resolve/service.js\";\nimport type { LoadedDoc } from \"../../core/c4/likec4.js\";\nimport { edgeKey } from \"../../core/diff/scope/edges.js\";\nimport { touched, type ValidateScope } from \"../../core/diff/scope/changed-paths.js\";\nimport { repoPath } from \"../../core/envelope/json.js\";\nimport type { FleetContext } from \"../../core/fleet-context.js\";\nimport { inOrder } from \"../../core/kernel/concurrency.js\";\nimport { serviceTreePath, type DocsDir } from \"../../core/kernel/ids/dirs.js\";\nimport { readOpenapi } from \"../../core/openapi/doc.js\";\nimport { capabilityDocsDir, glossaryDir } from \"../../core/repo/authored/paths.js\";\nimport type { ServiceEntry } from \"../../core/repo/entries.js\";\nimport { agentsPath, capabilitiesPath, obligationsPath, permissionsPath, servicePathsAt } from \"../../core/repo/paths.js\";\nimport type { Finding } from \"../../core/vocabulary/report.js\";\nimport { contractOf } from \"./service/api.js\";\nimport { spineFindings } from \"./service/spine.js\";\n\n/**\n * The landscape target's findings that grade a file other than the map, with\n * the file — or directory — that carries each.\n *\n * Only the families that are a VERDICT ON THAT FILE are listed: the vocabulary\n * that does not read, and the declaration nothing cites. The obligation codes\n * the MAP causes stay off this table — `obligation.unknown` (a tag naming no\n * rule) and `obligation.uncovered` (an applied rule no requirement covers) are\n * written by an edit to `architecture/`, and a scoped run over that edit owes\n * them. A code on no row rides the landscape target exactly as before.\n *\n * What this costs, said once: the \"nothing cites it\" grades also move when a\n * CITATION goes away — a branch deleting the last `Requires:` line naming a\n * permission. A branch that touches only a service never graded the landscape\n * at all, so that is not a new blind spot; the unscoped `validate --all` keeps\n * reporting every one of these.\n */\nconst CARRIED: readonly { carries: (code: string) => boolean; by: (docsDir: DocsDir) => string[] }[] = [\n { carries: (code) => code.startsWith(\"permissions.\"), by: (d) => [permissionsPath(d)] },\n { carries: (code) => code.startsWith(\"capability.\"), by: (d) => [capabilitiesPath(d), capabilityDocsDir(d)] },\n { carries: (code) => code === \"obligation.invalid\" || code === \"obligation.unapplied\", by: (d) => [obligationsPath(d)] },\n { carries: (code) => code.startsWith(\"glossary.\"), by: (d) => [glossaryDir(d)] },\n // The stamp is a fact about which binary wrote the file, and a branch that\n // did not edit the file did not move it — `loam doctor` is where a binary\n // upgrade is noticed, not every map PR that happens to follow one.\n { carries: (code) => code === \"agents.stale\" || code === \"docs.binary-behind\", by: (d) => [agentsPath(d)] },\n];\n\n/** What the scoped landscape grade needs from the run. */\nexport interface ScopedLandscape {\n docsDir: DocsDir;\n scope: ValidateScope;\n /** The parsed `architecture/` project, or null when the repo draws no fleet. */\n land: LoadedDoc | null;\n /** The run's FULL service enumeration: a changed edge's provider is found here whether or not it is in scope. */\n services: readonly ServiceEntry[];\n fleet: FleetContext;\n}\n\n/** The landscape target's `findings` as a `--base` run reports them. */\nexport async function scopedLandscapeFindings(findings: Finding[], scoped: ScopedLandscape): Promise<Finding[]> {\n const { docsDir, scope } = scoped;\n const kept = findings.filter((f) => {\n const carried = CARRIED.find((row) => row.carries(f.code));\n return carried === undefined || carried.by(docsDir).some((abs) => touched(scope, repoPath(docsDir, abs)));\n });\n return [...kept, ...(await changedEdgeFindings(scoped))];\n}\n\n/**\n * The spine of the edges this branch wrote, graded per provider by the\n * service target's own `spineFindings` over just those edges — so a changed\n * edge reads exactly as it would on the provider's target, and an unreadable\n * or absent contract proves nothing here for the reason it proves nothing\n * there.\n *\n * A provider the run already grades is skipped: its own target walks every\n * inbound edge, these included, and grading them twice would report one broken\n * join as two.\n */\nasync function changedEdgeFindings(scoped: ScopedLandscape): Promise<Finding[]> {\n const { docsDir, scope, land, services, fleet } = scoped;\n // A map that does not parse has no edges to read, and `landscape.invalid`\n // on this same target already says so.\n if (land === null || land.errors.length > 0 || scope.edges.size === 0) return [];\n const svcOf = serviceResolver(land.elements, new Set(services.map((s) => s.id)));\n const providerOf = (target: string): string => svcOf(target);\n const edges = land.relationships.filter((r) => scope.edges.has(edgeKey(r)));\n const graded = new Set(scope.services.map((s) => s.id));\n const providers = services.filter((s) => !graded.has(s.id) && edges.some((r) => providerOf(r.target) === s.id));\n const perProvider = await inOrder(providers, async (svc) => {\n const paths = servicePathsAt(svc.dir);\n return spineFindings({\n service: svc.id,\n docsDir,\n treePath: serviceTreePath(svc),\n me: svc.id,\n land: { ...land, relationships: edges.filter((r) => providerOf(r.target) === svc.id) },\n landSvcOf: svcOf,\n contract: contractOf(await readOpenapi(paths.openapi, fleet), !existsSync(paths.openapi)),\n landscapeReported: true,\n });\n });\n return perProvider.flat();\n}\n"]}