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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (901) hide show
  1. package/CHANGELOG.md +3448 -0
  2. package/COMPARISON.md +91 -3
  3. package/CONTRIBUTING.md +37 -0
  4. package/MIGRATING-from-OpenSpec.md +47 -23
  5. package/QUICKSTART.md +189 -12
  6. package/README.md +274 -65
  7. package/ROADMAP.md +572 -31
  8. package/SCHEMA.md +1709 -155
  9. package/WORKFLOW.md +298 -72
  10. package/dist/cli.js +26 -8
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/adopt/adopt.js +5 -10
  13. package/dist/commands/adopt/adopt.js.map +1 -1
  14. package/dist/commands/adopt/render.js +50 -9
  15. package/dist/commands/adopt/render.js.map +1 -1
  16. package/dist/commands/archive/archive.js +16 -19
  17. package/dist/commands/archive/archive.js.map +1 -1
  18. package/dist/commands/archive/closing.js +42 -0
  19. package/dist/commands/archive/closing.js.map +1 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js +36 -42
  21. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
  22. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  24. package/dist/commands/archive/plan/contracts/openapi.js +77 -43
  25. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
  26. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  28. package/dist/commands/archive/plan/document/head.js +151 -0
  29. package/dist/commands/archive/plan/document/head.js.map +1 -0
  30. package/dist/commands/archive/plan/document/links.js +284 -0
  31. package/dist/commands/archive/plan/document/links.js.map +1 -0
  32. package/dist/commands/archive/plan/document/run.js +136 -0
  33. package/dist/commands/archive/plan/document/run.js.map +1 -0
  34. package/dist/commands/archive/plan/gate.js +21 -19
  35. package/dist/commands/archive/plan/gate.js.map +1 -1
  36. package/dist/commands/archive/plan/landscape.js +167 -30
  37. package/dist/commands/archive/plan/landscape.js.map +1 -1
  38. package/dist/commands/archive/plan/model/extending.js +85 -0
  39. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  40. package/dist/commands/archive/plan/refusal.js +14 -19
  41. package/dist/commands/archive/plan/refusal.js.map +1 -1
  42. package/dist/commands/archive/plan/specs.js +137 -56
  43. package/dist/commands/archive/plan/specs.js.map +1 -1
  44. package/dist/commands/archive/plan/state.js +3 -0
  45. package/dist/commands/archive/plan/state.js.map +1 -1
  46. package/dist/commands/archive/run.js +134 -30
  47. package/dist/commands/archive/run.js.map +1 -1
  48. package/dist/commands/archive/shipped.js +49 -0
  49. package/dist/commands/archive/shipped.js.map +1 -0
  50. package/dist/commands/context/context.js +85 -18
  51. package/dist/commands/context/context.js.map +1 -1
  52. package/dist/commands/context/print.js +29 -7
  53. package/dist/commands/context/print.js.map +1 -1
  54. package/dist/commands/delta/delta.js +102 -14
  55. package/dist/commands/delta/delta.js.map +1 -1
  56. package/dist/commands/delta/print.js +17 -1
  57. package/dist/commands/delta/print.js.map +1 -1
  58. package/dist/commands/dependencies.js +3 -7
  59. package/dist/commands/dependencies.js.map +1 -1
  60. package/dist/commands/diff/diff.js +20 -27
  61. package/dist/commands/diff/diff.js.map +1 -1
  62. package/dist/commands/doctor.js +60 -1
  63. package/dist/commands/doctor.js.map +1 -1
  64. package/dist/commands/explain/explain.js +89 -13
  65. package/dist/commands/explain/explain.js.map +1 -1
  66. package/dist/commands/explore.js +16 -10
  67. package/dist/commands/explore.js.map +1 -1
  68. package/dist/commands/gate/gate.js +45 -8
  69. package/dist/commands/gate/gate.js.map +1 -1
  70. package/dist/commands/gate/print.js +15 -3
  71. package/dist/commands/gate/print.js.map +1 -1
  72. package/dist/commands/gherkin/commit.js +13 -54
  73. package/dist/commands/gherkin/commit.js.map +1 -1
  74. package/dist/commands/gherkin/gherkin.js +36 -20
  75. package/dist/commands/gherkin/gherkin.js.map +1 -1
  76. package/dist/commands/gherkin/reconcile.js +10 -13
  77. package/dist/commands/gherkin/reconcile.js.map +1 -1
  78. package/dist/commands/init/first-hour.js +44 -0
  79. package/dist/commands/init/first-hour.js.map +1 -1
  80. package/dist/commands/init/init.js +18 -22
  81. package/dist/commands/init/init.js.map +1 -1
  82. package/dist/commands/list/campaign/campaign.js +4 -6
  83. package/dist/commands/list/campaign/campaign.js.map +1 -1
  84. package/dist/commands/list/json.js +5 -7
  85. package/dist/commands/list/json.js.map +1 -1
  86. package/dist/commands/list/list.js +44 -29
  87. package/dist/commands/list/list.js.map +1 -1
  88. package/dist/commands/list/print.js +52 -9
  89. package/dist/commands/list/print.js.map +1 -1
  90. package/dist/commands/list/suites/suites.js +140 -0
  91. package/dist/commands/list/suites/suites.js.map +1 -0
  92. package/dist/commands/list/views.js +37 -34
  93. package/dist/commands/list/views.js.map +1 -1
  94. package/dist/commands/mcp/dispatch.js +91 -36
  95. package/dist/commands/mcp/dispatch.js.map +1 -1
  96. package/dist/commands/mcp/mcp.js +56 -15
  97. package/dist/commands/mcp/mcp.js.map +1 -1
  98. package/dist/commands/mcp/serve.js.map +1 -1
  99. package/dist/commands/migrate-openspec/materialize/active.js +27 -22
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
  101. package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
  102. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
  103. package/dist/commands/migrate-openspec/materialize/target.js +2 -2
  104. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
  105. package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
  106. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
  107. package/dist/commands/migrate-openspec/openspec/error.js +7 -8
  108. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
  109. package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
  110. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
  111. package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
  112. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
  113. package/dist/commands/new/capability-template.js +118 -0
  114. package/dist/commands/new/capability-template.js.map +1 -0
  115. package/dist/commands/new/commit.js +8 -22
  116. package/dist/commands/new/commit.js.map +1 -1
  117. package/dist/commands/new/modifies.js +206 -0
  118. package/dist/commands/new/modifies.js.map +1 -0
  119. package/dist/commands/new/new.js +59 -14
  120. package/dist/commands/new/new.js.map +1 -1
  121. package/dist/commands/new/templates.js +48 -124
  122. package/dist/commands/new/templates.js.map +1 -1
  123. package/dist/commands/open.js +3 -7
  124. package/dist/commands/open.js.map +1 -1
  125. package/dist/commands/policy/gate.js +27 -0
  126. package/dist/commands/policy/gate.js.map +1 -1
  127. package/dist/commands/rebase/plan.js +2 -2
  128. package/dist/commands/rebase/plan.js.map +1 -1
  129. package/dist/commands/rebase/rebase.js +60 -35
  130. package/dist/commands/rebase/rebase.js.map +1 -1
  131. package/dist/commands/seed/commit.js +55 -26
  132. package/dist/commands/seed/commit.js.map +1 -1
  133. package/dist/commands/seed/plan.js +158 -13
  134. package/dist/commands/seed/plan.js.map +1 -1
  135. package/dist/commands/seed/seed.js +13 -11
  136. package/dist/commands/seed/seed.js.map +1 -1
  137. package/dist/commands/show/feature.js +9 -5
  138. package/dist/commands/show/feature.js.map +1 -1
  139. package/dist/commands/show/introduced.js +157 -0
  140. package/dist/commands/show/introduced.js.map +1 -0
  141. package/dist/commands/show/marks.js +35 -6
  142. package/dist/commands/show/marks.js.map +1 -1
  143. package/dist/commands/show/service.js +41 -33
  144. package/dist/commands/show/service.js.map +1 -1
  145. package/dist/commands/show/show.js +17 -7
  146. package/dist/commands/show/show.js.map +1 -1
  147. package/dist/commands/status/fleet-next.js +90 -0
  148. package/dist/commands/status/fleet-next.js.map +1 -0
  149. package/dist/commands/status/json.js +2 -0
  150. package/dist/commands/status/json.js.map +1 -1
  151. package/dist/commands/status/print.js +89 -37
  152. package/dist/commands/status/print.js.map +1 -1
  153. package/dist/commands/status/status.js +3 -7
  154. package/dist/commands/status/status.js.map +1 -1
  155. package/dist/commands/steps/steps.js +103 -23
  156. package/dist/commands/steps/steps.js.map +1 -1
  157. package/dist/commands/subsystem/edit.js +7 -7
  158. package/dist/commands/subsystem/edit.js.map +1 -1
  159. package/dist/commands/subsystem/move.js +106 -46
  160. package/dist/commands/subsystem/move.js.map +1 -1
  161. package/dist/commands/subsystem/query.js +2 -4
  162. package/dist/commands/subsystem/query.js.map +1 -1
  163. package/dist/commands/subsystem/subsystem.js +4 -7
  164. package/dist/commands/subsystem/subsystem.js.map +1 -1
  165. package/dist/commands/subsystem/sync.js +289 -74
  166. package/dist/commands/subsystem/sync.js.map +1 -1
  167. package/dist/commands/subsystem/txn/exclude.js +132 -0
  168. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  169. package/dist/commands/subsystem/txn/links.js +128 -0
  170. package/dist/commands/subsystem/txn/links.js.map +1 -0
  171. package/dist/commands/subsystem/txn/report.js +174 -0
  172. package/dist/commands/subsystem/txn/report.js.map +1 -0
  173. package/dist/commands/subsystem/txn/txn.js +147 -45
  174. package/dist/commands/subsystem/txn/txn.js.map +1 -1
  175. package/dist/commands/subsystem/txn/views.js +200 -21
  176. package/dist/commands/subsystem/txn/views.js.map +1 -1
  177. package/dist/commands/tasks/actions.js +107 -0
  178. package/dist/commands/tasks/actions.js.map +1 -0
  179. package/dist/commands/tasks/render.js +253 -0
  180. package/dist/commands/tasks/render.js.map +1 -0
  181. package/dist/commands/tasks/tasks.js +119 -0
  182. package/dist/commands/tasks/tasks.js.map +1 -0
  183. package/dist/commands/unarchive/manifest.js +42 -26
  184. package/dist/commands/unarchive/manifest.js.map +1 -1
  185. package/dist/commands/unarchive/restore.js +83 -33
  186. package/dist/commands/unarchive/restore.js.map +1 -1
  187. package/dist/commands/unarchive/unarchive.js +22 -30
  188. package/dist/commands/unarchive/unarchive.js.map +1 -1
  189. package/dist/commands/validate/arch-coverage.js +78 -27
  190. package/dist/commands/validate/arch-coverage.js.map +1 -1
  191. package/dist/commands/validate/checks/fleet-shape.js +34 -126
  192. package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
  193. package/dist/commands/validate/checks/health-deps.js +9 -6
  194. package/dist/commands/validate/checks/health-deps.js.map +1 -1
  195. package/dist/commands/validate/checks/introduced.js +102 -0
  196. package/dist/commands/validate/checks/introduced.js.map +1 -0
  197. package/dist/commands/validate/checks/requirements.js +18 -8
  198. package/dist/commands/validate/checks/requirements.js.map +1 -1
  199. package/dist/commands/validate/checks/sources.js +11 -2
  200. package/dist/commands/validate/checks/sources.js.map +1 -1
  201. package/dist/commands/validate/coverage/covers-after.js +105 -0
  202. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  203. package/dist/commands/validate/feature.js +26 -20
  204. package/dist/commands/validate/feature.js.map +1 -1
  205. package/dist/commands/validate/fleet/census.js +37 -13
  206. package/dist/commands/validate/fleet/census.js.map +1 -1
  207. package/dist/commands/validate/fleet/landscape.js +144 -126
  208. package/dist/commands/validate/fleet/landscape.js.map +1 -1
  209. package/dist/commands/validate/fleet/load.js +66 -0
  210. package/dist/commands/validate/fleet/load.js.map +1 -1
  211. package/dist/commands/validate/fleet/map/attest.js +98 -0
  212. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  213. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  214. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  215. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  216. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  217. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  218. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  219. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  220. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  221. package/dist/commands/validate/fleet/obligations.js +44 -14
  222. package/dist/commands/validate/fleet/obligations.js.map +1 -1
  223. package/dist/commands/validate/fleet/scorecard/print.js +10 -2
  224. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
  225. package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
  226. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
  227. package/dist/commands/validate/fleet/usecases/place.js.map +1 -1
  228. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  229. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  230. package/dist/commands/validate/fleet/views/ids.js +50 -15
  231. package/dist/commands/validate/fleet/views/ids.js.map +1 -1
  232. package/dist/commands/validate/fleet/views/projects.js +278 -0
  233. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  234. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  235. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  236. package/dist/commands/validate/fleet/views/stale.js +40 -47
  237. package/dist/commands/validate/fleet/views/stale.js.map +1 -1
  238. package/dist/commands/validate/links/corpus.js +1 -4
  239. package/dist/commands/validate/links/corpus.js.map +1 -1
  240. package/dist/commands/validate/links/glossary.js.map +1 -1
  241. package/dist/commands/validate/render/repeats.js +63 -0
  242. package/dist/commands/validate/render/repeats.js.map +1 -0
  243. package/dist/commands/validate/render/rollups.js +115 -0
  244. package/dist/commands/validate/render/rollups.js.map +1 -0
  245. package/dist/commands/validate/render/text.js +199 -0
  246. package/dist/commands/validate/render/text.js.map +1 -0
  247. package/dist/commands/validate/report.js +36 -160
  248. package/dist/commands/validate/report.js.map +1 -1
  249. package/dist/commands/validate/scope.js +113 -0
  250. package/dist/commands/validate/scope.js.map +1 -0
  251. package/dist/commands/validate/service/api.js +21 -107
  252. package/dist/commands/validate/service/api.js.map +1 -1
  253. package/dist/commands/validate/service/contracts/generated.js +134 -0
  254. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  255. package/dist/commands/validate/service/events/events.js +36 -14
  256. package/dist/commands/validate/service/events/events.js.map +1 -1
  257. package/dist/commands/validate/service/events/message-producers.js +1 -1
  258. package/dist/commands/validate/service/events/message-producers.js.map +1 -1
  259. package/dist/commands/validate/service/evidence-pins.js +56 -10
  260. package/dist/commands/validate/service/evidence-pins.js.map +1 -1
  261. package/dist/commands/validate/service/model/diverged.js +226 -0
  262. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  263. package/dist/commands/validate/service/model/grade.js +163 -0
  264. package/dist/commands/validate/service/model/grade.js.map +1 -0
  265. package/dist/commands/validate/service/service.js +121 -61
  266. package/dist/commands/validate/service/service.js.map +1 -1
  267. package/dist/commands/validate/service/specs.js +88 -28
  268. package/dist/commands/validate/service/specs.js.map +1 -1
  269. package/dist/commands/validate/service/spine.js +38 -3
  270. package/dist/commands/validate/service/spine.js.map +1 -1
  271. package/dist/commands/validate/service/usecases/tags.js +113 -0
  272. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  273. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  274. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  275. package/dist/commands/validate/validate.js +85 -60
  276. package/dist/commands/validate/validate.js.map +1 -1
  277. package/dist/commands/verify/cross/diff.js +2 -6
  278. package/dist/commands/verify/cross/diff.js.map +1 -1
  279. package/dist/commands/verify/evidence/contract.js +1 -1
  280. package/dist/commands/verify/evidence/contract.js.map +1 -1
  281. package/dist/commands/verify/evidence/read.js +12 -3
  282. package/dist/commands/verify/evidence/read.js.map +1 -1
  283. package/dist/commands/verify/frozen.js +45 -23
  284. package/dist/commands/verify/frozen.js.map +1 -1
  285. package/dist/commands/verify/record.js +69 -17
  286. package/dist/commands/verify/record.js.map +1 -1
  287. package/dist/commands/verify/report.js +27 -44
  288. package/dist/commands/verify/report.js.map +1 -1
  289. package/dist/commands/verify/results.js +112 -30
  290. package/dist/commands/verify/results.js.map +1 -1
  291. package/dist/commands/verify/verify.js +55 -52
  292. package/dist/commands/verify/verify.js.map +1 -1
  293. package/dist/commands/vouch/pack/pack.js +2 -2
  294. package/dist/commands/vouch/pack/pack.js.map +1 -1
  295. package/dist/commands/vouch/pack/print.js +1 -6
  296. package/dist/commands/vouch/pack/print.js.map +1 -1
  297. package/dist/commands/vouch/pack/sections.js +1 -2
  298. package/dist/commands/vouch/pack/sections.js.map +1 -1
  299. package/dist/commands/vouch/run.js +26 -81
  300. package/dist/commands/vouch/run.js.map +1 -1
  301. package/dist/commands/vouch/sample/plan.js +20 -34
  302. package/dist/commands/vouch/sample/plan.js.map +1 -1
  303. package/dist/commands/vouch/vet/verify.js +39 -7
  304. package/dist/commands/vouch/vet/verify.js.map +1 -1
  305. package/dist/commands/vouch/vouch.js +10 -17
  306. package/dist/commands/vouch/vouch.js.map +1 -1
  307. package/dist/core/agent/agents-md/command-map.js +81 -106
  308. package/dist/core/agent/agents-md/command-map.js.map +1 -1
  309. package/dist/core/agent/agents-md/map/explain.js +21 -9
  310. package/dist/core/agent/agents-md/map/explain.js.map +1 -1
  311. package/dist/core/agent/agents-md/map/lenses/context.js +17 -8
  312. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
  313. package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
  314. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
  315. package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
  316. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
  317. package/dist/core/agent/agents-md/map/mcp.js +10 -7
  318. package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
  319. package/dist/core/agent/agents-md/map/status.js +24 -8
  320. package/dist/core/agent/agents-md/map/status.js.map +1 -1
  321. package/dist/core/agent/agents-md/map/subsystem.js +80 -8
  322. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
  323. package/dist/core/agent/agents-md/map/usecases.js +88 -10
  324. package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
  325. package/dist/core/agent/agents-md/refusals.js +49 -22
  326. package/dist/core/agent/agents-md/refusals.js.map +1 -1
  327. package/dist/core/agent/agents-md.js +39 -6
  328. package/dist/core/agent/agents-md.js.map +1 -1
  329. package/dist/core/agent/agents-stamp.js +10 -0
  330. package/dist/core/agent/agents-stamp.js.map +1 -1
  331. package/dist/core/agent/protocol.js +1 -1
  332. package/dist/core/agent/protocol.js.map +1 -1
  333. package/dist/core/agent/scaffold.js +10 -15
  334. package/dist/core/agent/scaffold.js.map +1 -1
  335. package/dist/core/agent/support/report.js +46 -5
  336. package/dist/core/agent/support/report.js.map +1 -1
  337. package/dist/core/agent/tools/dialects.js +1 -0
  338. package/dist/core/agent/tools/dialects.js.map +1 -1
  339. package/dist/core/agent/tools/registry.js +41 -76
  340. package/dist/core/agent/tools/registry.js.map +1 -1
  341. package/dist/core/agent/workflows/adopt.js +158 -11
  342. package/dist/core/agent/workflows/adopt.js.map +1 -1
  343. package/dist/core/agent/workflows/check.js +78 -39
  344. package/dist/core/agent/workflows/check.js.map +1 -1
  345. package/dist/core/agent/workflows/closing.js +88 -27
  346. package/dist/core/agent/workflows/closing.js.map +1 -1
  347. package/dist/core/agent/workflows/feature.js +128 -13
  348. package/dist/core/agent/workflows/feature.js.map +1 -1
  349. package/dist/core/agent/workflows/implement.js +96 -13
  350. package/dist/core/agent/workflows/implement.js.map +1 -1
  351. package/dist/core/agent/workflows/reference/authoring.js +106 -4
  352. package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
  353. package/dist/core/agent/workflows/reference/codes.js +8 -6
  354. package/dist/core/agent/workflows/reference/codes.js.map +1 -1
  355. package/dist/core/agent/workflows/reference/done-check.js +37 -15
  356. package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
  357. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  358. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  359. package/dist/core/agent/workflows/reference/reference.js +6 -3
  360. package/dist/core/agent/workflows/reference/reference.js.map +1 -1
  361. package/dist/core/agent/workflows/reference/spine.js +68 -27
  362. package/dist/core/agent/workflows/reference/spine.js.map +1 -1
  363. package/dist/core/asyncapi/baseline/plan.js +14 -81
  364. package/dist/core/asyncapi/baseline/plan.js.map +1 -1
  365. package/dist/core/asyncapi/digest.js +30 -25
  366. package/dist/core/asyncapi/digest.js.map +1 -1
  367. package/dist/core/asyncapi/merge/components.js +5 -4
  368. package/dist/core/asyncapi/merge/components.js.map +1 -1
  369. package/dist/core/asyncapi/merge/error.js +7 -2
  370. package/dist/core/asyncapi/merge/error.js.map +1 -1
  371. package/dist/core/asyncapi/merge/markers.js +32 -50
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -1
  373. package/dist/core/asyncapi/merge/merge.js +33 -53
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -1
  375. package/dist/core/asyncapi/merge/pin.js +12 -36
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -1
  377. package/dist/core/asyncapi/model.js.map +1 -1
  378. package/dist/core/asyncapi/read.js +36 -12
  379. package/dist/core/asyncapi/read.js.map +1 -1
  380. package/dist/core/brief/brief.js +96 -36
  381. package/dist/core/brief/brief.js.map +1 -1
  382. package/dist/core/brief/checks.js +138 -3
  383. package/dist/core/brief/checks.js.map +1 -1
  384. package/dist/core/brief/landscape.js +209 -130
  385. package/dist/core/brief/landscape.js.map +1 -1
  386. package/dist/core/brief/map/extend.js +84 -0
  387. package/dist/core/brief/map/extend.js.map +1 -0
  388. package/dist/core/brief/map/owed.js +266 -0
  389. package/dist/core/brief/map/owed.js.map +1 -0
  390. package/dist/core/brief/targets.js +109 -31
  391. package/dist/core/brief/targets.js.map +1 -1
  392. package/dist/core/brief/unchecked.js +14 -3
  393. package/dist/core/brief/unchecked.js.map +1 -1
  394. package/dist/core/c4/arch.js +90 -182
  395. package/dist/core/c4/arch.js.map +1 -1
  396. package/dist/core/c4/direction/direction.js +114 -0
  397. package/dist/core/c4/direction/direction.js.map +1 -0
  398. package/dist/core/c4/likec4.js +169 -14
  399. package/dist/core/c4/likec4.js.map +1 -1
  400. package/dist/core/c4/locate/unlocated.js +150 -0
  401. package/dist/core/c4/locate/unlocated.js.map +1 -0
  402. package/dist/core/c4/parsed/deployment.js +160 -0
  403. package/dist/core/c4/parsed/deployment.js.map +1 -0
  404. package/dist/core/c4/parsed/dynamic-views.js.map +1 -1
  405. package/dist/core/c4/parsed/values.js +54 -1
  406. package/dist/core/c4/parsed/values.js.map +1 -1
  407. package/dist/core/c4/parsed/view-ids.js +39 -1
  408. package/dist/core/c4/parsed/view-ids.js.map +1 -1
  409. package/dist/core/c4/prefetch/fleet.js +134 -0
  410. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  411. package/dist/core/c4/project/architecture.js +123 -7
  412. package/dist/core/c4/project/architecture.js.map +1 -1
  413. package/dist/core/c4/project/batch.js +140 -0
  414. package/dist/core/c4/project/batch.js.map +1 -0
  415. package/dist/core/c4/project/documents.js +43 -12
  416. package/dist/core/c4/project/documents.js.map +1 -1
  417. package/dist/core/c4/project/load.js +79 -43
  418. package/dist/core/c4/project/load.js.map +1 -1
  419. package/dist/core/c4/project/staged.js +277 -0
  420. package/dist/core/c4/project/staged.js.map +1 -0
  421. package/dist/core/c4/resolve/attested.js +0 -0
  422. package/dist/core/c4/resolve/attested.js.map +1 -0
  423. package/dist/core/c4/resolve/external.js +51 -0
  424. package/dist/core/c4/resolve/external.js.map +1 -0
  425. package/dist/core/c4/resolve/service.js +78 -17
  426. package/dist/core/c4/resolve/service.js.map +1 -1
  427. package/dist/core/c4/resolve/steps.js +290 -0
  428. package/dist/core/c4/resolve/steps.js.map +1 -0
  429. package/dist/core/c4/resolve/systems.js +154 -0
  430. package/dist/core/c4/resolve/systems.js.map +1 -0
  431. package/dist/core/c4/root-project/exclude.js +352 -0
  432. package/dist/core/c4/root-project/exclude.js.map +1 -0
  433. package/dist/core/c4/seed/template.js +65 -1
  434. package/dist/core/c4/seed/template.js.map +1 -1
  435. package/dist/core/c4/service-model/created/models.js +96 -0
  436. package/dist/core/c4/service-model/created/models.js.map +1 -0
  437. package/dist/core/c4/service-model/documents.js +47 -0
  438. package/dist/core/c4/service-model/documents.js.map +1 -0
  439. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  440. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  441. package/dist/core/c4/service-model/load.js +165 -0
  442. package/dist/core/c4/service-model/load.js.map +1 -0
  443. package/dist/core/c4/service-model/renderer.js +128 -0
  444. package/dist/core/c4/service-model/renderer.js.map +1 -0
  445. package/dist/core/c4/service-model/shape.js +106 -0
  446. package/dist/core/c4/service-model/shape.js.map +1 -0
  447. package/dist/core/c4/service-model/slice.js +188 -0
  448. package/dist/core/c4/service-model/slice.js.map +1 -0
  449. package/dist/core/c4/source-mask.js +297 -10
  450. package/dist/core/c4/source-mask.js.map +1 -1
  451. package/dist/core/c4/source-scan.js +222 -141
  452. package/dist/core/c4/source-scan.js.map +1 -1
  453. package/dist/core/c4/splice/authored-source.js +79 -13
  454. package/dist/core/c4/splice/authored-source.js.map +1 -1
  455. package/dist/core/c4/splice/contract.js +20 -0
  456. package/dist/core/c4/splice/contract.js.map +1 -1
  457. package/dist/core/c4/splice/delta-blocks.js +20 -20
  458. package/dist/core/c4/splice/delta-blocks.js.map +1 -1
  459. package/dist/core/c4/splice/identity/declared.js +87 -0
  460. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  461. package/dist/core/c4/splice/identity/edges.js +37 -0
  462. package/dist/core/c4/splice/identity/edges.js.map +1 -1
  463. package/dist/core/c4/splice/identity/existing.js +80 -0
  464. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  465. package/dist/core/c4/splice/identity/interior.js +80 -0
  466. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  467. package/dist/core/c4/splice/identity/owner.js +50 -0
  468. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  469. package/dist/core/c4/splice/landscape-merge.js +182 -114
  470. package/dist/core/c4/splice/landscape-merge.js.map +1 -1
  471. package/dist/core/c4/splice/model/merge.js +151 -0
  472. package/dist/core/c4/splice/model/merge.js.map +1 -0
  473. package/dist/core/c4/splice/placement.js +160 -56
  474. package/dist/core/c4/splice/placement.js.map +1 -1
  475. package/dist/core/c4/splice/text/spot.js +131 -0
  476. package/dist/core/c4/splice/text/spot.js.map +1 -0
  477. package/dist/core/c4/workspace.js +13 -19
  478. package/dist/core/c4/workspace.js.map +1 -1
  479. package/dist/core/capabilities/capabilities.js +6 -6
  480. package/dist/core/capabilities/capabilities.js.map +1 -1
  481. package/dist/core/capabilities/delta/doc.js +7 -10
  482. package/dist/core/capabilities/delta/doc.js.map +1 -1
  483. package/dist/core/capabilities/delta/uncovered.js +2 -2
  484. package/dist/core/capabilities/delta/uncovered.js.map +1 -1
  485. package/dist/core/capabilities/findings.js +18 -22
  486. package/dist/core/capabilities/findings.js.map +1 -1
  487. package/dist/core/capabilities/realizes/findings.js +12 -19
  488. package/dist/core/capabilities/realizes/findings.js.map +1 -1
  489. package/dist/core/capabilities/realizes/join.js +0 -20
  490. package/dist/core/capabilities/realizes/join.js.map +1 -1
  491. package/dist/core/capabilities/rollup.js +6 -0
  492. package/dist/core/capabilities/rollup.js.map +1 -1
  493. package/dist/core/capabilities/tree.js +6 -28
  494. package/dist/core/capabilities/tree.js.map +1 -1
  495. package/dist/core/capabilities/usecase-join.js +3 -13
  496. package/dist/core/capabilities/usecase-join.js.map +1 -1
  497. package/dist/core/coherence/authoring/scaffold.js +11 -3
  498. package/dist/core/coherence/authoring/scaffold.js.map +1 -1
  499. package/dist/core/coherence/authoring/sentinels.js +2 -1
  500. package/dist/core/coherence/authoring/sentinels.js.map +1 -1
  501. package/dist/core/coherence/calls/called.js +52 -0
  502. package/dist/core/coherence/calls/called.js.map +1 -0
  503. package/dist/core/coherence/coherence.js +103 -22
  504. package/dist/core/coherence/coherence.js.map +1 -1
  505. package/dist/core/coherence/consumed/operations.js +70 -0
  506. package/dist/core/coherence/consumed/operations.js.map +1 -0
  507. package/dist/core/coherence/consumed/refusal.js +38 -0
  508. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  509. package/dist/core/coherence/covers/health.js +85 -0
  510. package/dist/core/coherence/covers/health.js.map +1 -0
  511. package/dist/core/coherence/declared.js +60 -34
  512. package/dist/core/coherence/declared.js.map +1 -1
  513. package/dist/core/coherence/events/declared.js +44 -59
  514. package/dist/core/coherence/events/declared.js.map +1 -1
  515. package/dist/core/coherence/events/events.js +147 -16
  516. package/dist/core/coherence/events/events.js.map +1 -1
  517. package/dist/core/coherence/events/grades.js +31 -8
  518. package/dist/core/coherence/events/grades.js.map +1 -1
  519. package/dist/core/coherence/events/lookups.js +28 -87
  520. package/dist/core/coherence/events/lookups.js.map +1 -1
  521. package/dist/core/coherence/events/produced.js +100 -0
  522. package/dist/core/coherence/events/produced.js.map +1 -0
  523. package/dist/core/coherence/lookups.js +18 -78
  524. package/dist/core/coherence/lookups.js.map +1 -1
  525. package/dist/core/coherence/retired/archived.js +285 -0
  526. package/dist/core/coherence/retired/archived.js.map +1 -0
  527. package/dist/core/coherence/retired/event-pair.js +62 -0
  528. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  529. package/dist/core/coherence/retired/merged.js +79 -0
  530. package/dist/core/coherence/retired/merged.js.map +1 -0
  531. package/dist/core/coherence/retired/retirement.js +49 -0
  532. package/dist/core/coherence/retired/retirement.js.map +1 -0
  533. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  534. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  535. package/dist/core/coherence/retired/revival/revived.js +297 -0
  536. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  537. package/dist/core/consumers/after.js +113 -0
  538. package/dist/core/consumers/after.js.map +1 -0
  539. package/dist/core/consumers/consumers.js +296 -0
  540. package/dist/core/consumers/consumers.js.map +1 -0
  541. package/dist/core/consumers/current.js +211 -0
  542. package/dist/core/consumers/current.js.map +1 -0
  543. package/dist/core/consumers/scan.js +46 -0
  544. package/dist/core/consumers/scan.js.map +1 -0
  545. package/dist/core/consumers/state.js +27 -0
  546. package/dist/core/consumers/state.js.map +1 -0
  547. package/dist/core/delta/delta.js +51 -6
  548. package/dist/core/delta/delta.js.map +1 -1
  549. package/dist/core/dependencies/fanin.js +2 -2
  550. package/dist/core/dependencies/fanin.js.map +1 -1
  551. package/dist/core/deployment/delta.js +191 -0
  552. package/dist/core/deployment/delta.js.map +1 -0
  553. package/dist/core/deployment/objects.js +145 -0
  554. package/dist/core/deployment/objects.js.map +1 -0
  555. package/dist/core/diff/base-git.js +94 -12
  556. package/dist/core/diff/base-git.js.map +1 -1
  557. package/dist/core/diff/base-state.js +49 -21
  558. package/dist/core/diff/base-state.js.map +1 -1
  559. package/dist/core/diff/joins.js +136 -0
  560. package/dist/core/diff/joins.js.map +1 -0
  561. package/dist/core/diff/scope/changed-paths.js +22 -6
  562. package/dist/core/diff/scope/changed-paths.js.map +1 -1
  563. package/dist/core/diff/scope/edges.js +82 -0
  564. package/dist/core/diff/scope/edges.js.map +1 -0
  565. package/dist/core/diff/semantic.js +100 -31
  566. package/dist/core/diff/semantic.js.map +1 -1
  567. package/dist/core/docs.js +31 -22
  568. package/dist/core/docs.js.map +1 -1
  569. package/dist/core/doctor/agents.js +34 -18
  570. package/dist/core/doctor/agents.js.map +1 -1
  571. package/dist/core/doctor/config.js +7 -3
  572. package/dist/core/doctor/config.js.map +1 -1
  573. package/dist/core/doctor/doctor.js +91 -11
  574. package/dist/core/doctor/doctor.js.map +1 -1
  575. package/dist/core/doctor/report.js.map +1 -1
  576. package/dist/core/doctor/reports/scan.js +242 -0
  577. package/dist/core/doctor/reports/scan.js.map +1 -0
  578. package/dist/core/document/apply.js +158 -11
  579. package/dist/core/document/apply.js.map +1 -1
  580. package/dist/core/document/frontmatter.js +55 -0
  581. package/dist/core/document/frontmatter.js.map +1 -1
  582. package/dist/core/document/parse.js +29 -6
  583. package/dist/core/document/parse.js.map +1 -1
  584. package/dist/core/document/scenarios.js +17 -0
  585. package/dist/core/document/scenarios.js.map +1 -1
  586. package/dist/core/document/spec.js +4 -11
  587. package/dist/core/document/spec.js.map +1 -1
  588. package/dist/core/envelope/config.js +10 -0
  589. package/dist/core/envelope/config.js.map +1 -1
  590. package/dist/core/envelope/json.js +34 -0
  591. package/dist/core/envelope/json.js.map +1 -1
  592. package/dist/core/explain/families.js +26 -21
  593. package/dist/core/explain/families.js.map +1 -1
  594. package/dist/core/explain/lookup.js +14 -1
  595. package/dist/core/explain/lookup.js.map +1 -1
  596. package/dist/core/explain/refusals.js +5 -5
  597. package/dist/core/explain/refusals.js.map +1 -1
  598. package/dist/core/explain/terms/documents.js +227 -0
  599. package/dist/core/explain/terms/documents.js.map +1 -0
  600. package/dist/core/explain/terms/done-check.js +144 -0
  601. package/dist/core/explain/terms/done-check.js.map +1 -0
  602. package/dist/core/explain/terms/entry.js +14 -0
  603. package/dist/core/explain/terms/entry.js.map +1 -0
  604. package/dist/core/explain/terms/stages.js +71 -0
  605. package/dist/core/explain/terms/stages.js.map +1 -0
  606. package/dist/core/explain/terms/tasks.js +97 -0
  607. package/dist/core/explain/terms/tasks.js.map +1 -0
  608. package/dist/core/explain/terms.js +68 -109
  609. package/dist/core/explain/terms.js.map +1 -1
  610. package/dist/core/explore/explore.js +40 -10
  611. package/dist/core/explore/explore.js.map +1 -1
  612. package/dist/core/fleet-context.js +81 -95
  613. package/dist/core/fleet-context.js.map +1 -1
  614. package/dist/core/gate/checks.js +11 -4
  615. package/dist/core/gate/checks.js.map +1 -1
  616. package/dist/core/gate/partners.js +69 -28
  617. package/dist/core/gate/partners.js.map +1 -1
  618. package/dist/core/gate/report.js.map +1 -1
  619. package/dist/core/gate/verification.js +75 -12
  620. package/dist/core/gate/verification.js.map +1 -1
  621. package/dist/core/gherkin/stale.js +13 -37
  622. package/dist/core/gherkin/stale.js.map +1 -1
  623. package/dist/core/glossary/delta.js +10 -7
  624. package/dist/core/glossary/delta.js.map +1 -1
  625. package/dist/core/glossary/tree.js +6 -19
  626. package/dist/core/glossary/tree.js.map +1 -1
  627. package/dist/core/kernel/concurrency.js +19 -0
  628. package/dist/core/kernel/concurrency.js.map +1 -1
  629. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  630. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  631. package/dist/core/kernel/path-safety.js +38 -0
  632. package/dist/core/kernel/path-safety.js.map +1 -1
  633. package/dist/core/kernel/records.js +11 -0
  634. package/dist/core/kernel/records.js.map +1 -1
  635. package/dist/core/links/backlinks.js +1 -3
  636. package/dist/core/links/backlinks.js.map +1 -1
  637. package/dist/core/links/corpus.js +51 -37
  638. package/dist/core/links/corpus.js.map +1 -1
  639. package/dist/core/links/findings.js.map +1 -1
  640. package/dist/core/links/parse.js +38 -9
  641. package/dist/core/links/parse.js.map +1 -1
  642. package/dist/core/mcp/argv.js +101 -0
  643. package/dist/core/mcp/argv.js.map +1 -1
  644. package/dist/core/mcp/author-tools.js +2 -1
  645. package/dist/core/mcp/author-tools.js.map +1 -1
  646. package/dist/core/mcp/protocol.js +2 -2
  647. package/dist/core/mcp/protocol.js.map +1 -1
  648. package/dist/core/mcp/tools.js +43 -33
  649. package/dist/core/mcp/tools.js.map +1 -1
  650. package/dist/core/openapi/baseline/gate.js +53 -12
  651. package/dist/core/openapi/baseline/gate.js.map +1 -1
  652. package/dist/core/openapi/baseline/plan.js +40 -10
  653. package/dist/core/openapi/baseline/plan.js.map +1 -1
  654. package/dist/core/openapi/baseline/record.js +0 -1
  655. package/dist/core/openapi/baseline/record.js.map +1 -1
  656. package/dist/core/openapi/contract-text.js +33 -0
  657. package/dist/core/openapi/contract-text.js.map +1 -0
  658. package/dist/core/openapi/contract-tree.js +301 -0
  659. package/dist/core/openapi/contract-tree.js.map +1 -0
  660. package/dist/core/openapi/depth.js +38 -24
  661. package/dist/core/openapi/depth.js.map +1 -1
  662. package/dist/core/openapi/digest.js +52 -2
  663. package/dist/core/openapi/digest.js.map +1 -1
  664. package/dist/core/openapi/doc.js +12 -4
  665. package/dist/core/openapi/doc.js.map +1 -1
  666. package/dist/core/openapi/merge/components.js +25 -60
  667. package/dist/core/openapi/merge/components.js.map +1 -1
  668. package/dist/core/openapi/merge/error.js +3 -13
  669. package/dist/core/openapi/merge/error.js.map +1 -1
  670. package/dist/core/openapi/merge/markers.js +26 -30
  671. package/dist/core/openapi/merge/markers.js.map +1 -1
  672. package/dist/core/openapi/merge/merge.js +28 -52
  673. package/dist/core/openapi/merge/merge.js.map +1 -1
  674. package/dist/core/openapi/merge/pin.js +17 -35
  675. package/dist/core/openapi/merge/pin.js.map +1 -1
  676. package/dist/core/openspec/decide/verdict.js.map +1 -1
  677. package/dist/core/openspec/inventory.js +4 -5
  678. package/dist/core/openspec/inventory.js.map +1 -1
  679. package/dist/core/openspec/model/mapping.js +30 -28
  680. package/dist/core/openspec/model/mapping.js.map +1 -1
  681. package/dist/core/openspec/model/model.js +12 -7
  682. package/dist/core/openspec/model/model.js.map +1 -1
  683. package/dist/core/openspec/scan/changes.js +10 -4
  684. package/dist/core/openspec/scan/changes.js.map +1 -1
  685. package/dist/core/openspec/scan/config.js +7 -16
  686. package/dist/core/openspec/scan/config.js.map +1 -1
  687. package/dist/core/openspec/scan/shape.js +63 -19
  688. package/dist/core/openspec/scan/shape.js.map +1 -1
  689. package/dist/core/openspec/scan/walk.js +21 -38
  690. package/dist/core/openspec/scan/walk.js.map +1 -1
  691. package/dist/core/pack/living.js +43 -4
  692. package/dist/core/pack/living.js.map +1 -1
  693. package/dist/core/pack/pack.js +50 -6
  694. package/dist/core/pack/pack.js.map +1 -1
  695. package/dist/core/projection/arch-slice.js +2 -2
  696. package/dist/core/projection/arch-slice.js.map +1 -1
  697. package/dist/core/projection/introduced.js +14 -0
  698. package/dist/core/projection/introduced.js.map +1 -0
  699. package/dist/core/provenance/findings.js +48 -12
  700. package/dist/core/provenance/findings.js.map +1 -1
  701. package/dist/core/provenance/git.js +33 -57
  702. package/dist/core/provenance/git.js.map +1 -1
  703. package/dist/core/provenance/gitq/moves.js +71 -114
  704. package/dist/core/provenance/gitq/moves.js.map +1 -1
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
  707. package/dist/core/provenance/sources.js +23 -6
  708. package/dist/core/provenance/sources.js.map +1 -1
  709. package/dist/core/provenance/stamp.js +5 -17
  710. package/dist/core/provenance/stamp.js.map +1 -1
  711. package/dist/core/repo/authored/paths.js +18 -0
  712. package/dist/core/repo/authored/paths.js.map +1 -1
  713. package/dist/core/repo/entries.js.map +1 -1
  714. package/dist/core/repo/paths.js +92 -6
  715. package/dist/core/repo/paths.js.map +1 -1
  716. package/dist/core/repo/repo.js +74 -14
  717. package/dist/core/repo/repo.js.map +1 -1
  718. package/dist/core/repo/tree/find.js +12 -3
  719. package/dist/core/repo/tree/find.js.map +1 -1
  720. package/dist/core/repo/tree/fs.js +27 -1
  721. package/dist/core/repo/tree/fs.js.map +1 -1
  722. package/dist/core/repo/tree/render/body.js +258 -0
  723. package/dist/core/repo/tree/render/body.js.map +1 -0
  724. package/dist/core/repo/tree/render/projects.js +182 -0
  725. package/dist/core/repo/tree/render/projects.js.map +1 -0
  726. package/dist/core/repo/tree/render/service/header.js +125 -0
  727. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  728. package/dist/core/repo/tree/render/service/peers.js +28 -0
  729. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  730. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  731. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  732. package/dist/core/repo/tree/render/service/views.js +78 -0
  733. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  734. package/dist/core/repo/tree/render/stale.js +42 -0
  735. package/dist/core/repo/tree/render/stale.js.map +1 -0
  736. package/dist/core/repo/tree/render/text.js +84 -0
  737. package/dist/core/repo/tree/render/text.js.map +1 -0
  738. package/dist/core/repo/tree/render/views.js +293 -0
  739. package/dist/core/repo/tree/render/views.js.map +1 -0
  740. package/dist/core/repo/tree/walk.js +53 -32
  741. package/dist/core/repo/tree/walk.js.map +1 -1
  742. package/dist/core/results.js +47 -12
  743. package/dist/core/results.js.map +1 -1
  744. package/dist/core/scaffold/landscape.js +121 -13
  745. package/dist/core/scaffold/landscape.js.map +1 -1
  746. package/dist/core/scaffold/legacy.js +271 -0
  747. package/dist/core/scaffold/legacy.js.map +1 -0
  748. package/dist/core/staging/commit.js +26 -15
  749. package/dist/core/staging/commit.js.map +1 -1
  750. package/dist/core/staging/lock.js +74 -12
  751. package/dist/core/staging/lock.js.map +1 -1
  752. package/dist/core/staging/recovery/intent.js +2 -5
  753. package/dist/core/staging/recovery/intent.js.map +1 -1
  754. package/dist/core/staging/recovery/recover.js +84 -6
  755. package/dist/core/staging/recovery/recover.js.map +1 -1
  756. package/dist/core/staging/snapshot/manifest.js +188 -0
  757. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  758. package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +39 -45
  759. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  760. package/dist/core/staging/txn/forward.js +24 -14
  761. package/dist/core/staging/txn/forward.js.map +1 -1
  762. package/dist/core/staging/writes.js.map +1 -1
  763. package/dist/core/status/actions/execution.js +11 -0
  764. package/dist/core/status/actions/execution.js.map +1 -1
  765. package/dist/core/status/contracts.js +39 -15
  766. package/dist/core/status/contracts.js.map +1 -1
  767. package/dist/core/status/feature/artifacts.js +33 -8
  768. package/dist/core/status/feature/artifacts.js.map +1 -1
  769. package/dist/core/status/feature/feature.js +24 -17
  770. package/dist/core/status/feature/feature.js.map +1 -1
  771. package/dist/core/status/feature/next.js +20 -7
  772. package/dist/core/status/feature/next.js.map +1 -1
  773. package/dist/core/status/feature/words.js +96 -0
  774. package/dist/core/status/feature/words.js.map +1 -0
  775. package/dist/core/status/fleet/fleet.js +43 -14
  776. package/dist/core/status/fleet/fleet.js.map +1 -1
  777. package/dist/core/status/fleet/next.js +153 -58
  778. package/dist/core/status/fleet/next.js.map +1 -1
  779. package/dist/core/status/report.js.map +1 -1
  780. package/dist/core/status/scan.js.map +1 -1
  781. package/dist/core/status/verification.js +30 -15
  782. package/dist/core/status/verification.js.map +1 -1
  783. package/dist/core/tasks/packet.js +199 -0
  784. package/dist/core/tasks/packet.js.map +1 -0
  785. package/dist/core/tasks/record.js +43 -0
  786. package/dist/core/tasks/record.js.map +1 -0
  787. package/dist/core/tasks/sources.js +181 -0
  788. package/dist/core/tasks/sources.js.map +1 -0
  789. package/dist/core/tasks/stamps.js +76 -0
  790. package/dist/core/tasks/stamps.js.map +1 -0
  791. package/dist/core/tasks/unit.js +0 -0
  792. package/dist/core/tasks/unit.js.map +1 -0
  793. package/dist/core/usecases/capability.js +11 -14
  794. package/dist/core/usecases/capability.js.map +1 -1
  795. package/dist/core/usecases/delta/claims.js +31 -7
  796. package/dist/core/usecases/delta/claims.js.map +1 -1
  797. package/dist/core/usecases/delta/flows.js +5 -7
  798. package/dist/core/usecases/delta/flows.js.map +1 -1
  799. package/dist/core/usecases/delta/modified.js +315 -0
  800. package/dist/core/usecases/delta/modified.js.map +1 -0
  801. package/dist/core/usecases/delta/overlay.js +32 -191
  802. package/dist/core/usecases/delta/overlay.js.map +1 -1
  803. package/dist/core/usecases/fleet.js +195 -36
  804. package/dist/core/usecases/fleet.js.map +1 -1
  805. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/capability-tag.js +8 -9
  806. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  807. package/dist/core/usecases/grade/feature.js +88 -0
  808. package/dist/core/usecases/grade/feature.js.map +1 -0
  809. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/requirement-tag.js +3 -4
  810. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  811. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/steps.js +102 -33
  812. package/dist/core/usecases/grade/steps.js.map +1 -0
  813. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/usecases.js +23 -10
  814. package/dist/core/usecases/grade/usecases.js.map +1 -0
  815. package/dist/core/usecases/operations.js +26 -14
  816. package/dist/core/usecases/operations.js.map +1 -1
  817. package/dist/core/usecases/place.js.map +1 -1
  818. package/dist/core/usecases/service/exclude.js +119 -0
  819. package/dist/core/usecases/service/exclude.js.map +1 -0
  820. package/dist/core/usecases/service/flows.js +164 -0
  821. package/dist/core/usecases/service/flows.js.map +1 -0
  822. package/dist/core/usecases/suites/participants.js +83 -0
  823. package/dist/core/usecases/suites/participants.js.map +1 -0
  824. package/dist/core/usecases/suites/suites.js +45 -0
  825. package/dist/core/usecases/suites/suites.js.map +1 -0
  826. package/dist/core/verify/answers.js +12 -5
  827. package/dist/core/verify/answers.js.map +1 -1
  828. package/dist/core/verify/build.js +102 -82
  829. package/dist/core/verify/build.js.map +1 -1
  830. package/dist/core/verify/checklist.js +70 -12
  831. package/dist/core/verify/checklist.js.map +1 -1
  832. package/dist/core/verify/location.js +67 -0
  833. package/dist/core/verify/location.js.map +1 -0
  834. package/dist/core/verify/pins/lint.js +3 -2
  835. package/dist/core/verify/pins/lint.js.map +1 -1
  836. package/dist/core/verify/pins/pin.js +1 -1
  837. package/dist/core/verify/pins/pin.js.map +1 -1
  838. package/dist/core/verify/read/file.js +224 -0
  839. package/dist/core/verify/read/file.js.map +1 -0
  840. package/dist/core/verify/{file.js → read/shape.js} +16 -104
  841. package/dist/core/verify/read/shape.js.map +1 -0
  842. package/dist/core/verify/read/union.js +105 -0
  843. package/dist/core/verify/read/union.js.map +1 -0
  844. package/dist/core/verify/record.js +35 -12
  845. package/dist/core/verify/record.js.map +1 -1
  846. package/dist/core/verify/store/commit.js +40 -30
  847. package/dist/core/verify/store/commit.js.map +1 -1
  848. package/dist/core/verify/store/render.js +8 -4
  849. package/dist/core/verify/store/render.js.map +1 -1
  850. package/dist/core/vocabulary/issue.js +4 -0
  851. package/dist/core/vocabulary/issue.js.map +1 -1
  852. package/dist/core/vocabulary/maturity.js +75 -4
  853. package/dist/core/vocabulary/maturity.js.map +1 -1
  854. package/dist/core/vocabulary/report.js +16 -1
  855. package/dist/core/vocabulary/report.js.map +1 -1
  856. package/examples/README.md +54 -11
  857. package/examples/docs/architecture/landscape.likec4 +62 -6
  858. package/examples/docs/architecture/services.likec4 +70 -0
  859. package/examples/docs/architecture/subsystems.likec4 +7 -0
  860. package/examples/docs/architecture/usecases/order-notification.likec4 +16 -7
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
  863. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +4 -1
  864. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
  865. package/examples/docs/likec4.config.json +0 -1
  866. package/examples/docs/services/checkout-web/model.likec4 +39 -56
  867. package/examples/docs/services/order-service/arch.spec.md +13 -6
  868. package/examples/docs/services/order-service/asyncapi.yaml +3 -2
  869. package/examples/docs/services/order-service/model.likec4 +58 -70
  870. package/examples/docs/services/payment-service/arch.spec.md +7 -4
  871. package/examples/docs/services/payment-service/model.likec4 +38 -37
  872. package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
  873. package/examples/docs/services/platform/identity-service/model.likec4 +35 -37
  874. package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
  875. package/examples/docs/services/platform/notification-service/health.yaml +8 -3
  876. package/examples/docs/services/platform/notification-service/model.likec4 +43 -64
  877. package/package.json +1 -1
  878. package/dist/commands/validate/checks/vocabulary.js +0 -31
  879. package/dist/commands/validate/checks/vocabulary.js.map +0 -1
  880. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +0 -1
  881. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +0 -1
  882. package/dist/commands/validate/fleet/usecases/steps.js.map +0 -1
  883. package/dist/commands/validate/fleet/usecases/usecases.js.map +0 -1
  884. package/dist/core/agent/agents-md/artifacts.js +0 -220
  885. package/dist/core/agent/agents-md/artifacts.js.map +0 -1
  886. package/dist/core/agent/agents-md/cycle.js +0 -165
  887. package/dist/core/agent/agents-md/cycle.js.map +0 -1
  888. package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
  889. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
  890. package/dist/core/agent/agents-md/spine.js +0 -40
  891. package/dist/core/agent/agents-md/spine.js.map +0 -1
  892. package/dist/core/coherence/events/merged.js +0 -40
  893. package/dist/core/coherence/events/merged.js.map +0 -1
  894. package/dist/core/diff/current-state.js +0 -96
  895. package/dist/core/diff/current-state.js.map +0 -1
  896. package/dist/core/diff/victims.js +0 -247
  897. package/dist/core/diff/victims.js.map +0 -1
  898. package/dist/core/repo/tree/views.js +0 -172
  899. package/dist/core/repo/tree/views.js.map +0 -1
  900. package/dist/core/staging/snapshot.js.map +0 -1
  901. package/dist/core/verify/file.js.map +0 -1
