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

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 (1026) hide show
  1. package/CHANGELOG.md +2548 -86
  2. package/COMPARISON.md +80 -63
  3. package/CONTRIBUTING.md +84 -0
  4. package/MIGRATING-from-OpenSpec.md +213 -54
  5. package/QUICKSTART.md +125 -0
  6. package/README.md +450 -150
  7. package/ROADMAP.md +494 -0
  8. package/SCHEMA.md +2355 -256
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +701 -0
  11. package/dist/cli.js +113 -19
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +209 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +268 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +77 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/openapi.js +159 -0
  22. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  23. package/dist/commands/archive/plan/gate.js +317 -0
  24. package/dist/commands/archive/plan/gate.js.map +1 -0
  25. package/dist/commands/archive/plan/landscape.js +161 -0
  26. package/dist/commands/archive/plan/landscape.js.map +1 -0
  27. package/dist/commands/archive/plan/refusal.js +111 -0
  28. package/dist/commands/archive/plan/refusal.js.map +1 -0
  29. package/dist/commands/archive/plan/specs.js +237 -0
  30. package/dist/commands/archive/plan/specs.js.map +1 -0
  31. package/dist/commands/archive/plan/state.js +27 -0
  32. package/dist/commands/archive/plan/state.js.map +1 -0
  33. package/dist/commands/archive/run.js +251 -0
  34. package/dist/commands/archive/run.js.map +1 -0
  35. package/dist/commands/context/context.js +99 -0
  36. package/dist/commands/context/context.js.map +1 -0
  37. package/dist/commands/context/print.js +283 -0
  38. package/dist/commands/context/print.js.map +1 -0
  39. package/dist/commands/delta/delta.js +279 -0
  40. package/dist/commands/delta/delta.js.map +1 -0
  41. package/dist/commands/delta/print.js +205 -0
  42. package/dist/commands/delta/print.js.map +1 -0
  43. package/dist/commands/dependencies.js +9 -7
  44. package/dist/commands/dependencies.js.map +1 -1
  45. package/dist/commands/diff/diff.js +93 -0
  46. package/dist/commands/diff/diff.js.map +1 -0
  47. package/dist/commands/diff/print.js +38 -0
  48. package/dist/commands/diff/print.js.map +1 -0
  49. package/dist/commands/doctor.js +5 -4
  50. package/dist/commands/doctor.js.map +1 -1
  51. package/dist/commands/explain/explain.js +151 -0
  52. package/dist/commands/explain/explain.js.map +1 -0
  53. package/dist/commands/explore.js +29 -24
  54. package/dist/commands/explore.js.map +1 -1
  55. package/dist/commands/gate/gate.js +115 -0
  56. package/dist/commands/gate/gate.js.map +1 -0
  57. package/dist/commands/gate/print.js +54 -0
  58. package/dist/commands/gate/print.js.map +1 -0
  59. package/dist/commands/gherkin/commit.js +146 -0
  60. package/dist/commands/gherkin/commit.js.map +1 -0
  61. package/dist/commands/gherkin/gherkin.js +246 -0
  62. package/dist/commands/gherkin/gherkin.js.map +1 -0
  63. package/dist/commands/gherkin/reconcile.js +149 -0
  64. package/dist/commands/gherkin/reconcile.js.map +1 -0
  65. package/dist/commands/gherkin/render.js +77 -0
  66. package/dist/commands/gherkin/render.js.map +1 -0
  67. package/dist/commands/init/example.js +204 -0
  68. package/dist/commands/init/example.js.map +1 -0
  69. package/dist/commands/init/first-hour.js +28 -0
  70. package/dist/commands/init/first-hour.js.map +1 -0
  71. package/dist/commands/{init.js → init/init.js} +146 -71
  72. package/dist/commands/init/init.js.map +1 -0
  73. package/dist/commands/init/mcp.js +131 -0
  74. package/dist/commands/init/mcp.js.map +1 -0
  75. package/dist/commands/init/options.js +78 -0
  76. package/dist/commands/init/options.js.map +1 -0
  77. package/dist/commands/instructions.js +72 -14
  78. package/dist/commands/instructions.js.map +1 -1
  79. package/dist/commands/list/campaign/campaign.js +65 -0
  80. package/dist/commands/list/campaign/campaign.js.map +1 -0
  81. package/dist/commands/list/campaign/owners.js +65 -0
  82. package/dist/commands/list/campaign/owners.js.map +1 -0
  83. package/dist/commands/list/json.js +157 -0
  84. package/dist/commands/list/json.js.map +1 -0
  85. package/dist/commands/list/list.js +343 -0
  86. package/dist/commands/list/list.js.map +1 -0
  87. package/dist/commands/list/print.js +301 -0
  88. package/dist/commands/list/print.js.map +1 -0
  89. package/dist/commands/list/review.js +120 -0
  90. package/dist/commands/list/review.js.map +1 -0
  91. package/dist/commands/list/views.js +105 -0
  92. package/dist/commands/list/views.js.map +1 -0
  93. package/dist/commands/mcp/dispatch.js +183 -0
  94. package/dist/commands/mcp/dispatch.js.map +1 -0
  95. package/dist/commands/mcp/mcp.js +34 -0
  96. package/dist/commands/mcp/mcp.js.map +1 -0
  97. package/dist/commands/mcp/serve.js +55 -0
  98. package/dist/commands/mcp/serve.js.map +1 -0
  99. package/dist/commands/migrate-openspec/materialize/active.js +170 -0
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  101. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  102. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  103. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  104. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  105. package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
  106. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  107. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  108. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  109. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  110. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  111. package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
  112. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  113. package/dist/commands/migrate-openspec/openspec/error.js +19 -0
  114. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  115. package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
  116. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  117. package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
  118. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  119. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  120. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  121. package/dist/commands/migrate-openspec/print.js +89 -0
  122. package/dist/commands/migrate-openspec/print.js.map +1 -0
  123. package/dist/commands/new/commit.js +76 -0
  124. package/dist/commands/new/commit.js.map +1 -0
  125. package/dist/commands/new/new.js +283 -0
  126. package/dist/commands/new/new.js.map +1 -0
  127. package/dist/commands/new/templates.js +355 -0
  128. package/dist/commands/new/templates.js.map +1 -0
  129. package/dist/commands/open.js +203 -0
  130. package/dist/commands/open.js.map +1 -0
  131. package/dist/commands/policy/format.js +152 -0
  132. package/dist/commands/policy/format.js.map +1 -0
  133. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
  134. package/dist/commands/policy/gate.js.map +1 -0
  135. package/dist/commands/rebase/edit.js +106 -0
  136. package/dist/commands/rebase/edit.js.map +1 -0
  137. package/dist/commands/rebase/living.js +185 -0
  138. package/dist/commands/rebase/living.js.map +1 -0
  139. package/dist/commands/rebase/plan.js +245 -0
  140. package/dist/commands/rebase/plan.js.map +1 -0
  141. package/dist/commands/rebase/rebase.js +275 -0
  142. package/dist/commands/rebase/rebase.js.map +1 -0
  143. package/dist/commands/seed/commit.js +192 -0
  144. package/dist/commands/seed/commit.js.map +1 -0
  145. package/dist/commands/seed/plan.js +133 -0
  146. package/dist/commands/seed/plan.js.map +1 -0
  147. package/dist/commands/seed/seed.js +172 -0
  148. package/dist/commands/seed/seed.js.map +1 -0
  149. package/dist/commands/show/feature.js +178 -0
  150. package/dist/commands/show/feature.js.map +1 -0
  151. package/dist/commands/show/marks.js +24 -0
  152. package/dist/commands/show/marks.js.map +1 -0
  153. package/dist/commands/{show.js → show/service.js} +63 -152
  154. package/dist/commands/show/service.js.map +1 -0
  155. package/dist/commands/show/show.js +77 -0
  156. package/dist/commands/show/show.js.map +1 -0
  157. package/dist/commands/status/json.js +45 -0
  158. package/dist/commands/status/json.js.map +1 -0
  159. package/dist/commands/status/print.js +157 -0
  160. package/dist/commands/status/print.js.map +1 -0
  161. package/dist/commands/status/status.js +119 -0
  162. package/dist/commands/status/status.js.map +1 -0
  163. package/dist/commands/steps/steps.js +189 -0
  164. package/dist/commands/steps/steps.js.map +1 -0
  165. package/dist/commands/subsystem/edit.js +192 -0
  166. package/dist/commands/subsystem/edit.js.map +1 -0
  167. package/dist/commands/subsystem/move.js +265 -0
  168. package/dist/commands/subsystem/move.js.map +1 -0
  169. package/dist/commands/subsystem/query.js +115 -0
  170. package/dist/commands/subsystem/query.js.map +1 -0
  171. package/dist/commands/subsystem/subsystem.js +101 -0
  172. package/dist/commands/subsystem/subsystem.js.map +1 -0
  173. package/dist/commands/subsystem/sync.js +103 -0
  174. package/dist/commands/subsystem/sync.js.map +1 -0
  175. package/dist/commands/subsystem/txn/txn.js +94 -0
  176. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  177. package/dist/commands/subsystem/txn/views.js +70 -0
  178. package/dist/commands/subsystem/txn/views.js.map +1 -0
  179. package/dist/commands/unarchive/manifest.js +160 -0
  180. package/dist/commands/unarchive/manifest.js.map +1 -0
  181. package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
  182. package/dist/commands/unarchive/restore.js.map +1 -0
  183. package/dist/commands/unarchive/unarchive.js +67 -0
  184. package/dist/commands/unarchive/unarchive.js.map +1 -0
  185. package/dist/commands/validate/arch-coverage.js +194 -0
  186. package/dist/commands/validate/arch-coverage.js.map +1 -0
  187. package/dist/commands/validate/checks/fleet-shape.js +296 -0
  188. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  189. package/dist/commands/validate/checks/health-deps.js +55 -0
  190. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  191. package/dist/commands/validate/checks/requirements.js +254 -0
  192. package/dist/commands/validate/checks/requirements.js.map +1 -0
  193. package/dist/commands/validate/checks/sources.js +76 -0
  194. package/dist/commands/validate/checks/sources.js.map +1 -0
  195. package/dist/commands/validate/checks/vocabulary.js +31 -0
  196. package/dist/commands/validate/checks/vocabulary.js.map +1 -0
  197. package/dist/commands/validate/feature.js +216 -0
  198. package/dist/commands/validate/feature.js.map +1 -0
  199. package/dist/commands/validate/fleet/census.js +69 -0
  200. package/dist/commands/validate/fleet/census.js.map +1 -0
  201. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  202. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  203. package/dist/commands/validate/fleet/landscape.js +353 -0
  204. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  205. package/dist/commands/validate/fleet/load.js +52 -0
  206. package/dist/commands/validate/fleet/load.js.map +1 -0
  207. package/dist/commands/validate/fleet/obligations.js +236 -0
  208. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  209. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  210. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  211. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  212. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  213. package/dist/commands/validate/fleet/scorecard/print.js +63 -0
  214. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  215. package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
  216. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  217. package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
  218. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
  219. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  220. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  221. package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
  222. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
  223. package/dist/commands/validate/fleet/usecases/steps.js +197 -0
  224. package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
  225. package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
  226. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
  227. package/dist/commands/validate/fleet/views/ids.js +40 -0
  228. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  229. package/dist/commands/validate/fleet/views/stale.js +59 -0
  230. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  231. package/dist/commands/validate/links/corpus.js +92 -0
  232. package/dist/commands/validate/links/corpus.js.map +1 -0
  233. package/dist/commands/validate/links/glossary.js +75 -0
  234. package/dist/commands/validate/links/glossary.js.map +1 -0
  235. package/dist/commands/validate/report.js +269 -0
  236. package/dist/commands/validate/report.js.map +1 -0
  237. package/dist/commands/validate/service/api.js +338 -0
  238. package/dist/commands/validate/service/api.js.map +1 -0
  239. package/dist/commands/validate/service/events/events.js +219 -0
  240. package/dist/commands/validate/service/events/events.js.map +1 -0
  241. package/dist/commands/validate/service/events/message-producers.js +77 -0
  242. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  243. package/dist/commands/validate/service/evidence-pins.js +131 -0
  244. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  245. package/dist/commands/validate/service/service.js +250 -0
  246. package/dist/commands/validate/service/service.js.map +1 -0
  247. package/dist/commands/validate/service/specs.js +219 -0
  248. package/dist/commands/validate/service/specs.js.map +1 -0
  249. package/dist/commands/validate/service/spine.js +113 -0
  250. package/dist/commands/validate/service/spine.js.map +1 -0
  251. package/dist/commands/validate/validate.js +338 -0
  252. package/dist/commands/validate/validate.js.map +1 -0
  253. package/dist/commands/verify/cross/diff.js +182 -0
  254. package/dist/commands/verify/cross/diff.js.map +1 -0
  255. package/dist/commands/verify/evidence/contract.js +32 -0
  256. package/dist/commands/verify/evidence/contract.js.map +1 -0
  257. package/dist/commands/verify/evidence/pins.js +52 -0
  258. package/dist/commands/verify/evidence/pins.js.map +1 -0
  259. package/dist/commands/verify/evidence/read.js +72 -0
  260. package/dist/commands/verify/evidence/read.js.map +1 -0
  261. package/dist/commands/verify/frozen.js +241 -0
  262. package/dist/commands/verify/frozen.js.map +1 -0
  263. package/dist/commands/verify/record.js +226 -0
  264. package/dist/commands/verify/record.js.map +1 -0
  265. package/dist/commands/verify/report.js +223 -0
  266. package/dist/commands/verify/report.js.map +1 -0
  267. package/dist/commands/verify/results.js +246 -0
  268. package/dist/commands/verify/results.js.map +1 -0
  269. package/dist/commands/verify/verify.js +217 -0
  270. package/dist/commands/verify/verify.js.map +1 -0
  271. package/dist/commands/vouch/contract.js +11 -0
  272. package/dist/commands/vouch/contract.js.map +1 -0
  273. package/dist/commands/vouch/pack/contract.js +2 -0
  274. package/dist/commands/vouch/pack/contract.js.map +1 -0
  275. package/dist/commands/vouch/pack/pack.js +266 -0
  276. package/dist/commands/vouch/pack/pack.js.map +1 -0
  277. package/dist/commands/vouch/pack/print.js +271 -0
  278. package/dist/commands/vouch/pack/print.js.map +1 -0
  279. package/dist/commands/vouch/pack/sections.js +142 -0
  280. package/dist/commands/vouch/pack/sections.js.map +1 -0
  281. package/dist/commands/vouch/prompt/confirm.js +46 -0
  282. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  283. package/dist/commands/vouch/report.js +101 -0
  284. package/dist/commands/vouch/report.js.map +1 -0
  285. package/dist/commands/vouch/run.js +285 -0
  286. package/dist/commands/vouch/run.js.map +1 -0
  287. package/dist/commands/vouch/sample/plan.js +125 -0
  288. package/dist/commands/vouch/sample/plan.js.map +1 -0
  289. package/dist/commands/vouch/sample/print.js +109 -0
  290. package/dist/commands/vouch/sample/print.js.map +1 -0
  291. package/dist/commands/vouch/vet/verify.js +123 -0
  292. package/dist/commands/vouch/vet/verify.js.map +1 -0
  293. package/dist/commands/vouch/vouch.js +176 -0
  294. package/dist/commands/vouch/vouch.js.map +1 -0
  295. package/dist/core/agent/agents-md/artifacts.js +220 -0
  296. package/dist/core/agent/agents-md/artifacts.js.map +1 -0
  297. package/dist/core/agent/agents-md/command-map.js +324 -0
  298. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  299. package/dist/core/agent/agents-md/cycle.js +165 -0
  300. package/dist/core/agent/agents-md/cycle.js.map +1 -0
  301. package/dist/core/agent/agents-md/map/explain.js +34 -0
  302. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  303. package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
  304. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  305. package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
  306. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  307. package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
  308. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  309. package/dist/core/agent/agents-md/map/mcp.js +41 -0
  310. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  311. package/dist/core/agent/agents-md/map/status.js +62 -0
  312. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  313. package/dist/core/agent/agents-md/map/subsystem.js +32 -0
  314. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  315. package/dist/core/agent/agents-md/map/usecases.js +60 -0
  316. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  317. package/dist/core/agent/agents-md/refusals.js +246 -0
  318. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  319. package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
  320. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
  321. package/dist/core/agent/agents-md/spine.js +40 -0
  322. package/dist/core/agent/agents-md/spine.js.map +1 -0
  323. package/dist/core/agent/agents-md.js +170 -0
  324. package/dist/core/agent/agents-md.js.map +1 -0
  325. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +50 -0
  326. package/dist/core/agent/agents-stamp.js.map +1 -0
  327. package/dist/core/agent/contract.js +2 -0
  328. package/dist/core/agent/contract.js.map +1 -0
  329. package/dist/core/agent/protocol.js +193 -0
  330. package/dist/core/agent/protocol.js.map +1 -0
  331. package/dist/core/agent/scaffold.js +259 -0
  332. package/dist/core/agent/scaffold.js.map +1 -0
  333. package/dist/core/agent/support/report.js +103 -0
  334. package/dist/core/agent/support/report.js.map +1 -0
  335. package/dist/core/agent/tools/dialects.js +150 -0
  336. package/dist/core/agent/tools/dialects.js.map +1 -0
  337. package/dist/core/agent/tools/registry.js +228 -0
  338. package/dist/core/agent/tools/registry.js.map +1 -0
  339. package/dist/core/agent/workflows/adopt.js +133 -0
  340. package/dist/core/agent/workflows/adopt.js.map +1 -0
  341. package/dist/core/agent/workflows/check.js +334 -0
  342. package/dist/core/agent/workflows/check.js.map +1 -0
  343. package/dist/core/agent/workflows/closing.js +262 -0
  344. package/dist/core/agent/workflows/closing.js.map +1 -0
  345. package/dist/core/agent/workflows/feature.js +105 -0
  346. package/dist/core/agent/workflows/feature.js.map +1 -0
  347. package/dist/core/agent/workflows/implement.js +105 -0
  348. package/dist/core/agent/workflows/implement.js.map +1 -0
  349. package/dist/core/agent/workflows/reference/authoring.js +209 -0
  350. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  351. package/dist/core/agent/workflows/reference/codes.js +65 -0
  352. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  353. package/dist/core/agent/workflows/reference/done-check.js +188 -0
  354. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  355. package/dist/core/agent/workflows/reference/reference.js +16 -0
  356. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  357. package/dist/core/agent/workflows/reference/spine.js +297 -0
  358. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  359. package/dist/core/asyncapi/baseline/plan.js +110 -0
  360. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  361. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  362. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  363. package/dist/core/asyncapi/depth.js +164 -0
  364. package/dist/core/asyncapi/depth.js.map +1 -0
  365. package/dist/core/asyncapi/digest.js +141 -0
  366. package/dist/core/asyncapi/digest.js.map +1 -0
  367. package/dist/core/asyncapi/merge/components.js +91 -0
  368. package/dist/core/asyncapi/merge/components.js.map +1 -0
  369. package/dist/core/asyncapi/merge/error.js +33 -0
  370. package/dist/core/asyncapi/merge/error.js.map +1 -0
  371. package/dist/core/asyncapi/merge/markers.js +308 -0
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  373. package/dist/core/asyncapi/merge/merge.js +215 -0
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  375. package/dist/core/asyncapi/merge/pin.js +107 -0
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  377. package/dist/core/asyncapi/model.js +11 -0
  378. package/dist/core/asyncapi/model.js.map +1 -0
  379. package/dist/core/asyncapi/producers.js +50 -0
  380. package/dist/core/asyncapi/producers.js.map +1 -0
  381. package/dist/core/{asyncapi.js → asyncapi/read.js} +95 -109
  382. package/dist/core/asyncapi/read.js.map +1 -0
  383. package/dist/core/brief/brief.js +225 -0
  384. package/dist/core/brief/brief.js.map +1 -0
  385. package/dist/core/brief/checks.js +250 -0
  386. package/dist/core/brief/checks.js.map +1 -0
  387. package/dist/core/brief/landscape.js +194 -0
  388. package/dist/core/brief/landscape.js.map +1 -0
  389. package/dist/core/brief/targets.js +226 -0
  390. package/dist/core/brief/targets.js.map +1 -0
  391. package/dist/core/brief/unchecked.js +47 -0
  392. package/dist/core/brief/unchecked.js.map +1 -0
  393. package/dist/core/c4/arch.js +282 -0
  394. package/dist/core/c4/arch.js.map +1 -0
  395. package/dist/core/c4/likec4.js +88 -0
  396. package/dist/core/c4/likec4.js.map +1 -0
  397. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  398. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  399. package/dist/core/c4/parsed/specification.js +78 -0
  400. package/dist/core/c4/parsed/specification.js.map +1 -0
  401. package/dist/core/c4/parsed/values.js +57 -0
  402. package/dist/core/c4/parsed/values.js.map +1 -0
  403. package/dist/core/c4/parsed/view-ids.js +75 -0
  404. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  405. package/dist/core/c4/project/architecture.js +45 -0
  406. package/dist/core/c4/project/architecture.js.map +1 -0
  407. package/dist/core/c4/project/documents.js +58 -0
  408. package/dist/core/c4/project/documents.js.map +1 -0
  409. package/dist/core/c4/project/load.js +183 -0
  410. package/dist/core/c4/project/load.js.map +1 -0
  411. package/dist/core/c4/resolve/service.js +113 -0
  412. package/dist/core/c4/resolve/service.js.map +1 -0
  413. package/dist/core/c4/seed/fleet-file.js +201 -0
  414. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  415. package/dist/core/c4/seed/items.js +91 -0
  416. package/dist/core/c4/seed/items.js.map +1 -0
  417. package/dist/core/c4/seed/stamp.js +48 -0
  418. package/dist/core/c4/seed/stamp.js.map +1 -0
  419. package/dist/core/c4/seed/template.js +109 -0
  420. package/dist/core/c4/seed/template.js.map +1 -0
  421. package/dist/core/c4/source-mask.js +82 -0
  422. package/dist/core/c4/source-mask.js.map +1 -0
  423. package/dist/core/c4/source-scan.js +227 -0
  424. package/dist/core/c4/source-scan.js.map +1 -0
  425. package/dist/core/c4/splice/authored-source.js +101 -0
  426. package/dist/core/c4/splice/authored-source.js.map +1 -0
  427. package/dist/core/c4/splice/contract.js +10 -0
  428. package/dist/core/c4/splice/contract.js.map +1 -0
  429. package/dist/core/c4/splice/delta-blocks.js +126 -0
  430. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  431. package/dist/core/c4/splice/identity/edges.js +36 -0
  432. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  433. package/dist/core/c4/splice/landscape-merge.js +269 -0
  434. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  435. package/dist/core/c4/splice/placement.js +194 -0
  436. package/dist/core/c4/splice/placement.js.map +1 -0
  437. package/dist/core/c4/workspace.js +172 -0
  438. package/dist/core/c4/workspace.js.map +1 -0
  439. package/dist/core/capabilities/authoring/notes.js +141 -0
  440. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  441. package/dist/core/capabilities/capabilities.js +124 -0
  442. package/dist/core/capabilities/capabilities.js.map +1 -0
  443. package/dist/core/capabilities/delta/doc.js +50 -0
  444. package/dist/core/capabilities/delta/doc.js.map +1 -0
  445. package/dist/core/capabilities/delta/overlay.js +129 -0
  446. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  447. package/dist/core/capabilities/delta/summary.js +57 -0
  448. package/dist/core/capabilities/delta/summary.js.map +1 -0
  449. package/dist/core/capabilities/delta/tree.js +43 -0
  450. package/dist/core/capabilities/delta/tree.js.map +1 -0
  451. package/dist/core/capabilities/delta/uncovered.js +222 -0
  452. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  453. package/dist/core/capabilities/findings.js +342 -0
  454. package/dist/core/capabilities/findings.js.map +1 -0
  455. package/dist/core/capabilities/realizes/findings.js +181 -0
  456. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  457. package/dist/core/capabilities/realizes/join.js +143 -0
  458. package/dist/core/capabilities/realizes/join.js.map +1 -0
  459. package/dist/core/capabilities/rollup.js +199 -0
  460. package/dist/core/capabilities/rollup.js.map +1 -0
  461. package/dist/core/capabilities/tree.js +126 -0
  462. package/dist/core/capabilities/tree.js.map +1 -0
  463. package/dist/core/capabilities/usecase-join.js +277 -0
  464. package/dist/core/capabilities/usecase-join.js.map +1 -0
  465. package/dist/core/coherence/authoring/scaffold.js +177 -0
  466. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  467. package/dist/core/coherence/authoring/sentinels.js +74 -0
  468. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  469. package/dist/core/coherence/coherence.js +251 -0
  470. package/dist/core/coherence/coherence.js.map +1 -0
  471. package/dist/core/coherence/declared.js +269 -0
  472. package/dist/core/coherence/declared.js.map +1 -0
  473. package/dist/core/coherence/events/declared.js +206 -0
  474. package/dist/core/coherence/events/declared.js.map +1 -0
  475. package/dist/core/coherence/events/events.js +204 -0
  476. package/dist/core/coherence/events/events.js.map +1 -0
  477. package/dist/core/coherence/events/grades.js +166 -0
  478. package/dist/core/coherence/events/grades.js.map +1 -0
  479. package/dist/core/coherence/events/lookups.js +122 -0
  480. package/dist/core/coherence/events/lookups.js.map +1 -0
  481. package/dist/core/coherence/events/merged.js +40 -0
  482. package/dist/core/coherence/events/merged.js.map +1 -0
  483. package/dist/core/coherence/living.js +198 -0
  484. package/dist/core/coherence/living.js.map +1 -0
  485. package/dist/core/coherence/lookups.js +155 -0
  486. package/dist/core/coherence/lookups.js.map +1 -0
  487. package/dist/core/coherence/pending.js +39 -0
  488. package/dist/core/coherence/pending.js.map +1 -0
  489. package/dist/core/conflict-markers.js +60 -0
  490. package/dist/core/conflict-markers.js.map +1 -0
  491. package/dist/core/delta/claims.js +73 -0
  492. package/dist/core/delta/claims.js.map +1 -0
  493. package/dist/core/delta/delta.js +296 -0
  494. package/dist/core/delta/delta.js.map +1 -0
  495. package/dist/core/delta/document.js +177 -0
  496. package/dist/core/delta/document.js.map +1 -0
  497. package/dist/core/delta/scope.js +48 -0
  498. package/dist/core/delta/scope.js.map +1 -0
  499. package/dist/core/delta/select.js +237 -0
  500. package/dist/core/delta/select.js.map +1 -0
  501. package/dist/core/dependencies/dependencies.js +141 -0
  502. package/dist/core/dependencies/dependencies.js.map +1 -0
  503. package/dist/core/dependencies/facts.js +165 -0
  504. package/dist/core/dependencies/facts.js.map +1 -0
  505. package/dist/core/dependencies/fanin.js +88 -0
  506. package/dist/core/dependencies/fanin.js.map +1 -0
  507. package/dist/core/dependencies/graph.js +106 -0
  508. package/dist/core/dependencies/graph.js.map +1 -0
  509. package/dist/core/diff/base-git.js +148 -0
  510. package/dist/core/diff/base-git.js.map +1 -0
  511. package/dist/core/diff/base-state.js +209 -0
  512. package/dist/core/diff/base-state.js.map +1 -0
  513. package/dist/core/diff/current-state.js +96 -0
  514. package/dist/core/diff/current-state.js.map +1 -0
  515. package/dist/core/diff/scope/changed-paths.js +188 -0
  516. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  517. package/dist/core/diff/semantic.js +243 -0
  518. package/dist/core/diff/semantic.js.map +1 -0
  519. package/dist/core/diff/victims.js +247 -0
  520. package/dist/core/diff/victims.js.map +1 -0
  521. package/dist/core/docs.js +7 -64
  522. package/dist/core/docs.js.map +1 -1
  523. package/dist/core/doctor/agents.js +222 -0
  524. package/dist/core/doctor/agents.js.map +1 -0
  525. package/dist/core/doctor/config.js +135 -0
  526. package/dist/core/doctor/config.js.map +1 -0
  527. package/dist/core/doctor/doctor.js +275 -0
  528. package/dist/core/doctor/doctor.js.map +1 -0
  529. package/dist/core/doctor/report.js +13 -0
  530. package/dist/core/doctor/report.js.map +1 -0
  531. package/dist/core/doctor/residue.js +110 -0
  532. package/dist/core/doctor/residue.js.map +1 -0
  533. package/dist/core/document/apply.js +77 -0
  534. package/dist/core/document/apply.js.map +1 -0
  535. package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
  536. package/dist/core/document/frontmatter.js.map +1 -0
  537. package/dist/core/document/grammar/directives.js +143 -0
  538. package/dist/core/document/grammar/directives.js.map +1 -0
  539. package/dist/core/document/parse.js +263 -0
  540. package/dist/core/document/parse.js.map +1 -0
  541. package/dist/core/document/scenarios.js +221 -0
  542. package/dist/core/document/scenarios.js.map +1 -0
  543. package/dist/core/document/spec.js +241 -0
  544. package/dist/core/document/spec.js.map +1 -0
  545. package/dist/core/{config.js → envelope/config.js} +79 -18
  546. package/dist/core/envelope/config.js.map +1 -0
  547. package/dist/core/envelope/json.js +175 -0
  548. package/dist/core/envelope/json.js.map +1 -0
  549. package/dist/core/{version.js → envelope/version.js} +3 -3
  550. package/dist/core/envelope/version.js.map +1 -0
  551. package/dist/core/explain/families.js +175 -0
  552. package/dist/core/explain/families.js.map +1 -0
  553. package/dist/core/explain/fix-tables.js +178 -0
  554. package/dist/core/explain/fix-tables.js.map +1 -0
  555. package/dist/core/explain/lookup.js +181 -0
  556. package/dist/core/explain/lookup.js.map +1 -0
  557. package/dist/core/explain/refusals.js +49 -0
  558. package/dist/core/explain/refusals.js.map +1 -0
  559. package/dist/core/explain/terms.js +144 -0
  560. package/dist/core/explain/terms.js.map +1 -0
  561. package/dist/core/explore/describe.js +105 -0
  562. package/dist/core/explore/describe.js.map +1 -0
  563. package/dist/core/{explore.js → explore/explore.js} +50 -101
  564. package/dist/core/explore/explore.js.map +1 -0
  565. package/dist/core/fleet-context.js +120 -78
  566. package/dist/core/fleet-context.js.map +1 -1
  567. package/dist/core/gate/checks.js +201 -0
  568. package/dist/core/gate/checks.js.map +1 -0
  569. package/dist/core/gate/partners.js +205 -0
  570. package/dist/core/gate/partners.js.map +1 -0
  571. package/dist/core/gate/report.js +47 -0
  572. package/dist/core/gate/report.js.map +1 -0
  573. package/dist/core/gate/verification.js +113 -0
  574. package/dist/core/gate/verification.js.map +1 -0
  575. package/dist/core/gherkin/digest.js +60 -0
  576. package/dist/core/gherkin/digest.js.map +1 -0
  577. package/dist/core/gherkin/emit.js +177 -0
  578. package/dist/core/gherkin/emit.js.map +1 -0
  579. package/dist/core/gherkin/read.js +76 -0
  580. package/dist/core/gherkin/read.js.map +1 -0
  581. package/dist/core/gherkin/stale.js +234 -0
  582. package/dist/core/gherkin/stale.js.map +1 -0
  583. package/dist/core/gherkin/stamp.js +77 -0
  584. package/dist/core/gherkin/stamp.js.map +1 -0
  585. package/dist/core/gherkin/steps/catalogue.js +154 -0
  586. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  587. package/dist/core/gherkin/steps/inventory.js +98 -0
  588. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  589. package/dist/core/gherkin/steps/phrase.js +72 -0
  590. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  591. package/dist/core/glossary/delta.js +106 -0
  592. package/dist/core/glossary/delta.js.map +1 -0
  593. package/dist/core/glossary/tree.js +86 -0
  594. package/dist/core/glossary/tree.js.map +1 -0
  595. package/dist/core/kernel/concurrency.js.map +1 -0
  596. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  597. package/dist/core/kernel/document-bytes.js.map +1 -0
  598. package/dist/core/kernel/fences.js +42 -0
  599. package/dist/core/kernel/fences.js.map +1 -0
  600. package/dist/core/kernel/ids/capability.js +72 -0
  601. package/dist/core/kernel/ids/capability.js.map +1 -0
  602. package/dist/core/kernel/ids/dirs.js +33 -0
  603. package/dist/core/kernel/ids/dirs.js.map +1 -0
  604. package/dist/core/kernel/ids/feature.js +75 -0
  605. package/dist/core/kernel/ids/feature.js.map +1 -0
  606. package/dist/core/kernel/ids/service.js +156 -0
  607. package/dist/core/kernel/ids/service.js.map +1 -0
  608. package/dist/core/kernel/ids/subsystem.js +63 -0
  609. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  610. package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
  611. package/dist/core/kernel/path-safety.js.map +1 -0
  612. package/dist/core/kernel/records.js.map +1 -0
  613. package/dist/core/links/backlinks.js +68 -0
  614. package/dist/core/links/backlinks.js.map +1 -0
  615. package/dist/core/links/case.js +74 -0
  616. package/dist/core/links/case.js.map +1 -0
  617. package/dist/core/links/corpus.js +104 -0
  618. package/dist/core/links/corpus.js.map +1 -0
  619. package/dist/core/links/findings.js +110 -0
  620. package/dist/core/links/findings.js.map +1 -0
  621. package/dist/core/links/parse.js +236 -0
  622. package/dist/core/links/parse.js.map +1 -0
  623. package/dist/core/mcp/argv.js +111 -0
  624. package/dist/core/mcp/argv.js.map +1 -0
  625. package/dist/core/mcp/author-tools.js +72 -0
  626. package/dist/core/mcp/author-tools.js.map +1 -0
  627. package/dist/core/mcp/framing.js +46 -0
  628. package/dist/core/mcp/framing.js.map +1 -0
  629. package/dist/core/mcp/protocol.js +280 -0
  630. package/dist/core/mcp/protocol.js.map +1 -0
  631. package/dist/core/mcp/tools.js +314 -0
  632. package/dist/core/mcp/tools.js.map +1 -0
  633. package/dist/core/obligations/obligations.js +106 -0
  634. package/dist/core/obligations/obligations.js.map +1 -0
  635. package/dist/core/openapi/baseline/gate.js +166 -0
  636. package/dist/core/openapi/baseline/gate.js.map +1 -0
  637. package/dist/core/openapi/baseline/plan.js +112 -0
  638. package/dist/core/openapi/baseline/plan.js.map +1 -0
  639. package/dist/core/openapi/baseline/record.js +175 -0
  640. package/dist/core/openapi/baseline/record.js.map +1 -0
  641. package/dist/core/openapi/depth.js +122 -0
  642. package/dist/core/openapi/depth.js.map +1 -0
  643. package/dist/core/openapi/digest.js +189 -0
  644. package/dist/core/openapi/digest.js.map +1 -0
  645. package/dist/core/{openapi.js → openapi/doc.js} +44 -106
  646. package/dist/core/openapi/doc.js.map +1 -0
  647. package/dist/core/openapi/merge/components.js +234 -0
  648. package/dist/core/openapi/merge/components.js.map +1 -0
  649. package/dist/core/openapi/merge/error.js +26 -0
  650. package/dist/core/openapi/merge/error.js.map +1 -0
  651. package/dist/core/openapi/merge/markers.js +208 -0
  652. package/dist/core/openapi/merge/markers.js.map +1 -0
  653. package/dist/core/openapi/merge/merge.js +256 -0
  654. package/dist/core/openapi/merge/merge.js.map +1 -0
  655. package/dist/core/openapi/merge/pin.js +128 -0
  656. package/dist/core/openapi/merge/pin.js.map +1 -0
  657. package/dist/core/openspec/decide/capabilities.js +244 -0
  658. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  659. package/dist/core/openspec/decide/dispositions.js +63 -0
  660. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  661. package/dist/core/openspec/decide/renames.js +179 -0
  662. package/dist/core/openspec/decide/renames.js.map +1 -0
  663. package/dist/core/openspec/decide/verdict.js +84 -0
  664. package/dist/core/openspec/decide/verdict.js.map +1 -0
  665. package/dist/core/openspec/inventory.js +221 -0
  666. package/dist/core/openspec/inventory.js.map +1 -0
  667. package/dist/core/openspec/model/mapping.js +76 -0
  668. package/dist/core/openspec/model/mapping.js.map +1 -0
  669. package/dist/core/openspec/model/model.js +65 -0
  670. package/dist/core/openspec/model/model.js.map +1 -0
  671. package/dist/core/openspec/scan/changes.js +235 -0
  672. package/dist/core/openspec/scan/changes.js.map +1 -0
  673. package/dist/core/openspec/scan/config.js +200 -0
  674. package/dist/core/openspec/scan/config.js.map +1 -0
  675. package/dist/core/openspec/scan/shape.js +260 -0
  676. package/dist/core/openspec/scan/shape.js.map +1 -0
  677. package/dist/core/openspec/scan/walk.js +133 -0
  678. package/dist/core/openspec/scan/walk.js.map +1 -0
  679. package/dist/core/openspec/scan/workspace.js +71 -0
  680. package/dist/core/openspec/scan/workspace.js.map +1 -0
  681. package/dist/core/owners/codeowners.js +141 -0
  682. package/dist/core/owners/codeowners.js.map +1 -0
  683. package/dist/core/pack/features.js +120 -0
  684. package/dist/core/pack/features.js.map +1 -0
  685. package/dist/core/pack/joins.js +112 -0
  686. package/dist/core/pack/joins.js.map +1 -0
  687. package/dist/core/pack/living.js +118 -0
  688. package/dist/core/pack/living.js.map +1 -0
  689. package/dist/core/pack/pack.js +76 -0
  690. package/dist/core/pack/pack.js.map +1 -0
  691. package/dist/core/permissions/permissions.js +87 -0
  692. package/dist/core/permissions/permissions.js.map +1 -0
  693. package/dist/core/projection/api.js +84 -0
  694. package/dist/core/projection/api.js.map +1 -0
  695. package/dist/core/projection/arch-slice.js +63 -0
  696. package/dist/core/projection/arch-slice.js.map +1 -0
  697. package/dist/core/projection/events.js +34 -0
  698. package/dist/core/projection/events.js.map +1 -0
  699. package/dist/core/provenance/findings.js +208 -0
  700. package/dist/core/provenance/findings.js.map +1 -0
  701. package/dist/core/provenance/git.js +225 -0
  702. package/dist/core/provenance/git.js.map +1 -0
  703. package/dist/core/provenance/gitq/moves.js +182 -0
  704. package/dist/core/provenance/gitq/moves.js.map +1 -0
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  707. package/dist/core/provenance/sample/scope.js +238 -0
  708. package/dist/core/provenance/sample/scope.js.map +1 -0
  709. package/dist/core/provenance/sample/sections.js +61 -0
  710. package/dist/core/provenance/sample/sections.js.map +1 -0
  711. package/dist/core/provenance/sources.js +263 -0
  712. package/dist/core/provenance/sources.js.map +1 -0
  713. package/dist/core/provenance/stamp.js +232 -0
  714. package/dist/core/provenance/stamp.js.map +1 -0
  715. package/dist/core/provenance/walk.js +157 -0
  716. package/dist/core/provenance/walk.js.map +1 -0
  717. package/dist/core/repo/authored/paths.js +192 -0
  718. package/dist/core/repo/authored/paths.js.map +1 -0
  719. package/dist/core/repo/entries.js +126 -0
  720. package/dist/core/repo/entries.js.map +1 -0
  721. package/dist/core/repo/paths.js +236 -0
  722. package/dist/core/repo/paths.js.map +1 -0
  723. package/dist/core/repo/repo.js +248 -0
  724. package/dist/core/repo/repo.js.map +1 -0
  725. package/dist/core/repo/service-target.js +153 -0
  726. package/dist/core/repo/service-target.js.map +1 -0
  727. package/dist/core/repo/state.js +58 -0
  728. package/dist/core/repo/state.js.map +1 -0
  729. package/dist/core/repo/tree/find.js +52 -0
  730. package/dist/core/repo/tree/find.js.map +1 -0
  731. package/dist/core/repo/tree/fs.js +64 -0
  732. package/dist/core/repo/tree/fs.js.map +1 -0
  733. package/dist/core/repo/tree/marker.js +61 -0
  734. package/dist/core/repo/tree/marker.js.map +1 -0
  735. package/dist/core/repo/tree/views.js +172 -0
  736. package/dist/core/repo/tree/views.js.map +1 -0
  737. package/dist/core/repo/tree/walk.js +234 -0
  738. package/dist/core/repo/tree/walk.js.map +1 -0
  739. package/dist/core/results.js +99 -2
  740. package/dist/core/results.js.map +1 -1
  741. package/dist/core/scaffold/landscape.js +131 -0
  742. package/dist/core/scaffold/landscape.js.map +1 -0
  743. package/dist/core/scaffold/readme.js +84 -0
  744. package/dist/core/scaffold/readme.js.map +1 -0
  745. package/dist/core/staging/commit.js +241 -0
  746. package/dist/core/staging/commit.js.map +1 -0
  747. package/dist/core/staging/interrupted.js +96 -0
  748. package/dist/core/staging/interrupted.js.map +1 -0
  749. package/dist/core/staging/lock.js +206 -0
  750. package/dist/core/staging/lock.js.map +1 -0
  751. package/dist/core/staging/recovery/finding.js +35 -0
  752. package/dist/core/staging/recovery/finding.js.map +1 -0
  753. package/dist/core/staging/recovery/intent.js +98 -0
  754. package/dist/core/staging/recovery/intent.js.map +1 -0
  755. package/dist/core/staging/recovery/recover.js +126 -0
  756. package/dist/core/staging/recovery/recover.js.map +1 -0
  757. package/dist/core/staging/recovery/residue.js +62 -0
  758. package/dist/core/staging/recovery/residue.js.map +1 -0
  759. package/dist/core/staging/snapshot.js +202 -0
  760. package/dist/core/staging/snapshot.js.map +1 -0
  761. package/dist/core/staging/txn/forward.js +171 -0
  762. package/dist/core/staging/txn/forward.js.map +1 -0
  763. package/dist/core/staging/txn/journal.js +139 -0
  764. package/dist/core/staging/txn/journal.js.map +1 -0
  765. package/dist/core/staging/txn/transaction.js +75 -0
  766. package/dist/core/staging/txn/transaction.js.map +1 -0
  767. package/dist/core/staging/writes.js +113 -0
  768. package/dist/core/staging/writes.js.map +1 -0
  769. package/dist/core/status/actions/execution.js +49 -0
  770. package/dist/core/status/actions/execution.js.map +1 -0
  771. package/dist/core/status/contracts.js +102 -0
  772. package/dist/core/status/contracts.js.map +1 -0
  773. package/dist/core/status/feature/artifacts.js +171 -0
  774. package/dist/core/status/feature/artifacts.js.map +1 -0
  775. package/dist/core/status/feature/feature.js +207 -0
  776. package/dist/core/status/feature/feature.js.map +1 -0
  777. package/dist/core/status/feature/next.js +150 -0
  778. package/dist/core/status/feature/next.js.map +1 -0
  779. package/dist/core/status/feature/state.js +21 -0
  780. package/dist/core/status/feature/state.js.map +1 -0
  781. package/dist/core/status/fleet/fleet.js +187 -0
  782. package/dist/core/status/fleet/fleet.js.map +1 -0
  783. package/dist/core/status/fleet/next.js +207 -0
  784. package/dist/core/status/fleet/next.js.map +1 -0
  785. package/dist/core/status/interrupted.js +97 -0
  786. package/dist/core/status/interrupted.js.map +1 -0
  787. package/dist/core/status/report.js +31 -0
  788. package/dist/core/status/report.js.map +1 -0
  789. package/dist/core/status/scan.js +41 -0
  790. package/dist/core/status/scan.js.map +1 -0
  791. package/dist/core/status/verification.js +201 -0
  792. package/dist/core/status/verification.js.map +1 -0
  793. package/dist/core/usecases/capability.js +169 -0
  794. package/dist/core/usecases/capability.js.map +1 -0
  795. package/dist/core/usecases/delta/claims.js +116 -0
  796. package/dist/core/usecases/delta/claims.js.map +1 -0
  797. package/dist/core/usecases/delta/flows.js +103 -0
  798. package/dist/core/usecases/delta/flows.js.map +1 -0
  799. package/dist/core/usecases/delta/overlay.js +235 -0
  800. package/dist/core/usecases/delta/overlay.js.map +1 -0
  801. package/dist/core/usecases/fleet.js +137 -0
  802. package/dist/core/usecases/fleet.js.map +1 -0
  803. package/dist/core/usecases/operations.js +111 -0
  804. package/dist/core/usecases/operations.js.map +1 -0
  805. package/dist/core/usecases/place.js +44 -0
  806. package/dist/core/usecases/place.js.map +1 -0
  807. package/dist/core/usecases/touch.js +101 -0
  808. package/dist/core/usecases/touch.js.map +1 -0
  809. package/dist/core/verify/answers.js +173 -0
  810. package/dist/core/verify/answers.js.map +1 -0
  811. package/dist/core/verify/build.js +150 -0
  812. package/dist/core/verify/build.js.map +1 -0
  813. package/dist/core/verify/checklist.js +201 -0
  814. package/dist/core/verify/checklist.js.map +1 -0
  815. package/dist/core/verify/claims/identity.js +61 -0
  816. package/dist/core/verify/claims/identity.js.map +1 -0
  817. package/dist/core/verify/cross/diff.js +97 -0
  818. package/dist/core/verify/cross/diff.js.map +1 -0
  819. package/dist/core/verify/evidence/contract.js +169 -0
  820. package/dist/core/verify/evidence/contract.js.map +1 -0
  821. package/dist/core/verify/file.js +257 -0
  822. package/dist/core/verify/file.js.map +1 -0
  823. package/dist/core/verify/pins/lint.js +157 -0
  824. package/dist/core/verify/pins/lint.js.map +1 -0
  825. package/dist/core/verify/pins/pin.js +95 -0
  826. package/dist/core/verify/pins/pin.js.map +1 -0
  827. package/dist/core/verify/record.js +142 -0
  828. package/dist/core/verify/record.js.map +1 -0
  829. package/dist/core/verify/store/commit.js +89 -0
  830. package/dist/core/verify/store/commit.js.map +1 -0
  831. package/dist/core/verify/store/render.js +57 -0
  832. package/dist/core/verify/store/render.js.map +1 -0
  833. package/dist/core/vocabulary/health.js +91 -0
  834. package/dist/core/vocabulary/health.js.map +1 -0
  835. package/dist/core/vocabulary/issue.js +55 -0
  836. package/dist/core/vocabulary/issue.js.map +1 -0
  837. package/dist/core/vocabulary/maturity.js +145 -0
  838. package/dist/core/vocabulary/maturity.js.map +1 -0
  839. package/dist/core/{report.js → vocabulary/report.js} +30 -2
  840. package/dist/core/vocabulary/report.js.map +1 -0
  841. package/dist/core/vocabulary/steps.js +266 -0
  842. package/dist/core/vocabulary/steps.js.map +1 -0
  843. package/dist/core/workspace/discover.js +239 -0
  844. package/dist/core/workspace/discover.js.map +1 -0
  845. package/dist/core/workspace/render.js +52 -0
  846. package/dist/core/workspace/render.js.map +1 -0
  847. package/examples/README.md +189 -0
  848. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  849. package/examples/docs/architecture/capabilities.yaml +31 -0
  850. package/examples/docs/architecture/landscape.likec4 +280 -0
  851. package/examples/docs/architecture/obligations.yaml +23 -0
  852. package/examples/docs/architecture/permissions.yaml +50 -0
  853. package/examples/docs/architecture/subsystems.likec4 +11 -0
  854. package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
  855. package/examples/docs/capabilities/checkout/spec.md +55 -0
  856. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  857. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  858. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  859. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  860. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
  863. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  864. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  865. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  866. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  867. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  868. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
  869. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  870. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  871. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  872. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  873. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  874. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  875. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  876. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  877. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  878. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  879. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
  880. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  881. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  882. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  883. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  884. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  885. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  886. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  887. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  888. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  889. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  890. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  891. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  892. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  893. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  894. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  895. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  896. package/examples/docs/glossary/order.md +15 -0
  897. package/examples/docs/glossary/payments/authorization.md +14 -0
  898. package/examples/docs/likec4.config.json +9 -0
  899. package/examples/docs/loam.json +3 -0
  900. package/examples/docs/services/checkout-web/model.likec4 +109 -0
  901. package/examples/docs/services/checkout-web/spec.md +91 -0
  902. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  903. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  904. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  905. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  906. package/examples/docs/services/order-service/arch.spec.md +127 -0
  907. package/examples/docs/services/order-service/asyncapi.yaml +108 -0
  908. package/examples/docs/services/order-service/health.yaml +57 -0
  909. package/examples/docs/services/order-service/model.likec4 +138 -0
  910. package/examples/docs/services/order-service/openapi.yaml +257 -0
  911. package/examples/docs/services/order-service/runbook.md +62 -0
  912. package/examples/docs/services/order-service/spec.md +134 -0
  913. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  914. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  915. package/examples/docs/services/payment-service/arch.spec.md +73 -0
  916. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  917. package/examples/docs/services/payment-service/health.yaml +39 -0
  918. package/examples/docs/services/payment-service/model.likec4 +67 -0
  919. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  920. package/examples/docs/services/payment-service/runbook.md +37 -0
  921. package/examples/docs/services/payment-service/spec.md +88 -0
  922. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  923. package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
  924. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  925. package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
  926. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  927. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  928. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  929. package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
  930. package/examples/docs/services/platform/notification-service/health.yaml +35 -0
  931. package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
  932. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  933. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  934. package/examples/docs/services/platform/subsystem.yaml +2 -0
  935. package/examples/fleet.yaml +57 -0
  936. package/package.json +19 -6
  937. package/dist/commands/adopt.js +0 -240
  938. package/dist/commands/adopt.js.map +0 -1
  939. package/dist/commands/archive.js +0 -1313
  940. package/dist/commands/archive.js.map +0 -1
  941. package/dist/commands/delta.js +0 -388
  942. package/dist/commands/delta.js.map +0 -1
  943. package/dist/commands/docs-repo-gate.js.map +0 -1
  944. package/dist/commands/format.js +0 -17
  945. package/dist/commands/format.js.map +0 -1
  946. package/dist/commands/gherkin.js +0 -309
  947. package/dist/commands/gherkin.js.map +0 -1
  948. package/dist/commands/init.js.map +0 -1
  949. package/dist/commands/list.js +0 -295
  950. package/dist/commands/list.js.map +0 -1
  951. package/dist/commands/migrate-openspec.js +0 -950
  952. package/dist/commands/migrate-openspec.js.map +0 -1
  953. package/dist/commands/new.js +0 -413
  954. package/dist/commands/new.js.map +0 -1
  955. package/dist/commands/rebase.js +0 -356
  956. package/dist/commands/rebase.js.map +0 -1
  957. package/dist/commands/show.js.map +0 -1
  958. package/dist/commands/status.js +0 -262
  959. package/dist/commands/status.js.map +0 -1
  960. package/dist/commands/unarchive.js.map +0 -1
  961. package/dist/commands/validate.js +0 -1773
  962. package/dist/commands/validate.js.map +0 -1
  963. package/dist/commands/verify.js +0 -775
  964. package/dist/commands/verify.js.map +0 -1
  965. package/dist/commands/vouch.js +0 -421
  966. package/dist/commands/vouch.js.map +0 -1
  967. package/dist/core/agent.js +0 -2173
  968. package/dist/core/agent.js.map +0 -1
  969. package/dist/core/agents-stamp.js.map +0 -1
  970. package/dist/core/arch.js +0 -130
  971. package/dist/core/arch.js.map +0 -1
  972. package/dist/core/asyncapi.js.map +0 -1
  973. package/dist/core/brief.js +0 -755
  974. package/dist/core/brief.js.map +0 -1
  975. package/dist/core/coherence.js +0 -577
  976. package/dist/core/coherence.js.map +0 -1
  977. package/dist/core/concurrency.js.map +0 -1
  978. package/dist/core/config.js.map +0 -1
  979. package/dist/core/delta.js +0 -476
  980. package/dist/core/delta.js.map +0 -1
  981. package/dist/core/dependencies.js +0 -356
  982. package/dist/core/dependencies.js.map +0 -1
  983. package/dist/core/doctor.js +0 -596
  984. package/dist/core/doctor.js.map +0 -1
  985. package/dist/core/document-bytes.js.map +0 -1
  986. package/dist/core/explore.js.map +0 -1
  987. package/dist/core/frontmatter.js.map +0 -1
  988. package/dist/core/gherkin.js +0 -463
  989. package/dist/core/gherkin.js.map +0 -1
  990. package/dist/core/health.js +0 -67
  991. package/dist/core/health.js.map +0 -1
  992. package/dist/core/ids.js +0 -122
  993. package/dist/core/ids.js.map +0 -1
  994. package/dist/core/issue.js +0 -9
  995. package/dist/core/issue.js.map +0 -1
  996. package/dist/core/json.js +0 -74
  997. package/dist/core/json.js.map +0 -1
  998. package/dist/core/likec4.js +0 -489
  999. package/dist/core/likec4.js.map +0 -1
  1000. package/dist/core/maturity.js +0 -66
  1001. package/dist/core/maturity.js.map +0 -1
  1002. package/dist/core/openapi-merge.js +0 -552
  1003. package/dist/core/openapi-merge.js.map +0 -1
  1004. package/dist/core/openapi.js.map +0 -1
  1005. package/dist/core/openspec-inventory.js +0 -1440
  1006. package/dist/core/openspec-inventory.js.map +0 -1
  1007. package/dist/core/path-safety.js.map +0 -1
  1008. package/dist/core/provenance.js +0 -787
  1009. package/dist/core/provenance.js.map +0 -1
  1010. package/dist/core/records.js.map +0 -1
  1011. package/dist/core/repo.js +0 -438
  1012. package/dist/core/repo.js.map +0 -1
  1013. package/dist/core/report.js.map +0 -1
  1014. package/dist/core/spec.js +0 -505
  1015. package/dist/core/spec.js.map +0 -1
  1016. package/dist/core/staging.js +0 -890
  1017. package/dist/core/staging.js.map +0 -1
  1018. package/dist/core/status.js +0 -1132
  1019. package/dist/core/status.js.map +0 -1
  1020. package/dist/core/steps.js +0 -72
  1021. package/dist/core/steps.js.map +0 -1
  1022. package/dist/core/verify.js +0 -807
  1023. package/dist/core/verify.js.map +0 -1
  1024. package/dist/core/version.js.map +0 -1
  1025. /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
  1026. /package/dist/core/{records.js → kernel/records.js} +0 -0
