@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,187 @@
1
+ /**
2
+ * The whole repository — why the fleet form is cheaper than the feature form.
3
+ *
4
+ * `loam status` with no feature runs over every active feature, and deriving a
5
+ * coherence report or a verification checklist per feature means spinning a
6
+ * fresh LikeC4 workspace per feature. On a fleet-sized repository that is the
7
+ * cost that gets a command switched off — `list` made the same call about its
8
+ * verification column. So the fleet form grades nothing: it reports artifact
9
+ * PRESENCE, the dependency order, and a verification record only where one
10
+ * already exists, and its `next[]` hands off to `loam status <FEAT>`, which is
11
+ * where the checks actually run.
12
+ */
13
+ import { existsSync } from "node:fs";
14
+ import { readFile } from "node:fs/promises";
15
+ import { analyzeDependencies } from "../../dependencies/dependencies.js";
16
+ import {} from "../../dependencies/facts.js";
17
+ import { isLandscapeStub } from "../../scaffold/landscape.js";
18
+ import { repoPath } from "../../envelope/json.js";
19
+ import { FleetContext } from "../../fleet-context.js";
20
+ import { compareIds } from "../../repo/entries.js";
21
+ import { featurePaths, featureSpecPaths, landscapePath } from "../../repo/paths.js";
22
+ import { listFeatures, listServices } from "../../repo/repo.js";
23
+ import { contractOwners, contractsHeldElsewhere, owesContract } from "../contracts.js";
24
+ import { readInterruptedCommit } from "../interrupted.js";
25
+ import { undocumented, vouched, } from "../report.js";
26
+ import { governedServices, scanDeltas } from "../scan.js";
27
+ import { fullyVerified, verificationState } from "../verification.js";
28
+ import { fleetNext } from "./next.js";
29
+ /**
30
+ * The fleet view: how much of `services/` anyone has written down, every
31
+ * feature in flight with the stage it has reached, and the order they have to
32
+ * land in. Nothing here is graded — the module header says why — so the stages
33
+ * are drawn from artifact presence and from a record that already exists, and
34
+ * `next[]` hands off to `loam status <FEAT>` for everything else.
35
+ */
36
+ export async function fleetStatus(docsDir, opts = {}) {
37
+ const context = opts.context ?? new FleetContext();
38
+ const interrupted = await readInterruptedCommit(docsDir);
39
+ const narrowed = opts.service;
40
+ const all = await listServices(docsDir, context);
41
+ const services = narrowed === undefined ? all : all.filter((s) => s.id === narrowed);
42
+ // The service this repository says it IS, and whether the fleet has heard of
43
+ // it. Asked against the UNNARROWED list, because "is it adopted" is a question
44
+ // about the fleet and not about the view.
45
+ //
46
+ // Both facts travel, where only the unadopted case used to. This value was a
47
+ // `string | null` that went null exactly when the service directory EXISTED,
48
+ // so the walk could see the repository it stands in only while that
49
+ // repository was undocumented — and a developer in an adopted service repo
50
+ // got the whole fleet's worklist with their own boundary buried in it.
51
+ const binding = opts.bound === undefined ? null : { id: opts.bound, adopted: all.some((s) => s.id === opts.bound) };
52
+ const graph = await analyzeDependencies(docsDir, undefined, context);
53
+ const entries = await listFeatures(docsDir, {}, context);
54
+ const inScope = narrowed === undefined ? entries : entries.filter((f) => f.services.some((s) => s === narrowed));
55
+ // Once for the fleet, not once per feature: which features hold a contract
56
+ // for which service is one fact about the repository, and every feature below
57
+ // reads its own row out of it. Built over the UNNARROWED list on purpose — a
58
+ // `--service` view still has to know that a feature outside it discharges the
59
+ // contract, or the narrowing would invent an obligation.
60
+ const owners = await contractOwners(docsDir, context);
61
+ const features = await Promise.all(inScope.map((f) => fleetFeature(docsDir, f, {
62
+ graph,
63
+ contracted: contractsHeldElsewhere(owners, f.id),
64
+ living: new Map(all.map((s) => [s.id, s])),
65
+ context,
66
+ interrupted,
67
+ })));
68
+ features.sort((a, b) => compareIds(a.id, b.id));
69
+ // The first-hour ladder's fact, computed exactly when the ladder can apply
70
+ // — an unnarrowed run over a fleet with zero services and zero features —
71
+ // so the read disappears from every repository that has anything in it.
72
+ // Withheld on narrowed runs for the same reason the binding is withheld
73
+ // below: `--service X` is an explicit question about X, and the
74
+ // repository's onboarding ladder would be a different question's answer.
75
+ const teaching = narrowed === undefined && services.length === 0 && features.length === 0
76
+ ? { landscape: await landscapeTeaching(docsDir) }
77
+ : null;
78
+ return {
79
+ interrupted,
80
+ services: {
81
+ total: services.length,
82
+ undocumented: services.filter(undocumented).length,
83
+ draft: services.filter((s) => !undocumented(s) && !vouched(s)).length,
84
+ vouched: services.filter(vouched).length,
85
+ // A subset of `vouched`, never a fourth bucket: those services ARE
86
+ // vouched, and the three counts still sum to `total`. It rides beside
87
+ // the count it qualifies because this line is the fleet's trust
88
+ // headline, and "118 vouched" over a fleet where 90 of them were read
89
+ // from a sample is the misreading the scope exists to prevent.
90
+ sampledVouched: services.filter((s) => vouched(s) && s.vouchScope === "sampled").length,
91
+ },
92
+ features,
93
+ order: graph.order.filter((id) => features.some((f) => f.id === id)),
94
+ service: narrowed ?? null,
95
+ // The binding is passed only when this run was NOT narrowed, and that guard
96
+ // is unchanged now that the binding also decides ORDER. `--service X` is an
97
+ // explicit question about X, and answering it with a step about whichever
98
+ // service loam.json happens to name would be a different question's answer
99
+ // at the top of the list — which is as true of a rung promoted to the front
100
+ // as it was of `next.adopt-bound` emitted out of nowhere. A narrowed run
101
+ // sees at most the one service it asked about anyway, so withholding the
102
+ // binding here costs the reader nothing and keeps `--service X` answering
103
+ // only about X.
104
+ next: fleetNext({ services, features, graph, interrupted, teaching }, narrowed === undefined ? binding : null),
105
+ };
106
+ }
107
+ /**
108
+ * Which first-hour state the fleet map is in: absent, still the scaffold's own
109
+ * untouched bytes, or authored. One file read and a byte comparison — the
110
+ * module header's cost rule stands, no LikeC4 workspace is spun here.
111
+ */
112
+ async function landscapeTeaching(docsDir) {
113
+ const lp = landscapePath(docsDir);
114
+ if (!existsSync(lp))
115
+ return "missing";
116
+ try {
117
+ return isLandscapeStub(await readFile(lp, "utf8")) ? "stub" : "authored";
118
+ }
119
+ catch {
120
+ // Unreadable is not untouched. A map that cannot be read — a directory in
121
+ // the file's place, a permission — must not be called the scaffold's stub
122
+ // ("missing" and "stub" would each put a false statement in next[]), so it
123
+ // reads as "authored", which only drops the one teaching step: the gate
124
+ // entry still names `loam validate --all`, where an unreadable landscape
125
+ // is actually graded, and letting this read throw would hand the whole
126
+ // orientation surface — a command that reports and never gates — to the
127
+ // repository-unavailable refusal over a file status does not even parse.
128
+ return "authored";
129
+ }
130
+ }
131
+ async function fleetFeature(docsDir, feature, view) {
132
+ const { graph, contracted, living, context, interrupted } = view;
133
+ const paths = featurePaths(feature.dir);
134
+ const missing = [];
135
+ if (!existsSync(paths.intent))
136
+ missing.push("intent");
137
+ if (feature.services.length === 0)
138
+ missing.push("spec");
139
+ // Requirement text, not a coherence run: `Operations:` lines are read off the
140
+ // same cached parse `list` already pays for, and the contract question needs
141
+ // them (owesContract). No LikeC4 workspace is spun here, which is the cost
142
+ // this form actually refuses.
143
+ const governs = governedServices(await scanDeltas(docsDir, feature, feature.services, context));
144
+ for (const svc of feature.services) {
145
+ const p = featureSpecPaths(feature.dir, svc);
146
+ if (!existsSync(p.spec))
147
+ missing.push(`${svc}/spec`);
148
+ // The same question featureArtifacts asks, through the same function: the
149
+ // two forms must never disagree about whether a feature owes a contract.
150
+ if (owesContract(living.get(svc), contracted.has(svc), governs.has(svc)) && !existsSync(p.openapi)) {
151
+ missing.push(`${svc}/openapi`);
152
+ }
153
+ }
154
+ const verification = (await verificationState(docsDir, feature)).state;
155
+ const blockedBy = graph.nodes.find((n) => n.id === feature.id)?.dependsOn ?? [];
156
+ // No `draft` here, ever: that verdict needs the coherence run this form
157
+ // refuses to pay for, and inferring it from presence alone would be a second
158
+ // opinion about validity — the one thing status must never invent.
159
+ //
160
+ // The interrupted commit leads, exactly as it does in the feature form: every
161
+ // presence test below is a question about files a killed `archive` may have
162
+ // half-written, so answering `done` from them is a claim about bytes nobody
163
+ // has established. Without this the two forms contradicted each other over
164
+ // one repository — `loam status --json` said `done` and offered "ship it"
165
+ // while `loam status <FEAT>` said `blocked` — and the rule in report.ts's
166
+ // header is that this projection is never greener than the gates.
167
+ const stage = interrupted !== null
168
+ ? "blocked"
169
+ : missing.length > 0
170
+ ? "missing"
171
+ : blockedBy.length > 0
172
+ ? "blocked"
173
+ : fullyVerified(verification)
174
+ ? "done"
175
+ : "ready";
176
+ return {
177
+ id: feature.id,
178
+ dirName: feature.dirName,
179
+ path: repoPath(docsDir, feature.dir),
180
+ stage,
181
+ services: feature.services,
182
+ blockedBy,
183
+ missing,
184
+ verification,
185
+ };
186
+ }
187
+ //# sourceMappingURL=fleet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet.js","sourceRoot":"","sources":["../../../../src/core/status/fleet/fleet.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The whole repository — why the fleet form is cheaper than the feature form.\n *\n * `loam status` with no feature runs over every active feature, and deriving a\n * coherence report or a verification checklist per feature means spinning a\n * fresh LikeC4 workspace per feature. On a fleet-sized repository that is the\n * cost that gets a command switched off — `list` made the same call about its\n * verification column. So the fleet form grades nothing: it reports artifact\n * PRESENCE, the dependency order, and a verification record only where one\n * already exists, and its `next[]` hands off to `loam status <FEAT>`, which is\n * where the checks actually run.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { analyzeDependencies } from \"../../dependencies/dependencies.js\";\nimport { type DependencyGraph } from \"../../dependencies/facts.js\";\nimport { isLandscapeStub } from \"../../scaffold/landscape.js\";\nimport { repoPath } from \"../../envelope/json.js\";\nimport { FleetContext } from \"../../fleet-context.js\";\nimport { compareIds, type FeatureEntry, type ServiceEntry } from \"../../repo/entries.js\";\nimport { featurePaths, featureSpecPaths, landscapePath } from \"../../repo/paths.js\";\nimport { listFeatures, listServices } from \"../../repo/repo.js\";\nimport { contractOwners, contractsHeldElsewhere, owesContract } from \"../contracts.js\";\nimport { readInterruptedCommit } from \"../interrupted.js\";\nimport {\n undocumented,\n vouched,\n type ArtifactStatus,\n type FleetFeatureState,\n type FleetStatusReport,\n type InterruptedCommit,\n} from \"../report.js\";\nimport { governedServices, scanDeltas } from \"../scan.js\";\nimport { fullyVerified, verificationState } from \"../verification.js\";\nimport { fleetNext, type Binding } from \"./next.js\";\nimport type { DocsDir } from \"../../kernel/ids/dirs.js\";\n\n/**\n * The fleet view: how much of `services/` anyone has written down, every\n * feature in flight with the stage it has reached, and the order they have to\n * land in. Nothing here is graded — the module header says why — so the stages\n * are drawn from artifact presence and from a record that already exists, and\n * `next[]` hands off to `loam status <FEAT>` for everything else.\n */\nexport async function fleetStatus(\n docsDir: DocsDir,\n opts: { service?: string; bound?: string; context?: FleetContext } = {},\n): Promise<FleetStatusReport> {\n const context = opts.context ?? new FleetContext();\n const interrupted = await readInterruptedCommit(docsDir);\n const narrowed = opts.service;\n const all = await listServices(docsDir, context);\n const services = narrowed === undefined ? all : all.filter((s) => s.id === narrowed);\n // The service this repository says it IS, and whether the fleet has heard of\n // it. Asked against the UNNARROWED list, because \"is it adopted\" is a question\n // about the fleet and not about the view.\n //\n // Both facts travel, where only the unadopted case used to. This value was a\n // `string | null` that went null exactly when the service directory EXISTED,\n // so the walk could see the repository it stands in only while that\n // repository was undocumented — and a developer in an adopted service repo\n // got the whole fleet's worklist with their own boundary buried in it.\n const binding: Binding | null =\n opts.bound === undefined ? null : { id: opts.bound, adopted: all.some((s) => s.id === opts.bound) };\n const graph = await analyzeDependencies(docsDir, undefined, context);\n const entries = await listFeatures(docsDir, {}, context);\n const inScope = narrowed === undefined ? entries : entries.filter((f) => f.services.some((s) => s === narrowed));\n // Once for the fleet, not once per feature: which features hold a contract\n // for which service is one fact about the repository, and every feature below\n // reads its own row out of it. Built over the UNNARROWED list on purpose — a\n // `--service` view still has to know that a feature outside it discharges the\n // contract, or the narrowing would invent an obligation.\n const owners = await contractOwners(docsDir, context);\n\n const features = await Promise.all(\n inScope.map((f) =>\n fleetFeature(docsDir, f, {\n graph,\n contracted: contractsHeldElsewhere(owners, f.id),\n living: new Map(all.map((s) => [s.id, s])),\n context,\n interrupted,\n }),\n ),\n );\n features.sort((a, b) => compareIds(a.id, b.id));\n\n // The first-hour ladder's fact, computed exactly when the ladder can apply\n // — an unnarrowed run over a fleet with zero services and zero features —\n // so the read disappears from every repository that has anything in it.\n // Withheld on narrowed runs for the same reason the binding is withheld\n // below: `--service X` is an explicit question about X, and the\n // repository's onboarding ladder would be a different question's answer.\n const teaching =\n narrowed === undefined && services.length === 0 && features.length === 0\n ? { landscape: await landscapeTeaching(docsDir) }\n : null;\n\n return {\n interrupted,\n services: {\n total: services.length,\n undocumented: services.filter(undocumented).length,\n draft: services.filter((s) => !undocumented(s) && !vouched(s)).length,\n vouched: services.filter(vouched).length,\n // A subset of `vouched`, never a fourth bucket: those services ARE\n // vouched, and the three counts still sum to `total`. It rides beside\n // the count it qualifies because this line is the fleet's trust\n // headline, and \"118 vouched\" over a fleet where 90 of them were read\n // from a sample is the misreading the scope exists to prevent.\n sampledVouched: services.filter((s) => vouched(s) && s.vouchScope === \"sampled\").length,\n },\n features,\n order: graph.order.filter((id) => features.some((f) => f.id === id)),\n service: narrowed ?? null,\n // The binding is passed only when this run was NOT narrowed, and that guard\n // is unchanged now that the binding also decides ORDER. `--service X` is an\n // explicit question about X, and answering it with a step about whichever\n // service loam.json happens to name would be a different question's answer\n // at the top of the list — which is as true of a rung promoted to the front\n // as it was of `next.adopt-bound` emitted out of nowhere. A narrowed run\n // sees at most the one service it asked about anyway, so withholding the\n // binding here costs the reader nothing and keeps `--service X` answering\n // only about X.\n next: fleetNext(\n { services, features, graph, interrupted, teaching },\n narrowed === undefined ? binding : null,\n ),\n };\n}\n\n/**\n * Which first-hour state the fleet map is in: absent, still the scaffold's own\n * untouched bytes, or authored. One file read and a byte comparison — the\n * module header's cost rule stands, no LikeC4 workspace is spun here.\n */\nasync function landscapeTeaching(docsDir: DocsDir): Promise<\"missing\" | \"stub\" | \"authored\"> {\n const lp = landscapePath(docsDir);\n if (!existsSync(lp)) return \"missing\";\n try {\n return isLandscapeStub(await readFile(lp, \"utf8\")) ? \"stub\" : \"authored\";\n } catch {\n // Unreadable is not untouched. A map that cannot be read — a directory in\n // the file's place, a permission — must not be called the scaffold's stub\n // (\"missing\" and \"stub\" would each put a false statement in next[]), so it\n // reads as \"authored\", which only drops the one teaching step: the gate\n // entry still names `loam validate --all`, where an unreadable landscape\n // is actually graded, and letting this read throw would hand the whole\n // orientation surface — a command that reports and never gates — to the\n // repository-unavailable refusal over a file status does not even parse.\n return \"authored\";\n }\n}\n\n/** What a feature's fleet row needs about the fleet AROUND it. */\ninterface FleetView {\n graph: DependencyGraph;\n /** Operations some other feature's contract already holds. */\n contracted: ReadonlySet<string>;\n /** The enumeration's entries by id — where each living service is and what it has (owesContract reads both). */\n living: ReadonlyMap<string, ServiceEntry>;\n context: FleetContext;\n interrupted: InterruptedCommit | null;\n}\n\nasync function fleetFeature(\n docsDir: DocsDir,\n feature: FeatureEntry,\n view: FleetView,\n): Promise<FleetFeatureState> {\n const { graph, contracted, living, context, interrupted } = view;\n const paths = featurePaths(feature.dir);\n const missing: string[] = [];\n if (!existsSync(paths.intent)) missing.push(\"intent\");\n if (feature.services.length === 0) missing.push(\"spec\");\n // Requirement text, not a coherence run: `Operations:` lines are read off the\n // same cached parse `list` already pays for, and the contract question needs\n // them (owesContract). No LikeC4 workspace is spun here, which is the cost\n // this form actually refuses.\n const governs = governedServices(await scanDeltas(docsDir, feature, feature.services, context));\n for (const svc of feature.services) {\n const p = featureSpecPaths(feature.dir, svc);\n if (!existsSync(p.spec)) missing.push(`${svc}/spec`);\n // The same question featureArtifacts asks, through the same function: the\n // two forms must never disagree about whether a feature owes a contract.\n if (owesContract(living.get(svc), contracted.has(svc), governs.has(svc)) && !existsSync(p.openapi)) {\n missing.push(`${svc}/openapi`);\n }\n }\n const verification = (await verificationState(docsDir, feature)).state;\n const blockedBy = graph.nodes.find((n) => n.id === feature.id)?.dependsOn ?? [];\n\n // No `draft` here, ever: that verdict needs the coherence run this form\n // refuses to pay for, and inferring it from presence alone would be a second\n // opinion about validity — the one thing status must never invent.\n //\n // The interrupted commit leads, exactly as it does in the feature form: every\n // presence test below is a question about files a killed `archive` may have\n // half-written, so answering `done` from them is a claim about bytes nobody\n // has established. Without this the two forms contradicted each other over\n // one repository — `loam status --json` said `done` and offered \"ship it\"\n // while `loam status <FEAT>` said `blocked` — and the rule in report.ts's\n // header is that this projection is never greener than the gates.\n const stage: ArtifactStatus =\n interrupted !== null\n ? \"blocked\"\n : missing.length > 0\n ? \"missing\"\n : blockedBy.length > 0\n ? \"blocked\"\n : fullyVerified(verification)\n ? \"done\"\n : \"ready\";\n\n return {\n id: feature.id,\n dirName: feature.dirName,\n path: repoPath(docsDir, feature.dir),\n stage,\n services: feature.services,\n blockedBy,\n missing,\n verification,\n };\n}\n"]}
@@ -0,0 +1,207 @@
1
+ import { serviceTreePath } from "../../kernel/ids/dirs.js";
2
+ import { compareIds } from "../../repo/entries.js";
3
+ import { recoverStep } from "../interrupted.js";
4
+ import { undocumented, } from "../report.js";
5
+ /** How urgent a stage is at fleet level. See {@link fleetNext}. */
6
+ const STAGE_RANK = {
7
+ done: 0,
8
+ ready: 1,
9
+ draft: 2,
10
+ missing: 3,
11
+ blocked: 4,
12
+ };
13
+ /**
14
+ * How many per-service and per-feature steps the fleet form will print before
15
+ * it stops and says how many it left out. A fleet mid-adoption produced 135
16
+ * entries under the heading "the next thing to do" — a list nobody reads is a
17
+ * list that is not navigation, and the first ten are the ten that matter
18
+ * because the ordering below is already most-unblocking-first.
19
+ *
20
+ * Exported so the test asserts the cap through the constant: a literal 10 in a
21
+ * fixture is a second declaration of the limit, free to disagree the day this
22
+ * one moves.
23
+ */
24
+ export const FLEET_NEXT_LIMIT = 10;
25
+ export function fleetNext(fleet, binding) {
26
+ const { services, features, graph, interrupted, teaching } = fleet;
27
+ const steps = [];
28
+ // The two arms of the binding, each named for the question it answers. The
29
+ // first reproduces the old parameter exactly, so everything reading it below
30
+ // is unchanged; the second is the fact that used to be thrown away.
31
+ const unadoptedBinding = binding !== null && !binding.adopted ? binding.id : null;
32
+ const adoptedBinding = binding !== null && binding.adopted ? binding.id : null;
33
+ // The repository this command is standing in names a service the fleet has no
34
+ // directory for. First, ahead of every other service's partial adoption,
35
+ // because it is the only step that is about HERE.
36
+ //
37
+ // This form used to count the fleet and ignore the binding entirely, so in a
38
+ // service repo bound to an unadopted service — a freshly wired one, the most
39
+ // common repo there is — an empty fleet made "every service is written down"
40
+ // vacuously true and `next.fleet-clean` came out top. `loam doctor` had the
41
+ // right answer (`doctor.service-unknown`) at the same moment, and the
42
+ // documented agent loop reads `status`: an agent following it was sent to
43
+ // start a feature instead of adopting the service under its feet.
44
+ if (unadoptedBinding !== null) {
45
+ steps.push({
46
+ code: "next.adopt-bound",
47
+ statement: `This repository's loam.json says it is '${unadoptedBinding}', and the fleet has no ` +
48
+ `services/${unadoptedBinding}/ — nothing about the service you are standing in is written down yet.`,
49
+ command: `loam adopt --service ${unadoptedBinding} --json`,
50
+ service: unadoptedBinding,
51
+ });
52
+ }
53
+ // The first hour of a docs repo, in order. Zero services and zero features
54
+ // used to fall through every loop below into `next.fleet-clean` — the header
55
+ // says why that answer was vacuous — so the emptiest repository loam serves
56
+ // got the least from the command whose whole purpose is "what do I do next".
57
+ // These are ordinary steps on purpose: the gate entry still closes the list,
58
+ // and the tail ternary is untouched. The bind/adopt rungs are suppressed when
59
+ // `next.adopt-bound` above already names the exact adopt to run, and the
60
+ // whole ladder is withheld on narrowed runs (`teaching === null`).
61
+ if (teaching !== null && services.length === 0 && features.length === 0) {
62
+ if (teaching.landscape !== "authored") {
63
+ steps.push({
64
+ code: "next.author-landscape",
65
+ statement: teaching.landscape === "missing"
66
+ ? "architecture/landscape.likec4 does not exist — the fleet map is the one artifact every " +
67
+ "cross-service check reads. Run `loam init --create` to scaffold it, then draw the first service."
68
+ : "architecture/landscape.likec4 is still the scaffold's untouched map — no service is drawn. " +
69
+ "State the facts in a fleet.yaml (service ids, `a -> b` calls) and run " +
70
+ "`loam seed --from fleet.yaml` to template the map mechanically — or open the file " +
71
+ "and follow its own comments. Either way loam never guesses who calls whom.",
72
+ // The command each arm's own prose already names, and for a while it
73
+ // was neither: both arms carried the gate. WORKFLOW.md documents the
74
+ // agent loop as "read next[0], run the command it names, repeat" and
75
+ // every generated skill says to branch on the code rather than the
76
+ // prose — so an agent on the first rung of the first hour ran
77
+ // `validate --all` against a repository with no services in it, which
78
+ // answers ok:true with `landscape.matched` and changes nothing, and
79
+ // came back to the identical next[0] forever. A livelock on day zero,
80
+ // on the one command built to answer "what now". The gate is still
81
+ // named: `next.fleet-gate` closes this same list.
82
+ command: teaching.landscape === "missing" ? "loam init --create" : "loam seed --from fleet.yaml",
83
+ path: "architecture/landscape.likec4",
84
+ });
85
+ }
86
+ if (unadoptedBinding === null) {
87
+ steps.push({
88
+ code: "next.bind-service",
89
+ statement: "No service repository is bound to this fleet yet. From a service's own repo, point --docs " +
90
+ "here and --service at its canonical id, then commit the loam.json it writes.",
91
+ command: "loam init --docs <path-to-this-docs-repo> --service <service-id>",
92
+ });
93
+ steps.push({
94
+ code: "next.adopt-first",
95
+ statement: "services/ is empty — nothing about any service is written down yet. Adopt the first one: " +
96
+ "the brief walks an agent through writing its baseline docs as draft.",
97
+ command: "loam adopt --service <service-id> --json",
98
+ });
99
+ }
100
+ }
101
+ // The per-service rungs are collected into their own list rather than pushed
102
+ // straight onto `steps`, because the partition below acts on them as a group
103
+ // — and only on them. Nothing here may float above `next.adopt-bound` or the
104
+ // first-hour ladder, both of which are about the repository rather than about
105
+ // any one service in the fleet.
106
+ const perService = [];
107
+ for (const s of services.filter(undocumented)) {
108
+ perService.push({
109
+ code: "next.adopt",
110
+ statement: `${serviceTreePath(s)}/ has no spec.md — nothing about ${s.id} is written down, so no feature can be graded against it.`,
111
+ command: `loam adopt --service ${s.id} --json`,
112
+ service: s.id,
113
+ });
114
+ }
115
+ // Adoption does not end at spec.md. A service with a living spec and no
116
+ // model.likec4 is the state archive itself warns about (`service.no-model`)
117
+ // and the fleet gate reports — invisible here until now, because this form
118
+ // looked at exactly one bit of each service's artifact set.
119
+ for (const s of services.filter((x) => !undocumented(x) && !x.has.model)) {
120
+ perService.push({
121
+ code: "next.complete-service",
122
+ statement: `${serviceTreePath(s)}/ has a spec.md but no model.likec4 — the fleet gate reports the service incomplete until something models it.`,
123
+ command: `loam validate --service ${s.id} --json`,
124
+ service: s.id,
125
+ });
126
+ }
127
+ // The boundary this repository IS comes first among the boundaries it merely
128
+ // shares a fleet with. A stable PARTITION and deliberately not a sort: the
129
+ // bound service's rungs move to the front and every other service keeps the
130
+ // alphabetical order it already had, so the list an unbound reader sees — a
131
+ // docs repo, CI, `loam validate --all`'s scorecard — is byte-for-byte the one
132
+ // it saw before.
133
+ //
134
+ // The cap is why this is ordering and not cosmetics. Ten rungs print, and in
135
+ // the ten-repo case WORKFLOW.md describes every developer's `loam status`
136
+ // opened with nine other services' adoption work; past ten services the one
137
+ // rung this developer can actually act on was elided entirely, leaving a list
138
+ // of nothing but other people's boundaries under the heading "next". No new
139
+ // code is emitted for any of this — `next[]` has always been documented as
140
+ // most-unblocking first, and this is the line that makes the claim true from
141
+ // where the reader is standing.
142
+ steps.push(...(adoptedBinding === null
143
+ ? perService
144
+ : [
145
+ ...perService.filter((s) => s.service === adoptedBinding),
146
+ ...perService.filter((s) => s.service !== adoptedBinding),
147
+ ]));
148
+ const ordered = [...features].sort((a, b) => STAGE_RANK[a.stage] - STAGE_RANK[b.stage] ||
149
+ graph.order.indexOf(a.id) - graph.order.indexOf(b.id) ||
150
+ compareIds(a.id, b.id));
151
+ for (const f of ordered) {
152
+ if (f.stage === "done") {
153
+ steps.push({
154
+ code: "next.archive",
155
+ statement: `${f.id} is authored and verified — ship it, and everything waiting on it is released.`,
156
+ command: `loam archive ${f.id} --dry-run --json`,
157
+ });
158
+ continue;
159
+ }
160
+ steps.push({
161
+ code: "next.feature",
162
+ statement:
163
+ // The list, not the stage, is what this sentence names. `blocked` has
164
+ // two causes now — another feature in flight, and an interrupted commit
165
+ // that stalls the whole repository — and the second one names no
166
+ // feature, so keying off the stage alone printed "FEAT-1 is waiting
167
+ // on ." The recover step above already says what the repository is
168
+ // waiting on.
169
+ f.stage === "blocked" && f.blockedBy.length > 0
170
+ ? `${f.id} is waiting on ${f.blockedBy.join(", ")}.`
171
+ : `${f.id} is at '${f.stage}'${f.missing.length > 0 ? ` — missing ${f.missing.join(", ")}` : ""}.`,
172
+ command: `loam status ${f.id} --json`,
173
+ });
174
+ }
175
+ const elided = Math.max(0, steps.length - FLEET_NEXT_LIMIT);
176
+ // Outside the cap, not merely first inside it: the one step that must never
177
+ // be the one this list left out.
178
+ const out = [...(interrupted === null ? [] : [recoverStep(interrupted)]), ...steps.slice(0, FLEET_NEXT_LIMIT)];
179
+ if (elided > 0) {
180
+ out.push({
181
+ code: "next.elided",
182
+ statement: `${elided} more step(s) of the same kinds were left out — this list is ordered most-unblocking first, so work down it and run status again.`,
183
+ command: "loam list --json",
184
+ });
185
+ }
186
+ out.push(steps.length === 0
187
+ ? {
188
+ code: "next.fleet-clean",
189
+ statement: "Nothing is in flight and every service is written down — keep the fleet green, then start the next feature.",
190
+ command: "loam validate --all --json",
191
+ }
192
+ : {
193
+ code: "next.fleet-gate",
194
+ // `loam validate --all` inside the backticks, not the bare
195
+ // `validate --all` this sentence carried for a year: a span without
196
+ // the binary name is invisible to every check that reads a
197
+ // backticked `loam <verb>` as an instruction — the parse check in
198
+ // test/agent-commands-runnable.test.ts, and the statement/command
199
+ // invariant in test/status.test.ts. A prefix is cheaper than an
200
+ // exemption, and the exemption is what lets a wrong command through.
201
+ statement: `${features.length} feature(s) in flight over ${services.length} service(s) — ` +
202
+ "status grades none of them; `loam validate --all` is the gate this repository has to pass, and it is what CI runs.",
203
+ command: "loam validate --all --json",
204
+ });
205
+ return out;
206
+ }
207
+ //# sourceMappingURL=next.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next.js","sourceRoot":"","sources":["../../../../src/core/status/fleet/next.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `next[]` — the whole repository: adoption gaps first, then every feature in\n * flight, most-unblocking first, capped so the list stays navigation rather\n * than inventory.\n */\nimport type { DependencyGraph } from \"../../dependencies/facts.js\";\nimport { serviceTreePath } from \"../../kernel/ids/dirs.js\";\nimport { compareIds, type ServiceEntry } from \"../../repo/entries.js\";\nimport { recoverStep } from \"../interrupted.js\";\nimport {\n undocumented,\n type ArtifactStatus,\n type FleetFeatureState,\n type InterruptedCommit,\n type NextStep,\n} from \"../report.js\";\n\n/** How urgent a stage is at fleet level. See {@link fleetNext}. */\nconst STAGE_RANK: Record<ArtifactStatus, number> = {\n done: 0,\n ready: 1,\n draft: 2,\n missing: 3,\n blocked: 4,\n};\n\n/**\n * How many per-service and per-feature steps the fleet form will print before\n * it stops and says how many it left out. A fleet mid-adoption produced 135\n * entries under the heading \"the next thing to do\" — a list nobody reads is a\n * list that is not navigation, and the first ten are the ten that matter\n * because the ordering below is already most-unblocking-first.\n *\n * Exported so the test asserts the cap through the constant: a literal 10 in a\n * fixture is a second declaration of the limit, free to disagree the day this\n * one moves.\n */\nexport const FLEET_NEXT_LIMIT = 10;\n\n/**\n * Fleet-level steps, most-unblocking first. A feature ready to ship comes\n * before one that still needs authoring, because archiving it is what releases\n * everything queued behind it; a blocked feature comes last, because there is\n * nothing to do about it from here — its prerequisite is already higher up the\n * list under its own entry.\n *\n * The gate is the LAST entry and it is always there. `next.fleet-clean` used to\n * be the only route to `loam validate --all`, and it was emitted only when\n * nothing was in flight — so a repository that FAILS the fleet gate, which is\n * every repository with work in it, was handed a green-looking list that never\n * once named the command CI runs. This form grades nothing; the least it can do\n * is say where grading happens. `next.fleet-clean` is also no longer the\n * empty-repo answer: over zero services, \"every service is written down\" is\n * vacuously true, and the first hour of a docs repo used to get that green\n * sentence instead of its first three steps. The teaching ladder below owns\n * that case now, and the clean entry survives only for its truthful one —\n * services exist, and nothing is owed.\n */\n/** The whole fleet as the next-step walk reads it. */\nexport interface Fleet {\n services: ServiceEntry[];\n features: FleetFeatureState[];\n graph: DependencyGraph;\n interrupted: InterruptedCommit | null;\n /**\n * The ladder's fact, present exactly when the ladder can apply — an\n * unnarrowed run over an empty fleet. `null` otherwise: on a narrowed run\n * (withheld for the reason fleet.ts records beside the binding) and on any\n * fleet with services or features, where fleet.ts skips the read entirely.\n */\n teaching: { landscape: \"missing\" | \"stub\" | \"authored\" } | null;\n}\n\n/**\n * What this repository says it IS, as the walk needs it — and it needs BOTH\n * facts, which is why this is a record and not the bare id it used to be.\n *\n * `adopted: false` is the case the walk always handled: the fleet has no\n * `services/<id>/`, and `next.adopt-bound` leads. `adopted: true` was invisible\n * — the parameter was `string | null` and went null exactly when the directory\n * existed — so a repository bound to a service the fleet DOES know got the\n * whole system's worklist in alphabetical order, with its own boundary\n * somewhere in the middle of it or, past ten services, not on the list at all.\n */\nexport interface Binding {\n id: string;\n /** Whether the fleet has a `services/<id>/` for it. */\n adopted: boolean;\n}\n\nexport function fleetNext(fleet: Fleet, binding: Binding | null): NextStep[] {\n const { services, features, graph, interrupted, teaching } = fleet;\n const steps: NextStep[] = [];\n // The two arms of the binding, each named for the question it answers. The\n // first reproduces the old parameter exactly, so everything reading it below\n // is unchanged; the second is the fact that used to be thrown away.\n const unadoptedBinding = binding !== null && !binding.adopted ? binding.id : null;\n const adoptedBinding = binding !== null && binding.adopted ? binding.id : null;\n\n // The repository this command is standing in names a service the fleet has no\n // directory for. First, ahead of every other service's partial adoption,\n // because it is the only step that is about HERE.\n //\n // This form used to count the fleet and ignore the binding entirely, so in a\n // service repo bound to an unadopted service — a freshly wired one, the most\n // common repo there is — an empty fleet made \"every service is written down\"\n // vacuously true and `next.fleet-clean` came out top. `loam doctor` had the\n // right answer (`doctor.service-unknown`) at the same moment, and the\n // documented agent loop reads `status`: an agent following it was sent to\n // start a feature instead of adopting the service under its feet.\n if (unadoptedBinding !== null) {\n steps.push({\n code: \"next.adopt-bound\",\n statement:\n `This repository's loam.json says it is '${unadoptedBinding}', and the fleet has no ` +\n `services/${unadoptedBinding}/ — nothing about the service you are standing in is written down yet.`,\n command: `loam adopt --service ${unadoptedBinding} --json`,\n service: unadoptedBinding,\n });\n }\n\n // The first hour of a docs repo, in order. Zero services and zero features\n // used to fall through every loop below into `next.fleet-clean` — the header\n // says why that answer was vacuous — so the emptiest repository loam serves\n // got the least from the command whose whole purpose is \"what do I do next\".\n // These are ordinary steps on purpose: the gate entry still closes the list,\n // and the tail ternary is untouched. The bind/adopt rungs are suppressed when\n // `next.adopt-bound` above already names the exact adopt to run, and the\n // whole ladder is withheld on narrowed runs (`teaching === null`).\n if (teaching !== null && services.length === 0 && features.length === 0) {\n if (teaching.landscape !== \"authored\") {\n steps.push({\n code: \"next.author-landscape\",\n statement:\n teaching.landscape === \"missing\"\n ? \"architecture/landscape.likec4 does not exist — the fleet map is the one artifact every \" +\n \"cross-service check reads. Run `loam init --create` to scaffold it, then draw the first service.\"\n : \"architecture/landscape.likec4 is still the scaffold's untouched map — no service is drawn. \" +\n \"State the facts in a fleet.yaml (service ids, `a -> b` calls) and run \" +\n \"`loam seed --from fleet.yaml` to template the map mechanically — or open the file \" +\n \"and follow its own comments. Either way loam never guesses who calls whom.\",\n // The command each arm's own prose already names, and for a while it\n // was neither: both arms carried the gate. WORKFLOW.md documents the\n // agent loop as \"read next[0], run the command it names, repeat\" and\n // every generated skill says to branch on the code rather than the\n // prose — so an agent on the first rung of the first hour ran\n // `validate --all` against a repository with no services in it, which\n // answers ok:true with `landscape.matched` and changes nothing, and\n // came back to the identical next[0] forever. A livelock on day zero,\n // on the one command built to answer \"what now\". The gate is still\n // named: `next.fleet-gate` closes this same list.\n command: teaching.landscape === \"missing\" ? \"loam init --create\" : \"loam seed --from fleet.yaml\",\n path: \"architecture/landscape.likec4\",\n });\n }\n if (unadoptedBinding === null) {\n steps.push({\n code: \"next.bind-service\",\n statement:\n \"No service repository is bound to this fleet yet. From a service's own repo, point --docs \" +\n \"here and --service at its canonical id, then commit the loam.json it writes.\",\n command: \"loam init --docs <path-to-this-docs-repo> --service <service-id>\",\n });\n steps.push({\n code: \"next.adopt-first\",\n statement:\n \"services/ is empty — nothing about any service is written down yet. Adopt the first one: \" +\n \"the brief walks an agent through writing its baseline docs as draft.\",\n command: \"loam adopt --service <service-id> --json\",\n });\n }\n }\n\n // The per-service rungs are collected into their own list rather than pushed\n // straight onto `steps`, because the partition below acts on them as a group\n // — and only on them. Nothing here may float above `next.adopt-bound` or the\n // first-hour ladder, both of which are about the repository rather than about\n // any one service in the fleet.\n const perService: NextStep[] = [];\n for (const s of services.filter(undocumented)) {\n perService.push({\n code: \"next.adopt\",\n statement: `${serviceTreePath(s)}/ has no spec.md — nothing about ${s.id} is written down, so no feature can be graded against it.`,\n command: `loam adopt --service ${s.id} --json`,\n service: s.id,\n });\n }\n\n // Adoption does not end at spec.md. A service with a living spec and no\n // model.likec4 is the state archive itself warns about (`service.no-model`)\n // and the fleet gate reports — invisible here until now, because this form\n // looked at exactly one bit of each service's artifact set.\n for (const s of services.filter((x) => !undocumented(x) && !x.has.model)) {\n perService.push({\n code: \"next.complete-service\",\n statement: `${serviceTreePath(s)}/ has a spec.md but no model.likec4 — the fleet gate reports the service incomplete until something models it.`,\n command: `loam validate --service ${s.id} --json`,\n service: s.id,\n });\n }\n\n // The boundary this repository IS comes first among the boundaries it merely\n // shares a fleet with. A stable PARTITION and deliberately not a sort: the\n // bound service's rungs move to the front and every other service keeps the\n // alphabetical order it already had, so the list an unbound reader sees — a\n // docs repo, CI, `loam validate --all`'s scorecard — is byte-for-byte the one\n // it saw before.\n //\n // The cap is why this is ordering and not cosmetics. Ten rungs print, and in\n // the ten-repo case WORKFLOW.md describes every developer's `loam status`\n // opened with nine other services' adoption work; past ten services the one\n // rung this developer can actually act on was elided entirely, leaving a list\n // of nothing but other people's boundaries under the heading \"next\". No new\n // code is emitted for any of this — `next[]` has always been documented as\n // most-unblocking first, and this is the line that makes the claim true from\n // where the reader is standing.\n steps.push(\n ...(adoptedBinding === null\n ? perService\n : [\n ...perService.filter((s) => s.service === adoptedBinding),\n ...perService.filter((s) => s.service !== adoptedBinding),\n ]),\n );\n\n const ordered = [...features].sort(\n (a, b) =>\n STAGE_RANK[a.stage] - STAGE_RANK[b.stage] ||\n graph.order.indexOf(a.id) - graph.order.indexOf(b.id) ||\n compareIds(a.id, b.id),\n );\n for (const f of ordered) {\n if (f.stage === \"done\") {\n steps.push({\n code: \"next.archive\",\n statement: `${f.id} is authored and verified — ship it, and everything waiting on it is released.`,\n command: `loam archive ${f.id} --dry-run --json`,\n });\n continue;\n }\n steps.push({\n code: \"next.feature\",\n statement:\n // The list, not the stage, is what this sentence names. `blocked` has\n // two causes now — another feature in flight, and an interrupted commit\n // that stalls the whole repository — and the second one names no\n // feature, so keying off the stage alone printed \"FEAT-1 is waiting\n // on .\" The recover step above already says what the repository is\n // waiting on.\n f.stage === \"blocked\" && f.blockedBy.length > 0\n ? `${f.id} is waiting on ${f.blockedBy.join(\", \")}.`\n : `${f.id} is at '${f.stage}'${f.missing.length > 0 ? ` — missing ${f.missing.join(\", \")}` : \"\"}.`,\n command: `loam status ${f.id} --json`,\n });\n }\n\n const elided = Math.max(0, steps.length - FLEET_NEXT_LIMIT);\n // Outside the cap, not merely first inside it: the one step that must never\n // be the one this list left out.\n const out = [...(interrupted === null ? [] : [recoverStep(interrupted)]), ...steps.slice(0, FLEET_NEXT_LIMIT)];\n if (elided > 0) {\n out.push({\n code: \"next.elided\",\n statement: `${elided} more step(s) of the same kinds were left out — this list is ordered most-unblocking first, so work down it and run status again.`,\n command: \"loam list --json\",\n });\n }\n\n out.push(\n steps.length === 0\n ? {\n code: \"next.fleet-clean\",\n statement:\n \"Nothing is in flight and every service is written down — keep the fleet green, then start the next feature.\",\n command: \"loam validate --all --json\",\n }\n : {\n code: \"next.fleet-gate\",\n // `loam validate --all` inside the backticks, not the bare\n // `validate --all` this sentence carried for a year: a span without\n // the binary name is invisible to every check that reads a\n // backticked `loam <verb>` as an instruction — the parse check in\n // test/agent-commands-runnable.test.ts, and the statement/command\n // invariant in test/status.test.ts. A prefix is cheaper than an\n // exemption, and the exemption is what lets a wrong command through.\n statement:\n `${features.length} feature(s) in flight over ${services.length} service(s) — ` +\n \"status grades none of them; `loam validate --all` is the gate this repository has to pass, and it is what CI runs.\",\n command: \"loam validate --all --json\",\n },\n );\n return out;\n}\n"]}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * The one state that outranks everything else: a journaled writer — archive,
3
+ * unarchive, rebase, vouch, new, or a record — killed mid-commit, read off
4
+ * the intent journal `.loam-commit` leaves in the docs repo. The shape both report forms carry it in is `InterruptedCommit`
5
+ * (report.ts); this module is the cheap read behind it, and the recovery step
6
+ * that leads every `next[]` while the journal exists.
7
+ */
8
+ import { existsSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ import { COMMIT_INTENT } from "../staging/interrupted.js";
11
+ import { readCommitIntent } from "../staging/recovery/intent.js";
12
+ import { readTxnIntent } from "../staging/txn/journal.js";
13
+ /**
14
+ * The intent journal, if a commit left one behind. Null on every healthy repo,
15
+ * which is every repo except one whose last write was killed.
16
+ *
17
+ * Cheap on purpose: an `existsSync` and, at most, one small JSON read. `doctor`
18
+ * pays for the whole `scanWritePathResidue` walk because it is a diagnosis;
19
+ * `status` is run before every step of the loop and asks the one question whose
20
+ * answer invalidates all its others.
21
+ */
22
+ export async function readInterruptedCommit(docsDir) {
23
+ const intent = await readCommitIntent(docsDir);
24
+ if (intent === null) {
25
+ if (!existsSync(join(docsDir, COMMIT_INTENT)))
26
+ return null;
27
+ // Version 2 — the smaller journaled transaction. Its `rerun` field IS the
28
+ // recovering command: recovery runs at the start of that command's next
29
+ // invocation, exactly as archive's does under its own lock.
30
+ const txn = await readTxnIntent(docsDir);
31
+ if (txn !== null) {
32
+ return {
33
+ command: txn.command,
34
+ feature: txn.target,
35
+ host: txn.host,
36
+ pid: txn.pid,
37
+ at: txn.at,
38
+ files: txn.files.map((f) => f.path),
39
+ unreadable: false,
40
+ recover: txn.rerun,
41
+ };
42
+ }
43
+ return {
44
+ command: null,
45
+ feature: null,
46
+ host: null,
47
+ pid: null,
48
+ at: null,
49
+ files: [],
50
+ unreadable: true,
51
+ recover: null,
52
+ };
53
+ }
54
+ return {
55
+ command: intent.command,
56
+ feature: intent.feature,
57
+ // Coerced here rather than trusted. `readCommitIntent` validates exactly the
58
+ // fields a REPAIR needs — the version, the command, the restore direction,
59
+ // the feature, the two move paths and the file digests — so `host`, `pid`
60
+ // and `at` arrive as whatever the journal happened to hold, `undefined`
61
+ // included. That is worse than null in both renderings: `JSON.stringify`
62
+ // drops an undefined value's key entirely, so `--json` loses the field
63
+ // instead of reporting it empty, and the two human lines print
64
+ // "(undefined, pid undefined, undefined)". These three are the label a
65
+ // person places the crash against and nothing branches on them, so the
66
+ // coercion belongs at this boundary — widening the validator would change
67
+ // which journals `archive` and `unarchive` agree to repair, which is a
68
+ // decision about somebody's half-written docs, not about a label.
69
+ host: typeof intent.host === "string" ? intent.host : null,
70
+ pid: typeof intent.pid === "number" ? intent.pid : null,
71
+ at: typeof intent.at === "string" ? intent.at : null,
72
+ files: intent.files.map((f) => f.path),
73
+ unreadable: false,
74
+ // The recovering command is the interrupted one re-run: it repairs first,
75
+ // under the lock, from the snapshot it took before the commit. Spelled per
76
+ // branch rather than interpolated, like doctor's own repair line, so
77
+ // test/agent-commands-runnable.test.ts can parse it against the real program.
78
+ recover: intent.command === "archive" ? `loam archive ${intent.feature}` : `loam unarchive ${intent.feature}`,
79
+ };
80
+ }
81
+ /**
82
+ * The step that has to come before every other one. Always first, and never
83
+ * elided by the fleet form's cap: nothing else in the list can be done until
84
+ * somebody knows whether the living docs are the docs.
85
+ */
86
+ export function recoverStep(i) {
87
+ return {
88
+ code: "next.recover-commit",
89
+ statement: i.unreadable
90
+ ? `${COMMIT_INTENT} in this docs repo cannot be read — a commit was interrupted and the one record of which files it had already written is unreadable. Nothing below can be trusted until a human compares the living docs against version control.`
91
+ : `A \`${i.recover}\` was killed mid-commit (${i.host}, pid ${i.pid}, ${i.at}) — ${i.files.length} file(s) may be half-written: ${i.files.join(", ")}. Everything below is derived from those files.`,
92
+ // No command loam offers repairs an unreadable journal — saying otherwise
93
+ // would send an agent to run something that refuses.
94
+ command: i.recover ?? "loam doctor --json",
95
+ };
96
+ }
97
+ //# sourceMappingURL=interrupted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interrupted.js","sourceRoot":"","sources":["../../../src/core/status/interrupted.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The one state that outranks everything else: a journaled writer — archive,\n * unarchive, rebase, vouch, new, or a record — killed mid-commit, read off\n * the intent journal `.loam-commit` leaves in the docs repo. The shape both report forms carry it in is `InterruptedCommit`\n * (report.ts); this module is the cheap read behind it, and the recovery step\n * that leads every `next[]` while the journal exists.\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { COMMIT_INTENT } from \"../staging/interrupted.js\";\nimport { readCommitIntent } from \"../staging/recovery/intent.js\";\nimport { readTxnIntent } from \"../staging/txn/journal.js\";\nimport type { InterruptedCommit, NextStep } from \"./report.js\";\n\n/**\n * The intent journal, if a commit left one behind. Null on every healthy repo,\n * which is every repo except one whose last write was killed.\n *\n * Cheap on purpose: an `existsSync` and, at most, one small JSON read. `doctor`\n * pays for the whole `scanWritePathResidue` walk because it is a diagnosis;\n * `status` is run before every step of the loop and asks the one question whose\n * answer invalidates all its others.\n */\nexport async function readInterruptedCommit(docsDir: string): Promise<InterruptedCommit | null> {\n const intent = await readCommitIntent(docsDir);\n if (intent === null) {\n if (!existsSync(join(docsDir, COMMIT_INTENT))) return null;\n // Version 2 — the smaller journaled transaction. Its `rerun` field IS the\n // recovering command: recovery runs at the start of that command's next\n // invocation, exactly as archive's does under its own lock.\n const txn = await readTxnIntent(docsDir);\n if (txn !== null) {\n return {\n command: txn.command,\n feature: txn.target,\n host: txn.host,\n pid: txn.pid,\n at: txn.at,\n files: txn.files.map((f) => f.path),\n unreadable: false,\n recover: txn.rerun,\n };\n }\n return {\n command: null,\n feature: null,\n host: null,\n pid: null,\n at: null,\n files: [],\n unreadable: true,\n recover: null,\n };\n }\n return {\n command: intent.command,\n feature: intent.feature,\n // Coerced here rather than trusted. `readCommitIntent` validates exactly the\n // fields a REPAIR needs — the version, the command, the restore direction,\n // the feature, the two move paths and the file digests — so `host`, `pid`\n // and `at` arrive as whatever the journal happened to hold, `undefined`\n // included. That is worse than null in both renderings: `JSON.stringify`\n // drops an undefined value's key entirely, so `--json` loses the field\n // instead of reporting it empty, and the two human lines print\n // \"(undefined, pid undefined, undefined)\". These three are the label a\n // person places the crash against and nothing branches on them, so the\n // coercion belongs at this boundary — widening the validator would change\n // which journals `archive` and `unarchive` agree to repair, which is a\n // decision about somebody's half-written docs, not about a label.\n host: typeof intent.host === \"string\" ? intent.host : null,\n pid: typeof intent.pid === \"number\" ? intent.pid : null,\n at: typeof intent.at === \"string\" ? intent.at : null,\n files: intent.files.map((f) => f.path),\n unreadable: false,\n // The recovering command is the interrupted one re-run: it repairs first,\n // under the lock, from the snapshot it took before the commit. Spelled per\n // branch rather than interpolated, like doctor's own repair line, so\n // test/agent-commands-runnable.test.ts can parse it against the real program.\n recover: intent.command === \"archive\" ? `loam archive ${intent.feature}` : `loam unarchive ${intent.feature}`,\n };\n}\n\n/**\n * The step that has to come before every other one. Always first, and never\n * elided by the fleet form's cap: nothing else in the list can be done until\n * somebody knows whether the living docs are the docs.\n */\nexport function recoverStep(i: InterruptedCommit): NextStep {\n return {\n code: \"next.recover-commit\",\n statement: i.unreadable\n ? `${COMMIT_INTENT} in this docs repo cannot be read — a commit was interrupted and the one record of which files it had already written is unreadable. Nothing below can be trusted until a human compares the living docs against version control.`\n : `A \\`${i.recover}\\` was killed mid-commit (${i.host}, pid ${i.pid}, ${i.at}) — ${i.files.length} file(s) may be half-written: ${i.files.join(\", \")}. Everything below is derived from those files.`,\n // No command loam offers repairs an unreadable journal — saying otherwise\n // would send an agent to run something that refuses.\n command: i.recover ?? \"loam doctor --json\",\n };\n}\n"]}
@@ -0,0 +1,31 @@
1
+ /** The closed set. The module header says what each value instructs. */
2
+ export const ARTIFACT_STATUSES = ["missing", "blocked", "draft", "ready", "done"];
3
+ /**
4
+ * The artifact kinds a feature can owe, in the order the cycle authors them.
5
+ * `spec`, `arch-spec`, `openapi` and `asyncapi` are per-service and repeat
6
+ * once per service the feature touches; `capabilities` repeats once per
7
+ * capability document the feature's delta carries; the rest are feature-wide.
8
+ *
9
+ * `capabilities` sits where an analyst writes it — the business promise comes
10
+ * before the services that keep it, and a capability-only feature is a real and
11
+ * ordinary first commit.
12
+ */
13
+ export const ARTIFACT_IDS = [
14
+ "intent",
15
+ "delta",
16
+ "capabilities",
17
+ "spec",
18
+ "arch-spec",
19
+ "openapi",
20
+ "asyncapi",
21
+ "verification",
22
+ ];
23
+ /** Nothing is written down: no living spec at all. Every other absence is partial adoption. */
24
+ export function undocumented(s) {
25
+ return !s.has.spec;
26
+ }
27
+ /** A person stamped it — `loam vouch`'s exact postcondition, read back off the frontmatter. */
28
+ export function vouched(s) {
29
+ return s.status === "verified" && s.sources.stamped;
30
+ }
31
+ //# sourceMappingURL=report.js.map