@@ -1,9 +1,21 @@
1
1
  /**
2
2
  * The concept terms `loam explain` answers — the vocabulary wall an agent hits
3
- * in its first minute, before any docs repo exists to read.
3
+ * in its first minute, before any docs repo exists to read, and the words loam
4
+ * itself prints to a person: the stage `loam status` reports, the claims and
5
+ * verdicts of `loam verify`, the steps of `loam tasks`, the rungs of the
6
+ * maturity ladder.
4
7
  *
5
- * Each paragraph is authored HERE, but it is not free to drift: every entry
6
- * carries pin phrases lifted VERBATIM from the section that teaches the
8
+ * The paragraphs live one package down, in ./terms/, one module per subject;
9
+ * this module assembles them and names the texts their pins point at. The
10
+ * split came when the registry outgrew its first six terms: twenty-odd
11
+ * paragraphs do not fit one 400-line file, src/core/explain/ was already at
12
+ * its five-file cap, and the terms fall into the four clusters the listing
13
+ * prints them under — which is a subject seam, not a line count. `TERMS` and
14
+ * `PIN_SOURCE_TEXT` stay exported from here so every importer (the lookup, the
15
+ * MCP tool table, the tests) reads the registry from where it always did.
16
+ *
17
+ * Each paragraph is authored in ./terms/, but it is not free to drift: every
18
+ * entry carries pin phrases lifted VERBATIM from the section that teaches the
7
19
  * concept, and test/explain.test.ts asserts each phrase appears both in the
8
20
  * paragraph and in its named source constant. Rewording that prose therefore
9
21
  * breaks the pairing loudly — the same discipline the compiler applies to
@@ -16,129 +28,76 @@
16
28
  * with them, and `vouch`'s pin went with the text rather than being reworded
17
29
  * to something still in the file — the pairing is with whatever loam SHIPS as
18
30
  * the teaching, not with one delivery of it.
31
+ *
32
+ * The converse failure is a source that ships NOWHERE, and it happened: once
33
+ * AGENTS.md became the one ORIENTATION literal (../agent/agents-md.ts), the old
34
+ * section constants this file still imported — the long cycle, the layout
35
+ * opening, the binding rule — were assembled into nothing, so the pins on them
36
+ * guarded prose no reader could see and the drift test passed vacuously. Those
37
+ * sources were deleted with the constants; a pin now names a page the binary
38
+ * prints or the AGENTS.md it writes, never a constant that merely compiles.
39
+ * The five sources added with the printed-word terms follow that rule: each is
40
+ * a whole page `loam instructions` prints — the loam-codes page rather than its
41
+ * `loam status` section, the /loam-implement body rather than its step 3.
19
42
  */
