@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"covers-after.js","sourceRoot":"","sources":["../../../../src/commands/validate/coverage/covers-after.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A feature's `Covers:` lines, read in the id space they will LIVE in.\n *\n * Feature scope used to resolve an arch delta's `Covers:` entries against the\n * delta's own elements plus the living landscape (`../arch-coverage.ts`), and\n * living scope resolves them against the service's model plus the map\n * (`../service/specs.ts`). The two spaces are not the same. A delta re-declares\n * the elements its edges attach to wherever its author writes them, so a stub\n * `orderService` the living map nests as `marketplace.orderService` gave the\n * line `Covers: orderService -> notificationService` a match at feature scope\n * and `covers.unknown` the moment the archive landed it — and the\n * `c4.uncovered` hint had recommended exactly that delta id (the real-fleet\n * review, 2026-10-21). The landscape merge splices a stub's NEW children under\n * the living element it binds to, so a child's id changes with its parent's.\n *\n * WHAT SURVIVES, cheapest proof first. A service name survives both scopes —\n * the binding is spliced verbatim — so an entry naming services only is\n * settled without reading anything. So is one the living map and the service's\n * own model already answer. Only an entry that resolved through the delta's own\n * ids is then asked of the map the merge would leave, staged with the\n * archive's own function (`core/c4/project/staged.ts`) and parsed once per\n * feature, lazily: that is a LikeC4 workspace spin, and the clean path never\n * pays it. Where the preview cannot be had — no landscape, a merge the archive\n * refuses, a living document that does not parse — the entry is let stand:\n * those are other findings' to report, and grading a line against a map\n * nobody could read is the cascade `covers.unknown` already refuses\n * (`../service/specs.ts`).\n *\n * The same preview names the post-merge id of a NEW element that stands for\n * no service, which is what a `c4.uncovered` hint must offer for it: an element\n * that IS a service is offered by name, and an edge always by its endpoints'\n * service names, the one spelling that resolves in both scopes.\n */\nimport type { Elem, LoadedDoc, Rel } from \"../../../core/c4/likec4.js\";\nimport { entryResolves, parseCoversEntry, type CoverageScope, type CoversEntry } from \"../../../core/c4/arch.js\";\nimport { stageMergedProject } from \"../../../core/c4/project/staged.js\";\nimport { elementService, serviceResolver } from \"../../../core/c4/resolve/service.js\";\nimport type { Requirement } from \"../../../core/document/spec.js\";\nimport type { FleetContext } from \"../../../core/fleet-context.js\";\nimport type { DocsDir, FeatureDir } from \"../../../core/kernel/ids/dirs.js\";\nimport type { Finding } from \"../../../core/vocabulary/report.js\";\n\n/** The map the merge would leave, parsed, with its own element→service resolver. */\nexport interface MergedMap {\n doc: LoadedDoc;\n svcOf: (id: string) => string;\n}\n\n/** What the preview is computed from. */\nexport interface MergeSource {\n docsDir: DocsDir;\n featureDir: FeatureDir;\n featureId: string;\n fleet: FleetContext;\n /** The enumerated fleet plus the feature's own services — the resolver's set. */\n known: ReadonlySet<string>;\n}\n\n/**\n * The post-merge map, computed at most once and only when asked — `null` when\n * it cannot be had. Pre-routing on purpose (no extending models passed): an\n * addition the archive routes into a service's model keeps the fqn it has on\n * the map, and living scope reads model and map as one corpus, so the\n * pre-routing preview holds every id a `Covers:` line can name after archive.\n */\nexport function mergedMapOf(source: MergeSource): () => Promise<MergedMap | null> {\n let merged: Promise<MergedMap | null> | undefined;\n return () =>\n (merged ??= (async () => {\n const staged = await stageMergedProject({\n docsDir: source.docsDir,\n featureDir: source.featureDir,\n featureId: source.featureId,\n documents: [],\n load: (path) => source.fleet.loadLikeC4(path),\n });\n return staged.kind === \"read\" ? { doc: staged.doc, svcOf: serviceResolver(staged.doc.elements, source.known) } : null;\n })());\n}\n\n/**\n * The `Covers:` spelling for a new element that still resolves once it is\n * living: the service it stands for, else the id the merge gives it — matched in\n * the preview by kind, title and owning service, and offered only when exactly\n * one element answers. The delta's own id is the fallback, never a guess.\n */\nexport async function survivingElementCover(\n e: Elem,\n delta: { svcOf: (id: string) => string; known: ReadonlySet<string> },\n merged: () => Promise<MergedMap | null>,\n): Promise<string> {\n // An explicit binding is spliced verbatim, and living scope matches an\n // element entry by it (`namesElement`), so it survives whether or not the\n // service has a directory yet; a title only where it names a known service.\n const service = elementService(e);\n if (e.service !== undefined || delta.known.has(service)) return service;\n const map = await merged();\n if (map === null) return e.id;\n const owner = delta.svcOf(e.id);\n const [landed, ...others] = map.doc.elements.filter((m) => m.kind === e.kind && m.title === e.title && map.svcOf(m.id) === owner);\n return landed !== undefined && others.length === 0 ? landed.id : e.id;\n}\n\n/** The `Covers:` spelling for a new edge — its endpoints' service names, which both scopes resolve alike. */\nexport function survivingEdgeCover(r: Rel, svcOf: (id: string) => string): string {\n return `${svcOf(r.source)} -> ${svcOf(r.target)}`;\n}\n\n/** One arch delta's lines, and the scopes they are read in. */\nexport interface DeltaSpelledInput {\n service: string;\n reqs: Requirement[];\n /** The scope feature validation has always used — delta, living map, model where widened, health. */\n featureScope: CoverageScope;\n /** The living map's elements and edges — what the merge keeps whatever it adds. */\n living: { elements: Elem[]; relationships: Rel[] };\n /** The service's own model, read lazily; empty when there is none or it does not read. */\n model: () => Promise<{ elements: Elem[]; relationships: Rel[] }>;\n /** The delta's elements and resolver, for the spelling a finding offers instead. */\n elements: Elem[];\n svcOf: (id: string) => string;\n merged: () => Promise<MergedMap | null>;\n}\n\n/** Does every element name this entry spells belong to a service? Then it is settled — names survive the merge. */\nfunction namesServicesOnly(entry: CoversEntry, known: ReadonlySet<string>): boolean {\n if (entry.form === \"element\") return known.has(entry.id);\n if (entry.form === \"edge\") return known.has(entry.source) && known.has(entry.target);\n return true;\n}\n\n/**\n * `covers.unknown` for the entries feature scope resolves only through the\n * delta's own ids, which the map the merge leaves does not declare. Entries\n * that resolve nowhere are `coversUnknownFindings`' to report, so they are\n * skipped here: one breach, one finding.\n */\nexport async function deltaSpelledCovers(input: DeltaSpelledInput): Promise<Finding[]> {\n const { service, featureScope } = input;\n const known = featureScope.known ?? new Set<string>();\n const out: Finding[] = [];\n for (const r of input.reqs) {\n if (r.kind === \"REMOVED\") continue;\n for (const raw of r.covers) {\n const entry = parseCoversEntry(raw);\n if (entry.form !== \"element\" && entry.form !== \"edge\") continue;\n if (!entryResolves(entry, featureScope) || namesServicesOnly(entry, known)) continue;\n const model = await input.model();\n const after = (elements: Elem[], relationships: Rel[]): CoverageScope => ({\n ...featureScope,\n elements: [...elements, ...model.elements],\n relationships: [...relationships, ...model.relationships],\n });\n if (entryResolves(entry, after(input.living.elements, input.living.relationships))) continue;\n const map = await input.merged();\n if (map === null || entryResolves(entry, after(map.doc.elements, map.doc.relationships))) continue;\n const declared = entry.form === \"element\" ? input.elements.find((e) => e.id === entry.id) : undefined;\n const named =\n entry.form === \"edge\"\n ? `${input.svcOf(entry.source)} -> ${input.svcOf(entry.target)}`\n : declared === undefined\n ? entry.id\n : await survivingElementCover(declared, { svcOf: input.svcOf, known }, input.merged);\n out.push({\n severity: \"warn\",\n code: \"covers.unknown\",\n subject: service,\n message:\n `${service}: arch.spec.md: requirement '${r.name}' — Covers: '${raw}' resolves only through this ` +\n `feature's delta.likec4, whose ids are its own spelling: the map this merge leaves declares no such ` +\n `${entry.form === \"edge\" ? \"edge\" : \"element\"}, so the next \\`loam validate --all\\` reports covers.unknown ` +\n `on it. Name it the way the living map does — '${named}' resolves in both`,\n });\n }\n }\n return out;\n}\n"]}
@@ -12,8 +12,7 @@
12
12
  * new architecture — is `./arch-coverage.js`.