@@ -0,0 +1,301 @@
1
+ /**
2
+ * The columns a person reads, and the worklist under them.
3
+ *
4
+ * The worklist is the point of the command rather than a summary: a fleet list
5
+ * that only listed would leave the reader to work out which services are
6
+ * behind, which is the question they opened it with.
7
+ */
8
+ import { MATURITY_LADDER, maturityRollup } from "../../core/vocabulary/maturity.js";
9
+ import {} from "../../core/capabilities/rollup.js";
10
+ import { compareIds } from "../../core/repo/entries.js";
11
+ import {} from "./views.js";
12
+ function serviceFlags(v) {
13
+ const s = v.entry;
14
+ return [
15
+ s.has.model ? "M" : "-",
16
+ s.has.spec ? "S" : "-",
17
+ v.archSpec ? "a" : "-",
18
+ s.has.openapi ? "A" : "-",
19
+ // The async contract, lowercase like the arch spec and for the same reason:
20
+ // it is optional. A fleet where most services own no topic must not read as
21
+ // a fleet with a column of gaps in it.
22
+ s.has.asyncapi ? "e" : "-",
23
+ s.has.runbook ? "R" : "-",
24
+ s.has.health ? "H" : "-",
25
+ ].join(" ");
26
+ }
27
+ /**
28
+ * The rung as a person reads it. `vouched (sampled)` is a DISPLAY string, not
29
+ * a rung: the ladder, the rollup below and `--needs-work` all still see
30
+ * `vouched`, because that string is a published contract and the document
31
+ * really is stamped by a person. What the suffix says is what the stamp says
32
+ * — they read a recorded sample of it, and `loam validate` will report
33
+ * `sources.sampled-vouch` until somebody reads the rest. Without it, the one
34
+ * line a fleet lead scans for trust would show a sampled vouch and a full one
35
+ * as the same word.
36
+ *
37
+ * Only on `vouched`: a lower rung already says less than "a person vouched",
38
+ * and hanging a scope note on it would explain a claim nothing is making.
39
+ */
40
+ function rungLabel(v) {
41
+ return v.maturity === "vouched" && v.entry.vouchScope === "sampled" ? "vouched (sampled)" : v.maturity;
42
+ }
43
+ export function printServices(views, fleet) {
44
+ console.log(`services (${views.length}) [M]odel [S]pec [a]rch-spec [A]pi [R]unbook [H]ealth`);
45
+ const width = Math.max(0, ...views.map((v) => v.entry.id.length));
46
+ // Measured over the DISPLAY strings, so the column does not shear the first
47
+ // time a sampled row appears in a fleet.
48
+ const rungWidth = Math.max(0, ...views.map((v) => rungLabel(v).length));
49
+ for (const v of views) {
50
+ const s = v.entry;
51
+ const adrs = s.adrs > 0 ? ` (${s.adrs} adr${s.adrs === 1 ? "" : "s"})` : "";
52
+ // The rung per service, not only in the rollup: "12 partial" tells a reader
53
+ // the fleet is unfinished and nothing about which twelve, which is the one
54
+ // question the line is read to answer.
55
+ console.log(` ${serviceFlags(v)} ${s.id.padEnd(width)} ${rungLabel(v).padEnd(rungWidth)}${adrs}`.trimEnd());
56
+ }
57
+ // How much of the fleet anyone has actually vouched for. On 100+ services this
58
+ // is the number that says whether the docs can be trusted at all.
59
+ if (views.length > 0) {
60
+ const counted = new Map();
61
+ for (const v of views) {
62
+ const key = v.entry.status ?? "unmarked";
63
+ counted.set(key, (counted.get(key) ?? 0) + 1);
64
+ }
65
+ const parts = [...counted.entries()]
66
+ .sort((a, b) => compareIds(a[0], b[0]))
67
+ .map(([status, n]) => `${n} ${status}`);
68
+ console.log(` status: ${parts.join(" · ")}`);
69
+ // The campaign dial next to the trust dial: rungs in ladder order, so the
70
+ // line reads as progress left to right. Presence and provenance state only
71
+ // — completeness is unchecked, so this line never says "adopted".
72
+ const rollup = maturityRollup(views);
73
+ // The rollup itself is untouched — the rung IS `vouched`, and both the
74
+ // `--json` payload and `--needs-work` are computed from it. What the TEXT
75
+ // line adds is the qualifier the per-row suffix already carries, because
76
+ // this is the line a fleet lead reads for the trust answer, and recovering
77
+ // "how many of those 118 did anybody read in full" by scanning 118 rows is
78
+ // not an answer. Same layout as the validate scorecard's provenance row.
79
+ const sampled = views.filter((v) => v.maturity === "vouched" && v.entry.vouchScope === "sampled").length;
80
+ const rungs = MATURITY_LADDER.filter((m) => rollup[m] > 0).map((m) => `${rollup[m]} ${m}${m === "vouched" && sampled > 0 ? ` (${sampled} sampled)` : ""}`);
81
+ console.log(` maturity: ${rungs.join(" · ")}`);
82
+ // The tree dial, only once a tree exists: unfiled is permanent and normal
83
+ // (a count, never a finding), and a flat fleet has nothing to say here —
84
+ // printing "5 unfiled" over a fleet nobody groups would read as work.
85
+ if (fleet.tree !== undefined && fleet.tree.subsystems.length > 0) {
86
+ const unfiled = fleet.tree.services.filter((s) => s.subsystem.length === 0).length;
87
+ console.log(` subsystems: ${fleet.tree.subsystems.length} · unfiled: ${unfiled}`);
88
+ }
89
+ }
90
+ // OUTSIDE the rollup block above, which only runs when the fleet has
91
+ // services: a fleet can record a decision about how it will build services
92
+ // before it holds one, and that count would otherwise be printed by nothing.
93
+ // Silent at zero, exactly like the per-service `(3 adrs)` column: no fleet
94
+ // owes any fleet-level ADR, so "adrs: 0" would read as a gap.
95
+ if (fleet.adrs > 0) {
96
+ console.log(` adrs: ${fleet.adrs} fleet decision${fleet.adrs === 1 ? "" : "s"} (architecture/adrs/)`);
97
+ }
98
+ }
99
+ /**
100
+ * The one-shot adoption worklist. Onboarding ten legacy services means asking
101
+ * "what is left" once a day for a month, and the answer used to require reading
102
+ * a presence table and a rollup and joining them by eye. A service whose
103
+ * provenance cannot be judged from here is LISTED, tagged, never dropped:
104
+ * omitting it would read as done.
105
+ */
106
+ export function printWorklist(views, total, fanIn) {
107
+ if (views.length === 0) {
108
+ console.log(`nothing to do — all ${total} service(s) are vouched`);
109
+ return;
110
+ }
111
+ // Under --review-order the caller hands the rows pre-sorted; the header
112
+ // names the derivation as a caller count, never a priority judgement — the
113
+ // number is who depends on the service, not how important it is.
114
+ const ordered = fanIn === undefined ? "" : " — review order (fan-in: services depending on each)";
115
+ console.log(`${views.length} of ${total} service(s) need work${ordered}`);
116
+ const width = Math.max(0, ...views.map((v) => v.entry.id.length));
117
+ const rungWidth = Math.max(0, ...views.map((v) => rungLabel(v).length));
118
+ const cells = fanIn === undefined ? undefined : views.map((v) => `fan-in: ${fanIn.get(v.entry.id) ?? 0}`);
119
+ const cellWidth = cells === undefined ? 0 : Math.max(0, ...cells.map((c) => c.length));
120
+ for (const [i, v] of views.entries()) {
121
+ const note = v.unverifiableFromHere ? " (provenance: unverifiable-from-here)" : "";
122
+ // Indexing the same array the loop walks, like printFeatures' cells below.
123
+ const cell = cells === undefined ? "" : ` ${cells[i].padEnd(cellWidth)}`;
124
+ console.log(` ${v.entry.id.padEnd(width)} ${rungLabel(v).padEnd(rungWidth)}${cell} missing: ${v.missing.join(", ")}${note}`);
125
+ }
126
+ }
127
+ /**
128
+ * The owner-grouped view under `--owners`: every row of the current listing
129
+ * filed under the team CODEOWNERS names for its directory, unowned last —
130
+ * the per-team campaign queues, each in the exact order the ungrouped
131
+ * listing would print. Text side only; the ids-per-team contract is
132
+ * json.ts's `ownersJson`.
133
+ */
134
+ export function printOwners(join, byDir, fanIn) {
135
+ const row = (r) => {
136
+ // Joined back by DIRECTORY, the row's identity — ids can collide across
137
+ // a broken tree, and an id-keyed map would print one twin's cells under
138
+ // the other twin's team. The join was computed from these same rows so a
139
+ // miss is unreachable, but it is a key join on purpose (docs/CODE-STYLE.md:
140
+ // never join two arrays by position) — and a miss prints the bare id
141
+ // LOUDLY rather than vanishing, so a future row-set drift shows itself.
142
+ const v = byDir.get(r.repoDir);
143
+ if (v === undefined) {
144
+ console.log(` ${r.id}`);
145
+ return;
146
+ }
147
+ const cell = fanIn === undefined ? "" : ` fan-in: ${fanIn.get(r.id) ?? 0}`;
148
+ const missing = v.missing.length > 0 ? ` missing: ${v.missing.join(", ")}` : "";
149
+ console.log(` ${r.id} ${rungLabel(v)}${cell}${missing}`);
150
+ };
151
+ for (const team of join.teams) {
152
+ console.log(` ${team.owner} (${team.services.length})`);
153
+ for (const r of team.services)
154
+ row(r);
155
+ }
156
+ // Explicit even in a heading: an unmatched service silently absent from
157
+ // every team's queue would read as somebody else's work.
158
+ if (join.unowned.length > 0) {
159
+ console.log(` unowned (${join.unowned.length})`);
160
+ for (const r of join.unowned)
161
+ row(r);
162
+ }
163
+ if (join.skipped.length > 0) {
164
+ // Line AND pattern: `* @org/all` is the most common CODEOWNERS opener,
165
+ // and a note naming only "line 1" would leave the reader unable to tell
166
+ // the fleet-wide default was skipped rather than some docs rule.
167
+ console.log(` note: ${join.skipped.length} rule(s) outside the supported CODEOWNERS subset skipped: ${join.skipped
168
+ .map((rule) => `line ${rule.line} (${rule.pattern})`)
169
+ .join(", ")}`);
170
+ }
171
+ }
172
+ /**
173
+ * The capability table: what the fleet promises, and how much of each promise
174
+ * anything claims to implement. The `0 — unrealized` marker is the row's whole
175
+ * point — a declared capability nothing realizes is the drift this section
176
+ * exists to make visible — and the draft/verified split says how much of a
177
+ * realized one rests on vouched documents rather than drafts.
178
+ *
179
+ * `promises` is the use-case corpus's health, and it is a REQUIRED argument
180
+ * rather than an optional decoration: the two states it separates are "no flow
181
+ * keeps this promise" and "loam could not read the flows", and a default would
182
+ * silently pick the first. A caller with nothing to say here has no business
183
+ * printing a promises column at all.
184
+ */
185
+ export function printCapabilities(rows, promises) {
186
+ console.log(`capabilities (${rows.length})`);
187
+ if (rows.length === 0)
188
+ return;
189
+ const width = Math.max(0, ...rows.map((row) => row.id.length));
190
+ for (const row of rows) {
191
+ const count = row.realizedBy.length;
192
+ const cells = count === 0
193
+ ? ["0 — unrealized"]
194
+ : [
195
+ `${count} requirement${count === 1 ? "" : "s"}`,
196
+ row.services.join(", "),
197
+ Object.entries(row.statuses)
198
+ .map(([status, n]) => `${n} ${status}`)
199
+ .join(" · "),
200
+ ];
201
+ cells.push(...promiseCells(row, promises.kind === "read"));
202
+ const owner = row.owner === undefined ? "" : ` (owner: ${row.owner})`;
203
+ console.log(` ${row.id.padEnd(width)} ${cells.join(" · ")}${owner}`);
204
+ }
205
+ // ONE note for the table, not one per row: every row is equally unanswered,
206
+ // and the reader needs to be told the column is missing rather than empty.
207
+ // The wording says UNKNOWN rather than none deliberately — this is the same
208
+ // refusal `capability.requirement-unrealized` makes under `validate` when the
209
+ // project did not parse, and the two surfaces must not read differently. The
210
+ // parser's own message goes on its own line, exactly as `loam context` and
211
+ // `loam delta` print theirs: a LikeC4 error is several lines of expected-token
212
+ // list, and inlining it would push the sentence off the reader's screen.
213
+ if (promises.kind === "unreadable") {
214
+ console.log(" note: architecture/ did not parse, so no business flow could be read — " +
215
+ "which promises a use case keeps is UNKNOWN here, not none");
216
+ if (promises.errors[0] !== undefined)
217
+ console.log(` ${promises.errors[0]}`);
218
+ }
219
+ }
220
+ /**
221
+ * The promises cell(s) for one row: how many of a capability document's own
222
+ * requirements anything keeps, and which flows keep any of them.
223
+ *
224
+ * Only for a capability that HAS a document — `requirements` absent means there
225
+ * is no document to promise anything, and a `0 of 0` on such a row would read as
226
+ * a gap where there is not even a claim.
227
+ *
228
+ * `flowsRead` false marks the count as PARTIAL in the cell itself and not only
229
+ * in the note below the table. Without the suffix, a fleet whose promises are
230
+ * all kept by flows prints `0 of 4 promises kept` over an unreadable
231
+ * `architecture/` — a number a reader would act on before reaching the note,
232
+ * and the exact false negative this axis exists to refuse.
233
+ */
234
+ function promiseCells(row, flowsRead) {
235
+ if (row.requirements === undefined)
236
+ return [];
237
+ const total = row.requirements.length;
238
+ if (total === 0)
239
+ return [];
240
+ const kept = row.requirements.filter((req) => req.realizedBy.length > 0 || (req.keptBy?.length ?? 0) > 0).length;
241
+ // Distinct flows across the whole capability, sorted: the per-requirement
242
+ // lists are already sorted, and a reader scanning this column wants the
243
+ // documents to open, not the pairing (the `--json` rows carry that).
244
+ const flows = [...new Set(row.requirements.flatMap((req) => req.keptBy ?? []))].sort(compareIds);
245
+ const partial = flowsRead ? "" : " (flows unread)";
246
+ return [`${kept} of ${total} promise${total === 1 ? "" : "s"} kept${partial}`]
247
+ .concat(flows.length === 0 ? [] : [`flows: ${flows.join(", ")}`]);
248
+ }
249
+ /** Narrow verification cell: confirmed/claims when a record answers, one word when it does not. */
250
+ function verificationMark(v) {
251
+ if (v === null)
252
+ return "-";
253
+ if (v.state === "stale")
254
+ return "stale";
255
+ // `11/11` and `11/11 attested` are different facts — the first is a
256
+ // digest-matched green run, the second is somebody's word about one. Without
257
+ // the suffix a complete count is the same glyph either way, which is exactly
258
+ // the reading `verify`, `status` and the JSON envelope stopped giving.
259
+ return `${v.confirmed}/${v.claims}${v.verdict === "attested" ? " attested" : ""}`;
260
+ }
261
+ export function printFeatures(features, verification) {
262
+ const active = features.filter((f) => !f.archived).length;
263
+ const archived = features.length - active;
264
+ const counts = `${active} active${archived > 0 ? `, ${archived} archived` : ""}`;
265
+ // Not `verified`: the column reports three verdicts and only one of them is
266
+ // that one. A heading that names the strong verdict makes every other cell
267
+ // read as it.
268
+ console.log(`features (${counts}) [I]ntent [D]elta verification`);
269
+ const width = Math.max(0, ...features.map((f) => f.id.length));
270
+ const cells = verification.map(verificationMark);
271
+ const cellWidth = Math.max(0, ...cells.map((c) => c.length));
272
+ for (const [i, f] of features.entries()) {
273
+ const flags = `${f.has.intent ? "I" : "-"} ${f.has.delta ? "D" : "-"}`;
274
+ const svcs = f.services.length > 0 ? f.services.join(", ") : "—";
275
+ const tag = f.archived ? " (archived)" : "";
276
+ console.log(` ${flags} ${f.id.padEnd(width)} ${cells[i].padEnd(cellWidth)} ${svcs}${tag}`);
277
+ }
278
+ }
279
+ /**
280
+ * The glossary table: what the domain's words are, and who actually uses each.
281
+ *
282
+ * The citation count is the column that matters — a definition nothing cites is
283
+ * the drift `glossary.unlinked` warns about, and this is where a reader sees it
284
+ * before the gate does. `unreadable` is printed as a note rather than folded
285
+ * into the counts for `printCapabilities`' reason one section over: "cited by
286
+ * nobody" and "loam could not read everybody" are different answers, and a
287
+ * table that let them look alike would be the more comfortable of the two.
288
+ */
289
+ export function printGlossary(rows, unreadable) {
290
+ console.log(`glossary (${rows.length} term${rows.length === 1 ? "" : "s"})`);
291
+ const width = Math.max(0, ...rows.map((row) => row.id.length));
292
+ for (const row of rows) {
293
+ const n = row.linkedBy.length;
294
+ console.log(` ${row.id.padEnd(width)} ${n === 0 ? "cited by nothing" : `${n} document${n === 1 ? "" : "s"}`}`);
295
+ }
296
+ if (unreadable.length > 0) {
297
+ console.log(` note: ${unreadable.length} document(s) could not be read, so a citation from one of them is not counted here — ` +
298
+ `\`loam validate --all\` names each as link.unreadable`);
299
+ }
300
+ }
301
+ //# sourceMappingURL=print.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"print.js","sourceRoot":"","sources":["../../../src/commands/list/print.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The columns a person reads, and the worklist under them.\n *\n * The worklist is the point of the command rather than a summary: a fleet list\n * that only listed would leave the reader to work out which services are\n * behind, which is the question they opened it with.\n */\nimport { MATURITY_LADDER, maturityRollup } from \"../../core/vocabulary/maturity.js\";\nimport { type CapabilityRow } from \"../../core/capabilities/rollup.js\";\nimport { compareIds, type FeatureEntry } from \"../../core/repo/entries.js\";\nimport type { PromisesKept } from \"../../core/usecases/capability.js\";\nimport type { FleetTree } from \"../../core/repo/tree/walk.js\";\nimport type { OwnedRow, OwnersJoin } from \"./campaign/owners.js\";\nimport { type ServiceView, type VerificationCell } from \"./views.js\";\n\nfunction serviceFlags(v: ServiceView): string {\n const s = v.entry;\n return [\n s.has.model ? \"M\" : \"-\",\n s.has.spec ? \"S\" : \"-\",\n v.archSpec ? \"a\" : \"-\",\n s.has.openapi ? \"A\" : \"-\",\n // The async contract, lowercase like the arch spec and for the same reason:\n // it is optional. A fleet where most services own no topic must not read as\n // a fleet with a column of gaps in it.\n s.has.asyncapi ? \"e\" : \"-\",\n s.has.runbook ? \"R\" : \"-\",\n s.has.health ? \"H\" : \"-\",\n ].join(\" \");\n}\n\n/**\n * The rung as a person reads it. `vouched (sampled)` is a DISPLAY string, not\n * a rung: the ladder, the rollup below and `--needs-work` all still see\n * `vouched`, because that string is a published contract and the document\n * really is stamped by a person. What the suffix says is what the stamp says\n * — they read a recorded sample of it, and `loam validate` will report\n * `sources.sampled-vouch` until somebody reads the rest. Without it, the one\n * line a fleet lead scans for trust would show a sampled vouch and a full one\n * as the same word.\n *\n * Only on `vouched`: a lower rung already says less than \"a person vouched\",\n * and hanging a scope note on it would explain a claim nothing is making.\n */\nfunction rungLabel(v: ServiceView): string {\n return v.maturity === \"vouched\" && v.entry.vouchScope === \"sampled\" ? \"vouched (sampled)\" : v.maturity;\n}\n\n/**\n * The two facts printed under the table that are not about any row — and they\n * are withheld differently, which is the whole reason to name the record\n * instead of passing two arguments and hoping the next caller notices.\n */\nexport interface FleetFacts {\n /**\n * The subsystem tree, or undefined under `--subsystem`. A slice's own\n * \"unfiled: 0\" would be read as a fact about the slice, and it is not one.\n */\n tree: FleetTree | undefined;\n /**\n * Markdown files in `architecture/adrs/`. NEVER withheld: unlike the tree\n * dial it is not derived from the rows at all — the same fleet documents are\n * there whichever services this run listed — and the line names the directory\n * so it cannot be misread as a subsystem's own decisions. 0 prints nothing.\n */\n adrs: number;\n}\n\nexport function printServices(views: ServiceView[], fleet: FleetFacts): void {\n console.log(\n `services (${views.length}) [M]odel [S]pec [a]rch-spec [A]pi [R]unbook [H]ealth`,\n );\n const width = Math.max(0, ...views.map((v) => v.entry.id.length));\n // Measured over the DISPLAY strings, so the column does not shear the first\n // time a sampled row appears in a fleet.\n const rungWidth = Math.max(0, ...views.map((v) => rungLabel(v).length));\n for (const v of views) {\n const s = v.entry;\n const adrs = s.adrs > 0 ? ` (${s.adrs} adr${s.adrs === 1 ? \"\" : \"s\"})` : \"\";\n // The rung per service, not only in the rollup: \"12 partial\" tells a reader\n // the fleet is unfinished and nothing about which twelve, which is the one\n // question the line is read to answer.\n console.log(\n ` ${serviceFlags(v)} ${s.id.padEnd(width)} ${rungLabel(v).padEnd(rungWidth)}${adrs}`.trimEnd(),\n );\n }\n // How much of the fleet anyone has actually vouched for. On 100+ services this\n // is the number that says whether the docs can be trusted at all.\n if (views.length > 0) {\n const counted = new Map<string, number>();\n for (const v of views) {\n const key = v.entry.status ?? \"unmarked\";\n counted.set(key, (counted.get(key) ?? 0) + 1);\n }\n const parts = [...counted.entries()]\n .sort((a, b) => compareIds(a[0], b[0]))\n .map(([status, n]) => `${n} ${status}`);\n console.log(` status: ${parts.join(\" · \")}`);\n // The campaign dial next to the trust dial: rungs in ladder order, so the\n // line reads as progress left to right. Presence and provenance state only\n // — completeness is unchecked, so this line never says \"adopted\".\n const rollup = maturityRollup(views);\n // The rollup itself is untouched — the rung IS `vouched`, and both the\n // `--json` payload and `--needs-work` are computed from it. What the TEXT\n // line adds is the qualifier the per-row suffix already carries, because\n // this is the line a fleet lead reads for the trust answer, and recovering\n // \"how many of those 118 did anybody read in full\" by scanning 118 rows is\n // not an answer. Same layout as the validate scorecard's provenance row.\n const sampled = views.filter((v) => v.maturity === \"vouched\" && v.entry.vouchScope === \"sampled\").length;\n const rungs = MATURITY_LADDER.filter((m) => rollup[m] > 0).map(\n (m) => `${rollup[m]} ${m}${m === \"vouched\" && sampled > 0 ? ` (${sampled} sampled)` : \"\"}`,\n );\n console.log(` maturity: ${rungs.join(\" · \")}`);\n // The tree dial, only once a tree exists: unfiled is permanent and normal\n // (a count, never a finding), and a flat fleet has nothing to say here —\n // printing \"5 unfiled\" over a fleet nobody groups would read as work.\n if (fleet.tree !== undefined && fleet.tree.subsystems.length > 0) {\n const unfiled = fleet.tree.services.filter((s) => s.subsystem.length === 0).length;\n console.log(` subsystems: ${fleet.tree.subsystems.length} · unfiled: ${unfiled}`);\n }\n }\n // OUTSIDE the rollup block above, which only runs when the fleet has\n // services: a fleet can record a decision about how it will build services\n // before it holds one, and that count would otherwise be printed by nothing.\n // Silent at zero, exactly like the per-service `(3 adrs)` column: no fleet\n // owes any fleet-level ADR, so \"adrs: 0\" would read as a gap.\n if (fleet.adrs > 0) {\n console.log(` adrs: ${fleet.adrs} fleet decision${fleet.adrs === 1 ? \"\" : \"s\"} (architecture/adrs/)`);\n }\n}\n\n/**\n * The one-shot adoption worklist. Onboarding ten legacy services means asking\n * \"what is left\" once a day for a month, and the answer used to require reading\n * a presence table and a rollup and joining them by eye. A service whose\n * provenance cannot be judged from here is LISTED, tagged, never dropped:\n * omitting it would read as done.\n */\nexport function printWorklist(\n views: ServiceView[],\n total: number,\n fanIn?: ReadonlyMap<string, number>,\n): void {\n if (views.length === 0) {\n console.log(`nothing to do — all ${total} service(s) are vouched`);\n return;\n }\n // Under --review-order the caller hands the rows pre-sorted; the header\n // names the derivation as a caller count, never a priority judgement — the\n // number is who depends on the service, not how important it is.\n const ordered = fanIn === undefined ? \"\" : \" — review order (fan-in: services depending on each)\";\n console.log(`${views.length} of ${total} service(s) need work${ordered}`);\n const width = Math.max(0, ...views.map((v) => v.entry.id.length));\n const rungWidth = Math.max(0, ...views.map((v) => rungLabel(v).length));\n const cells = fanIn === undefined ? undefined : views.map((v) => `fan-in: ${fanIn.get(v.entry.id) ?? 0}`);\n const cellWidth = cells === undefined ? 0 : Math.max(0, ...cells.map((c) => c.length));\n for (const [i, v] of views.entries()) {\n const note = v.unverifiableFromHere ? \" (provenance: unverifiable-from-here)\" : \"\";\n // Indexing the same array the loop walks, like printFeatures' cells below.\n const cell = cells === undefined ? \"\" : ` ${cells[i]!.padEnd(cellWidth)}`;\n console.log(\n ` ${v.entry.id.padEnd(width)} ${rungLabel(v).padEnd(rungWidth)}${cell} missing: ${v.missing.join(\", \")}${note}`,\n );\n }\n}\n\n/**\n * The owner-grouped view under `--owners`: every row of the current listing\n * filed under the team CODEOWNERS names for its directory, unowned last —\n * the per-team campaign queues, each in the exact order the ungrouped\n * listing would print. Text side only; the ids-per-team contract is\n * json.ts's `ownersJson`.\n */\nexport function printOwners(\n join: OwnersJoin,\n byDir: ReadonlyMap<string, ServiceView>,\n fanIn?: ReadonlyMap<string, number>,\n): void {\n const row = (r: OwnedRow): void => {\n // Joined back by DIRECTORY, the row's identity — ids can collide across\n // a broken tree, and an id-keyed map would print one twin's cells under\n // the other twin's team. The join was computed from these same rows so a\n // miss is unreachable, but it is a key join on purpose (docs/CODE-STYLE.md:\n // never join two arrays by position) — and a miss prints the bare id\n // LOUDLY rather than vanishing, so a future row-set drift shows itself.\n const v = byDir.get(r.repoDir);\n if (v === undefined) {\n console.log(` ${r.id}`);\n return;\n }\n const cell = fanIn === undefined ? \"\" : ` fan-in: ${fanIn.get(r.id) ?? 0}`;\n const missing = v.missing.length > 0 ? ` missing: ${v.missing.join(\", \")}` : \"\";\n console.log(` ${r.id} ${rungLabel(v)}${cell}${missing}`);\n };\n for (const team of join.teams) {\n console.log(` ${team.owner} (${team.services.length})`);\n for (const r of team.services) row(r);\n }\n // Explicit even in a heading: an unmatched service silently absent from\n // every team's queue would read as somebody else's work.\n if (join.unowned.length > 0) {\n console.log(` unowned (${join.unowned.length})`);\n for (const r of join.unowned) row(r);\n }\n if (join.skipped.length > 0) {\n // Line AND pattern: `* @org/all` is the most common CODEOWNERS opener,\n // and a note naming only \"line 1\" would leave the reader unable to tell\n // the fleet-wide default was skipped rather than some docs rule.\n console.log(\n ` note: ${join.skipped.length} rule(s) outside the supported CODEOWNERS subset skipped: ${join.skipped\n .map((rule) => `line ${rule.line} (${rule.pattern})`)\n .join(\", \")}`,\n );\n }\n}\n\n/**\n * The capability table: what the fleet promises, and how much of each promise\n * anything claims to implement. The `0 — unrealized` marker is the row's whole\n * point — a declared capability nothing realizes is the drift this section\n * exists to make visible — and the draft/verified split says how much of a\n * realized one rests on vouched documents rather than drafts.\n *\n * `promises` is the use-case corpus's health, and it is a REQUIRED argument\n * rather than an optional decoration: the two states it separates are \"no flow\n * keeps this promise\" and \"loam could not read the flows\", and a default would\n * silently pick the first. A caller with nothing to say here has no business\n * printing a promises column at all.\n */\nexport function printCapabilities(rows: CapabilityRow[], promises: PromisesKept): void {\n console.log(`capabilities (${rows.length})`);\n if (rows.length === 0) return;\n const width = Math.max(0, ...rows.map((row) => row.id.length));\n for (const row of rows) {\n const count = row.realizedBy.length;\n const cells =\n count === 0\n ? [\"0 — unrealized\"]\n : [\n `${count} requirement${count === 1 ? \"\" : \"s\"}`,\n row.services.join(\", \"),\n Object.entries(row.statuses)\n .map(([status, n]) => `${n} ${status}`)\n .join(\" · \"),\n ];\n cells.push(...promiseCells(row, promises.kind === \"read\"));\n const owner = row.owner === undefined ? \"\" : ` (owner: ${row.owner})`;\n console.log(` ${row.id.padEnd(width)} ${cells.join(\" · \")}${owner}`);\n }\n // ONE note for the table, not one per row: every row is equally unanswered,\n // and the reader needs to be told the column is missing rather than empty.\n // The wording says UNKNOWN rather than none deliberately — this is the same\n // refusal `capability.requirement-unrealized` makes under `validate` when the\n // project did not parse, and the two surfaces must not read differently. The\n // parser's own message goes on its own line, exactly as `loam context` and\n // `loam delta` print theirs: a LikeC4 error is several lines of expected-token\n // list, and inlining it would push the sentence off the reader's screen.\n if (promises.kind === \"unreadable\") {\n console.log(\n \" note: architecture/ did not parse, so no business flow could be read — \" +\n \"which promises a use case keeps is UNKNOWN here, not none\",\n );\n if (promises.errors[0] !== undefined) console.log(` ${promises.errors[0]}`);\n }\n}\n\n/**\n * The promises cell(s) for one row: how many of a capability document's own\n * requirements anything keeps, and which flows keep any of them.\n *\n * Only for a capability that HAS a document — `requirements` absent means there\n * is no document to promise anything, and a `0 of 0` on such a row would read as\n * a gap where there is not even a claim.\n *\n * `flowsRead` false marks the count as PARTIAL in the cell itself and not only\n * in the note below the table. Without the suffix, a fleet whose promises are\n * all kept by flows prints `0 of 4 promises kept` over an unreadable\n * `architecture/` — a number a reader would act on before reaching the note,\n * and the exact false negative this axis exists to refuse.\n */\nfunction promiseCells(row: CapabilityRow, flowsRead: boolean): string[] {\n if (row.requirements === undefined) return [];\n const total = row.requirements.length;\n if (total === 0) return [];\n const kept = row.requirements.filter(\n (req) => req.realizedBy.length > 0 || (req.keptBy?.length ?? 0) > 0,\n ).length;\n // Distinct flows across the whole capability, sorted: the per-requirement\n // lists are already sorted, and a reader scanning this column wants the\n // documents to open, not the pairing (the `--json` rows carry that).\n const flows = [...new Set(row.requirements.flatMap((req) => req.keptBy ?? []))].sort(compareIds);\n const partial = flowsRead ? \"\" : \" (flows unread)\";\n return [`${kept} of ${total} promise${total === 1 ? \"\" : \"s\"} kept${partial}`]\n .concat(flows.length === 0 ? [] : [`flows: ${flows.join(\", \")}`]);\n}\n\n/** Narrow verification cell: confirmed/claims when a record answers, one word when it does not. */\nfunction verificationMark(v: VerificationCell | null): string {\n if (v === null) return \"-\";\n if (v.state === \"stale\") return \"stale\";\n // `11/11` and `11/11 attested` are different facts — the first is a\n // digest-matched green run, the second is somebody's word about one. Without\n // the suffix a complete count is the same glyph either way, which is exactly\n // the reading `verify`, `status` and the JSON envelope stopped giving.\n return `${v.confirmed}/${v.claims}${v.verdict === \"attested\" ? \" attested\" : \"\"}`;\n}\n\nexport function printFeatures(features: FeatureEntry[], verification: (VerificationCell | null)[]): void {\n const active = features.filter((f) => !f.archived).length;\n const archived = features.length - active;\n const counts = `${active} active${archived > 0 ? `, ${archived} archived` : \"\"}`;\n // Not `verified`: the column reports three verdicts and only one of them is\n // that one. A heading that names the strong verdict makes every other cell\n // read as it.\n console.log(`features (${counts}) [I]ntent [D]elta verification`);\n const width = Math.max(0, ...features.map((f) => f.id.length));\n const cells = verification.map(verificationMark);\n const cellWidth = Math.max(0, ...cells.map((c) => c.length));\n for (const [i, f] of features.entries()) {\n const flags = `${f.has.intent ? \"I\" : \"-\"} ${f.has.delta ? \"D\" : \"-\"}`;\n const svcs = f.services.length > 0 ? f.services.join(\", \") : \"—\";\n const tag = f.archived ? \" (archived)\" : \"\";\n console.log(` ${flags} ${f.id.padEnd(width)} ${cells[i]!.padEnd(cellWidth)} ${svcs}${tag}`);\n }\n}\n\n/**\n * The glossary table: what the domain's words are, and who actually uses each.\n *\n * The citation count is the column that matters — a definition nothing cites is\n * the drift `glossary.unlinked` warns about, and this is where a reader sees it\n * before the gate does. `unreadable` is printed as a note rather than folded\n * into the counts for `printCapabilities`' reason one section over: \"cited by\n * nobody\" and \"loam could not read everybody\" are different answers, and a\n * table that let them look alike would be the more comfortable of the two.\n */\nexport function printGlossary(\n rows: Array<{ id: string; linkedBy: string[] }>,\n unreadable: string[],\n): void {\n console.log(`glossary (${rows.length} term${rows.length === 1 ? \"\" : \"s\"})`);\n const width = Math.max(0, ...rows.map((row) => row.id.length));\n for (const row of rows) {\n const n = row.linkedBy.length;\n console.log(` ${row.id.padEnd(width)} ${n === 0 ? \"cited by nothing\" : `${n} document${n === 1 ? \"\" : \"s\"}`}`);\n }\n if (unreadable.length > 0) {\n console.log(\n ` note: ${unreadable.length} document(s) could not be read, so a citation from one of them is not counted here — ` +\n `\\`loam validate --all\\` names each as link.unreadable`,\n );\n }\n}\n"]}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * The review-order gathering and sort behind `loam list --needs-work
3
+ * --review-order`: per-service contract reads (contained per read), the one
4
+ * landscape load, and the deterministic ordering. The derivation itself is
5
+ * pure and lives in core/dependencies/fanin.ts.
6
+ *
7
+ * Fifth and LAST file of the list package — the next module added here forces
8
+ * a split along a named seam (docs/CODE-STYLE.md, the five-file limit).
9
+ */
10
+ import { existsSync } from "node:fs";
11
+ import { readAsyncapi } from "../../core/asyncapi/read.js";
12
+ import {} from "../../core/c4/likec4.js";
13
+ import { serviceResolver } from "../../core/c4/resolve/service.js";
14
+ import { fleetFanIn } from "../../core/dependencies/fanin.js";
15
+ import {} from "../../core/fleet-context.js";
16
+ import { inOrder } from "../../core/kernel/concurrency.js";
17
+ import { compareIds } from "../../core/repo/entries.js";
18
+ import { landscapePath, servicePathsAt } from "../../core/repo/paths.js";
19
+ import {} from "./views.js";
20
+ /**
21
+ * The landscape for the review path, loaded ONCE through the run's memo and
22
+ * handed both to serviceViews (as `preloaded`) and to the fan-in joins — a
23
+ * second parse of a document the run already holds is the cost the shared
24
+ * load exists to retire.
25
+ *
26
+ * Deliberately NOT `readLandscape` from commands/validate/fleet/load.ts: that
27
+ * import would add a list→validate/fleet package edge while
28
+ * validate/fleet/scorecard→list already exists, and the containment is four
29
+ * lines.
30
+ */
31
+ export async function reviewLandscape(docsDir, fleet) {
32
+ const lp = landscapePath(docsDir);
33
+ // Absent is `null` — the same "there is none" serviceViews' own load
34
+ // spells. An UNREADABLE file is deliberately not contained here: bare
35
+ // `loam list` refuses `repository-unavailable` when serviceViews' load
36
+ // throws on it, and a rendering flag must never change what the run
37
+ // refuses — a swallowed throw here answered ok over the exact file the
38
+ // flagless run refuses on, with rows CHANGED by the silent null
39
+ // (`proven: false` flips apiExpected and the missing lists). The throw
40
+ // reaches list.ts's existing handler, so both paths refuse identically.
41
+ if (!existsSync(lp))
42
+ return null;
43
+ return fleet.loadLikeC4(lp);
44
+ }
45
+ /**
46
+ * One service's contract slice for the message join, contained PER READ, not
47
+ * per slice. The distinction is somebody else's rank: a slice is a caller's
48
+ * evidence about OTHER services' fan-in, not only its own row, so a slice
49
+ * that discarded its readable spec.md because its arch.spec.md is broken
50
+ * would silently under-report every producer that spec subscribes to.
51
+ */
52
+ async function contractSlice(entry, fleet) {
53
+ const paths = servicePathsAt(entry.dir);
54
+ const [sent, specConsumes, archConsumes] = await Promise.all([
55
+ readOr([], async () => {
56
+ const events = await readAsyncapi(paths.asyncapi, fleet);
57
+ // An unreadable contract declares nothing this join may count —
58
+ // swallowing it into its parsed subset would grade a broken file as a
59
+ // thin one (the scorecard's contracts.ts spells the same rule).
60
+ return events.unreadable === true ? [] : events.sent;
61
+ }),
62
+ readOr([], () => livingConsumes(paths.spec, fleet)),
63
+ readOr([], () => livingConsumes(paths.archSpec, fleet)),
64
+ ]);
65
+ return { sent, consumed: [...specConsumes, ...archConsumes] };
66
+ }
67
+ /** `Consumes:` names of a spec file's living requirements; absent file, nothing. */
68
+ async function livingConsumes(path, fleet) {
69
+ if (!existsSync(path))
70
+ return [];
71
+ // A REMOVED requirement is on its way out and subscribes to nothing, from
72
+ // either spec namespace.
73
+ return (await fleet.readRequirements(path)).filter((r) => r.kind !== "REMOVED").flatMap((r) => r.consumes);
74
+ }
75
+ /**
76
+ * The containment: an unreadable artifact contributes nothing — and ONLY that
77
+ * artifact's evidence, per the doctrine above. The catch also exists for a
78
+ * mechanical reason (commands/validate/fleet/scorecard/contracts.ts): these
79
+ * are memoized reads whose REJECTION rejects again on every await, so an
80
+ * uncontained one would delete the whole queue from inside the pool.
81
+ */
82
+ async function readOr(fallback, read) {
83
+ try {
84
+ return await read();
85
+ }
86
+ catch {
87
+ // Unreadable reads as "declares nothing" — never as a refusal, and never
88
+ // as its neighbours' silence.
89
+ return fallback;
90
+ }
91
+ }
92
+ /**
93
+ * Fan-in per service id, FLEET-WIDE — the joins need every service's slice
94
+ * anyway; the caller ranks only the worklist, so vouched services carry a
95
+ * count without occupying a rank.
96
+ */
97
+ export async function fanInByService(services, fleet, land) {
98
+ const known = new Set(services.map((s) => s.id));
99
+ const slices = await inOrder(services, async (s) => [s.id, await contractSlice(s, fleet)]);
100
+ const request = {
101
+ services: services.map((s) => s.id),
102
+ contracts: new Map(slices),
103
+ };
104
+ if (land !== null && land.errors.length === 0) {
105
+ return fleetFanIn({
106
+ ...request,
107
+ landscape: { parses: true, relationships: land.relationships, svcOf: serviceResolver(land.elements, known) },
108
+ });
109
+ }
110
+ return fleetFanIn({ ...request, landscape: { parses: false } });
111
+ }
112
+ /**
113
+ * The queue: fan-in descending, ties broken by id — fully deterministic, no
114
+ * clocks, no readdir order, so two runs over one repository are byte-identical
115
+ * (fan-in is a set size and both joins are order-insensitive).
116
+ */
117
+ export function reviewOrder(views, fanIn) {
118
+ return [...views].sort((a, b) => (fanIn.get(b.entry.id) ?? 0) - (fanIn.get(a.entry.id) ?? 0) || compareIds(a.entry.id, b.entry.id));
119
+ }
120
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../../src/commands/list/review.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The review-order gathering and sort behind `loam list --needs-work\n * --review-order`: per-service contract reads (contained per read), the one\n * landscape load, and the deterministic ordering. The derivation itself is\n * pure and lives in core/dependencies/fanin.ts.\n *\n * Fifth and LAST file of the list package — the next module added here forces\n * a split along a named seam (docs/CODE-STYLE.md, the five-file limit).\n */\nimport { existsSync } from \"node:fs\";\nimport { readAsyncapi } from \"../../core/asyncapi/read.js\";\nimport { type LoadedDoc } from \"../../core/c4/likec4.js\";\nimport { serviceResolver } from \"../../core/c4/resolve/service.js\";\nimport { fleetFanIn, type FanInContracts } from \"../../core/dependencies/fanin.js\";\nimport { type FleetContext } from \"../../core/fleet-context.js\";\nimport { inOrder } from \"../../core/kernel/concurrency.js\";\nimport { compareIds, type ServiceEntry } from \"../../core/repo/entries.js\";\nimport { landscapePath, servicePathsAt } from \"../../core/repo/paths.js\";\nimport { type ServiceView } from \"./views.js\";\nimport type { DocsDir } from \"../../core/kernel/ids/dirs.js\";\n\n/**\n * The landscape for the review path, loaded ONCE through the run's memo and\n * handed both to serviceViews (as `preloaded`) and to the fan-in joins — a\n * second parse of a document the run already holds is the cost the shared\n * load exists to retire.\n *\n * Deliberately NOT `readLandscape` from commands/validate/fleet/load.ts: that\n * import would add a list→validate/fleet package edge while\n * validate/fleet/scorecard→list already exists, and the containment is four\n * lines.\n */\nexport async function reviewLandscape(docsDir: DocsDir, fleet: FleetContext): Promise<LoadedDoc | null> {\n const lp = landscapePath(docsDir);\n // Absent is `null` — the same \"there is none\" serviceViews' own load\n // spells. An UNREADABLE file is deliberately not contained here: bare\n // `loam list` refuses `repository-unavailable` when serviceViews' load\n // throws on it, and a rendering flag must never change what the run\n // refuses — a swallowed throw here answered ok over the exact file the\n // flagless run refuses on, with rows CHANGED by the silent null\n // (`proven: false` flips apiExpected and the missing lists). The throw\n // reaches list.ts's existing handler, so both paths refuse identically.\n if (!existsSync(lp)) return null;\n return fleet.loadLikeC4(lp);\n}\n\n/**\n * One service's contract slice for the message join, contained PER READ, not\n * per slice. The distinction is somebody else's rank: a slice is a caller's\n * evidence about OTHER services' fan-in, not only its own row, so a slice\n * that discarded its readable spec.md because its arch.spec.md is broken\n * would silently under-report every producer that spec subscribes to.\n */\nasync function contractSlice(entry: ServiceEntry, fleet: FleetContext): Promise<FanInContracts> {\n const paths = servicePathsAt(entry.dir);\n const [sent, specConsumes, archConsumes] = await Promise.all([\n readOr([], async () => {\n const events = await readAsyncapi(paths.asyncapi, fleet);\n // An unreadable contract declares nothing this join may count —\n // swallowing it into its parsed subset would grade a broken file as a\n // thin one (the scorecard's contracts.ts spells the same rule).\n return events.unreadable === true ? ([] as readonly string[]) : events.sent;\n }),\n readOr([], () => livingConsumes(paths.spec, fleet)),\n readOr([], () => livingConsumes(paths.archSpec, fleet)),\n ]);\n return { sent, consumed: [...specConsumes, ...archConsumes] };\n}\n\n/** `Consumes:` names of a spec file's living requirements; absent file, nothing. */\nasync function livingConsumes(path: string, fleet: FleetContext): Promise<readonly string[]> {\n if (!existsSync(path)) return [];\n // A REMOVED requirement is on its way out and subscribes to nothing, from\n // either spec namespace.\n return (await fleet.readRequirements(path)).filter((r) => r.kind !== \"REMOVED\").flatMap((r) => r.consumes);\n}\n\n/**\n * The containment: an unreadable artifact contributes nothing — and ONLY that\n * artifact's evidence, per the doctrine above. The catch also exists for a\n * mechanical reason (commands/validate/fleet/scorecard/contracts.ts): these\n * are memoized reads whose REJECTION rejects again on every await, so an\n * uncontained one would delete the whole queue from inside the pool.\n */\nasync function readOr<T>(fallback: T, read: () => Promise<T>): Promise<T> {\n try {\n return await read();\n } catch {\n // Unreadable reads as \"declares nothing\" — never as a refusal, and never\n // as its neighbours' silence.\n return fallback;\n }\n}\n\n/**\n * Fan-in per service id, FLEET-WIDE — the joins need every service's slice\n * anyway; the caller ranks only the worklist, so vouched services carry a\n * count without occupying a rank.\n */\nexport async function fanInByService(\n services: ServiceEntry[],\n fleet: FleetContext,\n land: LoadedDoc | null,\n): Promise<Map<string, number>> {\n const known = new Set<string>(services.map((s) => s.id));\n const slices = await inOrder(services, async (s) => [s.id, await contractSlice(s, fleet)] as const);\n const request = {\n services: services.map((s) => s.id),\n contracts: new Map<string, FanInContracts>(slices),\n };\n if (land !== null && land.errors.length === 0) {\n return fleetFanIn({\n ...request,\n landscape: { parses: true, relationships: land.relationships, svcOf: serviceResolver(land.elements, known) },\n });\n }\n return fleetFanIn({ ...request, landscape: { parses: false } });\n}\n\n/**\n * The queue: fan-in descending, ties broken by id — fully deterministic, no\n * clocks, no readdir order, so two runs over one repository are byte-identical\n * (fan-in is a set size and both joins are order-insensitive).\n */\nexport function reviewOrder(views: ServiceView[], fanIn: ReadonlyMap<string, number>): ServiceView[] {\n return [...views].sort(\n (a, b) =>\n (fanIn.get(b.entry.id) ?? 0) - (fanIn.get(a.entry.id) ?? 0) || compareIds(a.entry.id, b.entry.id),\n );\n}\n"]}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * What the list actually reads: one row per service, one verification cell per
3
+ * feature.
4
+ *
5
+ * Both are gathered before anything is printed or serialized, because the same
6
+ * numbers appear in `--json` and in the worklist footer — a footer computed
7
+ * from a second read is a footer that can contradict the rows above it.
8
+ */
9
+ import { existsSync } from "node:fs";
10
+ import { loadFile } from "../../core/c4/likec4.js";
11
+ import { serviceResolver } from "../../core/c4/resolve/service.js";
12
+ import { maturityGaps, serviceMaturity, } from "../../core/vocabulary/maturity.js";
13
+ import {} from "../../core/repo/entries.js";
14
+ import { landscapePath, servicePathsAt } from "../../core/repo/paths.js";
15
+ import { featureChecklist } from "../../core/verify/checklist.js";
16
+ import { readVerification } from "../../core/verify/file.js";
17
+ import {} from "../../core/verify/answers.js";
18
+ import { confirmedProvenance, tallyRecord, verificationVerdict, } from "../../core/verify/record.js";
19
+ /**
20
+ * Read the living landscape ONCE and decide, per service, whether an API is
21
+ * expected of it. `serviceResolver` is handed the real service ids so an edge
22
+ * drawn into a modelled container (`paymentService.api`) counts for the service
23
+ * that owns it — the same resolution `validate` uses, so the two commands
24
+ * cannot disagree about who is called.
25
+ */
26
+ export async function serviceViews(docsDir, services, boundService, preloaded) {
27
+ const known = new Set(services.map((s) => s.id));
28
+ const lp = landscapePath(docsDir);
29
+ // `preloaded` is the landscape a caller already holds — `undefined` means
30
+ // "load it if it exists", null "there is none", the convention
31
+ // validateService's own `preloaded` follows. The fleet scorecard hands in
32
+ // the batch-parsed doc because a healthy `validate --all` must spin ZERO
33
+ // per-document workspaces (test/validate-batch-fallback.test.ts counts
34
+ // them), and a second parse of a document that run already holds was the
35
+ // exact per-path cost the batch loader exists to retire.
36
+ const land = preloaded !== undefined ? preloaded : existsSync(lp) ? await loadFile(lp) : null;
37
+ const called = new Set();
38
+ // Positive evidence only: with no landscape, or one that does not parse, we
39
+ // know nothing about who is called and every service is assumed to have an
40
+ // API — the conservative direction, because claiming a service needs no
41
+ // contract is how a real one goes undocumented. This is the SAME rule
42
+ // `landscapeEvidence` (core/vocabulary/maturity.ts) spells per service for
43
+ // explore and the context pack — derived fleet-wide here in one pass (one
44
+ // `called` set for every service) because calling the per-service partition
45
+ // from this loop would re-walk the whole relationship list once per
46
+ // service. If the rule moves, both spellings move.
47
+ const proven = land !== null && land.errors.length === 0;
48
+ if (proven) {
49
+ const svcOf = serviceResolver(land.elements, known);
50
+ for (const r of land.relationships) {
51
+ if (r.op !== undefined)
52
+ called.add(svcOf(r.target));
53
+ }
54
+ }
55
+ return services.map((entry) => {
56
+ const archSpec = existsSync(servicePathsAt(entry.dir).archSpec);
57
+ const apiExpected = !proven || called.has(entry.id);
58
+ const view = {
59
+ entry,
60
+ archSpec,
61
+ apiExpected,
62
+ unverifiableFromHere: entry.sources.declared && boundService !== entry.id,
63
+ };
64
+ const missing = maturityGaps(view);
65
+ return { ...view, maturity: serviceMaturity(view), missing };
66
+ });
67
+ }
68
+ /**
69
+ * The verification column. `readVerification` is one file read; the checklist
70
+ * is derived only when there is a record to judge — on a fleet-sized repo most
71
+ * features have none, and deriving N checklists to print N dashes is the cost
72
+ * that would get this column dropped.
73
+ *
74
+ * An archived feature's record is frozen history (see `core/verify/record.ts`): archive
75
+ * merged the feature's operations into the living openapi, so a re-derived
76
+ * checklist can only mismatch — the record is reported as recorded, never
77
+ * judged stale.
78
+ */
79
+ export async function featureVerification(docsDir, f) {
80
+ const v = await readVerification(f.dir);
81
+ if (v === null)
82
+ return null;
83
+ const stale = f.archived
84
+ ? false
85
+ : (await featureChecklist(docsDir, f.dir, f.id)).digest !== v.checklist;
86
+ const tally = tallyRecord(v);
87
+ return {
88
+ state: stale ? "stale" : "recorded",
89
+ recorded: v.recorded,
90
+ verdict: verificationVerdict(tally, stale),
91
+ confirmed: tally.confirmed,
92
+ claims: tally.claims,
93
+ attested: tally.attested,
94
+ answered: confirmedProvenance(v.claims),
95
+ };
96
+ }
97
+ /* ------------------------------------------------------------------ */
98
+ /* Text */
99
+ /* ------------------------------------------------------------------ */
100
+ /**
101
+ * Fixed-width presence flags. `a` and `A` are deliberately the same letter in
102
+ * two cases: the arch spec and the API are the two things a reader most often
103
+ * mistakes for each other, and one is lowercase because it is optional.
104
+ */
105
+ //# sourceMappingURL=views.js.map