20
- import { ARTIFACTS } from "../agent/agents-md/artifacts.js";
21
- import { CYCLE } from "../agent/agents-md/cycle.js";
43
+ import { AGENTS_MD } from "../agent/agents-md.js";
22
44
  import { REFUSALS } from "../agent/agents-md/refusals.js";
23
- import { SPINE } from "../agent/agents-md/spine.js";
45
+ import { LOAM_CHECK } from "../agent/workflows/check.js";
46
+ import { LOAM_VERIFY } from "../agent/workflows/closing.js";
47
+ import { LOAM_FEATURE } from "../agent/workflows/feature.js";
48
+ import { LOAM_IMPLEMENT } from "../agent/workflows/implement.js";
24
49
  import { LOAM_AUTHORING } from "../agent/workflows/reference/authoring.js";
50
+ import { LOAM_CODES } from "../agent/workflows/reference/codes.js";
25
51
  import { LOAM_DONE_CHECK } from "../agent/workflows/reference/done-check.js";
52
+ import { LOAM_DRAWING } from "../agent/workflows/reference/drawing/drawing.js";
26
53
  import { LOAM_SPINE } from "../agent/workflows/reference/spine.js";
54
+ import { DOCUMENT_TERMS, DRAWING_TERMS } from "./terms/documents.js";
55
+ import { DONE_CHECK_TERMS } from "./terms/done-check.js";
56
+ import { STAGE_TERMS } from "./terms/stages.js";
57
+ import { TASK_TERMS } from "./terms/tasks.js";
27
58
  /**
28
- * The section constants the pins point at, for the drift test and for anyone
59
+ * The shipped texts the pins point at, for the drift test and for anyone
29
60
  * auditing a pairing.
30
61
  *
31
62
  * `REFUSALS` is still listed and still pinned against, and it is no longer a
32
63
  * section of AGENTS.md — it is the refusal half of the `loam-codes` page. The
33
64
  * constant is what a pin names, and the constant did not move; only its
34
- * delivery did.
65
+ * delivery did. `CODES_PAGE` is that whole page, which is where the `loam
66
+ * status` section teaching the five stage values is printed.
67
+ *
68
+ * The workflow bodies are the raw protocol text, `$1`/`$2` placeholders and
69
+ * all — `loam instructions` substitutes them on the way out — so a pin phrase
70
+ * must never span a placeholder, or it would match here and not on the page a
71
+ * reader is shown.
35
72
  */