13
13
  */
14
14
  import { existsSync } from "node:fs";
15
- import { readFile } from "node:fs/promises";
16
- import { loadFile } from "../../core/c4/likec4.js";
15
+ import {} from "../../core/c4/likec4.js";
17
16
  import { elementService } from "../../core/c4/resolve/service.js";
18
17
  import {} from "../../core/kernel/ids/service.js";
19
18
  import {} from "../../core/repo/entries.js";
@@ -22,21 +21,19 @@ import { enumeratedServiceIds } from "../../core/repo/service-target.js";
22
21
  import { docsRepoState } from "../../core/repo/state.js";
23
22
  import { featureSpecServices, listServices } from "../../core/repo/repo.js";
24
23
  import {} from "../../core/vocabulary/report.js";
25
- import { parseRequirements } from "../../core/document/parse.js";
26
- import { assertionlessFindings, examplesFindings, steplessFindings, } from "../../core/document/scenarios.js";
27
24
  import {} from "../../core/document/spec.js";
28
25
  import { featureCoherence } from "../../core/coherence/coherence.js";
29
26
  import { deltaServiceUnknownFinding, invalidSpecServiceFindings, } from "../../core/coherence/living.js";
30
27
  import { issueFinding } from "../../core/vocabulary/issue.js";
31
28
  import { featureProvenance } from "../../core/provenance/findings.js";
32
29
  import { documentConflictFinding } from "../../core/conflict-markers.js";
33
- import { featureCapabilityDeltas } from "../../core/capabilities/delta/tree.js";
34
30
  import { docMissingFindings } from "../../core/capabilities/findings.js";
35
31
  import { FleetContext } from "../../core/fleet-context.js";
36
- import { errorText } from "./checks/vocabulary.js";
37
- import { coverageFinding, repeatedListLineFindings } from "./checks/requirements.js";
32
+ import { errorText } from "../../core/c4/likec4.js";
33
+ import { coverageFinding, repeatedListLineFindings, scenarioShapeFindings } from "./checks/requirements.js";
38
34
  import { deltaArchCoverage } from "./arch-coverage.js";
39
35
  import { featureLinkFindings } from "./links/corpus.js";
36
+ import { featureRecordFindings } from "./service/evidence-pins.js";
40
37
  export async function validateFeature(docsDir, feature, preloadedLand, fleet) {
41
38
  const findings = [];
42
39
  const featureDir = feature.dir;
@@ -51,7 +48,7 @@ export async function validateFeature(docsDir, feature, preloadedLand, fleet) {
51
48
  let deltaDoc;
52
49
  const deltaPath = featurePaths(featureDir).delta;
53
50
  if (existsSync(deltaPath)) {
54
- const res = fleet === undefined ? await loadFile(deltaPath) : await fleet.loadLikeC4(deltaPath);
51
+ const res = await fleet.loadLikeC4(deltaPath);
55
52
  deltaDoc = res;
56
53
  if (res.errors.length > 0) {
57
54
  findings.push({
@@ -74,6 +71,17 @@ export async function validateFeature(docsDir, feature, preloadedLand, fleet) {
74
71
  }
75
72
  }
76
73
  findings.push(...(await featureProvenance(featureDir, featureId)));
74
+ // The verification record, graded for READABILITY only — never for what it
75
+ // concludes. A conflict-marked or hand-broken `verification.yaml` /
76
+ // `verification/<svc>.yaml` was refused by `verify`, reported by `status`,
77
+ // `gate` and `tasks`, and invisible here: `validate --all` from the docs repo
78
+ // (and so the PR gate) stayed green over a record nobody can read, because
79
+ // the only target raising this code was the service one, which runs from a
80
+ // service repo. Same code and severity as that target
81
+ // (`./service/evidence-pins.ts`) — a warn, so `valid` and `loam archive` are
82
+ // untouched (verify never gates archive) and `--strict` is the lever. The
83
+ // verdict itself stays `verify`'s and `status`'s to state.
84
+ findings.push(...(await featureRecordFindings(docsDir, feature)));
77
85
  // Who this feature is allowed to address. `specs/<svc>/` is what the archive
78
86
  // materialises `services/<svc>/` from, and nothing used to ask whether that
79
87
  // name means anything: one wrong character in `--touches` passed
@@ -122,9 +130,9 @@ export async function validateFeature(docsDir, feature, preloadedLand, fleet) {
122
130
  for (const svc of featureServices) {
123
131
  const p = featureSpecPaths(featureDir, svc);
124
132
  if (existsSync(p.spec)) {
125
- const raw = fleet === undefined ? await readFile(p.spec, "utf8") : await fleet.readText(p.spec);
133
+ const raw = await fleet.readText(p.spec);
126
134
  scenarioText += "\n" + raw.toLowerCase();
127
- const reqs = fleet === undefined ? parseRequirements(raw) : await fleet.readRequirements(p.spec);
135
+ const reqs = await fleet.readRequirements(p.spec);
128
136
  // Both document-level breaches carry into the living spec through the
129
137
  // merge, so a delta is graded for them exactly as a living document is:
130
138
  // conflict markers merge as prose under someone's requirement, and a
@@ -134,25 +142,21 @@ export async function validateFeature(docsDir, feature, preloadedLand, fleet) {
134
142
  if (conflict !== null)
135
143
  findings.push(conflict);
136
144
  findings.push({ ...coverageFinding(`${svc}: requirements`, reqs), subject: svc });
137
- findings.push(...steplessFindings(`${svc}: requirements`, svc, reqs));
138
- findings.push(...assertionlessFindings(`${svc}: requirements`, svc, reqs));
139
- findings.push(...examplesFindings(`${svc}: requirements`, svc, reqs));
145
+ findings.push(...scenarioShapeFindings(`${svc}: requirements`, svc, reqs));
140
146
  // The keep-last quirk loses lines in a delta exactly as in a living spec
141
147
  // — and a delta's lost Operations: line then merges into the living one.
142
148
  findings.push(...repeatedListLineFindings(reqs, `${svc}: spec.md`, svc));
143
149
  }
144
150
  if (existsSync(p.archSpec)) {
145
- const raw = fleet === undefined ? await readFile(p.archSpec, "utf8") : await fleet.readText(p.archSpec);
151
+ const raw = await fleet.readText(p.archSpec);
146
152
  scenarioText += "\n" + raw.toLowerCase();
147
- const reqs = fleet === undefined ? parseRequirements(raw) : await fleet.readRequirements(p.archSpec);
153
+ const reqs = await fleet.readRequirements(p.archSpec);
148
154
  archDeltas.push({ service: svc, reqs });
149
155
  const conflict = documentConflictFinding(`${svc}: arch.spec.md`, svc, raw);
150
156
  if (conflict !== null)
151
157
  findings.push(conflict);
152
158
  findings.push({ ...coverageFinding(`${svc}: arch requirements`, reqs), subject: svc });
153
- findings.push(...steplessFindings(`${svc}: arch requirements`, svc, reqs));
154
- findings.push(...assertionlessFindings(`${svc}: arch requirements`, svc, reqs));
155
- findings.push(...examplesFindings(`${svc}: arch requirements`, svc, reqs));
159
+ findings.push(...scenarioShapeFindings(`${svc}: arch requirements`, svc, reqs));
156
160
  findings.push(...repeatedListLineFindings(reqs, `${svc}: arch.spec.md`, svc));
157
161
  }
158
162
  }
@@ -164,7 +168,7 @@ export async function validateFeature(docsDir, feature, preloadedLand, fleet) {
164
168
  // feature is archived, nothing walks the delta again, and the living
165
169
  // capability documents are only conflict-scanned while some feature still
166
170
  // carries a delta for them.
167
- const capabilityDeltas = fleet === undefined ? await featureCapabilityDeltas(featureDir) : await fleet.featureCapabilityDeltas(featureDir);
171
+ const capabilityDeltas = await fleet.featureCapabilityDeltas(featureDir);
168
172
  // The half-created directory, on the FEATURE side. The living tree has warned
169
173
  // about `capabilities/<id>/` with no document since the axis landed; the same
170
174
  // `mkdir` inside `features/<FEAT>/capabilities/` earned nothing, and it is the
@@ -175,7 +179,7 @@ export async function validateFeature(docsDir, feature, preloadedLand, fleet) {
175
179
  // message spelling `features/FEAT-1/` names a path nobody can open.
176
180
  findings.push(...docMissingFindings(capabilityDeltas, feature.dirName));
177
181
  for (const doc of capabilityDeltas.docs) {
178
- const raw = fleet === undefined ? await readFile(doc.spec, "utf8") : await fleet.readText(doc.spec);
182
+ const raw = await fleet.readText(doc.spec);
179
183
  const conflict = documentConflictFinding(`capability ${doc.id}: spec.md`, doc.id, raw);
180
184
  if (conflict !== null)
181
185
  findings.push(conflict);
@@ -186,6 +190,8 @@ export async function validateFeature(docsDir, feature, preloadedLand, fleet) {
186
190
  findings.push(...(await featureLinkFindings({ docsDir, subject: featureId, fleet }, featureDir)));
187
191
  findings.push(...(await deltaArchCoverage({
188
192
  docsDir,
193
+ featureDir,
194
+ featureId,
189
195
  elements,
190
196
  relationships: deltaRels,
191
197
  taggedEls,
@@ -1 +1 @@
1
- {"version":3,"file":"feature.js","sourceRoot":"","sources":["../../../src/commands/validate/feature.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The feature target: a delta graded on its own, before anything merges.\n *\n * Everything here reads the feature directory — delta.likec4, the per-service\n * spec.md/arch.spec.md deltas, the provenance stamp — and grades the documents\n * a merge is about to fold into living ones. A delta is held to the same\n * document rules as the file it becomes (`./checks/requirements.js`), because\n * grading it more leniently is how a defect acquires a signature saying it was\n * reviewed.\n *\n * The one question that needs the LIVING fleet — what in this delta is actually\n * new architecture — is `./arch-coverage.js`.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { loadFile, type Elem, type LoadedDoc, type Rel } from \"../../core/c4/likec4.js\";\nimport { elementService } from \"../../core/c4/resolve/service.js\";\nimport { type PathableService } from \"../../core/kernel/ids/service.js\";\nimport { type FeatureEntry } from \"../../core/repo/entries.js\";\nimport { featurePaths, featureSpecPaths } from \"../../core/repo/paths.js\";\nimport { enumeratedServiceIds } from \"../../core/repo/service-target.js\";\nimport { docsRepoState } from \"../../core/repo/state.js\";\nimport { featureSpecServices, listServices } from \"../../core/repo/repo.js\";\nimport { type Finding, type TargetReport } from \"../../core/vocabulary/report.js\";\nimport { parseRequirements } from \"../../core/document/parse.js\";\nimport {\n assertionlessFindings,\n examplesFindings,\n steplessFindings,\n} from \"../../core/document/scenarios.js\";\nimport { type Requirement } from \"../../core/document/spec.js\";\nimport { featureCoherence } from \"../../core/coherence/coherence.js\";\nimport {\n deltaServiceUnknownFinding,\n invalidSpecServiceFindings,\n} from \"../../core/coherence/living.js\";\nimport { issueFinding } from \"../../core/vocabulary/issue.js\";\nimport { featureProvenance } from \"../../core/provenance/findings.js\";\nimport { documentConflictFinding } from \"../../core/conflict-markers.js\";\nimport { featureCapabilityDeltas } from \"../../core/capabilities/delta/tree.js\";\nimport { docMissingFindings } from \"../../core/capabilities/findings.js\";\nimport { FleetContext } from \"../../core/fleet-context.js\";\nimport { errorText } from \"./checks/vocabulary.js\";\nimport { coverageFinding, repeatedListLineFindings } from \"./checks/requirements.js\";\nimport { deltaArchCoverage } from \"./arch-coverage.js\";\nimport { featureLinkFindings } from \"./links/corpus.js\";\nimport type { DocsDir } from \"../../core/kernel/ids/dirs.js\";\n\nexport async function validateFeature(\n docsDir: DocsDir,\n feature: FeatureEntry,\n preloadedLand?: LoadedDoc | null,\n fleet?: FleetContext,\n): Promise<TargetReport> {\n const findings: Finding[] = [];\n const featureDir = feature.dir;\n const featureId = feature.id;\n\n // delta.likec4 parse + collect tagged edges. The loaded doc is kept and\n // handed to featureCoherence below — loading it is a Langium workspace spin,\n // and paying it twice per feature was the dominant cost of `validate --all`.\n let taggedEls: Elem[] = [];\n let taggedRels: Rel[] = [];\n let elements: Elem[] = [];\n let deltaRels: Rel[] = [];\n let deltaDoc: LoadedDoc | undefined;\n const deltaPath = featurePaths(featureDir).delta;\n if (existsSync(deltaPath)) {\n const res = fleet === undefined ? await loadFile(deltaPath) : await fleet.loadLikeC4(deltaPath);\n deltaDoc = res;\n if (res.errors.length > 0) {\n findings.push({\n severity: \"error\",\n code: \"delta.invalid\",\n message: `delta.likec4 has ${res.errors.length} error(s)`,\n details: res.errors.map(errorText),\n });\n } else {\n elements = res.elements;\n deltaRels = res.relationships;\n taggedEls = res.elements.filter((e) => e.tags.includes(featureId));\n taggedRels = res.relationships.filter((r) => r.tags.includes(featureId));\n findings.push({\n severity: \"ok\",\n code: \"delta.valid\",\n message: `delta.likec4 valid (${res.elements.length} elements · ${res.relationships.length} relationships)`,\n });\n }\n }\n\n findings.push(...(await featureProvenance(featureDir, featureId)));\n\n // Who this feature is allowed to address. `specs/<svc>/` is what the archive\n // materialises `services/<svc>/` from, and nothing used to ask whether that\n // name means anything: one wrong character in `--touches` passed\n // `validate --all` with zero errors, and archive then created the phantom\n // directory. A delta may legitimately name a service that does not exist yet\n // — but only one it INTRODUCES itself, in its own tagged C4. A delta that did\n // not parse proves neither (`delta.invalid` is that finding), so the question\n // is suspended there rather than answered by guessing.\n //\n // Existence is enumeration MEMBERSHIP through the no-services-tolerant\n // spelling, never `existsSync(services/<svc>/)` at the root: a service filed\n // into a subsystem exists wherever the tree walk found it, and the root\n // probe graded every filed service `delta.service-unknown`. The tolerance\n // carries the old carve-out forward — `validate --feature` is allowed to run\n // in a docs repo with no services/ at all, where enumerating is a refusal;\n // `enumeratedServiceIds` swallows exactly that refusal to an empty list, in\n // which every service is honestly absent.\n const featureServices = await featureSpecServices(featureDir, fleet);\n const introduces: ReadonlySet<string> = new Set(taggedEls.map(elementService));\n const deltaReadable = deltaDoc === undefined || deltaDoc.errors.length === 0;\n const enumerated = new Set<string>(await enumeratedServiceIds(docsDir, fleet));\n const unknownServices = deltaReadable\n ? featureServices.filter((svc) => !enumerated.has(svc) && !introduces.has(svc))\n : [];\n // The near-miss hint, on the same rule `service.unknown` uses — a typo is\n // only diagnosable against the ids that DO exist.\n const closeTo =\n unknownServices.length > 0 && docsRepoState(docsDir).kind === \"ok\"\n ? (await listServices(docsDir, fleet)).map((s) => s.id)\n : [];\n // The finding is coherence/living.ts's — the same words archive refuses with,\n // because it is the same conclusion about the same directory.\n for (const svc of unknownServices) findings.push(deltaServiceUnknownFinding(svc, closeTo));\n\n // The grammar half of the same guarantee. `delta.service-unknown` asks whether\n // the directory names a service anyone knows; this asks whether the NAME could\n // ever be one. The two are independent on purpose: a tagged element whose\n // title matches the directory answers the first question, which is exactly how\n // `specs/Payment Service/` used to validate green and archive into a directory\n // no loam command can address. Not suspended on an unreadable delta either —\n // no reading of the architecture axis can make the name legal.\n findings.push(...(await invalidSpecServiceFindings(featureDir, fleet)));\n\n // Requirement coverage across every per-service delta — the business spec and\n // the arch spec through the same check — and collect scenario text.\n let scenarioText = \"\";\n const archDeltas: Array<{ service: PathableService; reqs: Requirement[] }> = [];\n for (const svc of featureServices) {\n const p = featureSpecPaths(featureDir, svc);\n if (existsSync(p.spec)) {\n const raw = fleet === undefined ? await readFile(p.spec, \"utf8\") : await fleet.readText(p.spec);\n scenarioText += \"\\n\" + raw.toLowerCase();\n const reqs = fleet === undefined ? parseRequirements(raw) : await fleet.readRequirements(p.spec);\n // Both document-level breaches carry into the living spec through the\n // merge, so a delta is graded for them exactly as a living document is:\n // conflict markers merge as prose under someone's requirement, and a\n // stepless scenario merges as a requirement the coverage rule calls\n // covered forever after.\n const conflict = documentConflictFinding(`${svc}: spec.md`, svc, raw);\n if (conflict !== null) findings.push(conflict);\n findings.push({ ...coverageFinding(`${svc}: requirements`, reqs), subject: svc });\n findings.push(...steplessFindings(`${svc}: requirements`, svc, reqs));\n findings.push(...assertionlessFindings(`${svc}: requirements`, svc, reqs));\n findings.push(...examplesFindings(`${svc}: requirements`, svc, reqs));\n // The keep-last quirk loses lines in a delta exactly as in a living spec\n // — and a delta's lost Operations: line then merges into the living one.\n findings.push(...repeatedListLineFindings(reqs, `${svc}: spec.md`, svc));\n }\n if (existsSync(p.archSpec)) {\n const raw = fleet === undefined ? await readFile(p.archSpec, \"utf8\") : await fleet.readText(p.archSpec);\n scenarioText += \"\\n\" + raw.toLowerCase();\n const reqs = fleet === undefined ? parseRequirements(raw) : await fleet.readRequirements(p.archSpec);\n archDeltas.push({ service: svc, reqs });\n const conflict = documentConflictFinding(`${svc}: arch.spec.md`, svc, raw);\n if (conflict !== null) findings.push(conflict);\n findings.push({ ...coverageFinding(`${svc}: arch requirements`, reqs), subject: svc });\n findings.push(...steplessFindings(`${svc}: arch requirements`, svc, reqs));\n findings.push(...assertionlessFindings(`${svc}: arch requirements`, svc, reqs));\n findings.push(...examplesFindings(`${svc}: arch requirements`, svc, reqs));\n findings.push(...repeatedListLineFindings(reqs, `${svc}: arch.spec.md`, svc));\n }\n }\n\n // The BUSINESS corpus's delta documents, graded for the same document-level\n // breach as the service ones and for the same reason: a conflicted delta\n // parses as prose, so every other check reads it as a valid document, and\n // `loam archive` then re-serializes both sides of somebody's merge into the\n // LIVING capability document. It is worse there than one tree over — once the\n // feature is archived, nothing walks the delta again, and the living\n // capability documents are only conflict-scanned while some feature still\n // carries a delta for them.\n const capabilityDeltas =\n fleet === undefined ? await featureCapabilityDeltas(featureDir) : await fleet.featureCapabilityDeltas(featureDir);\n // The half-created directory, on the FEATURE side. The living tree has warned\n // about `capabilities/<id>/` with no document since the axis landed; the same\n // `mkdir` inside `features/<FEAT>/capabilities/` earned nothing, and it is the\n // quieter of the two — an empty directory is not a delta, so the walk finds\n // no document, the merge carries nothing, and the business change ships as\n // zero at exit 0. Same code, feature-scoped message (`../../core/capabilities/findings.ts`).\n // `dirName`, not the id: the directory is `features/FEAT-1-split/`, and a\n // message spelling `features/FEAT-1/` names a path nobody can open.\n findings.push(...docMissingFindings(capabilityDeltas, feature.dirName));\n for (const doc of capabilityDeltas.docs) {\n const raw = fleet === undefined ? await readFile(doc.spec, \"utf8\") : await fleet.readText(doc.spec);\n const conflict = documentConflictFinding(`capability ${doc.id}: spec.md`, doc.id, raw);\n if (conflict !== null) findings.push(conflict);\n }\n\n // The links this feature's own documents write — the intent, each service's\n // two spec deltas, its ADRs and its capability deltas. Same place in the\n // order as the service target's: after every join loam defined a line for.\n findings.push(...(await featureLinkFindings({ docsDir, subject: featureId, fleet }, featureDir)));\n\n findings.push(\n ...(await deltaArchCoverage({\n docsDir,\n elements,\n relationships: deltaRels,\n taggedEls,\n taggedRels,\n archDeltas,\n featureServices,\n scenarioText,\n preloadedLand,\n fleet,\n })),\n );\n\n\n // Coherence — cross-axis consistency (C4 ↔ requirements ↔ OpenAPI).\n const issues = await featureCoherence({ docsDir, featureDir, featureId, preloadedDelta: deltaDoc, context: fleet });\n if (issues.length === 0) {\n findings.push({\n severity: \"ok\",\n code: \"coherence.ok\",\n message: \"coherence: ✓ C4 · requirements · OpenAPI agree\",\n text: { indent: 2, marker: false },\n });\n } else {\n for (const i of issues) {\n findings.push({ ...issueFinding(i), text: { indent: 4, header: \"coherence:\" } });\n }\n }\n\n return { kind: \"feature\", id: featureId, path: `features/${feature.dirName}`, findings };\n}\n"]}
1
+ {"version":3,"file":"feature.js","sourceRoot":"","sources":["../../../src/commands/validate/feature.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The feature target: a delta graded on its own, before anything merges.\n *\n * Everything here reads the feature directory — delta.likec4, the per-service\n * spec.md/arch.spec.md deltas, the provenance stamp — and grades the documents\n * a merge is about to fold into living ones. A delta is held to the same\n * document rules as the file it becomes (`./checks/requirements.js`), because\n * grading it more leniently is how a defect acquires a signature saying it was\n * reviewed.\n *\n * The one question that needs the LIVING fleet — what in this delta is actually\n * new architecture — is `./arch-coverage.js`.\n */\nimport { existsSync } from \"node:fs\";\nimport { type Elem, type LoadedDoc, type Rel } from \"../../core/c4/likec4.js\";\nimport { elementService } from \"../../core/c4/resolve/service.js\";\nimport { type PathableService } from \"../../core/kernel/ids/service.js\";\nimport { type FeatureEntry } from \"../../core/repo/entries.js\";\nimport { featurePaths, featureSpecPaths } from \"../../core/repo/paths.js\";\nimport { enumeratedServiceIds } from \"../../core/repo/service-target.js\";\nimport { docsRepoState } from \"../../core/repo/state.js\";\nimport { featureSpecServices, listServices } from \"../../core/repo/repo.js\";\nimport { type Finding, type TargetReport } from \"../../core/vocabulary/report.js\";\nimport { type Requirement } from \"../../core/document/spec.js\";\nimport { featureCoherence } from \"../../core/coherence/coherence.js\";\nimport {\n deltaServiceUnknownFinding,\n invalidSpecServiceFindings,\n} from \"../../core/coherence/living.js\";\nimport { issueFinding } from \"../../core/vocabulary/issue.js\";\nimport { featureProvenance } from \"../../core/provenance/findings.js\";\nimport { documentConflictFinding } from \"../../core/conflict-markers.js\";\nimport { docMissingFindings } from \"../../core/capabilities/findings.js\";\nimport { FleetContext } from \"../../core/fleet-context.js\";\nimport { errorText } from \"../../core/c4/likec4.js\";\nimport { coverageFinding, repeatedListLineFindings, scenarioShapeFindings } from \"./checks/requirements.js\";\nimport { deltaArchCoverage } from \"./arch-coverage.js\";\nimport { featureLinkFindings } from \"./links/corpus.js\";\nimport { featureRecordFindings } from \"./service/evidence-pins.js\";\nimport type { DocsDir } from \"../../core/kernel/ids/dirs.js\";\n\nexport async function validateFeature(\n docsDir: DocsDir,\n feature: FeatureEntry,\n preloadedLand: LoadedDoc | null | undefined,\n fleet: FleetContext,\n): Promise<TargetReport> {\n const findings: Finding[] = [];\n const featureDir = feature.dir;\n const featureId = feature.id;\n\n // delta.likec4 parse + collect tagged edges. The loaded doc is kept and\n // handed to featureCoherence below — loading it is a Langium workspace spin,\n // and paying it twice per feature was the dominant cost of `validate --all`.\n let taggedEls: Elem[] = [];\n let taggedRels: Rel[] = [];\n let elements: Elem[] = [];\n let deltaRels: Rel[] = [];\n let deltaDoc: LoadedDoc | undefined;\n const deltaPath = featurePaths(featureDir).delta;\n if (existsSync(deltaPath)) {\n const res = await fleet.loadLikeC4(deltaPath);\n deltaDoc = res;\n if (res.errors.length > 0) {\n findings.push({\n severity: \"error\",\n code: \"delta.invalid\",\n message: `delta.likec4 has ${res.errors.length} error(s)`,\n details: res.errors.map(errorText),\n });\n } else {\n elements = res.elements;\n deltaRels = res.relationships;\n taggedEls = res.elements.filter((e) => e.tags.includes(featureId));\n taggedRels = res.relationships.filter((r) => r.tags.includes(featureId));\n findings.push({\n severity: \"ok\",\n code: \"delta.valid\",\n message: `delta.likec4 valid (${res.elements.length} elements · ${res.relationships.length} relationships)`,\n });\n }\n }\n\n findings.push(...(await featureProvenance(featureDir, featureId)));\n\n // The verification record, graded for READABILITY only — never for what it\n // concludes. A conflict-marked or hand-broken `verification.yaml` /\n // `verification/<svc>.yaml` was refused by `verify`, reported by `status`,\n // `gate` and `tasks`, and invisible here: `validate --all` from the docs repo\n // (and so the PR gate) stayed green over a record nobody can read, because\n // the only target raising this code was the service one, which runs from a\n // service repo. Same code and severity as that target\n // (`./service/evidence-pins.ts`) — a warn, so `valid` and `loam archive` are\n // untouched (verify never gates archive) and `--strict` is the lever. The\n // verdict itself stays `verify`'s and `status`'s to state.\n findings.push(...(await featureRecordFindings(docsDir, feature)));\n\n // Who this feature is allowed to address. `specs/<svc>/` is what the archive\n // materialises `services/<svc>/` from, and nothing used to ask whether that\n // name means anything: one wrong character in `--touches` passed\n // `validate --all` with zero errors, and archive then created the phantom\n // directory. A delta may legitimately name a service that does not exist yet\n // — but only one it INTRODUCES itself, in its own tagged C4. A delta that did\n // not parse proves neither (`delta.invalid` is that finding), so the question\n // is suspended there rather than answered by guessing.\n //\n // Existence is enumeration MEMBERSHIP through the no-services-tolerant\n // spelling, never `existsSync(services/<svc>/)` at the root: a service filed\n // into a subsystem exists wherever the tree walk found it, and the root\n // probe graded every filed service `delta.service-unknown`. The tolerance\n // carries the old carve-out forward — `validate --feature` is allowed to run\n // in a docs repo with no services/ at all, where enumerating is a refusal;\n // `enumeratedServiceIds` swallows exactly that refusal to an empty list, in\n // which every service is honestly absent.\n const featureServices = await featureSpecServices(featureDir, fleet);\n const introduces: ReadonlySet<string> = new Set(taggedEls.map(elementService));\n const deltaReadable = deltaDoc === undefined || deltaDoc.errors.length === 0;\n const enumerated = new Set<string>(await enumeratedServiceIds(docsDir, fleet));\n const unknownServices = deltaReadable\n ? featureServices.filter((svc) => !enumerated.has(svc) && !introduces.has(svc))\n : [];\n // The near-miss hint, on the same rule `service.unknown` uses — a typo is\n // only diagnosable against the ids that DO exist.\n const closeTo =\n unknownServices.length > 0 && docsRepoState(docsDir).kind === \"ok\"\n ? (await listServices(docsDir, fleet)).map((s) => s.id)\n : [];\n // The finding is coherence/living.ts's — the same words archive refuses with,\n // because it is the same conclusion about the same directory.\n for (const svc of unknownServices) findings.push(deltaServiceUnknownFinding(svc, closeTo));\n\n // The grammar half of the same guarantee. `delta.service-unknown` asks whether\n // the directory names a service anyone knows; this asks whether the NAME could\n // ever be one. The two are independent on purpose: a tagged element whose\n // title matches the directory answers the first question, which is exactly how\n // `specs/Payment Service/` used to validate green and archive into a directory\n // no loam command can address. Not suspended on an unreadable delta either —\n // no reading of the architecture axis can make the name legal.\n findings.push(...(await invalidSpecServiceFindings(featureDir, fleet)));\n\n // Requirement coverage across every per-service delta — the business spec and\n // the arch spec through the same check — and collect scenario text.\n let scenarioText = \"\";\n const archDeltas: Array<{ service: PathableService; reqs: Requirement[] }> = [];\n for (const svc of featureServices) {\n const p = featureSpecPaths(featureDir, svc);\n if (existsSync(p.spec)) {\n const raw = await fleet.readText(p.spec);\n scenarioText += \"\\n\" + raw.toLowerCase();\n const reqs = await fleet.readRequirements(p.spec);\n // Both document-level breaches carry into the living spec through the\n // merge, so a delta is graded for them exactly as a living document is:\n // conflict markers merge as prose under someone's requirement, and a\n // stepless scenario merges as a requirement the coverage rule calls\n // covered forever after.\n const conflict = documentConflictFinding(`${svc}: spec.md`, svc, raw);\n if (conflict !== null) findings.push(conflict);\n findings.push({ ...coverageFinding(`${svc}: requirements`, reqs), subject: svc });\n findings.push(...scenarioShapeFindings(`${svc}: requirements`, svc, reqs));\n // The keep-last quirk loses lines in a delta exactly as in a living spec\n // — and a delta's lost Operations: line then merges into the living one.\n findings.push(...repeatedListLineFindings(reqs, `${svc}: spec.md`, svc));\n }\n if (existsSync(p.archSpec)) {\n const raw = await fleet.readText(p.archSpec);\n scenarioText += \"\\n\" + raw.toLowerCase();\n const reqs = await fleet.readRequirements(p.archSpec);\n archDeltas.push({ service: svc, reqs });\n const conflict = documentConflictFinding(`${svc}: arch.spec.md`, svc, raw);\n if (conflict !== null) findings.push(conflict);\n findings.push({ ...coverageFinding(`${svc}: arch requirements`, reqs), subject: svc });\n findings.push(...scenarioShapeFindings(`${svc}: arch requirements`, svc, reqs));\n findings.push(...repeatedListLineFindings(reqs, `${svc}: arch.spec.md`, svc));\n }\n }\n\n // The BUSINESS corpus's delta documents, graded for the same document-level\n // breach as the service ones and for the same reason: a conflicted delta\n // parses as prose, so every other check reads it as a valid document, and\n // `loam archive` then re-serializes both sides of somebody's merge into the\n // LIVING capability document. It is worse there than one tree over — once the\n // feature is archived, nothing walks the delta again, and the living\n // capability documents are only conflict-scanned while some feature still\n // carries a delta for them.\n const capabilityDeltas = await fleet.featureCapabilityDeltas(featureDir);\n // The half-created directory, on the FEATURE side. The living tree has warned\n // about `capabilities/<id>/` with no document since the axis landed; the same\n // `mkdir` inside `features/<FEAT>/capabilities/` earned nothing, and it is the\n // quieter of the two — an empty directory is not a delta, so the walk finds\n // no document, the merge carries nothing, and the business change ships as\n // zero at exit 0. Same code, feature-scoped message (`../../core/capabilities/findings.ts`).\n // `dirName`, not the id: the directory is `features/FEAT-1-split/`, and a\n // message spelling `features/FEAT-1/` names a path nobody can open.\n findings.push(...docMissingFindings(capabilityDeltas, feature.dirName));\n for (const doc of capabilityDeltas.docs) {\n const raw = await fleet.readText(doc.spec);\n const conflict = documentConflictFinding(`capability ${doc.id}: spec.md`, doc.id, raw);\n if (conflict !== null) findings.push(conflict);\n }\n\n // The links this feature's own documents write — the intent, each service's\n // two spec deltas, its ADRs and its capability deltas. Same place in the\n // order as the service target's: after every join loam defined a line for.\n findings.push(...(await featureLinkFindings({ docsDir, subject: featureId, fleet }, featureDir)));\n\n findings.push(\n ...(await deltaArchCoverage({\n docsDir,\n featureDir,\n featureId,\n elements,\n relationships: deltaRels,\n taggedEls,\n taggedRels,\n archDeltas,\n featureServices,\n scenarioText,\n preloadedLand,\n fleet,\n })),\n );\n\n\n // Coherence — cross-axis consistency (C4 ↔ requirements ↔ OpenAPI).\n const issues = await featureCoherence({ docsDir, featureDir, featureId, preloadedDelta: deltaDoc, context: fleet });\n if (issues.length === 0) {\n findings.push({\n severity: \"ok\",\n code: \"coherence.ok\",\n message: \"coherence: ✓ C4 · requirements · OpenAPI agree\",\n text: { indent: 2, marker: false },\n });\n } else {\n for (const i of issues) {\n findings.push({ ...issueFinding(i), text: { indent: 4, header: \"coherence:\" } });\n }\n }\n\n return { kind: \"feature\", id: featureId, path: `features/${feature.dirName}`, findings };\n}\n"]}
@@ -10,7 +10,8 @@
10
10
  * emits a finding, or knows what a target is.
11
11
  */
12
12
  import {} from "../../../core/c4/likec4.js";
13
- import { ACTOR_KINDS, EXTERNAL_TAG } from "../../../core/vocabulary/maturity.js";
13
+ import { properAncestorIds } from "../../../core/kernel/ids/fqn/ancestors.js";
14
+ import { ACTOR_KINDS, EXTERNAL_TAG, INFRA_KINDS } from "../../../core/vocabulary/maturity.js";
14
15
  /**
15
16
  * Does this element stand for a `services/<id>/` directory — an explicit
16
17
  * `metadata { service }` binding, or a title naming a real one? The question
@@ -35,21 +36,22 @@ export function standsForService(e, services) {
35
36
  */
36
37
  export function serviceLevelElements(elements, services) {
37
38
  const byId = new Map(elements.map((e) => [e.id, e]));
38
- /** Declared ancestors of an element, nearest first. */
39
- const ancestorsOf = (e) => {
40
- const out = [];
41
- for (let dot = e.id.lastIndexOf("."); dot !== -1; dot = e.id.lastIndexOf(".", dot - 1)) {
42
- const parent = byId.get(e.id.slice(0, dot));
43
- if (parent !== undefined)
44
- out.push(parent);
45
- }
46
- return out;
47
- };
39
+ /**
40
+ * The ancestors this document actually DECLARES, nearest first. The chain
41
+ * itself is `core/kernel/ids/fqn/ancestors.ts`'s — the one spelling of it —
42
+ * and the filter is this function's own: an id may name a level nothing
43
+ * declares, and an undeclared level answers for no service.
44
+ */
45
+ const ancestorsOf = (e) => properAncestorIds(e.id).flatMap((id) => {
46
+ const parent = byId.get(id);
47
+ return parent === undefined ? [] : [parent];
48
+ });
48
49
  return elements.filter((e) => !ancestorsOf(e).some((p) => standsForService(p, services)));
49
50
  }
50
51
  /**
51
52
  * The drawn SYSTEMS: service-level elements minus everything the map itself
52
- * says is not a service. Actor kinds model people; `#external` is somebody
53
+ * says is not a service. Actor kinds model people; INFRA kinds model the
54
+ * datastores, queues and buckets the fleet RUNS; `#external` is somebody
53
55
  * else's system; and an element that CONTAINS a service is a grouping — a
54
56
  * domain, a boundary, an enterprise — not a service nobody adopted. There is
55
57
  * nothing to bind on a grouping and nothing to tag #external, so asking for
@@ -58,12 +60,34 @@ export function serviceLevelElements(elements, services) {
58
60
  * the scorecard's `c4.elements` census counts it — one predicate, two readers,
59
61
  * zero drift.
60
62
  *
63
+ * The INFRA skip is the newest and the one with a measured cost behind it. A
64
+ * `database` the fleet OWNS and draws at fleet level is neither a person nor
65
+ * somebody else's system, so it used to earn `landscape.service-undocumented`
66
+ * — "bind it with `metadata { service '<id>' }`, or tag it `#external`" —
67
+ * whose two remedies are both FALSE of it: there is no directory to bind, and
68
+ * it is ours. Measured on a one-service fixture drawing an owned `database` at
69
+ * fleet level (2026-09-07): that warning plus `landscape.datastore-private`
70
+ * plus `gate.partner-undocumented` on its one consumer, three findings and no
71
+ * correct fix, which is why both `examples/docs` and this repo's own suite
72
+ * tagged an owned Redis `#external` to buy silence.
73
+ *
74
+ * `standsForService` wins over the kind, and that guard is load-bearing rather
75
+ * than defensive: a `database` bound with `metadata { service '<id>' }`, or one
76
+ * whose title names a real `services/<id>/`, IS an adopted service — dropping
77
+ * it here would take it out of the scorecard's `c4.elements` denominator and
78
+ * out of the binding passes at once. The kind is the fallback for an element
79
+ * nothing else answers for, never an override.
80
+ *
61
81
  * The `#external` skip here is exactly what `./kind-tags.ts` guards: read off a
62
- * tag a KIND declared, it can empty this census for a whole fleet at once.
82
+ * tag a KIND declared, it can empty this census for a whole fleet at once. The
83
+ * INFRA skip is NOT guarded there and does not need to be — a kind is what an
84
+ * element already is, not a claim declared over the fleet, and `#infrastructure`
85
+ * is deliberately not a tag loam grades on (`GRADED_TAGS`).
63
86
  */
64
87
  export function drawnSystems(elements, services) {
65
88
  return serviceLevelElements(elements, services).filter((e) => !e.tags.includes(EXTERNAL_TAG) &&
66
89
  !ACTOR_KINDS.has(e.kind.toLowerCase()) &&
90
+ !(INFRA_KINDS.has(e.kind.toLowerCase()) && !standsForService(e, services)) &&
67
91
  !elements.some((c) => c.id.startsWith(`${e.id}.`) && standsForService(c, services)));
68
92
  }
69
93
  //# sourceMappingURL=census.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"census.js","sourceRoot":"","sources":["../../../../src/commands/validate/fleet/census.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAa,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEjF;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAO,EAAE,QAA6B;IACrE,OAAO,CAAC,CAAC,OAAO,KAAK,SAAS,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,QAA6B;IAClF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,uDAAuD;IACvD,MAAM,WAAW,GAAG,CAAC,CAAO,EAAU,EAAE;QACtC,MAAM,GAAG,GAAW,EAAE,CAAC;QACvB,KAAK,IAAI,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;YACvF,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YAC5C,IAAI,MAAM,KAAK,SAAS;gBAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;IACF,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,QAA6B;IAC1E,OAAO,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,MAAM,CACpD,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;QAC9B,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACtC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,gBAAgB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CACtF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The fleet map's census: which drawn elements answer for a `services/<id>/`.\n *\n * Three predicates, in one place because every exemption in the fleet target,\n * the scorecard's `c4.elements` count and the kind-tag check all have to answer\n * the same question the same way — a second spelling of \"is this element a\n * service\" is how a map and a rollup start disagreeing about the same fleet.\n * They lived in `./landscape.ts` beside their first reader until that file hit\n * its line limit; the seam was already there, since nothing here reads a file,\n * emits a finding, or knows what a target is.\n */\nimport { type Elem } from \"../../../core/c4/likec4.js\";\nimport { ACTOR_KINDS, EXTERNAL_TAG } from \"../../../core/vocabulary/maturity.js\";\n\n/**\n * Does this element stand for a `services/<id>/` directory — an explicit\n * `metadata { service }` binding, or a title naming a real one? The question\n * every exemption in `./landscape.ts`, the scorecard's census and\n * `./kind-tags.ts` all ask, exported so they cannot answer it differently.\n */\nexport function standsForService(e: Elem, services: ReadonlySet<string>): boolean {\n return e.service !== undefined || services.has(e.title);\n}\n\n/**\n * Service-LEVEL elements: everything not drawn inside something that is\n * already a service.\n *\n * Depth is not a fact about a service. This used to keep only top-level\n * elements (`!e.id.includes(\".\")`), which ordinary C4 breaks the moment it\n * groups services under a parent: every nested element was thrown away, so a\n * bound service read as unmodelled — an ERROR, on every service in the fleet\n * — and a binding written one level down was never checked at all. The tree\n * is walked instead, the way `serviceResolver` walks it for edges: a binding\n * wins at any depth, then a title naming a real services/<id>/, and what sits\n * INSIDE one of those is that service's container, not a service of its own.\n */\nexport function serviceLevelElements(elements: Elem[], services: ReadonlySet<string>): Elem[] {\n const byId = new Map(elements.map((e) => [e.id, e]));\n /** Declared ancestors of an element, nearest first. */\n const ancestorsOf = (e: Elem): Elem[] => {\n const out: Elem[] = [];\n for (let dot = e.id.lastIndexOf(\".\"); dot !== -1; dot = e.id.lastIndexOf(\".\", dot - 1)) {\n const parent = byId.get(e.id.slice(0, dot));\n if (parent !== undefined) out.push(parent);\n }\n return out;\n };\n return elements.filter((e) => !ancestorsOf(e).some((p) => standsForService(p, services)));\n}\n\n/**\n * The drawn SYSTEMS: service-level elements minus everything the map itself\n * says is not a service. Actor kinds model people; `#external` is somebody\n * else's system; and an element that CONTAINS a service is a grouping — a\n * domain, a boundary, an enterprise — not a service nobody adopted. There is\n * nothing to bind on a grouping and nothing to tag #external, so asking for\n * either would be a warning with no correct fix; the services under it answer\n * for themselves. `validateLandscape`'s undocumented pass walks this set, and\n * the scorecard's `c4.elements` census counts it — one predicate, two readers,\n * zero drift.\n *\n * The `#external` skip here is exactly what `./kind-tags.ts` guards: read off a\n * tag a KIND declared, it can empty this census for a whole fleet at once.\n */\nexport function drawnSystems(elements: Elem[], services: ReadonlySet<string>): Elem[] {\n return serviceLevelElements(elements, services).filter(\n (e) =>\n !e.tags.includes(EXTERNAL_TAG) &&\n !ACTOR_KINDS.has(e.kind.toLowerCase()) &&\n !elements.some((c) => c.id.startsWith(`${e.id}.`) && standsForService(c, services)),\n );\n}\n"]}
1
+ {"version":3,"file":"census.js","sourceRoot":"","sources":["../../../../src/commands/validate/fleet/census.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAa,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2CAA2C,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAE9F;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAO,EAAE,QAA6B;IACrE,OAAO,CAAC,CAAC,OAAO,KAAK,SAAS,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,QAA6B;IAClF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD;;;;;OAKG;IACH,MAAM,WAAW,GAAG,CAAC,CAAO,EAAU,EAAE,CACtC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IACL,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,QAA6B;IAC1E,OAAO,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,MAAM,CACpD,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;QAC9B,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACtC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC1E,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,gBAAgB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CACtF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The fleet map's census: which drawn elements answer for a `services/<id>/`.\n *\n * Three predicates, in one place because every exemption in the fleet target,\n * the scorecard's `c4.elements` count and the kind-tag check all have to answer\n * the same question the same way — a second spelling of \"is this element a\n * service\" is how a map and a rollup start disagreeing about the same fleet.\n * They lived in `./landscape.ts` beside their first reader until that file hit\n * its line limit; the seam was already there, since nothing here reads a file,\n * emits a finding, or knows what a target is.\n */\nimport { type Elem } from \"../../../core/c4/likec4.js\";\nimport { properAncestorIds } from \"../../../core/kernel/ids/fqn/ancestors.js\";\nimport { ACTOR_KINDS, EXTERNAL_TAG, INFRA_KINDS } from \"../../../core/vocabulary/maturity.js\";\n\n/**\n * Does this element stand for a `services/<id>/` directory — an explicit\n * `metadata { service }` binding, or a title naming a real one? The question\n * every exemption in `./landscape.ts`, the scorecard's census and\n * `./kind-tags.ts` all ask, exported so they cannot answer it differently.\n */\nexport function standsForService(e: Elem, services: ReadonlySet<string>): boolean {\n return e.service !== undefined || services.has(e.title);\n}\n\n/**\n * Service-LEVEL elements: everything not drawn inside something that is\n * already a service.\n *\n * Depth is not a fact about a service. This used to keep only top-level\n * elements (`!e.id.includes(\".\")`), which ordinary C4 breaks the moment it\n * groups services under a parent: every nested element was thrown away, so a\n * bound service read as unmodelled — an ERROR, on every service in the fleet\n * — and a binding written one level down was never checked at all. The tree\n * is walked instead, the way `serviceResolver` walks it for edges: a binding\n * wins at any depth, then a title naming a real services/<id>/, and what sits\n * INSIDE one of those is that service's container, not a service of its own.\n */\nexport function serviceLevelElements(elements: Elem[], services: ReadonlySet<string>): Elem[] {\n const byId = new Map(elements.map((e) => [e.id, e]));\n /**\n * The ancestors this document actually DECLARES, nearest first. The chain\n * itself is `core/kernel/ids/fqn/ancestors.ts`'s — the one spelling of it —\n * and the filter is this function's own: an id may name a level nothing\n * declares, and an undeclared level answers for no service.\n */\n const ancestorsOf = (e: Elem): Elem[] =>\n properAncestorIds(e.id).flatMap((id) => {\n const parent = byId.get(id);\n return parent === undefined ? [] : [parent];\n });\n return elements.filter((e) => !ancestorsOf(e).some((p) => standsForService(p, services)));\n}\n\n/**\n * The drawn SYSTEMS: service-level elements minus everything the map itself\n * says is not a service. Actor kinds model people; INFRA kinds model the\n * datastores, queues and buckets the fleet RUNS; `#external` is somebody\n * else's system; and an element that CONTAINS a service is a grouping — a\n * domain, a boundary, an enterprise — not a service nobody adopted. There is\n * nothing to bind on a grouping and nothing to tag #external, so asking for\n * either would be a warning with no correct fix; the services under it answer\n * for themselves. `validateLandscape`'s undocumented pass walks this set, and\n * the scorecard's `c4.elements` census counts it — one predicate, two readers,\n * zero drift.\n *\n * The INFRA skip is the newest and the one with a measured cost behind it. A\n * `database` the fleet OWNS and draws at fleet level is neither a person nor\n * somebody else's system, so it used to earn `landscape.service-undocumented`\n * — \"bind it with `metadata { service '<id>' }`, or tag it `#external`\" —\n * whose two remedies are both FALSE of it: there is no directory to bind, and\n * it is ours. Measured on a one-service fixture drawing an owned `database` at\n * fleet level (2026-09-07): that warning plus `landscape.datastore-private`\n * plus `gate.partner-undocumented` on its one consumer, three findings and no\n * correct fix, which is why both `examples/docs` and this repo's own suite\n * tagged an owned Redis `#external` to buy silence.\n *\n * `standsForService` wins over the kind, and that guard is load-bearing rather\n * than defensive: a `database` bound with `metadata { service '<id>' }`, or one\n * whose title names a real `services/<id>/`, IS an adopted service — dropping\n * it here would take it out of the scorecard's `c4.elements` denominator and\n * out of the binding passes at once. The kind is the fallback for an element\n * nothing else answers for, never an override.\n *\n * The `#external` skip here is exactly what `./kind-tags.ts` guards: read off a\n * tag a KIND declared, it can empty this census for a whole fleet at once. The\n * INFRA skip is NOT guarded there and does not need to be — a kind is what an\n * element already is, not a claim declared over the fleet, and `#infrastructure`\n * is deliberately not a tag loam grades on (`GRADED_TAGS`).\n */\nexport function drawnSystems(elements: Elem[], services: ReadonlySet<string>): Elem[] {\n return serviceLevelElements(elements, services).filter(\n (e) =>\n !e.tags.includes(EXTERNAL_TAG) &&\n !ACTOR_KINDS.has(e.kind.toLowerCase()) &&\n !(INFRA_KINDS.has(e.kind.toLowerCase()) && !standsForService(e, services)) &&\n !elements.some((c) => c.id.startsWith(`${e.id}.`) && standsForService(c, services)),\n );\n}\n"]}