36
73
  export const PIN_SOURCE_TEXT = {
37
- SPINE,
74
+ AGENTS_MD,
38
75
  SPINE_PAGE: LOAM_SPINE.body,
39
76
  REFUSALS,
40
- CYCLE,
41
- ARTIFACTS,
42
77
  AUTHORING: LOAM_AUTHORING.body,
78
+ DRAWING: LOAM_DRAWING.body,
43
79
  DONE_CHECK: LOAM_DONE_CHECK.body,
80
+ CODES_PAGE: LOAM_CODES.body,
81
+ CHECK: LOAM_CHECK.body,
82
+ FEATURE: LOAM_FEATURE.body,
83
+ IMPLEMENT: LOAM_IMPLEMENT.body,
84
+ VERIFY: LOAM_VERIFY.body,
44
85
  };
45
- export const TERMS = [
46
- {
47
- term: "vouch",
48
- aliases: ["vouched", "vouching"],
49
- paragraph: "A vouch is the human promotion of a living document from draft to verified. " +
50
- "Promoting draft to verified is their call, not yours: a person runs `loam vouch --service <id>` in the service's own repo, " +
51
- "and the stamp records the date, who vouched (from git), and digests of both the source files and the document body — " +
52
- "which is what lets a later `loam validate` report `sources.stale` and `content.stale` when the code or the words move. " +
53
- "**`loam vouch` is not yours to run**, and it is built so that it cannot be. It refuses unattended runs (`vouch-unattended`), " +
54
- "records a no as `vouch-declined`, and refuses to stamp when git can name nobody (`vouch-unattributable`); " +
55
- "when your work leaves a document ready, hand back and say a vouch is owed.",
56
- pins: [
57
- // Both phrases left AGENTS.md with the frontmatter teaching and are now
58
- // in `loam instructions loam-authoring`. Repaired by following the text,
59
- // not by rewording the paragraph to something still in the file: the
60
- // pairing exists so this paragraph and the teaching cannot drift, and
61
- // re-pinning to a different sentence would have quietly ended it.
62
- { source: "AUTHORING", phrase: "Promoting draft to verified is their call, not yours" },
63
- { source: "AUTHORING", phrase: "**`loam vouch` is not yours to run**, and it is built so that it cannot be." },
64
- ],
65
- },
66
- {
67
- term: "attested",
68
- aliases: ["attest", "attestation"],
69
- paragraph: "Attested is the verdict one rung below verified on the done-check's ladder. " +
70
- "Verified means somebody says the code was built and showed evidence — and for scenario claims that evidence is a " +
71
- "test runner's report, answered mechanically. Without a runnable suite your word can still answer them " +
72
- "(`loam verify <FEAT> --record` alone), but the record says who answered, and a feature whose " +
73
- "scenario claims rest on an agent's word is **attested**, not verified. Nothing gates on the difference; " +
74
- "pass `--results <report>` the moment a suite runs and the verdict moves on its own.",
75
- pins: [
76
- { source: "REFUSALS", phrase: "somebody says the code was built and showed evidence" },
77
- // Left the cycle with the done-check teaching; repaired by following the
78
- // text, as `vouch`'s two were.
79
- { source: "DONE_CHECK", phrase: "scenario claims rest on an agent's word is **attested**, not verified" },
80
- ],
81
- },
82
- {
83
- term: "spine",
84
- aliases: [],
85
- paragraph: "The spine is a family of exact joins, not one magic id. Its ids are the feature tag (`#FEAT-101`), the service " +
86
- "binding (`metadata { service }`), the synchronous operationId, the asynchronous message name, `Covers:` " +
87
- "architecture coverage, `Requires:` permissions and `Capability:` realization. Three artifacts describe one synchronous call — " +
88
- "a C4 edge, a requirement's `Operations:` line, the provider's openapi.yaml — joined by the operationId, and that " +
89
- "join is what `loam validate` checks. Spell it identically in all three places. The `spine.*` findings are exactly " +
90
- "these joins failing to resolve, and a mismatch is a broken contract between services, not a style problem.",
91
- pins: [
92
- { source: "SPINE_PAGE", phrase: "The spine is a family of exact joins, not one magic id" },
93
- { source: "SPINE_PAGE", phrase: "Spell it identically in all three places." },
94
- ],
95
- },
96
- {
97
- term: "delta",
98
- aliases: ["deltas"],
99
- paragraph: "A delta is a feature's change, stated against the living docs rather than in them. " +
100
- "The living spec.md is the complete current state; a feature's copy is a diff against it, reviewed as a diff, with " +
101
- "requirements grouped under `## ADDED`, `## MODIFIED` or `## REMOVED Requirements`; delta.likec4 carries the " +
102
- "architecture change with every changed element tagged `#<FEAT>` (untagged elements are context, not changes); " +
103
- "and the contract deltas are complete documents whose baseline pins mark what is merely quoted. " +
104
- "`loam archive` folds the delta into the living state. The `delta.*` findings grade that algebra — whether the " +
105
- "diff still applies to the living document it claims to change.",
106
- pins: [
107
- { source: "ARTIFACTS", phrase: "is a diff against it, reviewed as a diff" },
108
- { source: "ARTIFACTS", phrase: "`loam archive` folds the delta into the living state." },
109
- ],
110
- },
111
- {
112
- term: "axis",
113
- aliases: ["axes"],
114
- paragraph: "An axis is one language a service is described in, and loam's checks are joins BETWEEN axes rather than opinions within one. " +
115
- "The three: architecture — a C4 edge names the operation it calls; behaviour — a requirement declares the " +
116
- "operations it governs; contract — the provider's `openapi.yaml` defines it (asyncapi.yaml is the same axis for " +
117
- "events, and arch.spec.md is the behaviour axis for architectural obligations). A finding code's prefix names the " +
118
- "axes that disagree — `spec-api.op-undefined` is the behaviour axis joined against the contract axis — and the fix " +
119
- "is whichever side is wrong about the world.",
120
- pins: [
121
- { source: "SPINE_PAGE", phrase: "architecture — a C4 edge names the operation it calls" },
122
- { source: "SPINE_PAGE", phrase: "behaviour — a requirement declares the operations it governs" },
123
- { source: "SPINE_PAGE", phrase: "contract — the provider's `openapi.yaml` defines it" },
124
- ],
125
- },
126
- {
127
- term: "baseline",
128
- aliases: ["based-on", "baselines"],
129
- paragraph: "A baseline is the pin tying a delta to the living version it was written against. It rides as `Based-On:` under a " +
130
- "MODIFIED/REMOVED requirement and `x-loam-based-on` on a contract surface — written by `loam rebase <FEAT>`, never by " +
131
- "hand. It exists because a MODIFIED requirement carries its FULL new text, not a diff, so the merge REPLACES the " +
132
- "living text wholesale; the pin is what lets archive tell an edit from a quote and refuse a stale one " +
133
- "(`delta.baseline-stale`, `openapi.baseline-stale`) instead of silently reverting work that landed in between. " +
134
- `**Restamping is not resolving.** A pin claims "I read this version". ` +
135
- "Re-read the living text and fold in what you still mean before you re-pin.",
136
- pins: [
137
- // Without the sentence-initial "A": the paragraph embeds the clause
138
- // mid-sentence, and a pin is a verbatim substring of BOTH sides.
139
- { source: "SPINE_PAGE", phrase: "MODIFIED requirement carries its FULL new text, not a diff" },
140
- { source: "SPINE_PAGE", phrase: `**Restamping is not resolving.** A pin claims "I read this version".` },
141
- ],
142
- },
86
+ /**
87
+ * The registry, by subject, in the order the bare `loam explain` listing
88
+ * prints it: where a feature stands first, because `loam status` is the first
89
+ * command a newcomer runs, then the two commands whose words its next steps
90
+ * send a reader to, then the document vocabulary underneath all three, and
91
+ * last the words for drawing the map, which no command prints and every page
92
+ * that draws an edge uses.
93
+ */
94
+ export const TERM_GROUPS = [
95
+ STAGE_TERMS,
96
+ DONE_CHECK_TERMS,
97
+ TASK_TERMS,
98
+ DOCUMENT_TERMS,
99
+ DRAWING_TERMS,
143
100
  ];
101
+ /** Every term, flat, in listing order — what the lookup searches and the `--json` listing returns. */
102
+ export const TERMS = TERM_GROUPS.flatMap((group) => group.terms);
144
103
  //# sourceMappingURL=terms.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"terms.js","sourceRoot":"","sources":["../../../src/core/explain/terms.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The concept terms `loam explain` answers — the vocabulary wall an agent hits\n * in its first minute, before any docs repo exists to read.\n *\n * Each paragraph is authored HERE, but it is not free to drift: every entry\n * carries pin phrases lifted VERBATIM from the section that teaches the\n * concept, and test/explain.test.ts asserts each phrase appears both in the\n * paragraph and in its named source constant. Rewording that prose therefore\n * breaks the pairing loudly — the same discipline the compiler applies to\n * refusals.ts, done with a test because prose has no type. A pin phrase is\n * kept to one source LINE, because the sections wrap at ~80 columns and a\n * phrase spanning a wrap would never match.\n *\n * A source is no longer always an agents-md section. When the reference pages\n * were split out of the scaffolded AGENTS.md, the frontmatter teaching went\n * with them, and `vouch`'s pin went with the text rather than being reworded\n * to something still in the file — the pairing is with whatever loam SHIPS as\n * the teaching, not with one delivery of it.\n */\nimport { ARTIFACTS } from \"../agent/agents-md/artifacts.js\";\nimport { CYCLE } from \"../agent/agents-md/cycle.js\";\nimport { REFUSALS } from \"../agent/agents-md/refusals.js\";\nimport { SPINE } from \"../agent/agents-md/spine.js\";\nimport { LOAM_AUTHORING } from \"../agent/workflows/reference/authoring.js\";\nimport { LOAM_DONE_CHECK } from \"../agent/workflows/reference/done-check.js\";\nimport { LOAM_SPINE } from \"../agent/workflows/reference/spine.js\";\n\nexport type PinSource =\n | \"SPINE\"\n | \"SPINE_PAGE\"\n | \"REFUSALS\"\n | \"CYCLE\"\n | \"ARTIFACTS\"\n | \"AUTHORING\"\n | \"DONE_CHECK\";\n\n/**\n * The section constants the pins point at, for the drift test and for anyone\n * auditing a pairing.\n *\n * `REFUSALS` is still listed and still pinned against, and it is no longer a\n * section of AGENTS.md — it is the refusal half of the `loam-codes` page. The\n * constant is what a pin names, and the constant did not move; only its\n * delivery did.\n */\nexport const PIN_SOURCE_TEXT: Record<PinSource, string> = {\n SPINE,\n SPINE_PAGE: LOAM_SPINE.body,\n REFUSALS,\n CYCLE,\n ARTIFACTS,\n AUTHORING: LOAM_AUTHORING.body,\n DONE_CHECK: LOAM_DONE_CHECK.body,\n};\n\nexport interface TermPin {\n readonly source: PinSource;\n /** A verbatim single-line substring of both the paragraph and the source section. */\n readonly phrase: string;\n}\n\nexport interface TermEntry {\n readonly term: string;\n readonly aliases: readonly string[];\n /** The explanation. Its FIRST sentence doubles as the no-argument listing's summary. */\n readonly paragraph: string;\n readonly pins: readonly TermPin[];\n}\n\nexport const TERMS: readonly TermEntry[] = [\n {\n term: \"vouch\",\n aliases: [\"vouched\", \"vouching\"],\n paragraph:\n \"A vouch is the human promotion of a living document from draft to verified. \" +\n \"Promoting draft to verified is their call, not yours: a person runs `loam vouch --service <id>` in the service's own repo, \" +\n \"and the stamp records the date, who vouched (from git), and digests of both the source files and the document body — \" +\n \"which is what lets a later `loam validate` report `sources.stale` and `content.stale` when the code or the words move. \" +\n \"**`loam vouch` is not yours to run**, and it is built so that it cannot be. It refuses unattended runs (`vouch-unattended`), \" +\n \"records a no as `vouch-declined`, and refuses to stamp when git can name nobody (`vouch-unattributable`); \" +\n \"when your work leaves a document ready, hand back and say a vouch is owed.\",\n pins: [\n // Both phrases left AGENTS.md with the frontmatter teaching and are now\n // in `loam instructions loam-authoring`. Repaired by following the text,\n // not by rewording the paragraph to something still in the file: the\n // pairing exists so this paragraph and the teaching cannot drift, and\n // re-pinning to a different sentence would have quietly ended it.\n { source: \"AUTHORING\", phrase: \"Promoting draft to verified is their call, not yours\" },\n { source: \"AUTHORING\", phrase: \"**`loam vouch` is not yours to run**, and it is built so that it cannot be.\" },\n ],\n },\n {\n term: \"attested\",\n aliases: [\"attest\", \"attestation\"],\n paragraph:\n \"Attested is the verdict one rung below verified on the done-check's ladder. \" +\n \"Verified means somebody says the code was built and showed evidence — and for scenario claims that evidence is a \" +\n \"test runner's report, answered mechanically. Without a runnable suite your word can still answer them \" +\n \"(`loam verify <FEAT> --record` alone), but the record says who answered, and a feature whose \" +\n \"scenario claims rest on an agent's word is **attested**, not verified. Nothing gates on the difference; \" +\n \"pass `--results <report>` the moment a suite runs and the verdict moves on its own.\",\n pins: [\n { source: \"REFUSALS\", phrase: \"somebody says the code was built and showed evidence\" },\n // Left the cycle with the done-check teaching; repaired by following the\n // text, as `vouch`'s two were.\n { source: \"DONE_CHECK\", phrase: \"scenario claims rest on an agent's word is **attested**, not verified\" },\n ],\n },\n {\n term: \"spine\",\n aliases: [],\n paragraph:\n \"The spine is a family of exact joins, not one magic id. Its ids are the feature tag (`#FEAT-101`), the service \" +\n \"binding (`metadata { service }`), the synchronous operationId, the asynchronous message name, `Covers:` \" +\n \"architecture coverage, `Requires:` permissions and `Capability:` realization. Three artifacts describe one synchronous call — \" +\n \"a C4 edge, a requirement's `Operations:` line, the provider's openapi.yaml — joined by the operationId, and that \" +\n \"join is what `loam validate` checks. Spell it identically in all three places. The `spine.*` findings are exactly \" +\n \"these joins failing to resolve, and a mismatch is a broken contract between services, not a style problem.\",\n pins: [\n { source: \"SPINE_PAGE\", phrase: \"The spine is a family of exact joins, not one magic id\" },\n { source: \"SPINE_PAGE\", phrase: \"Spell it identically in all three places.\" },\n ],\n },\n {\n term: \"delta\",\n aliases: [\"deltas\"],\n paragraph:\n \"A delta is a feature's change, stated against the living docs rather than in them. \" +\n \"The living spec.md is the complete current state; a feature's copy is a diff against it, reviewed as a diff, with \" +\n \"requirements grouped under `## ADDED`, `## MODIFIED` or `## REMOVED Requirements`; delta.likec4 carries the \" +\n \"architecture change with every changed element tagged `#<FEAT>` (untagged elements are context, not changes); \" +\n \"and the contract deltas are complete documents whose baseline pins mark what is merely quoted. \" +\n \"`loam archive` folds the delta into the living state. The `delta.*` findings grade that algebra — whether the \" +\n \"diff still applies to the living document it claims to change.\",\n pins: [\n { source: \"ARTIFACTS\", phrase: \"is a diff against it, reviewed as a diff\" },\n { source: \"ARTIFACTS\", phrase: \"`loam archive` folds the delta into the living state.\" },\n ],\n },\n {\n term: \"axis\",\n aliases: [\"axes\"],\n paragraph:\n \"An axis is one language a service is described in, and loam's checks are joins BETWEEN axes rather than opinions within one. \" +\n \"The three: architecture — a C4 edge names the operation it calls; behaviour — a requirement declares the \" +\n \"operations it governs; contract — the provider's `openapi.yaml` defines it (asyncapi.yaml is the same axis for \" +\n \"events, and arch.spec.md is the behaviour axis for architectural obligations). A finding code's prefix names the \" +\n \"axes that disagree — `spec-api.op-undefined` is the behaviour axis joined against the contract axis — and the fix \" +\n \"is whichever side is wrong about the world.\",\n pins: [\n { source: \"SPINE_PAGE\", phrase: \"architecture — a C4 edge names the operation it calls\" },\n { source: \"SPINE_PAGE\", phrase: \"behaviour — a requirement declares the operations it governs\" },\n { source: \"SPINE_PAGE\", phrase: \"contract — the provider's `openapi.yaml` defines it\" },\n ],\n },\n {\n term: \"baseline\",\n aliases: [\"based-on\", \"baselines\"],\n paragraph:\n \"A baseline is the pin tying a delta to the living version it was written against. It rides as `Based-On:` under a \" +\n \"MODIFIED/REMOVED requirement and `x-loam-based-on` on a contract surface — written by `loam rebase <FEAT>`, never by \" +\n \"hand. It exists because a MODIFIED requirement carries its FULL new text, not a diff, so the merge REPLACES the \" +\n \"living text wholesale; the pin is what lets archive tell an edit from a quote and refuse a stale one \" +\n \"(`delta.baseline-stale`, `openapi.baseline-stale`) instead of silently reverting work that landed in between. \" +\n `**Restamping is not resolving.** A pin claims \"I read this version\". ` +\n \"Re-read the living text and fold in what you still mean before you re-pin.\",\n pins: [\n // Without the sentence-initial \"A\": the paragraph embeds the clause\n // mid-sentence, and a pin is a verbatim substring of BOTH sides.\n { source: \"SPINE_PAGE\", phrase: \"MODIFIED requirement carries its FULL new text, not a diff\" },\n { source: \"SPINE_PAGE\", phrase: `**Restamping is not resolving.** A pin claims \"I read this version\".` },\n ],\n },\n];\n"]}
1
+ {"version":3,"file":"terms.js","sourceRoot":"","sources":["../../../src/core/explain/terms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,iDAAiD,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,eAAe,GAA8B;IACxD,SAAS;IACT,UAAU,EAAE,UAAU,CAAC,IAAI;IAC3B,QAAQ;IACR,SAAS,EAAE,cAAc,CAAC,IAAI;IAC9B,OAAO,EAAE,YAAY,CAAC,IAAI;IAC1B,UAAU,EAAE,eAAe,CAAC,IAAI;IAChC,UAAU,EAAE,UAAU,CAAC,IAAI;IAC3B,KAAK,EAAE,UAAU,CAAC,IAAI;IACtB,OAAO,EAAE,YAAY,CAAC,IAAI;IAC1B,SAAS,EAAE,cAAc,CAAC,IAAI;IAC9B,MAAM,EAAE,WAAW,CAAC,IAAI;CACzB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAyB;IAC/C,WAAW;IACX,gBAAgB;IAChB,UAAU;IACV,cAAc;IACd,aAAa;CACd,CAAC;AAEF,sGAAsG;AACtG,MAAM,CAAC,MAAM,KAAK,GAAyB,WAAW,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC","sourcesContent":["/**\n * The concept terms `loam explain` answers — the vocabulary wall an agent hits\n * in its first minute, before any docs repo exists to read, and the words loam\n * itself prints to a person: the stage `loam status` reports, the claims and\n * verdicts of `loam verify`, the steps of `loam tasks`, the rungs of the\n * maturity ladder.\n *\n * The paragraphs live one package down, in ./terms/, one module per subject;\n * this module assembles them and names the texts their pins point at. The\n * split came when the registry outgrew its first six terms: twenty-odd\n * paragraphs do not fit one 400-line file, src/core/explain/ was already at\n * its five-file cap, and the terms fall into the four clusters the listing\n * prints them under — which is a subject seam, not a line count. `TERMS` and\n * `PIN_SOURCE_TEXT` stay exported from here so every importer (the lookup, the\n * MCP tool table, the tests) reads the registry from where it always did.\n *\n * Each paragraph is authored in ./terms/, but it is not free to drift: every\n * entry carries pin phrases lifted VERBATIM from the section that teaches the\n * concept, and test/explain.test.ts asserts each phrase appears both in the\n * paragraph and in its named source constant. Rewording that prose therefore\n * breaks the pairing loudly — the same discipline the compiler applies to\n * refusals.ts, done with a test because prose has no type. A pin phrase is\n * kept to one source LINE, because the sections wrap at ~80 columns and a\n * phrase spanning a wrap would never match.\n *\n * A source is no longer always an agents-md section. When the reference pages\n * were split out of the scaffolded AGENTS.md, the frontmatter teaching went\n * with them, and `vouch`'s pin went with the text rather than being reworded\n * to something still in the file — the pairing is with whatever loam SHIPS as\n * the teaching, not with one delivery of it.\n *\n * The converse failure is a source that ships NOWHERE, and it happened: once\n * AGENTS.md became the one ORIENTATION literal (../agent/agents-md.ts), the old\n * section constants this file still imported — the long cycle, the layout\n * opening, the binding rule — were assembled into nothing, so the pins on them\n * guarded prose no reader could see and the drift test passed vacuously. Those\n * sources were deleted with the constants; a pin now names a page the binary\n * prints or the AGENTS.md it writes, never a constant that merely compiles.\n * The five sources added with the printed-word terms follow that rule: each is\n * a whole page `loam instructions` prints — the loam-codes page rather than its\n * `loam status` section, the /loam-implement body rather than its step 3.\n */\nimport { AGENTS_MD } from \"../agent/agents-md.js\";\nimport { REFUSALS } from \"../agent/agents-md/refusals.js\";\nimport { LOAM_CHECK } from \"../agent/workflows/check.js\";\nimport { LOAM_VERIFY } from \"../agent/workflows/closing.js\";\nimport { LOAM_FEATURE } from \"../agent/workflows/feature.js\";\nimport { LOAM_IMPLEMENT } from \"../agent/workflows/implement.js\";\nimport { LOAM_AUTHORING } from \"../agent/workflows/reference/authoring.js\";\nimport { LOAM_CODES } from \"../agent/workflows/reference/codes.js\";\nimport { LOAM_DONE_CHECK } from \"../agent/workflows/reference/done-check.js\";\nimport { LOAM_DRAWING } from \"../agent/workflows/reference/drawing/drawing.js\";\nimport { LOAM_SPINE } from \"../agent/workflows/reference/spine.js\";\nimport { DOCUMENT_TERMS, DRAWING_TERMS } from \"./terms/documents.js\";\nimport { DONE_CHECK_TERMS } from \"./terms/done-check.js\";\nimport type { PinSource, TermEntry, TermGroup } from \"./terms/entry.js\";\nimport { STAGE_TERMS } from \"./terms/stages.js\";\nimport { TASK_TERMS } from \"./terms/tasks.js\";\n\n/**\n * The shipped texts the pins point at, for the drift test and for anyone\n * auditing a pairing.\n *\n * `REFUSALS` is still listed and still pinned against, and it is no longer a\n * section of AGENTS.md — it is the refusal half of the `loam-codes` page. The\n * constant is what a pin names, and the constant did not move; only its\n * delivery did. `CODES_PAGE` is that whole page, which is where the `loam\n * status` section teaching the five stage values is printed.\n *\n * The workflow bodies are the raw protocol text, `$1`/`$2` placeholders and\n * all — `loam instructions` substitutes them on the way out — so a pin phrase\n * must never span a placeholder, or it would match here and not on the page a\n * reader is shown.\n */\nexport const PIN_SOURCE_TEXT: Record<PinSource, string> = {\n AGENTS_MD,\n SPINE_PAGE: LOAM_SPINE.body,\n REFUSALS,\n AUTHORING: LOAM_AUTHORING.body,\n DRAWING: LOAM_DRAWING.body,\n DONE_CHECK: LOAM_DONE_CHECK.body,\n CODES_PAGE: LOAM_CODES.body,\n CHECK: LOAM_CHECK.body,\n FEATURE: LOAM_FEATURE.body,\n IMPLEMENT: LOAM_IMPLEMENT.body,\n VERIFY: LOAM_VERIFY.body,\n};\n\n/**\n * The registry, by subject, in the order the bare `loam explain` listing\n * prints it: where a feature stands first, because `loam status` is the first\n * command a newcomer runs, then the two commands whose words its next steps\n * send a reader to, then the document vocabulary underneath all three, and\n * last the words for drawing the map, which no command prints and every page\n * that draws an edge uses.\n */\nexport const TERM_GROUPS: readonly TermGroup[] = [\n STAGE_TERMS,\n DONE_CHECK_TERMS,\n TASK_TERMS,\n DOCUMENT_TERMS,\n DRAWING_TERMS,\n];\n\n/** Every term, flat, in listing order — what the lookup searches and the `--json` listing returns. */\nexport const TERMS: readonly TermEntry[] = TERM_GROUPS.flatMap((group) => group.terms);\n"]}
@@ -16,15 +16,20 @@
16
16
  * documentation has got — and stops. Which of those neighbours the feature
17
17
  * really touches is a judgement about intent, and loam does not make those.
18
18
  *
19
- * The landscape is parsed ONCE for the whole exploration. Per-service reads of
20
- * it exist (`brief/landscape.ts`'s `landscapeContext`) and are correct for one service;
19
+ * "The fleet map" here is the `architecture/` PROJECT — the landscape plus every
20
+ * other `.likec4` under it, minus the generated views file — and not the
21
+ * landscape FILE. See the read below for the disagreement that reading one file
22
+ * caused.
23
+ *
24
+ * It is parsed ONCE for the whole exploration. Per-service reads of it exist
25
+ * (`brief/landscape.ts`'s `landscapeContext`) and are correct for one service;
21
26
  * calling one of those per seed is how `validate --all` came to cost 13 seconds
22
27
  * on 120 services, and this command sits in front of authoring, where that is
23
28
  * the difference between a habit and a thing people skip.
24
29
  */
25
30
  import { existsSync } from "node:fs";
26
31
  import { FleetContext } from "../fleet-context.js";
27
- import {} from "../c4/likec4.js";
32
+ import { brokenDocumentPaths } from "../c4/likec4.js";
28
33
  import { serviceResolver } from "../c4/resolve/service.js";
29
34
  import {} from "../vocabulary/maturity.js";
30
35
  import { capabilityRollup, unresolvedCapabilities } from "../capabilities/rollup.js";
@@ -43,9 +48,24 @@ export async function explore(req) {
43
48
  const entries = await context.listServices(docsDir);
44
49
  const byId = new Map(entries.map((e) => [e.id, e]));
45
50
  const known = new Set(byId.keys());
46
- const landPath = landscapePath(docsDir);
47
- const present = existsSync(landPath);
48
- const land = present ? await context.loadLikeC4(landPath) : null;
51
+ // The `architecture/` PROJECT, never `architecture/landscape.likec4` alone.
52
+ // The map is a project — the landscape merged with every use case, palette and
53
+ // second `model { }` block beside it — and reading one file of it made this
54
+ // command answer differently from `loam adopt` and `loam context` about the
55
+ // same tree (reproduced: with a broken `architecture/palette.likec4` beside a
56
+ // landscape that parses, `context checkout-web --json` reported
57
+ // `landscape.parses: false` while `explore checkout-web --json` reported
58
+ // `parses: true` and went on to describe every edge). `core/pack/living.ts`
59
+ // named this module as the last reader that disagreed. Whichever answer is
60
+ // right, an agent handed both has no way to tell — and the renderer's answer
61
+ // is the project's.
62
+ //
63
+ // `present` stays a fact about the FILE, because that file is the WRITE target:
64
+ // `loam new`'s scaffold and every brief ask for edits to
65
+ // `architecture/landscape.likec4` by name, and "the project is empty" is not
66
+ // the same instruction as "there is no map to edit".
67
+ const present = existsSync(landscapePath(docsDir));
68
+ const land = present ? await context.architecture(docsDir) : null;
49
69
  const parses = land !== null && land.errors.length === 0;
50
70
  const elements = parses ? land.elements : [];
51
71
  const relationships = parses ? land.relationships : [];
@@ -79,9 +99,15 @@ export async function explore(req) {
79
99
  // other: a service can realize a capability without appearing in its drawn
80
100
  // flow, and a flow can pass through a service that has written nothing down.
81
101
  //
82
- // The scan gates its own load, and this whole block is already behind
83
- // `--capability` being passed at all, so an exploration by service or by
84
- // operation never touches `architecture/` as a project.
102
+ // The scan gates its own load — a fleet whose documents mention no reserved
103
+ // tag never starts LikeC4 for it — and this whole block is behind
104
+ // `--capability` being passed at all. What it is no longer behind is the
105
+ // project itself: the read above loads `architecture/` for every exploration,
106
+ // so a `--capability` run pays for a SECOND parse of the same documents
107
+ // (`readUseCases` takes a `DocsDir`, not this invocation's memo). Accepted
108
+ // rather than unnoticed: the alternative is a seam that hands the scan a
109
+ // pre-loaded project, which is a change to a module five callers share, and
110
+ // the cost lands only on the flag that already opts into the fleet rollup.
85
111
  const capSeeds = [];
86
112
  let unresolvedCaps = [];
87
113
  if (req.capabilities.length > 0) {
@@ -167,7 +193,11 @@ export async function explore(req) {
167
193
  services,
168
194
  neighbours: [...ring.keys()].sort(compareIds),
169
195
  overlaps,
170
- landscape: { present, parses },
196
+ landscape: {
197
+ present,
198
+ parses,
199
+ broken: land === null ? [] : brokenDocumentPaths(docsDir, land.errors),
200
+ },
171
201
  scaffold: newCommand(featureId, seeds, known),
172
202
  };
173
203
  }
@@ -1 +1 @@
1
- {"version":3,"file":"explore.js","sourceRoot":"","sources":["../../../src/core/explore/explore.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The blast radius of a change nobody has written down yet.\n *\n * Everything else in loam answers a question about documents that exist. This\n * module answers the one that comes BEFORE the first document: which services\n * does this feature actually touch? On a fleet of a hundred that call is the\n * hardest one in the cycle and the only one made with no tool in hand —\n * `loam new FEAT-101 --touches a --touches b` takes the answer as an argument\n * and scaffolds whatever it was told. A `--touches` list short by one service\n * is not caught by anything: the feature validates, archives, and ships with a\n * consumer nobody updated.\n *\n * So this states the work the same way `brief/brief.ts` does. It reads the fleet map\n * and the living contracts, reports the ring of services around the seeds, the\n * features already in flight over the same ground, and how far each service's\n * documentation has got — and stops. Which of those neighbours the feature\n * really touches is a judgement about intent, and loam does not make those.\n *\n * The landscape is parsed ONCE for the whole exploration. Per-service reads of\n * it exist (`brief/landscape.ts`'s `landscapeContext`) and are correct for one service;\n * calling one of those per seed is how `validate --all` came to cost 13 seconds\n * on 120 services, and this command sits in front of authoring, where that is\n * the difference between a habit and a thing people skip.\n */\nimport { existsSync } from \"node:fs\";\nimport { FleetContext } from \"../fleet-context.js\";\nimport { type Rel } from \"../c4/likec4.js\";\nimport { serviceResolver } from \"../c4/resolve/service.js\";\nimport { type Maturity } from \"../vocabulary/maturity.js\";\nimport { capabilityRollup, unresolvedCapabilities } from \"../capabilities/rollup.js\";\nimport { compareIds, nearestIds, type ServiceEntry } from \"../repo/entries.js\";\nimport { landscapePath } from \"../repo/paths.js\";\nimport { readUseCases } from \"../usecases/fleet.js\";\nimport { servicesInFlowsClaiming } from \"../usecases/capability.js\";\nimport { describe, newCommand, operationOwner } from \"./describe.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\n\n/** One end of a call the fleet map already draws. */\nexport interface ExploreEdge {\n /** The service at the other end. */\n service: string;\n /** The operationId the call uses, or null for an edge nobody tied to one. */\n op: string | null;\n title: string | null;\n}\n\n/**\n * Why a service is in the answer. Seeds were asked for; the rest were derived.\n *\n * A neighbour on both sides of a seed reports `calls-seed` — see the overlap\n * rule in `explore`. The field is a hint about where to look, not a complete\n * description of the edges; `inbound`/`outbound` are that.\n */\nexport type ExploreReason = \"seed\" | \"calls-seed\" | \"called-by-seed\";\n\nexport interface ExploreService {\n id: string;\n reason: ExploreReason;\n /** Whether `services/<id>/` exists at all. */\n known: boolean;\n /**\n * How far this service's documentation has got, or null when it does not\n * exist yet. A `--touches` naming a service at `empty` or `partial` is a\n * different job from one naming a vouched service, and the difference decides\n * whether the feature starts with `loam adopt`.\n */\n maturity: Maturity | null;\n /** What stands between it and `vouched` — `maturityGaps`, so it matches `list --needs-work`. */\n missing: string[];\n /** Whether anything in the fleet map resolves to it. */\n modelled: boolean;\n /** operationIds its living contract exposes today, `x-loam-remove` markers excluded. */\n operations: string[];\n /**\n * Whether that contract could be read at all, beside the `error` the parser\n * gave when it could not.\n *\n * It rides next to `operations` rather than inside it for the reason `delta`\n * carries the same pair: an unreadable contract yields an EMPTY operation\n * list, indistinguishable from a service with no endpoints — and this is the\n * field the workflow tells an agent to read before deciding whether an\n * operation it is about to add already exists. Answering `[]` over a YAML\n * error is how a MODIFIED requirement gets authored as ADDED.\n */\n openapi: { unreadable: boolean; error?: string };\n inbound: ExploreEdge[];\n outbound: ExploreEdge[];\n}\n\n/** An active feature already working over ground the exploration covers. */\nexport interface ExploreOverlap {\n feature: string;\n /** The explored services it already carries a delta for. */\n services: string[];\n}\n\nexport interface Exploration {\n /** The seed ids, as asked for. */\n seeds: string[];\n /**\n * Seeds that name no `services/<id>/`, each with the closest real ids. A seed\n * may legitimately be a service the feature INTRODUCES, so this is reported\n * rather than refused — but a typo produces exactly the same shape, and the\n * near-miss list is what tells the two apart.\n */\n unknown: Array<{ id: string; nearest: string[] }>;\n /** Operation seeds that resolved to no service's living contract. */\n unresolvedOperations: string[];\n /**\n * Capability seeds that seeded nothing: not declared in\n * architecture/capabilities.yaml (the file may not exist at all — explore\n * refuses nothing, every miss is a field), or declared and realized by no\n * living requirement. One list on purpose; splitting the two miss kinds\n * waits for a consumer to ask.\n */\n unresolvedCapabilities: string[];\n /** Seeds first, then the ring, each in id order. */\n services: ExploreService[];\n /** Ids the ring added that were not asked for — the candidates to weigh. */\n neighbours: string[];\n overlaps: ExploreOverlap[];\n landscape: { present: boolean; parses: boolean };\n /**\n * The literal `loam new` line the seeds imply — seeds only. The ring is\n * deliberately NOT folded in: this module's whole claim is that it does not\n * know which neighbours the feature touches, and a command line that quietly\n * included them would make the guess on the reader's behalf and look derived\n * while doing it.\n *\n * Named for what it does rather than `command`, which is the envelope's key\n * for the command that RAN. The rename is not cosmetic: `emitJson` spreads\n * the payload LAST, so a payload field called `command` would silently\n * OVERRIDE the envelope's — `command` would come back as\n * `\"loam new FEAT-000 …\"`, and every consumer branching on\n * `command === \"explore\"` (the same key `status`, `doctor`, `dependencies`,\n * `archive` and `unarchive` emit) would quietly stop matching, with tsc and\n * the linter green throughout.\n */\n scaffold: string;\n}\n\nexport interface ExploreRequest {\n docsDir: DocsDir;\n /** Service ids to explore around. Checked at the command boundary. */\n services: ServiceEntry[\"id\"][];\n /** operationIds to explore around; each resolves to the service that defines it. */\n operations: string[];\n /** Declared capability ids to explore around; each seeds its realizing services. */\n capabilities: string[];\n /** Placeholder feature id for the suggested command line. */\n featureId: string;\n context?: FleetContext;\n}\n\n/**\n * Read the fleet around a proposed change. Reads only; writes nothing, and\n * refuses nothing — every miss is reported as a field.\n */\nexport async function explore(req: ExploreRequest): Promise<Exploration> {\n const { docsDir, featureId } = req;\n const context = req.context ?? new FleetContext();\n const entries = await context.listServices(docsDir);\n const byId = new Map<string, ServiceEntry>(entries.map((e) => [e.id, e]));\n const known: ReadonlySet<string> = new Set(byId.keys());\n\n const landPath = landscapePath(docsDir);\n const present = existsSync(landPath);\n const land = present ? await context.loadLikeC4(landPath) : null;\n const parses = land !== null && land.errors.length === 0;\n const elements = parses ? land.elements : [];\n const relationships: Rel[] = parses ? land.relationships : [];\n // One resolver for the whole scan, built with the real service ids so an edge\n // drawn into a modelled container (`paymentService.api`) counts for the\n // service that owns it — the same resolution `list`, `show` and `validate`\n // use, so no two commands can disagree about who calls whom.\n const svcOf = serviceResolver(elements, known);\n\n // Operation seeds resolve through the living contracts, not the map: the map\n // says who CALLS an operation, and the question here is who DEFINES it.\n const opSeeds: ServiceEntry[\"id\"][] = [];\n const unresolvedOperations: string[] = [];\n for (const op of req.operations) {\n const owner = await operationOwner(entries, op, context);\n if (owner === null) unresolvedOperations.push(op);\n else opSeeds.push(owner);\n }\n\n // Capability seeds resolve through the vocabulary and the fleet rollup —\n // one rollup pass for ALL requested ids, through this exploration's shared\n // context cache, never a fresh walk per capability. A realizing service is\n // by construction an enumerated one, so every seed it adds is `known`.\n //\n // And through the fleet's USE CASES, which answer the same question off a\n // different document. The rollup finds services whose living requirements\n // carry a `Capability:` line; a `dynamic view` tagged `#cap-<slug>` finds the\n // services the flow actually runs through — including ones whose spec.md has\n // never named the capability, which on a brownfield fleet is most of them.\n // The two are unioned rather than ranked because neither is a subset of the\n // other: a service can realize a capability without appearing in its drawn\n // flow, and a flow can pass through a service that has written nothing down.\n //\n // The scan gates its own load, and this whole block is already behind\n // `--capability` being passed at all, so an exploration by service or by\n // operation never touches `architecture/` as a project.\n const capSeeds: ServiceEntry[\"id\"][] = [];\n let unresolvedCaps: string[] = [];\n if (req.capabilities.length > 0) {\n const vocab = await context.capabilities(docsDir);\n const rows = await capabilityRollup({ services: entries, vocab, read: (p) => context.readRequirements(p) });\n const wanted = new Set(req.capabilities);\n const realizing = new Set(rows.filter((r) => wanted.has(r.id)).flatMap((r) => r.services));\n const scan = await readUseCases({ docsDir, known });\n for (const id of servicesInFlowsClaiming(scan, req.capabilities)) realizing.add(id);\n capSeeds.push(...entries.filter((e) => realizing.has(e.id)).map((e) => e.id));\n // `unresolvedCapabilities` is unchanged on purpose: it grades the\n // VOCABULARY — declared or not, realized by a living requirement or not —\n // and a capability drawn in a flow but realized by nobody is still a\n // capability nothing implements. Letting a tag silence that would hide the\n // gap the field exists to name.\n unresolvedCaps = unresolvedCapabilities(rows, req.capabilities);\n }\n\n const seeds = [...new Set([...req.services, ...opSeeds, ...capSeeds])];\n const unknown = seeds\n .filter((id) => !known.has(id))\n .map((id) => ({ id, nearest: nearestIds(id, [...known]) }));\n\n // The ring: one hop, both directions. A seed that is not modelled contributes\n // nothing here and that is the honest answer — an invisible service has no\n // neighbours anyone can derive, which is what `landscape.service-unmodelled`\n // is about.\n //\n // The two directions are collected separately rather than written into one\n // map as the loop goes, because a neighbour can be BOTH — it calls a seed and\n // the seed calls it — and a single-map version answers whichever edge the\n // parser happened to yield last. That is a field whose value depends on the\n // order lines appear in a `.likec4` file, which is the kind of answer that\n // reads as derived and is not.\n const seedSet = new Set<string>(seeds);\n const callsSeed = new Set<string>();\n const calledBySeed = new Set<string>();\n for (const r of relationships) {\n const from = svcOf(r.source);\n const to = svcOf(r.target);\n if (seedSet.has(from) && !seedSet.has(to)) calledBySeed.add(to);\n if (seedSet.has(to) && !seedSet.has(from)) callsSeed.add(from);\n }\n\n // `calls-seed` wins the overlap, deterministically. Of the two directions it\n // is the one that more often has to be touched: a consumer depends on the\n // seed's contract, so a change to that contract is what breaks it, while a\n // provider the seed merely calls is usually unaffected by the seed changing.\n const ring = new Map<string, ExploreReason>([\n ...[...calledBySeed].map((id) => [id, \"called-by-seed\" as const] as const),\n ...[...callsSeed].map((id) => [id, \"calls-seed\" as const] as const),\n ]);\n\n const ordered: Array<{ id: string; reason: ExploreReason }> = [\n ...[...seeds].sort(compareIds).map((id) => ({ id, reason: \"seed\" as const })),\n ...[...ring]\n .sort(([a], [b]) => compareIds(a, b))\n .map(([id, reason]) => ({ id, reason })),\n ];\n\n const services: ExploreService[] = [];\n for (const { id, reason } of ordered) {\n services.push(\n await describe({\n id,\n reason,\n entry: byId.get(id),\n relationships,\n svcOf,\n elements,\n parses,\n context,\n }),\n );\n }\n\n const covered = new Set(services.map((s) => s.id));\n const features = await context.listFeatures(docsDir);\n const overlaps: ExploreOverlap[] = features\n .map((f) => ({ feature: f.id, services: f.services.filter((s) => covered.has(s)) }))\n .filter((o) => o.services.length > 0)\n .sort((a, b) => compareIds(a.feature, b.feature));\n\n return {\n seeds,\n unknown,\n unresolvedOperations,\n unresolvedCapabilities: unresolvedCaps,\n services,\n neighbours: [...ring.keys()].sort(compareIds),\n overlaps,\n landscape: { present, parses },\n scaffold: newCommand(featureId, seeds, known),\n };\n}\n"]}
1
+ {"version":3,"file":"explore.js","sourceRoot":"","sources":["../../../src/core/explore/explore.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The blast radius of a change nobody has written down yet.\n *\n * Everything else in loam answers a question about documents that exist. This\n * module answers the one that comes BEFORE the first document: which services\n * does this feature actually touch? On a fleet of a hundred that call is the\n * hardest one in the cycle and the only one made with no tool in hand —\n * `loam new FEAT-101 --touches a --touches b` takes the answer as an argument\n * and scaffolds whatever it was told. A `--touches` list short by one service\n * is not caught by anything: the feature validates, archives, and ships with a\n * consumer nobody updated.\n *\n * So this states the work the same way `brief/brief.ts` does. It reads the fleet map\n * and the living contracts, reports the ring of services around the seeds, the\n * features already in flight over the same ground, and how far each service's\n * documentation has got — and stops. Which of those neighbours the feature\n * really touches is a judgement about intent, and loam does not make those.\n *\n * \"The fleet map\" here is the `architecture/` PROJECT — the landscape plus every\n * other `.likec4` under it, minus the generated views file — and not the\n * landscape FILE. See the read below for the disagreement that reading one file\n * caused.\n *\n * It is parsed ONCE for the whole exploration. Per-service reads of it exist\n * (`brief/landscape.ts`'s `landscapeContext`) and are correct for one service;\n * calling one of those per seed is how `validate --all` came to cost 13 seconds\n * on 120 services, and this command sits in front of authoring, where that is\n * the difference between a habit and a thing people skip.\n */\nimport { existsSync } from \"node:fs\";\nimport { FleetContext } from \"../fleet-context.js\";\nimport { brokenDocumentPaths, type Rel } from \"../c4/likec4.js\";\nimport { serviceResolver } from \"../c4/resolve/service.js\";\nimport { type Maturity } from \"../vocabulary/maturity.js\";\nimport { capabilityRollup, unresolvedCapabilities } from \"../capabilities/rollup.js\";\nimport { compareIds, nearestIds, type ServiceEntry } from \"../repo/entries.js\";\nimport { landscapePath } from \"../repo/paths.js\";\nimport { readUseCases } from \"../usecases/fleet.js\";\nimport { servicesInFlowsClaiming } from \"../usecases/capability.js\";\nimport { describe, newCommand, operationOwner } from \"./describe.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\n\n/** One end of a call the fleet map already draws. */\nexport interface ExploreEdge {\n /** The service at the other end. */\n service: string;\n /** The operationId the call uses, or null for an edge nobody tied to one. */\n op: string | null;\n title: string | null;\n}\n\n/**\n * Why a service is in the answer. Seeds were asked for; the rest were derived.\n *\n * A neighbour on both sides of a seed reports `calls-seed` — see the overlap\n * rule in `explore`. The field is a hint about where to look, not a complete\n * description of the edges; `inbound`/`outbound` are that.\n */\nexport type ExploreReason = \"seed\" | \"calls-seed\" | \"called-by-seed\";\n\nexport interface ExploreService {\n id: string;\n reason: ExploreReason;\n /** Whether `services/<id>/` exists at all. */\n known: boolean;\n /**\n * How far this service's documentation has got, or null when it does not\n * exist yet. A `--touches` naming a service at `empty` or `partial` is a\n * different job from one naming a vouched service, and the difference decides\n * whether the feature starts with `loam adopt`.\n */\n maturity: Maturity | null;\n /** What stands between it and `vouched` — `maturityGaps`, so it matches `list --needs-work`. */\n missing: string[];\n /** Whether anything in the fleet map resolves to it. */\n modelled: boolean;\n /** operationIds its living contract exposes today, `x-loam-remove` markers excluded. */\n operations: string[];\n /**\n * Whether that contract could be read at all, beside the `error` the parser\n * gave when it could not.\n *\n * It rides next to `operations` rather than inside it for the reason `delta`\n * carries the same pair: an unreadable contract yields an EMPTY operation\n * list, indistinguishable from a service with no endpoints — and this is the\n * field the workflow tells an agent to read before deciding whether an\n * operation it is about to add already exists. Answering `[]` over a YAML\n * error is how a MODIFIED requirement gets authored as ADDED.\n */\n openapi: { unreadable: boolean; error?: string };\n inbound: ExploreEdge[];\n outbound: ExploreEdge[];\n}\n\n/** An active feature already working over ground the exploration covers. */\nexport interface ExploreOverlap {\n feature: string;\n /** The explored services it already carries a delta for. */\n services: string[];\n}\n\nexport interface Exploration {\n /** The seed ids, as asked for. */\n seeds: string[];\n /**\n * Seeds that name no `services/<id>/`, each with the closest real ids. A seed\n * may legitimately be a service the feature INTRODUCES, so this is reported\n * rather than refused — but a typo produces exactly the same shape, and the\n * near-miss list is what tells the two apart.\n */\n unknown: Array<{ id: string; nearest: string[] }>;\n /** Operation seeds that resolved to no service's living contract. */\n unresolvedOperations: string[];\n /**\n * Capability seeds that seeded nothing: not declared in\n * architecture/capabilities.yaml (the file may not exist at all — explore\n * refuses nothing, every miss is a field), or declared and realized by no\n * living requirement. One list on purpose; splitting the two miss kinds\n * waits for a consumer to ask.\n */\n unresolvedCapabilities: string[];\n /** Seeds first, then the ring, each in id order. */\n services: ExploreService[];\n /** Ids the ring added that were not asked for — the candidates to weigh. */\n neighbours: string[];\n overlaps: ExploreOverlap[];\n /**\n * `broken` is the `architecture/` documents that failed, docs-relative POSIX,\n * deduped and sorted — `[]` while `parses` is true. `parses` answers for the\n * PROJECT, so the broken document is very often a SIBLING beside a landscape\n * that reads perfectly, and naming the landscape file was a claim about bytes\n * loam read fine (verification 2026-09-04). Spelled as `landscape.invalid`\n * spells it (both through `c4/likec4.ts`'s `brokenDocumentPaths`), so the\n * two surfaces name one file one way.\n */\n landscape: { present: boolean; parses: boolean; broken: string[] };\n /**\n * The literal `loam new` line the seeds imply — seeds only. The ring is\n * deliberately NOT folded in: this module's whole claim is that it does not\n * know which neighbours the feature touches, and a command line that quietly\n * included them would make the guess on the reader's behalf and look derived\n * while doing it.\n *\n * Named for what it does rather than `command`, which is the envelope's key\n * for the command that RAN. The rename is not cosmetic: `emitJson` spreads\n * the payload LAST, so a payload field called `command` would silently\n * OVERRIDE the envelope's — `command` would come back as\n * `\"loam new FEAT-000 …\"`, and every consumer branching on\n * `command === \"explore\"` (the same key `status`, `doctor`, `dependencies`,\n * `archive` and `unarchive` emit) would quietly stop matching, with tsc and\n * the linter green throughout.\n */\n scaffold: string;\n}\n\nexport interface ExploreRequest {\n docsDir: DocsDir;\n /** Service ids to explore around. Checked at the command boundary. */\n services: ServiceEntry[\"id\"][];\n /** operationIds to explore around; each resolves to the service that defines it. */\n operations: string[];\n /** Declared capability ids to explore around; each seeds its realizing services. */\n capabilities: string[];\n /** Placeholder feature id for the suggested command line. */\n featureId: string;\n context?: FleetContext;\n}\n\n/**\n * Read the fleet around a proposed change. Reads only; writes nothing, and\n * refuses nothing — every miss is reported as a field.\n */\nexport async function explore(req: ExploreRequest): Promise<Exploration> {\n const { docsDir, featureId } = req;\n const context = req.context ?? new FleetContext();\n const entries = await context.listServices(docsDir);\n const byId = new Map<string, ServiceEntry>(entries.map((e) => [e.id, e]));\n const known: ReadonlySet<string> = new Set(byId.keys());\n\n // The `architecture/` PROJECT, never `architecture/landscape.likec4` alone.\n // The map is a project — the landscape merged with every use case, palette and\n // second `model { }` block beside it — and reading one file of it made this\n // command answer differently from `loam adopt` and `loam context` about the\n // same tree (reproduced: with a broken `architecture/palette.likec4` beside a\n // landscape that parses, `context checkout-web --json` reported\n // `landscape.parses: false` while `explore checkout-web --json` reported\n // `parses: true` and went on to describe every edge). `core/pack/living.ts`\n // named this module as the last reader that disagreed. Whichever answer is\n // right, an agent handed both has no way to tell — and the renderer's answer\n // is the project's.\n //\n // `present` stays a fact about the FILE, because that file is the WRITE target:\n // `loam new`'s scaffold and every brief ask for edits to\n // `architecture/landscape.likec4` by name, and \"the project is empty\" is not\n // the same instruction as \"there is no map to edit\".\n const present = existsSync(landscapePath(docsDir));\n const land = present ? await context.architecture(docsDir) : null;\n const parses = land !== null && land.errors.length === 0;\n const elements = parses ? land.elements : [];\n const relationships: Rel[] = parses ? land.relationships : [];\n // One resolver for the whole scan, built with the real service ids so an edge\n // drawn into a modelled container (`paymentService.api`) counts for the\n // service that owns it — the same resolution `list`, `show` and `validate`\n // use, so no two commands can disagree about who calls whom.\n const svcOf = serviceResolver(elements, known);\n\n // Operation seeds resolve through the living contracts, not the map: the map\n // says who CALLS an operation, and the question here is who DEFINES it.\n const opSeeds: ServiceEntry[\"id\"][] = [];\n const unresolvedOperations: string[] = [];\n for (const op of req.operations) {\n const owner = await operationOwner(entries, op, context);\n if (owner === null) unresolvedOperations.push(op);\n else opSeeds.push(owner);\n }\n\n // Capability seeds resolve through the vocabulary and the fleet rollup —\n // one rollup pass for ALL requested ids, through this exploration's shared\n // context cache, never a fresh walk per capability. A realizing service is\n // by construction an enumerated one, so every seed it adds is `known`.\n //\n // And through the fleet's USE CASES, which answer the same question off a\n // different document. The rollup finds services whose living requirements\n // carry a `Capability:` line; a `dynamic view` tagged `#cap-<slug>` finds the\n // services the flow actually runs through — including ones whose spec.md has\n // never named the capability, which on a brownfield fleet is most of them.\n // The two are unioned rather than ranked because neither is a subset of the\n // other: a service can realize a capability without appearing in its drawn\n // flow, and a flow can pass through a service that has written nothing down.\n //\n // The scan gates its own load — a fleet whose documents mention no reserved\n // tag never starts LikeC4 for it — and this whole block is behind\n // `--capability` being passed at all. What it is no longer behind is the\n // project itself: the read above loads `architecture/` for every exploration,\n // so a `--capability` run pays for a SECOND parse of the same documents\n // (`readUseCases` takes a `DocsDir`, not this invocation's memo). Accepted\n // rather than unnoticed: the alternative is a seam that hands the scan a\n // pre-loaded project, which is a change to a module five callers share, and\n // the cost lands only on the flag that already opts into the fleet rollup.\n const capSeeds: ServiceEntry[\"id\"][] = [];\n let unresolvedCaps: string[] = [];\n if (req.capabilities.length > 0) {\n const vocab = await context.capabilities(docsDir);\n const rows = await capabilityRollup({ services: entries, vocab, read: (p) => context.readRequirements(p) });\n const wanted = new Set(req.capabilities);\n const realizing = new Set(rows.filter((r) => wanted.has(r.id)).flatMap((r) => r.services));\n const scan = await readUseCases({ docsDir, known });\n for (const id of servicesInFlowsClaiming(scan, req.capabilities)) realizing.add(id);\n capSeeds.push(...entries.filter((e) => realizing.has(e.id)).map((e) => e.id));\n // `unresolvedCapabilities` is unchanged on purpose: it grades the\n // VOCABULARY — declared or not, realized by a living requirement or not —\n // and a capability drawn in a flow but realized by nobody is still a\n // capability nothing implements. Letting a tag silence that would hide the\n // gap the field exists to name.\n unresolvedCaps = unresolvedCapabilities(rows, req.capabilities);\n }\n\n const seeds = [...new Set([...req.services, ...opSeeds, ...capSeeds])];\n const unknown = seeds\n .filter((id) => !known.has(id))\n .map((id) => ({ id, nearest: nearestIds(id, [...known]) }));\n\n // The ring: one hop, both directions. A seed that is not modelled contributes\n // nothing here and that is the honest answer — an invisible service has no\n // neighbours anyone can derive, which is what `landscape.service-unmodelled`\n // is about.\n //\n // The two directions are collected separately rather than written into one\n // map as the loop goes, because a neighbour can be BOTH — it calls a seed and\n // the seed calls it — and a single-map version answers whichever edge the\n // parser happened to yield last. That is a field whose value depends on the\n // order lines appear in a `.likec4` file, which is the kind of answer that\n // reads as derived and is not.\n const seedSet = new Set<string>(seeds);\n const callsSeed = new Set<string>();\n const calledBySeed = new Set<string>();\n for (const r of relationships) {\n const from = svcOf(r.source);\n const to = svcOf(r.target);\n if (seedSet.has(from) && !seedSet.has(to)) calledBySeed.add(to);\n if (seedSet.has(to) && !seedSet.has(from)) callsSeed.add(from);\n }\n\n // `calls-seed` wins the overlap, deterministically. Of the two directions it\n // is the one that more often has to be touched: a consumer depends on the\n // seed's contract, so a change to that contract is what breaks it, while a\n // provider the seed merely calls is usually unaffected by the seed changing.\n const ring = new Map<string, ExploreReason>([\n ...[...calledBySeed].map((id) => [id, \"called-by-seed\" as const] as const),\n ...[...callsSeed].map((id) => [id, \"calls-seed\" as const] as const),\n ]);\n\n const ordered: Array<{ id: string; reason: ExploreReason }> = [\n ...[...seeds].sort(compareIds).map((id) => ({ id, reason: \"seed\" as const })),\n ...[...ring]\n .sort(([a], [b]) => compareIds(a, b))\n .map(([id, reason]) => ({ id, reason })),\n ];\n\n const services: ExploreService[] = [];\n for (const { id, reason } of ordered) {\n services.push(\n await describe({\n id,\n reason,\n entry: byId.get(id),\n relationships,\n svcOf,\n elements,\n parses,\n context,\n }),\n );\n }\n\n const covered = new Set(services.map((s) => s.id));\n const features = await context.listFeatures(docsDir);\n const overlaps: ExploreOverlap[] = features\n .map((f) => ({ feature: f.id, services: f.services.filter((s) => covered.has(s)) }))\n .filter((o) => o.services.length > 0)\n .sort((a, b) => compareIds(a.feature, b.feature));\n\n return {\n seeds,\n unknown,\n unresolvedOperations,\n unresolvedCapabilities: unresolvedCaps,\n services,\n neighbours: [...ring.keys()].sort(compareIds),\n overlaps,\n landscape: {\n present,\n parses,\n broken: land === null ? [] : brokenDocumentPaths(docsDir, land.errors),\n },\n scaffold: newCommand(featureId, seeds, known),\n };\n}\n"]}