@ybotok/loam 0.2.0-alpha.7 → 0.2.0-alpha.9

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 (648) hide show
  1. package/CHANGELOG.md +1315 -1
  2. package/COMPARISON.md +91 -3
  3. package/CONTRIBUTING.md +37 -0
  4. package/MIGRATING-from-OpenSpec.md +40 -22
  5. package/QUICKSTART.md +181 -9
  6. package/README.md +256 -57
  7. package/ROADMAP.md +83 -7
  8. package/SCHEMA.md +569 -98
  9. package/WORKFLOW.md +272 -62
  10. package/dist/cli.js +26 -8
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/adopt/adopt.js +5 -10
  13. package/dist/commands/adopt/adopt.js.map +1 -1
  14. package/dist/commands/archive/archive.js +15 -18
  15. package/dist/commands/archive/archive.js.map +1 -1
  16. package/dist/commands/archive/plan/contracts/asyncapi.js +27 -41
  17. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
  18. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  19. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  20. package/dist/commands/archive/plan/contracts/openapi.js +25 -42
  21. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
  22. package/dist/commands/archive/plan/contracts/verdict-lines.js +41 -0
  23. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  24. package/dist/commands/archive/plan/gate.js +3 -7
  25. package/dist/commands/archive/plan/gate.js.map +1 -1
  26. package/dist/commands/archive/plan/landscape.js +4 -4
  27. package/dist/commands/archive/plan/landscape.js.map +1 -1
  28. package/dist/commands/archive/plan/refusal.js +8 -18
  29. package/dist/commands/archive/plan/refusal.js.map +1 -1
  30. package/dist/commands/archive/plan/specs.js +134 -25
  31. package/dist/commands/archive/plan/specs.js.map +1 -1
  32. package/dist/commands/archive/plan/state.js +1 -0
  33. package/dist/commands/archive/plan/state.js.map +1 -1
  34. package/dist/commands/archive/run.js +33 -11
  35. package/dist/commands/archive/run.js.map +1 -1
  36. package/dist/commands/archive/shipped.js +49 -0
  37. package/dist/commands/archive/shipped.js.map +1 -0
  38. package/dist/commands/context/context.js +4 -7
  39. package/dist/commands/context/context.js.map +1 -1
  40. package/dist/commands/context/print.js +2 -2
  41. package/dist/commands/context/print.js.map +1 -1
  42. package/dist/commands/delta/delta.js +44 -12
  43. package/dist/commands/delta/delta.js.map +1 -1
  44. package/dist/commands/delta/print.js +1 -1
  45. package/dist/commands/delta/print.js.map +1 -1
  46. package/dist/commands/dependencies.js +3 -7
  47. package/dist/commands/dependencies.js.map +1 -1
  48. package/dist/commands/diff/diff.js +20 -27
  49. package/dist/commands/diff/diff.js.map +1 -1
  50. package/dist/commands/explore.js +4 -8
  51. package/dist/commands/explore.js.map +1 -1
  52. package/dist/commands/gate/gate.js +45 -8
  53. package/dist/commands/gate/gate.js.map +1 -1
  54. package/dist/commands/gate/print.js +15 -3
  55. package/dist/commands/gate/print.js.map +1 -1
  56. package/dist/commands/gherkin/commit.js +13 -54
  57. package/dist/commands/gherkin/commit.js.map +1 -1
  58. package/dist/commands/gherkin/gherkin.js +36 -20
  59. package/dist/commands/gherkin/gherkin.js.map +1 -1
  60. package/dist/commands/gherkin/reconcile.js +10 -13
  61. package/dist/commands/gherkin/reconcile.js.map +1 -1
  62. package/dist/commands/init/first-hour.js +44 -0
  63. package/dist/commands/init/first-hour.js.map +1 -1
  64. package/dist/commands/init/init.js +18 -22
  65. package/dist/commands/init/init.js.map +1 -1
  66. package/dist/commands/list/campaign/campaign.js +4 -6
  67. package/dist/commands/list/campaign/campaign.js.map +1 -1
  68. package/dist/commands/list/json.js +0 -4
  69. package/dist/commands/list/json.js.map +1 -1
  70. package/dist/commands/list/list.js +38 -23
  71. package/dist/commands/list/list.js.map +1 -1
  72. package/dist/commands/list/print.js +38 -6
  73. package/dist/commands/list/print.js.map +1 -1
  74. package/dist/commands/list/suites/suites.js +140 -0
  75. package/dist/commands/list/suites/suites.js.map +1 -0
  76. package/dist/commands/list/views.js +28 -33
  77. package/dist/commands/list/views.js.map +1 -1
  78. package/dist/commands/mcp/dispatch.js +91 -36
  79. package/dist/commands/mcp/dispatch.js.map +1 -1
  80. package/dist/commands/mcp/mcp.js +56 -15
  81. package/dist/commands/mcp/mcp.js.map +1 -1
  82. package/dist/commands/mcp/serve.js.map +1 -1
  83. package/dist/commands/migrate-openspec/materialize/active.js +27 -22
  84. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
  85. package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
  86. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
  87. package/dist/commands/migrate-openspec/materialize/target.js +2 -2
  88. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
  89. package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
  90. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
  91. package/dist/commands/migrate-openspec/openspec/error.js +7 -8
  92. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
  93. package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
  94. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
  95. package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
  96. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
  97. package/dist/commands/new/capability-template.js +118 -0
  98. package/dist/commands/new/capability-template.js.map +1 -0
  99. package/dist/commands/new/commit.js +8 -22
  100. package/dist/commands/new/commit.js.map +1 -1
  101. package/dist/commands/new/modifies.js +206 -0
  102. package/dist/commands/new/modifies.js.map +1 -0
  103. package/dist/commands/new/new.js +59 -14
  104. package/dist/commands/new/new.js.map +1 -1
  105. package/dist/commands/new/templates.js +48 -124
  106. package/dist/commands/new/templates.js.map +1 -1
  107. package/dist/commands/open.js +3 -7
  108. package/dist/commands/open.js.map +1 -1
  109. package/dist/commands/policy/gate.js +27 -0
  110. package/dist/commands/policy/gate.js.map +1 -1
  111. package/dist/commands/rebase/plan.js +2 -2
  112. package/dist/commands/rebase/plan.js.map +1 -1
  113. package/dist/commands/rebase/rebase.js +60 -35
  114. package/dist/commands/rebase/rebase.js.map +1 -1
  115. package/dist/commands/seed/commit.js +21 -25
  116. package/dist/commands/seed/commit.js.map +1 -1
  117. package/dist/commands/seed/seed.js +6 -9
  118. package/dist/commands/seed/seed.js.map +1 -1
  119. package/dist/commands/show/show.js +3 -7
  120. package/dist/commands/show/show.js.map +1 -1
  121. package/dist/commands/status/print.js +13 -4
  122. package/dist/commands/status/print.js.map +1 -1
  123. package/dist/commands/status/status.js +3 -7
  124. package/dist/commands/status/status.js.map +1 -1
  125. package/dist/commands/steps/steps.js +3 -7
  126. package/dist/commands/steps/steps.js.map +1 -1
  127. package/dist/commands/subsystem/edit.js +3 -5
  128. package/dist/commands/subsystem/edit.js.map +1 -1
  129. package/dist/commands/subsystem/move.js +5 -8
  130. package/dist/commands/subsystem/move.js.map +1 -1
  131. package/dist/commands/subsystem/query.js +2 -4
  132. package/dist/commands/subsystem/query.js.map +1 -1
  133. package/dist/commands/subsystem/subsystem.js +4 -7
  134. package/dist/commands/subsystem/subsystem.js.map +1 -1
  135. package/dist/commands/subsystem/sync.js +14 -41
  136. package/dist/commands/subsystem/sync.js.map +1 -1
  137. package/dist/commands/subsystem/txn/txn.js +17 -38
  138. package/dist/commands/subsystem/txn/txn.js.map +1 -1
  139. package/dist/commands/subsystem/txn/views.js +32 -5
  140. package/dist/commands/subsystem/txn/views.js.map +1 -1
  141. package/dist/commands/tasks/render.js +116 -0
  142. package/dist/commands/tasks/render.js.map +1 -0
  143. package/dist/commands/tasks/tasks.js +113 -0
  144. package/dist/commands/tasks/tasks.js.map +1 -0
  145. package/dist/commands/unarchive/manifest.js +6 -9
  146. package/dist/commands/unarchive/manifest.js.map +1 -1
  147. package/dist/commands/unarchive/restore.js +17 -28
  148. package/dist/commands/unarchive/restore.js.map +1 -1
  149. package/dist/commands/unarchive/unarchive.js +22 -30
  150. package/dist/commands/unarchive/unarchive.js.map +1 -1
  151. package/dist/commands/validate/arch-coverage.js +6 -15
  152. package/dist/commands/validate/arch-coverage.js.map +1 -1
  153. package/dist/commands/validate/checks/fleet-shape.js +4 -49
  154. package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
  155. package/dist/commands/validate/checks/requirements.js +18 -8
  156. package/dist/commands/validate/checks/requirements.js.map +1 -1
  157. package/dist/commands/validate/checks/sources.js +6 -2
  158. package/dist/commands/validate/checks/sources.js.map +1 -1
  159. package/dist/commands/validate/feature.js +23 -19
  160. package/dist/commands/validate/feature.js.map +1 -1
  161. package/dist/commands/validate/fleet/landscape.js +23 -23
  162. package/dist/commands/validate/fleet/landscape.js.map +1 -1
  163. package/dist/commands/validate/fleet/map/attest.js +6 -10
  164. package/dist/commands/validate/fleet/map/attest.js.map +1 -1
  165. package/dist/commands/validate/fleet/map/bindings.js +1 -3
  166. package/dist/commands/validate/fleet/map/bindings.js.map +1 -1
  167. package/dist/commands/validate/fleet/map/usecases.js +5 -11
  168. package/dist/commands/validate/fleet/map/usecases.js.map +1 -1
  169. package/dist/commands/validate/fleet/obligations.js +1 -5
  170. package/dist/commands/validate/fleet/obligations.js.map +1 -1
  171. package/dist/commands/validate/fleet/scorecard/print.js +5 -1
  172. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
  173. package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
  174. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
  175. package/dist/commands/validate/fleet/usecases/usecases.js +6 -4
  176. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -1
  177. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -1
  178. package/dist/commands/validate/fleet/views/root-documents.js +8 -28
  179. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -1
  180. package/dist/commands/validate/links/corpus.js +1 -4
  181. package/dist/commands/validate/links/corpus.js.map +1 -1
  182. package/dist/commands/validate/links/glossary.js.map +1 -1
  183. package/dist/commands/validate/report.js +5 -4
  184. package/dist/commands/validate/report.js.map +1 -1
  185. package/dist/commands/validate/scope.js +113 -0
  186. package/dist/commands/validate/scope.js.map +1 -0
  187. package/dist/commands/validate/service/api.js +16 -104
  188. package/dist/commands/validate/service/api.js.map +1 -1
  189. package/dist/commands/validate/service/contracts/generated.js +134 -0
  190. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  191. package/dist/commands/validate/service/events/events.js +1 -1
  192. package/dist/commands/validate/service/events/events.js.map +1 -1
  193. package/dist/commands/validate/service/events/message-producers.js +1 -1
  194. package/dist/commands/validate/service/events/message-producers.js.map +1 -1
  195. package/dist/commands/validate/service/evidence-pins.js +56 -10
  196. package/dist/commands/validate/service/evidence-pins.js.map +1 -1
  197. package/dist/commands/validate/service/service.js +16 -26
  198. package/dist/commands/validate/service/service.js.map +1 -1
  199. package/dist/commands/validate/service/specs.js +31 -38
  200. package/dist/commands/validate/service/specs.js.map +1 -1
  201. package/dist/commands/validate/service/spine.js +8 -11
  202. package/dist/commands/validate/service/spine.js.map +1 -1
  203. package/dist/commands/validate/service/usecases/usecases.js +3 -3
  204. package/dist/commands/validate/service/usecases/usecases.js.map +1 -1
  205. package/dist/commands/validate/validate.js +44 -26
  206. package/dist/commands/validate/validate.js.map +1 -1
  207. package/dist/commands/verify/cross/diff.js +2 -6
  208. package/dist/commands/verify/cross/diff.js.map +1 -1
  209. package/dist/commands/verify/evidence/contract.js +1 -1
  210. package/dist/commands/verify/evidence/contract.js.map +1 -1
  211. package/dist/commands/verify/evidence/read.js +12 -3
  212. package/dist/commands/verify/evidence/read.js.map +1 -1
  213. package/dist/commands/verify/frozen.js +45 -23
  214. package/dist/commands/verify/frozen.js.map +1 -1
  215. package/dist/commands/verify/record.js +69 -17
  216. package/dist/commands/verify/record.js.map +1 -1
  217. package/dist/commands/verify/report.js +27 -44
  218. package/dist/commands/verify/report.js.map +1 -1
  219. package/dist/commands/verify/results.js +112 -30
  220. package/dist/commands/verify/results.js.map +1 -1
  221. package/dist/commands/verify/verify.js +54 -51
  222. package/dist/commands/verify/verify.js.map +1 -1
  223. package/dist/commands/vouch/pack/pack.js +2 -2
  224. package/dist/commands/vouch/pack/pack.js.map +1 -1
  225. package/dist/commands/vouch/pack/print.js +1 -6
  226. package/dist/commands/vouch/pack/print.js.map +1 -1
  227. package/dist/commands/vouch/pack/sections.js +1 -2
  228. package/dist/commands/vouch/pack/sections.js.map +1 -1
  229. package/dist/commands/vouch/run.js +26 -81
  230. package/dist/commands/vouch/run.js.map +1 -1
  231. package/dist/commands/vouch/sample/plan.js +20 -34
  232. package/dist/commands/vouch/sample/plan.js.map +1 -1
  233. package/dist/commands/vouch/vet/verify.js +39 -7
  234. package/dist/commands/vouch/vet/verify.js.map +1 -1
  235. package/dist/commands/vouch/vouch.js +10 -17
  236. package/dist/commands/vouch/vouch.js.map +1 -1
  237. package/dist/core/agent/agents-md/command-map.js +56 -101
  238. package/dist/core/agent/agents-md/command-map.js.map +1 -1
  239. package/dist/core/agent/agents-md/map/explain.js +4 -3
  240. package/dist/core/agent/agents-md/map/explain.js.map +1 -1
  241. package/dist/core/agent/agents-md/map/lenses/context.js +4 -3
  242. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
  243. package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
  244. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
  245. package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
  246. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
  247. package/dist/core/agent/agents-md/map/mcp.js +10 -7
  248. package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
  249. package/dist/core/agent/agents-md/map/status.js +9 -3
  250. package/dist/core/agent/agents-md/map/status.js.map +1 -1
  251. package/dist/core/agent/agents-md/map/subsystem.js +4 -3
  252. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
  253. package/dist/core/agent/agents-md/map/usecases.js +24 -6
  254. package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
  255. package/dist/core/agent/agents-md/refusals.js +32 -18
  256. package/dist/core/agent/agents-md/refusals.js.map +1 -1
  257. package/dist/core/agent/agents-md.js +9 -3
  258. package/dist/core/agent/agents-md.js.map +1 -1
  259. package/dist/core/agent/agents-stamp.js +10 -0
  260. package/dist/core/agent/agents-stamp.js.map +1 -1
  261. package/dist/core/agent/scaffold.js +10 -15
  262. package/dist/core/agent/scaffold.js.map +1 -1
  263. package/dist/core/agent/tools/dialects.js +1 -0
  264. package/dist/core/agent/tools/dialects.js.map +1 -1
  265. package/dist/core/agent/tools/registry.js +41 -76
  266. package/dist/core/agent/tools/registry.js.map +1 -1
  267. package/dist/core/agent/workflows/adopt.js +5 -3
  268. package/dist/core/agent/workflows/adopt.js.map +1 -1
  269. package/dist/core/agent/workflows/check.js +20 -16
  270. package/dist/core/agent/workflows/check.js.map +1 -1
  271. package/dist/core/agent/workflows/closing.js +54 -21
  272. package/dist/core/agent/workflows/closing.js.map +1 -1
  273. package/dist/core/agent/workflows/feature.js +79 -11
  274. package/dist/core/agent/workflows/feature.js.map +1 -1
  275. package/dist/core/agent/workflows/implement.js +91 -13
  276. package/dist/core/agent/workflows/implement.js.map +1 -1
  277. package/dist/core/agent/workflows/reference/authoring.js +3 -1
  278. package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
  279. package/dist/core/agent/workflows/reference/codes.js +8 -6
  280. package/dist/core/agent/workflows/reference/codes.js.map +1 -1
  281. package/dist/core/agent/workflows/reference/done-check.js +37 -15
  282. package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
  283. package/dist/core/agent/workflows/reference/reference.js.map +1 -1
  284. package/dist/core/agent/workflows/reference/spine.js +50 -18
  285. package/dist/core/agent/workflows/reference/spine.js.map +1 -1
  286. package/dist/core/asyncapi/baseline/plan.js +14 -81
  287. package/dist/core/asyncapi/baseline/plan.js.map +1 -1
  288. package/dist/core/asyncapi/digest.js +30 -25
  289. package/dist/core/asyncapi/digest.js.map +1 -1
  290. package/dist/core/asyncapi/merge/components.js +5 -4
  291. package/dist/core/asyncapi/merge/components.js.map +1 -1
  292. package/dist/core/asyncapi/merge/error.js +7 -2
  293. package/dist/core/asyncapi/merge/error.js.map +1 -1
  294. package/dist/core/asyncapi/merge/markers.js +30 -50
  295. package/dist/core/asyncapi/merge/markers.js.map +1 -1
  296. package/dist/core/asyncapi/merge/merge.js +31 -53
  297. package/dist/core/asyncapi/merge/merge.js.map +1 -1
  298. package/dist/core/asyncapi/merge/pin.js +10 -36
  299. package/dist/core/asyncapi/merge/pin.js.map +1 -1
  300. package/dist/core/asyncapi/model.js.map +1 -1
  301. package/dist/core/asyncapi/read.js +36 -12
  302. package/dist/core/asyncapi/read.js.map +1 -1
  303. package/dist/core/brief/brief.js +6 -18
  304. package/dist/core/brief/brief.js.map +1 -1
  305. package/dist/core/brief/landscape.js +8 -12
  306. package/dist/core/brief/landscape.js.map +1 -1
  307. package/dist/core/brief/map/extend.js +8 -5
  308. package/dist/core/brief/map/extend.js.map +1 -1
  309. package/dist/core/brief/map/owed.js +8 -26
  310. package/dist/core/brief/map/owed.js.map +1 -1
  311. package/dist/core/brief/targets.js +15 -5
  312. package/dist/core/brief/targets.js.map +1 -1
  313. package/dist/core/c4/likec4.js +147 -16
  314. package/dist/core/c4/likec4.js.map +1 -1
  315. package/dist/core/c4/locate/unlocated.js +150 -0
  316. package/dist/core/c4/locate/unlocated.js.map +1 -0
  317. package/dist/core/c4/parsed/values.js +54 -1
  318. package/dist/core/c4/parsed/values.js.map +1 -1
  319. package/dist/core/c4/prefetch/fleet.js +1 -9
  320. package/dist/core/c4/prefetch/fleet.js.map +1 -1
  321. package/dist/core/c4/project/documents.js +31 -6
  322. package/dist/core/c4/project/documents.js.map +1 -1
  323. package/dist/core/c4/project/load.js +6 -17
  324. package/dist/core/c4/project/load.js.map +1 -1
  325. package/dist/core/c4/resolve/external.js +51 -0
  326. package/dist/core/c4/resolve/external.js.map +1 -0
  327. package/dist/core/c4/resolve/service.js +25 -1
  328. package/dist/core/c4/resolve/service.js.map +1 -1
  329. package/dist/core/c4/seed/template.js +15 -1
  330. package/dist/core/c4/seed/template.js.map +1 -1
  331. package/dist/core/c4/service-model/shape.js +2 -22
  332. package/dist/core/c4/service-model/shape.js.map +1 -1
  333. package/dist/core/c4/source-mask.js +288 -4
  334. package/dist/core/c4/source-mask.js.map +1 -1
  335. package/dist/core/c4/source-scan.js +203 -147
  336. package/dist/core/c4/source-scan.js.map +1 -1
  337. package/dist/core/c4/splice/authored-source.js +19 -0
  338. package/dist/core/c4/splice/authored-source.js.map +1 -1
  339. package/dist/core/c4/splice/delta-blocks.js +5 -18
  340. package/dist/core/c4/splice/delta-blocks.js.map +1 -1
  341. package/dist/core/c4/splice/landscape-merge.js +13 -8
  342. package/dist/core/c4/splice/landscape-merge.js.map +1 -1
  343. package/dist/core/c4/splice/model/merge.js +10 -6
  344. package/dist/core/c4/splice/model/merge.js.map +1 -1
  345. package/dist/core/c4/splice/placement.js +108 -18
  346. package/dist/core/c4/splice/placement.js.map +1 -1
  347. package/dist/core/c4/workspace.js +13 -22
  348. package/dist/core/c4/workspace.js.map +1 -1
  349. package/dist/core/capabilities/capabilities.js +6 -6
  350. package/dist/core/capabilities/capabilities.js.map +1 -1
  351. package/dist/core/capabilities/delta/doc.js +7 -10
  352. package/dist/core/capabilities/delta/doc.js.map +1 -1
  353. package/dist/core/capabilities/findings.js +15 -20
  354. package/dist/core/capabilities/findings.js.map +1 -1
  355. package/dist/core/capabilities/realizes/findings.js +12 -19
  356. package/dist/core/capabilities/realizes/findings.js.map +1 -1
  357. package/dist/core/capabilities/realizes/join.js +0 -20
  358. package/dist/core/capabilities/realizes/join.js.map +1 -1
  359. package/dist/core/capabilities/rollup.js +6 -0
  360. package/dist/core/capabilities/rollup.js.map +1 -1
  361. package/dist/core/capabilities/tree.js +6 -28
  362. package/dist/core/capabilities/tree.js.map +1 -1
  363. package/dist/core/capabilities/usecase-join.js +3 -13
  364. package/dist/core/capabilities/usecase-join.js.map +1 -1
  365. package/dist/core/coherence/authoring/scaffold.js +11 -3
  366. package/dist/core/coherence/authoring/scaffold.js.map +1 -1
  367. package/dist/core/coherence/authoring/sentinels.js +2 -1
  368. package/dist/core/coherence/authoring/sentinels.js.map +1 -1
  369. package/dist/core/coherence/coherence.js +30 -16
  370. package/dist/core/coherence/coherence.js.map +1 -1
  371. package/dist/core/coherence/consumed/operations.js +70 -0
  372. package/dist/core/coherence/consumed/operations.js.map +1 -0
  373. package/dist/core/coherence/consumed/refusal.js +38 -0
  374. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  375. package/dist/core/coherence/declared.js +60 -34
  376. package/dist/core/coherence/declared.js.map +1 -1
  377. package/dist/core/coherence/events/declared.js +44 -59
  378. package/dist/core/coherence/events/declared.js.map +1 -1
  379. package/dist/core/coherence/events/events.js +119 -8
  380. package/dist/core/coherence/events/events.js.map +1 -1
  381. package/dist/core/coherence/events/grades.js +31 -8
  382. package/dist/core/coherence/events/grades.js.map +1 -1
  383. package/dist/core/coherence/events/lookups.js +14 -82
  384. package/dist/core/coherence/events/lookups.js.map +1 -1
  385. package/dist/core/coherence/lookups.js +18 -78
  386. package/dist/core/coherence/lookups.js.map +1 -1
  387. package/dist/core/coherence/retired/archived.js +285 -0
  388. package/dist/core/coherence/retired/archived.js.map +1 -0
  389. package/dist/core/coherence/retired/event-pair.js +62 -0
  390. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  391. package/dist/core/coherence/retired/merged.js +79 -0
  392. package/dist/core/coherence/retired/merged.js.map +1 -0
  393. package/dist/core/coherence/retired/retirement.js +49 -0
  394. package/dist/core/coherence/retired/retirement.js.map +1 -0
  395. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  396. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  397. package/dist/core/coherence/retired/revival/revived.js +297 -0
  398. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  399. package/dist/core/consumers/after.js +113 -0
  400. package/dist/core/consumers/after.js.map +1 -0
  401. package/dist/core/consumers/consumers.js +296 -0
  402. package/dist/core/consumers/consumers.js.map +1 -0
  403. package/dist/core/consumers/current.js +211 -0
  404. package/dist/core/consumers/current.js.map +1 -0
  405. package/dist/core/consumers/scan.js +46 -0
  406. package/dist/core/consumers/scan.js.map +1 -0
  407. package/dist/core/consumers/state.js +27 -0
  408. package/dist/core/consumers/state.js.map +1 -0
  409. package/dist/core/delta/delta.js +1 -1
  410. package/dist/core/delta/delta.js.map +1 -1
  411. package/dist/core/deployment/delta.js +3 -6
  412. package/dist/core/deployment/delta.js.map +1 -1
  413. package/dist/core/diff/base-git.js +94 -12
  414. package/dist/core/diff/base-git.js.map +1 -1
  415. package/dist/core/diff/base-state.js +28 -16
  416. package/dist/core/diff/base-state.js.map +1 -1
  417. package/dist/core/diff/joins.js +136 -0
  418. package/dist/core/diff/joins.js.map +1 -0
  419. package/dist/core/diff/scope/changed-paths.js +22 -6
  420. package/dist/core/diff/scope/changed-paths.js.map +1 -1
  421. package/dist/core/diff/scope/edges.js +82 -0
  422. package/dist/core/diff/scope/edges.js.map +1 -0
  423. package/dist/core/diff/semantic.js +100 -31
  424. package/dist/core/diff/semantic.js.map +1 -1
  425. package/dist/core/doctor/agents.js +34 -18
  426. package/dist/core/doctor/agents.js.map +1 -1
  427. package/dist/core/doctor/report.js.map +1 -1
  428. package/dist/core/document/apply.js +10 -2
  429. package/dist/core/document/apply.js.map +1 -1
  430. package/dist/core/document/frontmatter.js +55 -0
  431. package/dist/core/document/frontmatter.js.map +1 -1
  432. package/dist/core/document/parse.js +29 -6
  433. package/dist/core/document/parse.js.map +1 -1
  434. package/dist/core/document/scenarios.js +17 -0
  435. package/dist/core/document/scenarios.js.map +1 -1
  436. package/dist/core/document/spec.js +4 -11
  437. package/dist/core/document/spec.js.map +1 -1
  438. package/dist/core/envelope/config.js +10 -0
  439. package/dist/core/envelope/config.js.map +1 -1
  440. package/dist/core/envelope/json.js +34 -0
  441. package/dist/core/envelope/json.js.map +1 -1
  442. package/dist/core/explain/families.js +17 -12
  443. package/dist/core/explain/families.js.map +1 -1
  444. package/dist/core/explain/refusals.js +3 -3
  445. package/dist/core/explain/refusals.js.map +1 -1
  446. package/dist/core/explain/terms.js +18 -9
  447. package/dist/core/explain/terms.js.map +1 -1
  448. package/dist/core/explore/explore.js +2 -7
  449. package/dist/core/explore/explore.js.map +1 -1
  450. package/dist/core/fleet-context.js +34 -95
  451. package/dist/core/fleet-context.js.map +1 -1
  452. package/dist/core/gate/checks.js +5 -2
  453. package/dist/core/gate/checks.js.map +1 -1
  454. package/dist/core/gate/partners.js +4 -2
  455. package/dist/core/gate/partners.js.map +1 -1
  456. package/dist/core/gate/report.js.map +1 -1
  457. package/dist/core/gate/verification.js +75 -12
  458. package/dist/core/gate/verification.js.map +1 -1
  459. package/dist/core/gherkin/stale.js +13 -37
  460. package/dist/core/gherkin/stale.js.map +1 -1
  461. package/dist/core/glossary/tree.js +6 -19
  462. package/dist/core/glossary/tree.js.map +1 -1
  463. package/dist/core/kernel/concurrency.js +19 -0
  464. package/dist/core/kernel/concurrency.js.map +1 -1
  465. package/dist/core/kernel/records.js +11 -0
  466. package/dist/core/kernel/records.js.map +1 -1
  467. package/dist/core/links/backlinks.js +1 -3
  468. package/dist/core/links/backlinks.js.map +1 -1
  469. package/dist/core/links/corpus.js +5 -36
  470. package/dist/core/links/corpus.js.map +1 -1
  471. package/dist/core/mcp/argv.js +101 -0
  472. package/dist/core/mcp/argv.js.map +1 -1
  473. package/dist/core/mcp/author-tools.js +2 -1
  474. package/dist/core/mcp/author-tools.js.map +1 -1
  475. package/dist/core/mcp/protocol.js +2 -2
  476. package/dist/core/mcp/protocol.js.map +1 -1
  477. package/dist/core/mcp/tools.js +43 -33
  478. package/dist/core/mcp/tools.js.map +1 -1
  479. package/dist/core/openapi/baseline/gate.js +53 -12
  480. package/dist/core/openapi/baseline/gate.js.map +1 -1
  481. package/dist/core/openapi/baseline/plan.js +22 -8
  482. package/dist/core/openapi/baseline/plan.js.map +1 -1
  483. package/dist/core/openapi/baseline/record.js +0 -1
  484. package/dist/core/openapi/baseline/record.js.map +1 -1
  485. package/dist/core/openapi/contract-text.js +33 -0
  486. package/dist/core/openapi/contract-text.js.map +1 -0
  487. package/dist/core/openapi/contract-tree.js +56 -0
  488. package/dist/core/openapi/contract-tree.js.map +1 -0
  489. package/dist/core/openapi/depth.js +38 -24
  490. package/dist/core/openapi/depth.js.map +1 -1
  491. package/dist/core/openapi/digest.js +52 -2
  492. package/dist/core/openapi/digest.js.map +1 -1
  493. package/dist/core/openapi/doc.js +12 -4
  494. package/dist/core/openapi/doc.js.map +1 -1
  495. package/dist/core/openapi/merge/components.js +25 -60
  496. package/dist/core/openapi/merge/components.js.map +1 -1
  497. package/dist/core/openapi/merge/error.js +3 -13
  498. package/dist/core/openapi/merge/error.js.map +1 -1
  499. package/dist/core/openapi/merge/markers.js +26 -30
  500. package/dist/core/openapi/merge/markers.js.map +1 -1
  501. package/dist/core/openapi/merge/merge.js +26 -52
  502. package/dist/core/openapi/merge/merge.js.map +1 -1
  503. package/dist/core/openapi/merge/pin.js +15 -35
  504. package/dist/core/openapi/merge/pin.js.map +1 -1
  505. package/dist/core/openspec/decide/verdict.js.map +1 -1
  506. package/dist/core/openspec/inventory.js +4 -5
  507. package/dist/core/openspec/inventory.js.map +1 -1
  508. package/dist/core/openspec/model/mapping.js +30 -28
  509. package/dist/core/openspec/model/mapping.js.map +1 -1
  510. package/dist/core/openspec/model/model.js +12 -7
  511. package/dist/core/openspec/model/model.js.map +1 -1
  512. package/dist/core/openspec/scan/changes.js +10 -4
  513. package/dist/core/openspec/scan/changes.js.map +1 -1
  514. package/dist/core/openspec/scan/config.js +7 -16
  515. package/dist/core/openspec/scan/config.js.map +1 -1
  516. package/dist/core/openspec/scan/shape.js +63 -19
  517. package/dist/core/openspec/scan/shape.js.map +1 -1
  518. package/dist/core/openspec/scan/walk.js +21 -38
  519. package/dist/core/openspec/scan/walk.js.map +1 -1
  520. package/dist/core/pack/living.js +2 -16
  521. package/dist/core/pack/living.js.map +1 -1
  522. package/dist/core/provenance/findings.js +48 -12
  523. package/dist/core/provenance/findings.js.map +1 -1
  524. package/dist/core/provenance/git.js +33 -57
  525. package/dist/core/provenance/git.js.map +1 -1
  526. package/dist/core/provenance/gitq/moves.js +71 -114
  527. package/dist/core/provenance/gitq/moves.js.map +1 -1
  528. package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
  529. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
  530. package/dist/core/provenance/sources.js +23 -6
  531. package/dist/core/provenance/sources.js.map +1 -1
  532. package/dist/core/provenance/stamp.js +5 -17
  533. package/dist/core/provenance/stamp.js.map +1 -1
  534. package/dist/core/repo/entries.js.map +1 -1
  535. package/dist/core/repo/repo.js +24 -14
  536. package/dist/core/repo/repo.js.map +1 -1
  537. package/dist/core/repo/tree/find.js +12 -3
  538. package/dist/core/repo/tree/find.js.map +1 -1
  539. package/dist/core/repo/tree/fs.js +27 -1
  540. package/dist/core/repo/tree/fs.js.map +1 -1
  541. package/dist/core/repo/tree/walk.js +8 -30
  542. package/dist/core/repo/tree/walk.js.map +1 -1
  543. package/dist/core/results.js +47 -12
  544. package/dist/core/results.js.map +1 -1
  545. package/dist/core/staging/commit.js +10 -12
  546. package/dist/core/staging/commit.js.map +1 -1
  547. package/dist/core/staging/lock.js +74 -12
  548. package/dist/core/staging/lock.js.map +1 -1
  549. package/dist/core/staging/recovery/intent.js +2 -5
  550. package/dist/core/staging/recovery/intent.js.map +1 -1
  551. package/dist/core/staging/recovery/recover.js +60 -1
  552. package/dist/core/staging/recovery/recover.js.map +1 -1
  553. package/dist/core/staging/snapshot/manifest.js +152 -0
  554. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  555. package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +10 -34
  556. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  557. package/dist/core/status/actions/execution.js +11 -0
  558. package/dist/core/status/actions/execution.js.map +1 -1
  559. package/dist/core/status/feature/artifacts.js +2 -2
  560. package/dist/core/status/feature/artifacts.js.map +1 -1
  561. package/dist/core/status/feature/feature.js +5 -11
  562. package/dist/core/status/feature/feature.js.map +1 -1
  563. package/dist/core/status/fleet/fleet.js +6 -2
  564. package/dist/core/status/fleet/fleet.js.map +1 -1
  565. package/dist/core/status/fleet/next.js +26 -3
  566. package/dist/core/status/fleet/next.js.map +1 -1
  567. package/dist/core/status/report.js.map +1 -1
  568. package/dist/core/status/verification.js +30 -15
  569. package/dist/core/status/verification.js.map +1 -1
  570. package/dist/core/tasks/packet.js +174 -0
  571. package/dist/core/tasks/packet.js.map +1 -0
  572. package/dist/core/tasks/record.js +43 -0
  573. package/dist/core/tasks/record.js.map +1 -0
  574. package/dist/core/tasks/sources.js +181 -0
  575. package/dist/core/tasks/sources.js.map +1 -0
  576. package/dist/core/tasks/stamps.js +76 -0
  577. package/dist/core/tasks/stamps.js.map +1 -0
  578. package/dist/core/tasks/unit.js +0 -0
  579. package/dist/core/tasks/unit.js.map +1 -0
  580. package/dist/core/usecases/capability.js +11 -14
  581. package/dist/core/usecases/capability.js.map +1 -1
  582. package/dist/core/usecases/delta/flows.js +5 -7
  583. package/dist/core/usecases/delta/flows.js.map +1 -1
  584. package/dist/core/usecases/fleet.js +178 -31
  585. package/dist/core/usecases/fleet.js.map +1 -1
  586. package/dist/core/usecases/operations.js +5 -4
  587. package/dist/core/usecases/operations.js.map +1 -1
  588. package/dist/core/usecases/service/flows.js +9 -6
  589. package/dist/core/usecases/service/flows.js.map +1 -1
  590. package/dist/core/usecases/suites/participants.js +83 -0
  591. package/dist/core/usecases/suites/participants.js.map +1 -0
  592. package/dist/core/usecases/suites/suites.js +45 -0
  593. package/dist/core/usecases/suites/suites.js.map +1 -0
  594. package/dist/core/verify/answers.js +12 -5
  595. package/dist/core/verify/answers.js.map +1 -1
  596. package/dist/core/verify/build.js +102 -82
  597. package/dist/core/verify/build.js.map +1 -1
  598. package/dist/core/verify/checklist.js +3 -0
  599. package/dist/core/verify/checklist.js.map +1 -1
  600. package/dist/core/verify/location.js +67 -0
  601. package/dist/core/verify/location.js.map +1 -0
  602. package/dist/core/verify/pins/lint.js +3 -2
  603. package/dist/core/verify/pins/lint.js.map +1 -1
  604. package/dist/core/verify/pins/pin.js +1 -1
  605. package/dist/core/verify/pins/pin.js.map +1 -1
  606. package/dist/core/verify/read/file.js +224 -0
  607. package/dist/core/verify/read/file.js.map +1 -0
  608. package/dist/core/verify/{file.js → read/shape.js} +16 -104
  609. package/dist/core/verify/read/shape.js.map +1 -0
  610. package/dist/core/verify/read/union.js +105 -0
  611. package/dist/core/verify/read/union.js.map +1 -0
  612. package/dist/core/verify/record.js +35 -12
  613. package/dist/core/verify/record.js.map +1 -1
  614. package/dist/core/verify/store/commit.js +40 -30
  615. package/dist/core/verify/store/commit.js.map +1 -1
  616. package/dist/core/verify/store/render.js +8 -4
  617. package/dist/core/verify/store/render.js.map +1 -1
  618. package/dist/core/vocabulary/issue.js +1 -0
  619. package/dist/core/vocabulary/issue.js.map +1 -1
  620. package/dist/core/vocabulary/maturity.js +12 -2
  621. package/dist/core/vocabulary/maturity.js.map +1 -1
  622. package/examples/README.md +21 -6
  623. package/examples/docs/architecture/landscape.likec4 +8 -0
  624. package/examples/docs/architecture/usecases/order-notification.likec4 +6 -2
  625. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
  626. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
  627. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
  628. package/examples/docs/services/order-service/asyncapi.yaml +3 -2
  629. package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
  630. package/package.json +1 -1
  631. package/dist/commands/validate/checks/vocabulary.js +0 -16
  632. package/dist/commands/validate/checks/vocabulary.js.map +0 -1
  633. package/dist/core/agent/agents-md/artifacts.js +0 -221
  634. package/dist/core/agent/agents-md/artifacts.js.map +0 -1
  635. package/dist/core/agent/agents-md/cycle.js +0 -180
  636. package/dist/core/agent/agents-md/cycle.js.map +0 -1
  637. package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
  638. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
  639. package/dist/core/agent/agents-md/spine.js +0 -40
  640. package/dist/core/agent/agents-md/spine.js.map +0 -1
  641. package/dist/core/coherence/events/merged.js +0 -40
  642. package/dist/core/coherence/events/merged.js.map +0 -1
  643. package/dist/core/diff/current-state.js +0 -96
  644. package/dist/core/diff/current-state.js.map +0 -1
  645. package/dist/core/diff/victims.js +0 -256
  646. package/dist/core/diff/victims.js.map +0 -1
  647. package/dist/core/staging/snapshot.js.map +0 -1
  648. package/dist/core/verify/file.js.map +0 -1
package/README.md CHANGED
@@ -7,12 +7,14 @@
7
7
  [![CI](https://github.com/ybotok/loam/actions/workflows/ci.yml/badge.svg)](https://github.com/ybotok/loam/actions/workflows/ci.yml)
8
8
  [![npm](https://img.shields.io/npm/v/@ybotok/loam/alpha.svg?label=npm%20alpha)](https://www.npmjs.com/package/@ybotok/loam)
9
9
 
10
- > **Pre-release: `0.2.0-alpha.7`**, the sixth published release of the 0.2 line and the newest published
11
- > version of [`@ybotok/loam`](https://www.npmjs.com/package/@ybotok/loam). It publishes under the
12
- > `alpha` npm dist-tag — which is what the badge above reads: `npm i @ybotok/loam@alpha`, or the
13
- > exact version, always installs this line. `latest` is moved onto a release by hand once it has
14
- > published, so a plain `npm i @ybotok/loam` resolves to an earlier release until it is moved. See
15
- > [Status](#status).
10
+ > **Pre-release: `0.2.0-alpha.9`** is the version this checkout's `package.json` names, on the 0.2
11
+ > line of [`@ybotok/loam`](https://www.npmjs.com/package/@ybotok/loam). Whether npm serves it is not
12
+ > something this file can know — a version is cut before its publish runs, and a publish can fail
13
+ > after — so **the npm dist-tags are the source of truth**: the badge above reads the `alpha` tag, and
14
+ > `npm view @ybotok/loam dist-tags` prints every tag. Prereleases publish under `alpha`, so
15
+ > `npm i @ybotok/loam@alpha` installs the newest one that did. `latest` is moved onto a release by
16
+ > hand once it has published, so a plain `npm i @ybotok/loam` resolves to an earlier release until it
17
+ > is moved. See [Status](#status).
16
18
 
17
19
  `loam` keeps an authored C4 model, requirements, API and event contracts, permissions, domain
18
20
  vocabulary and verification evidence in explicit agreement as a system changes. The same lifecycle
@@ -109,7 +111,7 @@ and says what its architecture *means*, and a model that was guessed is worse th
109
111
  downstream has to re-derive it to know whether to believe it. So loam takes the half of the job that
110
112
  is mechanical: it **states the work** and it **checks the result**. An agent does the reading, and
111
113
  both halves are written down: the question in the brief or the checklist, the answer in `sources` or
112
- `verification.yaml`.
114
+ the verification record.
113
115
 
114
116
  ### What green means here, and what it does not
115
117
 
@@ -220,22 +222,42 @@ a contract spelling it `authorizePayment` fails here and nowhere else a team nor
220
222
  **Expect a red run, and read it correctly.** Five seeded services with no C4 centre report
221
223
  `service.no-model` (error) five times, and `service.no-spec` (warn) five times. Those are not
222
224
  misconfiguration: they are a truthful reading of a fleet where adoption has not started, and they
223
- stay until you write those documents. The finding you came for is the spine one.
225
+ stay until you write those documents. The finding you came for is the spine one. Under the `--base`
226
+ PR gate [below](#guard-the-fleets-edges-on-every-pr), a PR that adds a service's `openapi.yaml`
227
+ stays red until that service has a `model.likec4` — the gate grades the service the PR touched, and
228
+ `service.no-model` is that ratchet working as designed — while a PR that only names operations on
229
+ the map is graded on those edges alone.
224
230
  [`test/spine-first.test.ts`](https://github.com/ybotok/loam/blob/main/test/spine-first.test.ts)
225
231
  pins this whole sequence against the shipped `examples/fleet.yaml`, so the recipe cannot drift from
226
232
  the binary.
227
233
 
228
234
  From here, [WORKFLOW.md's day zero](WORKFLOW.md#day-zero-onboarding-a-fleet) is the rest: bind each
229
- service repo, adopt, grade, promote.
235
+ service repo, adopt, grade, promote. Bind each one with the service profile:
236
+
237
+ ```bash
238
+ # in each service checkout, beside the docs repo
239
+ loam init --docs ../docs --service payment-service --agent-profile service
240
+ loam doctor
241
+ ```
242
+
243
+ Pass the profile explicitly. `--agent-profile` defaults to `full`, with `--service` or without it,
244
+ and `full` writes all seven entry points into the checkout — `loam-feature` and `loam-ship` among
245
+ them, the two workflows that author a feature and archive it into the living docs, which the `docs`
246
+ profile gives to the docs repo. `service` writes the five that run beside the code: `loam-adopt`,
247
+ `loam-implement`, `loam-check`, `loam-verify` and `loam-report`. Across a hundred service repos that
248
+ is the difference between one place a cross-service change starts and a hundred places an agent
249
+ can be told to start one. The people in those service repos need about a screen of this:
250
+ [docs/SERVICE-TEAMS.md](https://github.com/ybotok/loam/blob/main/docs/SERVICE-TEAMS.md).
230
251
 
231
252
  ### Guard the fleet's edges on every PR
232
253
 
233
254
  Two commands, each installable on its own with no part of the workflow above adopted. **`loam diff`
234
255
  exits 1 when a pull request removes an operation or an event message the fleet still consumes**,
235
- and names the consumers. That question — *who still calls this?* — is the one a fleet answers wrong,
236
- and it is answerable only from a document that knows the whole fleet. **`loam validate --all --base
237
- <ref>` grades only the boundaries the branch touched**, which is what lets a strict gate go in on
238
- the first day of adoption and tighten as the system gets written down.
256
+ and names the consumers — of a removal, a deprecation, or a change to what an operation or message
257
+ returns. That question — *who is joined to this?* — is the one a fleet answers wrong, and it is
258
+ answerable only from a document that knows the whole fleet. **`loam validate --all --base <ref>`
259
+ grades only the boundaries the branch touched**, which is what lets a strict gate go in on the
260
+ first day of adoption and tighten as the system gets written down.
239
261
 
240
262
  ```yaml
241
263
  # .github/workflows/fleet-edges.yml — in the docs repo
@@ -244,34 +266,198 @@ on: pull_request
244
266
  jobs:
245
267
  edges:
246
268
  runs-on: ubuntu-latest
269
+ env:
270
+ LOAM: "@ybotok/loam@0.2.0-alpha.9" # an exact version: bump it in a PR of its own
271
+ BASE: origin/${{ github.base_ref }}
247
272
  steps:
248
273
  - uses: actions/checkout@v4
249
- with: { fetch-depth: 0 } # both read the base out of git history
274
+ with: { fetch-depth: 0 } # every step reads the base out of git history
250
275
  - uses: actions/setup-node@v4
251
276
  with: { node-version: 22 }
252
- # did you break a consumer?
253
- - run: npx -y @ybotok/loam diff --base origin/${{ github.base_ref }}
277
+ # did you remove something an authored consumer still names? (fails) — and
278
+ # who is joined to each operation or message you changed? (warns, naming them)
279
+ - run: npx -y "$LOAM" diff --base "$BASE"
254
280
  # did you document what you touched?
255
- - run: npx -y @ybotok/loam validate --all --base origin/${{ github.base_ref }} --strict
281
+ - run: npx -y "$LOAM" validate --all --base "$BASE" --strict
282
+ # does a changed operation break its readers? oasdiff answers that; loam does not
283
+ - run: |
284
+ for spec in $(git diff --name-only --diff-filter=M "$BASE"... -- 'services/*openapi.yaml'); do
285
+ git show "$BASE:./$spec" > "$RUNNER_TEMP/base.yaml"
286
+ docker run --rm -v "$RUNNER_TEMP:/base:ro" -v "$PWD:/head:ro" tufin/oasdiff \
287
+ breaking /base/base.yaml "/head/$spec" --fail-on ERR
288
+ done
256
289
  ```
257
290
 
258
- Two gates, two different questions, and neither is the other's cheaper form. `diff` reports every
259
- removal against the system's current consumers rather than against a rule list, which is why it
260
- repays installation before anything else exists. `validate --base` grades the boundaries this
261
- branch changed, at full strictness, and says out loud how much of the system that was — a run with
262
- nothing in scope prints that it graded nothing rather than the word valid. Unscoped, neither
263
- setting is usable on a partly-documented system: `loam validate --all` is green over boundaries
264
- nobody has written yet, because warnings do not gate, and `--strict` over all of them is red from
265
- the first minute of adoption until the last one is done.
291
+ **Pin loam, and move the pin on purpose.** An unpinned `npx -y @ybotok/loam` runs whatever the
292
+ `latest` tag points at on the day the job starts, so a release can change what gates your pull
293
+ requests in the middle of a review. Bump `LOAM` in a pull request of its own: run
294
+ `loam subsystem sync` with the new version, update the `<!-- generated by loam vX.Y.Z -->` stamp
295
+ in the docs repo's `AGENTS.md`, and read the release's CHANGELOG entry, which opens with what a
296
+ repository notices after upgrading. Pin the oasdiff image's tag the same way.
297
+
298
+ Three steps, three different questions, and none is another's cheaper form. `diff` reports every
299
+ removal against the fleet's authored consumers — landscape edges, other services' living
300
+ requirements, use-case hops — rather than against a rule list, which is why it repays installation
301
+ before anything else exists. It names who is joined to a changed operation or message, and it never
302
+ says whether the change breaks them: loam does not read what a schema says, so a renamed required
303
+ field and a new optional one are the same warning to it. That half is oasdiff's, and
304
+ `asyncapi diff`'s for event contracts. A caller drawn on the map with no operation on its edge is
305
+ listed as one nobody could check, never counted as no caller. `validate --base` grades the
306
+ boundaries this branch changed, at full strictness, and says out loud how much of the system that
307
+ was — a run with nothing in scope prints that it graded nothing rather than the word valid.
308
+ Unscoped, neither setting is usable on a partly-documented system: `loam validate --all` is green
309
+ over boundaries nobody has written yet, because warnings do not gate, and `--strict` over all of
310
+ them is red from the first minute of adoption until the last one is done.
311
+
312
+ An archive's PR stays red under `--base --strict` until its re-vouches land: the merge moves every
313
+ vouched spec it touches under its vouch stamp, so `content.stale` follows, and `loam archive` names
314
+ each such spec and its owner (`revouchOwed`) so those re-vouches can join the same PR.
266
315
 
267
316
  **A `--base`-scoped validate cannot see a victim boundary the change did not touch.** Remove an
268
317
  operation `payment-service` owns, and `checkout-web` — whose living requirement still names it —
269
318
  is not in scope, so nothing in that gate reports the broken join. That is `loam diff --base`'s
270
319
  question, it stays `loam diff --base`'s, and a green scoped validate is not a statement about the
271
- consumers of what changed. [WORKFLOW.md](WORKFLOW.md#what-actually-gates) has what each does and
320
+ consumers of what changed. A join the branch itself *wrote* is the other case: a call edge it adds
321
+ or edits in `architecture/` is graded against its provider's contract even with the provider out of
322
+ scope, so the one-letter `authorisePayment` above fails on the PR that introduces it.
323
+ [WORKFLOW.md](WORKFLOW.md#what-actually-gates) has what each does and
272
324
  does not grade — including the oasdiff invocation for the byte-level OpenAPI breaking-change
273
325
  catalogue, which loam deliberately does not reimplement.
274
326
 
327
+ ### Check each service repo on its own pull requests
328
+
329
+ The docs repo's job cannot see provenance. `sources` resolve only inside a service's own
330
+ repository, so `sources.stale` — the code under a vouched spec moved — surfaces only in that
331
+ service repo's CI ([SCHEMA.md](SCHEMA.md), "Operating at fleet scale"). Its committed `loam.json`
332
+ reaches the docs repo through a relative `docsDir` such as `"../docs"`, so the job rebuilds the
333
+ side-by-side layout a laptop has. `actions/checkout` refuses `path: ../docs` — it writes only
334
+ beneath `GITHUB_WORKSPACE` — so check out **both** repositories as subdirectories of the workspace,
335
+ siblings, and run loam from the service's:
336
+
337
+ ```yaml
338
+ # .github/workflows/loam.yml — in each service repo
339
+ name: loam
340
+ on: pull_request
341
+ jobs:
342
+ docs:
343
+ runs-on: ubuntu-latest
344
+ env:
345
+ LOAM: "@ybotok/loam@0.2.0-alpha.9" # the docs repo's pin: move them together
346
+ SERVICE: payment-service # this repo's "service" in its loam.json
347
+ steps:
348
+ # Both repositories as siblings under the workspace, the way a laptop holds
349
+ # them, so the committed "docsDir": "../docs" resolves unchanged.
350
+ - uses: actions/checkout@v4
351
+ with: { path: payment-service }
352
+ - uses: actions/checkout@v4
353
+ with:
354
+ repository: acme/docs # your docs repo
355
+ path: docs # the last segment of docsDir
356
+ token: ${{ secrets.LOAM_DOCS_READ_TOKEN }} # contents: read on the docs repo
357
+ - uses: actions/setup-node@v4
358
+ with: { node-version: 22 }
359
+ - name: loam validate --service
360
+ working-directory: payment-service
361
+ run: |
362
+ rc=0
363
+ npx -y "$LOAM" validate --service "$SERVICE" --json > "$RUNNER_TEMP/loam.json" || rc=$?
364
+ # one annotation per error and warning; a refusal (docs-missing, …) is one error
365
+ jq -r '
366
+ def esc: gsub("%"; "%25") | gsub("\r"; "%0D") | gsub("\n"; "%0A");
367
+ if .ok then
368
+ .targets[].findings[] | select(.severity != "ok")
369
+ | "::\(if .severity == "error" then "error" else "warning" end) title=\(.code)::\(.message | esc) (docs: \(.locations[0].path))"
370
+ else "::error title=\(.error.code)::\(.error.message | esc)" end
371
+ ' "$RUNNER_TEMP/loam.json"
372
+ # the same findings as a table on the run's summary page
373
+ jq -r '
374
+ if .ok then
375
+ "### loam validate --service \(.targets[0].id) — \(.summary.errors) error(s), \(.summary.warnings) warning(s)",
376
+ "", "| severity | code | finding |", "|---|---|---|",
377
+ (.targets[].findings[] | select(.severity != "ok")
378
+ | "| \(.severity) | `\(.code)` | \(.message | gsub("\\|"; "\\|") | gsub("\n"; " ")) |")
379
+ else "### loam refused: `\(.error.code)`", "", .error.message end
380
+ ' "$RUNNER_TEMP/loam.json" >> "$GITHUB_STEP_SUMMARY"
381
+ exit "$rc"
382
+ ```
383
+
384
+ Run from a `payment-service` checkout beside `examples/docs`, in a repository with no
385
+ `src/main/java/` — the source that service's specs name — the step exits 1 and prints:
386
+
387
+ ```text
388
+ ::warning title=spine.op-link-missing::payment-service: landscape edge checkout-web → payment-service ("Calls the payment API") has no operation link (metadata { op }) (docs: services/payment-service)
389
+ ::error title=sources.path-missing::payment-service: spec.md: 1 source(s) do not exist — src/main/java/ (docs: services/payment-service)
390
+ ::error title=sources.path-missing::payment-service: arch.spec.md: 1 source(s) do not exist — src/main/java/ (docs: services/payment-service)
391
+ ```
392
+
393
+ The annotations carry no `file=`, on purpose: every location loam reports is a path in the docs
394
+ repo, which is not the repository this pull request diffs, so GitHub could not place one on a line
395
+ here. They land on the check run and its summary instead. A docs repo that is private needs a token
396
+ that can read it — a fine-grained token or a GitHub App token with `contents: read` on that one
397
+ repository — because the workflow's own `GITHUB_TOKEN` reads only the repository it runs in. Add
398
+ `--strict` once the service is vouched and its warnings are ones you mean to keep at zero; before
399
+ that, the warnings are the adoption still to do.
400
+
401
+ The same layout answers the deploy question. In the deploy pipeline, check the docs repo out with
402
+ `fetch-depth: 0` — `--since` is read from its git history — and ask whether this service may ship:
403
+
404
+ ```bash
405
+ npx -y "$LOAM" gate --service "$SERVICE" --since "$DOCS_SHA_OF_LAST_DEPLOY"
406
+ ```
407
+
408
+ `gate` executes nothing and writes nothing, and without `--strict` its warnings stay advisory;
409
+ [WORKFLOW.md](WORKFLOW.md#what-actually-gates) says what each finding of it means for a pipeline.
410
+
411
+ **Cloud agents in a service repo** need the same sibling on disk before they start: a lone clone
412
+ of the service answers every docs-reading command with `docs-missing`. GitHub's Copilot coding
413
+ agent and Codex cloud each start from the one repository the task names and run a setup step you
414
+ own, so clone the docs repo there, into the committed `docsDir`. Copilot reads the job
415
+ `copilot-setup-steps` from `.github/workflows/copilot-setup-steps.yml` on the default branch, and
416
+ an
417
+ [Agents secret](https://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/configure-secrets-and-variables)
418
+ reaches those steps as an environment variable:
419
+
420
+ ```yaml
421
+ # .github/workflows/copilot-setup-steps.yml — in each service repo
422
+ name: Copilot setup steps
423
+ on: workflow_dispatch
424
+ jobs:
425
+ copilot-setup-steps:
426
+ runs-on: ubuntu-latest
427
+ permissions: { contents: read }
428
+ steps:
429
+ - uses: actions/checkout@v4
430
+ - uses: actions/setup-node@v4
431
+ with: { node-version: 22 }
432
+ - run: npm install -g @ybotok/loam@0.2.0-alpha.9
433
+ # "../docs" is outside the workspace, so git clone rather than actions/checkout;
434
+ # the second command takes the token back out of the clone's config
435
+ - run: |
436
+ git clone --depth 1 "https://x-access-token:${LOAM_DOCS_READ_TOKEN}@github.com/acme/docs.git" ../docs
437
+ git -C ../docs remote set-url origin https://github.com/acme/docs.git
438
+ - run: loam doctor
439
+ ```
440
+
441
+ Codex cloud has no workflow file: the same commands go in the environment's setup script, with
442
+ the token as an environment **secret** — Codex hands secrets to the setup script only and removes
443
+ them before the agent phase, which is all a clone needs. Pin Node.js to 22 or newer in the
444
+ environment's package versions, and spell the target from the repository root, because where the
445
+ script starts is not documented:
446
+
447
+ ```bash
448
+ npm install -g @ybotok/loam@0.2.0-alpha.9
449
+ DOCS="$(git rev-parse --show-toplevel)/../docs"
450
+ git clone --depth 1 "https://x-access-token:${LOAM_DOCS_READ_TOKEN}@github.com/acme/docs.git" "$DOCS"
451
+ git -C "$DOCS" remote set-url origin https://github.com/acme/docs.git
452
+ loam doctor
453
+ ```
454
+
455
+ The clone is the agent's reading, not a second place it can deliver. A cloud agent opens its pull
456
+ request against the repository it was started in, so anything it writes into the docs checkout —
457
+ a verification record, a spec edit — stays in its sandbox. `loam-implement`'s own outputs, the
458
+ generated Gherkin and the code, land in the service repo as usual; what belongs in the docs repo
459
+ goes there through that repo's own pull request.
460
+
275
461
  ### Try loam on one governed system in five minutes
276
462
 
277
463
  The full model may be one application or a fleet; the trial is one repository. In the codebase you
@@ -350,29 +536,30 @@ cannot hold.
350
536
  |---|---|---|
351
537
  | `loam init` | `--docs <dir>` `--service <id>` `--create` `--force` `--tools <ids>` `--agent-profile <full\|service\|docs>` `--example <dir>` `--no-commands` `--no-skills` `--mcp` `--mcp-author` | Bind this repository to the single shared docs repo: a committed local `loam.json`, plus command and Agent Skill pointers for detected AI tools. Profiles narrow the six lifecycle workflows to a repo's role; the support-only `loam-report` stays in every profile. Re-running init refreshes only unchanged loam-owned pointers; edited files are preserved. `--mcp` writes the read-only host entry, while `--mcp-author` opts into the bounded authoring tools. `--create` scaffolds the docs repo; `--example` copies the packaged example and stops |
352
538
  | `loam seed` | `--from <file>` | Template the fleet map and one `services/<id>/` directory per service from a tiny human-authored `fleet.yaml`. Mechanical, never a guess: a human stated every fact. Refuses once the landscape has been hand-edited |
353
- | `loam list [services\|features\|capabilities\|glossary]` | `--archived` `--needs-work` `--review-order` `--subsystem <name>` `--owners <path>` | What is in the docs repo, and what is missing from it. `capabilities` rolls up who realizes each promise; `glossary` rolls up each term with the documents that cite it |
539
+ | `loam list [services\|features\|capabilities\|glossary\|suites]` | `--archived` `--needs-work` `--review-order` `--subsystem <name>` `--owners <path>` | What is in the docs repo, and what is missing from it. `capabilities` rolls up who realizes each promise; `glossary` rolls up each term with the documents that cite it; `suites` groups the use cases by `#suite-` tag and names the services each suite needs up (`loam list suites <name>` shows one) |
354
540
  | `loam status [<FEAT>]` | `--service <id>` | Where the work stands and what to do next, as a projection over the two gates. Each `next[]` row has an `execution` object that says whether it is runnable, where, and what input or edit is still needed. Derived every run; writes nothing |
355
541
  | `loam doctor` | — | Read-only preflight for runtime, config, docs-repo access, fleet roots, counts, and the current service binding. Blockers exit 1; incomplete optional bindings stay warnings |
356
542
  | `loam dependencies [<FEAT>]` | — | The active-feature dependency graph and same-identity conflicts, derived from requirement deltas and OpenAPI operationIds |
357
- | `loam diff` | `--base <ref>` | Semantic diff of the living docs against a base git ref of the docs repo — the review lens for a docs-repo PR, with the current consumers of every removal named. Exit 1 on a removal the fleet still consumes |
543
+ | `loam diff` | `--base <ref>` | Semantic diff of the living docs against a base git ref of the docs repo — the review lens for a docs-repo PR, with the authored consumers of every removal, deprecation and contract change named. Exit 1 on a removal the fleet still consumes |
358
544
  | `loam explore [<service>...]` | `--op <operationId>` `--capability <id>` `--as <FEAT>` | Read the fleet around a change nobody has written down yet: the ring one hop out, each service's maturity and living operations, the features already in flight over the same ground, and the `loam new` line the seeds imply |
359
545
  | `loam context <service>` | `--feature <FEAT>` | Assemble one service's docs slice — living requirements verbatim, both contracts, the fleet edges around it, permissions, capabilities, provenance, and every active feature's delta over it — as one deterministic briefing |
360
546
  | `loam steps` | `--service <id>` `--duplicates` `--json` | Inventory the step phrases of one service's scenarios: how many distinct steps its suite is written in, how few definitions cover most of them, and which phrases differ only by an article or a trailing clause. Reads the living specs, writes nothing — the work-list a team writes its step definitions from, diffed against the optional `services/<svc>/steps.yaml` catalogue when one exists |
361
- | `loam instructions [<workflow>] [args...]` | `--no-fix-tables` | Print one of the six workflow protocols, the separate `loam-report` support protocol, or one of the four reference pages `loam-codes`, `loam-spine`, `loam-authoring` and `loam-done-check`, version-matched to this binary. Workflow `$1`/`$2` placeholders are filled; support/reference pages take no arguments. Reads no config. `--no-fix-tables` collapses the per-code fix tables to a line each, keeping the paragraph that says which scope graded them: `loam-check`'s page goes 84,151 bytes to 3,541, while a support/reference page holds no such table and comes back byte-identical |
362
- | `loam explain [<subject>]` | `--codes` | Explain a finding code, a refusal code, or a concept term. Most finding prose is parsed at runtime from the shipped fix tables, so it cannot drift from the binary; the `doctor.*`, `next.*`, `diff.*` and `gate.*` families, which no fix table grades, are answered from a registry written beside them. Every text-mode refusal prints `<code> · loam explain <code>` on stderr and every non-`ok` finding line carries its code in parentheses, so the lookup is reachable without re-running under `--json`. Omit the subject to list the terms; `--codes` lists the whole vocabulary — 293 finding codes and 46 refusal codes, each row the same answer `explain <code> --json` gives for that one |
547
+ | `loam instructions [<workflow>] [args...]` | `--no-fix-tables` | Print one of the six workflow protocols, the separate `loam-report` support protocol, or one of the four reference pages `loam-codes`, `loam-spine`, `loam-authoring` and `loam-done-check`, version-matched to this binary. Workflow `$1`/`$2` placeholders are filled; support/reference pages take no arguments. Reads no config. `--no-fix-tables` collapses the per-code fix tables to a line each, keeping the paragraph that says which scope graded them: `loam-check`'s page, almost all of it fix tables, comes back in a few kilobytes, while a support/reference page holds no such table and comes back byte-identical |
548
+ | `loam explain [<subject>]` | `--codes` | Explain a finding code, a refusal code, or a concept term. Most finding prose is parsed at runtime from the shipped fix tables, so it cannot drift from the binary; the `doctor.*`, `next.*`, `diff.*` and `gate.*` families, which no fix table grades, are answered from a registry written beside them. Every text-mode refusal prints `<code> · loam explain <code>` on stderr and every non-`ok` finding line carries its code in parentheses, so the lookup is reachable without re-running under `--json`. Omit the subject to list the terms; `--codes` lists the whole vocabulary — every finding code and every refusal code it can answer, each row the same answer `explain <code> --json` gives for that one |
363
549
  | `loam open` | `--root <dir>` `--out <file>` `--force` | Write a `.code-workspace` joining the docs repo and every service checkout whose committed `loam.json` binds to it. Never overwrites without `--force` |
364
- | `loam mcp` | `--author` | Serve fourteen read tools, version-matched instruction resources and a declared envelope output schema over MCP. `--author` adds `new`, `rebase`, `gherkin` and an archive dry-run; it never exposes `vouch`, verification recording or a committing archive — [the MCP server](WORKFLOW.md#the-mcp-server) |
365
- | `loam new <FEAT>` | `--title <text>` `--touches <id>` `--new-service <id>` `--capability <id>` | Scaffold a feature: intent, C4 delta, a requirement delta per service named by `--touches`/`--new-service`, and a capability delta per promise named by `--capability` (all repeatable) |
550
+ | `loam mcp` | `--author` | Serve sixteen read tools, version-matched instruction resources and a declared envelope output schema over MCP. `--author` adds `new`, `rebase`, `gherkin` and an archive dry-run; it never exposes `vouch`, verification recording or a committing archive — [the MCP server](WORKFLOW.md#the-mcp-server) |
551
+ | `loam new <FEAT>` | `--title <text>` `--touches <id>` `--new-service <id>` `--capability <id>` `--modifies <Req-ID>` | Scaffold a feature: intent, C4 delta, a requirement delta per service named by `--touches`/`--new-service`, and a capability delta per promise named by `--capability` (all repeatable). `--modifies` copies a touched service's living requirement into an uncommented `## MODIFIED Requirements` block with its `Based-On:` pin already set, so a small change is new → edit → archive; when every touched service is rewritten that way and nothing is introduced, no `delta.likec4` is written |
366
552
  | `loam show <service\|FEAT>` | `--type <kind>` | Everything loam knows about one service or feature. A feature's JSON includes a semantic `review` pack: intent, exact architecture objects, API/event slices, dependencies, artifacts, verification, blockers and next actions. `--type` forces an ambiguous reading |
367
553
  | `loam subsystem <verb> [names...]` | `--into <name>` `--under <name>` `--title <text>` `--description <text>` `--owner <name>` | Manage the grouping tree under `services/` — a navigable tree no identity depends on. `new`/`rm`, `move … --into`, `rename`, `list`, `history`, `sync` |
368
- | `loam adopt` | `--service <id>` `--subsystem <name>` `--targets` | Brief an agent to write this service's baseline into the docs repo as `draft`: the target paths, the grammar of each, what the landscape already says — and, for an element no edge touches, the edges the service's own model.likec4 attests — and the checks that follow. Writes nothing. `--targets` narrows it to what varies by service — the walk, the 52 checks and the seventeen statements of what nothing checks are the same bytes everywhere, so a `full` field names the one run that carries them: 54,833 bytes to 20,062 on the example fleet's payment-service (measured 2026-09-04) |
554
+ | `loam adopt` | `--service <id>` `--subsystem <name>` `--targets` | Brief an agent to write this service's baseline into the docs repo as `draft`: the target paths, the grammar of each, what the landscape already says — and, for an element no edge touches, the edges the service's own model.likec4 attests — and the checks that follow. Writes nothing. `--targets` narrows it to what varies by service — the walk, the 52 checks and the seventeen statements of what nothing checks are the same bytes everywhere, so a `full` field names the one run that carries them. Both sizes, for the example fleet's payment-service, are in the payload table of [docs/BENCHMARKS.md](https://github.com/ybotok/loam/blob/main/docs/BENCHMARKS.md#what-an-agent-is-handed--payload-sizes), which a test regenerates from the tree |
369
555
  | `loam delta <FEAT>` | `--service <id>` | Project a feature onto one service: the intent, its requirement deltas with every body and Given/When/Then line verbatim, the endpoints it adds or retires, and the edges around it. Doubles as a coding-agent task |
556
+ | `loam tasks <FEAT>` | `--service <id>` `--next` | The same checklist `loam verify` grades, read forwards: one work unit per promise the feature makes, each carrying the step it waits on (`describe`, `generate`, `implement`, `attested`) and the fact that closes it — only a confirmed claim in a non-stale verification record retires one, and an attested scenario stays visible. Derived every run and writes nothing. `--service` is a pure lens that adds what this service is waiting on elsewhere; the frontier orders providers before consumers as advice, never a lock. The per-unit work packet, and `--next` is the single leaf packet an orchestrator hands a coding agent |
370
557
  | `loam gherkin [<FEAT>]` | `--service <id>` `--dry-run` | Emit spec scenarios as digest-stamped Gherkin `.feature` files into the service repo's `<gherkinDir>/loam/` |
371
558
  | `loam rebase [<FEAT>]` | `--service <id>` `--dry-run` `--living` | Pin the feature to the living versions it was written against, on the requirement axis and the contract axis. `--living` takes no feature: it pins the living corpus's `Realizes:` entries to the capability requirements they name, which is what makes `capability.realizes-stale` able to fire later |
372
559
  | `loam validate [<id>]` | `--service <id>` `--feature <id>` `--all` `--base <ref>` `--strict` `--errors-only` | Validate one service or feature, or the whole fleet in one run. JSON findings carry `locations[]`: an exact primary location when the check knows one, otherwise the narrowest proved scope. `--base` is the adoption ratchet, not a substitute for `loam diff`; `--strict` exits 1 on warnings; `--errors-only` drops the `ok` confirmations from the text view, keeping every warning |
373
560
  | `loam verify <FEAT>` | `--record <file>` `--results <file>` `--contract-results <file>` `--diff-answers <files...>` `--service <id>` | The done-check: derive a checklist of the feature's own promises, and record the answers with their evidence. `--results`/`--contract-results` answer claims from a test report; `--diff-answers` cross-examines two blind answer sets |
374
561
  | `loam vouch` | `--service <id>` `--yes` `--pack` `--sample <n>` | The human promotion `draft` → `verified`: stamp a living spec against the code it was written from. `--pack` prints the re-vouch reading pack; `--sample <n>` records a partial read as one. Run in the service's own repo |
375
- | `loam gate` | `--service <id>` `--strict` | Can this service deploy? A pure query over recorded evidence for deploy pipelines outside loam's lifecycle. Executes nothing, writes nothing; errors exit 1, warnings stay advisory |
562
+ | `loam gate` | `--service <id>` `--since <ref>` `--strict` | Can this service deploy? A pure query over recorded evidence for deploy pipelines outside loam's lifecycle. Executes nothing, writes nothing; errors exit 1, warnings stay advisory. Without `--since` it grades in-flight features only; `--since` (the docs commit the last deploy recorded) adds every feature archived after it |
376
563
  | `loam archive <FEAT>` | `--approve` `--dry-run` | Merge a shipped feature into the living specs, API, events, business tree and landscape; gated on what only the computed merge can see. `--approve` overrides the judgement calls, never the mechanical losses |
377
564
  | `loam unarchive <FEAT>` | `--force` | Take that back: restore the living docs from the snapshot archive left behind, and re-open the feature |
378
565
  | `loam audit-openspec <root>` | `--write-mapping <path>` | Read-only inventory of an OpenSpec checkout/workspace/Store checkout. `--write-mapping` emits the decision skeleton you fill in |
@@ -398,7 +585,9 @@ repo it runs in, every `init` writes pointers for the six workflow bodies (`loam
398
585
  twenty-one targets**: as a command file you type — `/loam-check` for most, `/loam:check` where the
399
586
  tool namespaces by directory, `@loam-check` in Amazon Q's prompt library — and as an Agent Skill
400
587
  at `<tool-dir>/skills/loam-<x>/SKILL.md`, which the model loads by itself when the task matches. Two
401
- targets are skills only: Codex reads `.codex/skills/` and loads no custom command files, and
588
+ targets are skills only: Codex loads no custom command files, and its target writes
589
+ `.codex/skills/` — a root Codex still reads but no longer documents (its skills page names only
590
+ `.agents/skills`; select `agents` too if you want the documented one) — and
402
591
  `agents` is not a tool at all but the vendor-neutral `.agents/skills/` root that Cursor, GitHub
403
592
  Copilot, Codex, Gemini CLI, Zed and Roo Code each document reading — one copy those six share
404
593
  instead of six copies of the same bytes. `--no-commands` and `--no-skills` each suppress one
@@ -436,29 +625,31 @@ run. That split exists because the two go stale in opposite directions and only
436
625
  fixable: embedded protocol text eventually describes a different loam with total confidence, while
437
626
  the command cannot. Pointing at the binary is also what makes the protocol
438
627
  affordable to load: `loam instructions loam-check --no-fix-tables` prints the same page with its
439
- per-code fix tables collapsed to a line each — 84,151 bytes down to 3,541 — and
440
- `loam explain <code> --json` answers, in 473 bytes, whichever two or three of those rows a run
441
- actually reported. A copy frozen into the generated file would have charged the full 84 KB every
442
- session, and gone stale doing it. `AGENTS.md` itself was the one generated file that argument did
628
+ per-code fix tables collapsed to a line each — from a page that is almost all tables down to a few
629
+ kilobytes — and `loam explain <code> --json` answers, one code at a time, whichever two or three of
630
+ those rows a run actually reported. What each of those costs in bytes and tokens, page by page, is
631
+ [docs/BENCHMARKS.md](https://github.com/ybotok/loam/blob/main/docs/BENCHMARKS.md)'s payload table,
632
+ generated from the tree rather than typed. A copy frozen into the generated file would have charged
633
+ the whole page every session, and gone stale doing it. `AGENTS.md` itself was the one generated file that argument did
443
634
  not reach — it was the process contract *and* the reference manual, and every session paid for all
444
635
  of it — so four **reference pages** now come out of the binary instead, printed by
445
636
  `loam instructions`: `loam-codes` (which codes each invocation can raise), `loam-spine` (every join
446
637
  between the artifacts, and the `Based-On:` pins), `loam-authoring` (`arch.spec.md`, the generated
447
638
  Gherkin suite, frontmatter) and `loam-done-check` (how `loam verify` derives its claims, and
448
639
  verified versus attested). What stayed is what a reader needs to form a question at all: the layout,
449
- the cycle, which element is which service, the validator's rules and the archive gate. The current
450
- orientation is **8,762 bytes**, below both the 32,768-byte Codex chain limit and the smaller 12,000
451
- workspace-rule ceiling. Detailed pages are fetched only when the task reaches them. `loam init`
640
+ the cycle, which element is which service, the validator's rules and the archive gate. The
641
+ orientation stays below both the 32,768-byte Codex chain limit and the smaller 12,000-byte
642
+ workspace-rule ceiling — `test/agents.test.ts` fails the build the day it does not. Detailed pages are fetched only when the task reaches them. `loam init`
452
643
  writes **no file** for a reference page: a page printed on demand describes the loam you are
453
644
  running, not the one that scaffolded the repository.
454
645
 
455
646
  The code inventory is that same split applied twice, and the largest page is what it left behind.
456
- `loam instructions loam-codes` lists which codes each invocation can raise — 331 of the 335 the
457
- scaffolded docs name between them, the one fact no other surface carries — and no longer says what
647
+ `loam instructions loam-codes` lists which codes each invocation can raise — nearly every code the
648
+ scaffolded docs name, and the one fact no other surface carries — and no longer says what
458
649
  any of them means, because `loam explain <code>` answers that from the binary actually running and a
459
650
  paragraph written once at `init` cannot. Dropping the duplicated gloss came first and took the file
460
651
  from 120,896 bytes to 109,399; moving the inventory off it took the remaining 79,679. The OpenSpec
461
- migration codes keep their notes inline on the page, because they are 49 of the 51 codes
652
+ migration codes keep their notes inline on the page, because they are almost all of the codes
462
653
  `loam explain` does not answer yet, and a pointer to an explanation that does not exist is worse
463
654
  than the prose it replaced.
464
655
 
@@ -488,15 +679,21 @@ always preserved byte for byte, with the entry printed for manual merge.
488
679
  - [COMPARISON.md](COMPARISON.md) — where loam fits beside architecture-as-code tools, software and
489
680
  event catalogs, contract verification and diff engines, requirements traceability, and code-level
490
681
  architecture checks. Each is treated as a neighbouring specialist, not an opponent loam needs to
491
- replace.
682
+ replace. One dated section sets out what the spec-driven change tools — OpenSpec, Spec Kit and
683
+ Kiro — each offer for a change that crosses repositories, what is still open upstream, and where
684
+ loam differs.
492
685
  - [MIGRATING-from-OpenSpec.md](MIGRATING-from-OpenSpec.md) — moving an OpenSpec repo onto loam: what
493
686
  maps, what is lost, what must be added.
494
687
  - [ROADMAP.md](ROADMAP.md) — the evidence-backed improvement plan, priorities, non-goals and exit
495
688
  criteria.
496
- - [CHANGELOG.md](CHANGELOG.md) — released beta.1–alpha.7 plus the changes on `main` under
689
+ - [CHANGELOG.md](CHANGELOG.md) — released beta.1–alpha.9 plus the changes on `main` under
497
690
  `[Unreleased]`.
691
+ - [docs/SERVICE-TEAMS.md](https://github.com/ybotok/loam/blob/main/docs/SERVICE-TEAMS.md) — one
692
+ screen for a team whose repository is one service in the fleet: the commands, the slash
693
+ commands, what to know before vouching, and the codes they will actually meet.
498
694
  - [docs/BENCHMARKS.md](https://github.com/ybotok/loam/blob/main/docs/BENCHMARKS.md) — what a
499
- fleet-sized run costs, with the method, the machine and the committed runs behind every number.
695
+ fleet-sized run costs, with the method, the machine and the committed runs behind every number,
696
+ and what each payload loam hands an agent weighs in bytes and tokens.
500
697
 
501
698
  ## Development
502
699
 
@@ -509,9 +706,9 @@ npm run arch:check # package-level dependency graph stays acyclic
509
706
  npm test # vitest
510
707
  npm run test:coverage # full src/**/*.ts coverage with enforced thresholds
511
708
  npm run test:package # clean, pack, install the tarball, run its loam binary
512
- # optional, against the exact upstream checkout named in MIGRATING-from-OpenSpec.md (the
513
- # flag matters: --baseline defaults to canary, and the sweep refuses a checkout
514
- # at any other HEAD):
709
+ # optional, against the exact upstream checkout named in MIGRATING-from-OpenSpec.md
710
+ # (--baseline defaults to release, the certified pin; every pinned baseline refuses a
711
+ # checkout at any other HEAD, and only --baseline latest sweeps an unpinned one):
515
712
  npm run test:openspec-corpus -- --baseline release /path/to/OpenSpec
516
713
  ```
517
714
 
@@ -529,15 +726,17 @@ authored-capability axes with the `Realizes:` join, use cases graded as `dynamic
529
726
  `architecture/obligations.yaml` architectural obligations checked through `#obl-` tags and
530
727
  `Covers:`. Known limits, each with its owner in [ROADMAP.md](ROADMAP.md): the scheduled CI
531
728
  `stability` job has still to be observed green. Speculative `render`, health composition and UI
532
- generation come later. Behind that status stand **174 test files** (counted 2026-09-07): the count is graded
729
+ generation come later. Behind that status stand **190 test files** (counted 2026-10-20): the count is graded
533
730
  against a live readdir by `test/docs-facts.test.ts`, so this sentence fails the suite the moment it
534
731
  trails the tree.
535
732
 
536
- The package is published as [`@ybotok/loam`](https://www.npmjs.com/package/@ybotok/loam), currently
537
- `0.2.0-alpha.7`: the unscoped `loam` name is taken by an unrelated GDAL wrapper, so the package ships
538
- under the maintainer's own npm user scope. Releases are tag-driven and maintainer-only
539
- ([CONTRIBUTING.md](CONTRIBUTING.md)); the version this line names is pinned to `package.json` by a
540
- drift test, so it cannot silently trail a release.
733
+ The package is published as [`@ybotok/loam`](https://www.npmjs.com/package/@ybotok/loam): the
734
+ unscoped `loam` name is taken by an unrelated GDAL wrapper, so the package ships under the
735
+ maintainer's own npm user scope. Releases are tag-driven and maintainer-only
736
+ ([CONTRIBUTING.md](CONTRIBUTING.md)). This checkout is `0.2.0-alpha.9` — a version pinned to
737
+ `package.json` by a drift test, so it is always the version of the checkout you are reading, and for
738
+ that reason it says nothing about whether that version reached npm.
739
+ `npm view @ybotok/loam dist-tags` is the answer to what installs.
541
740
 
542
741
  ## Contributing
543
742
 
package/ROADMAP.md CHANGED
@@ -18,11 +18,11 @@ acceptance tests, and implementation evidence remain ordinary files in repositor
18
18
  state inside a service. The CLI is small enough to audit, and every writer — not only archive — now
19
19
  commits through a locked, journaled transaction that a crash cannot leave half-applied.
20
20
 
21
- The tree contains **468 TypeScript modules in 144 source packages**, with an acyclic package graph
21
+ The tree contains **500 TypeScript modules in 155 source packages**, with an acyclic package graph
22
22
  checked by
23
23
  [scripts/package-graph.mjs](https://github.com/ybotok/loam/blob/main/scripts/package-graph.mjs). The
24
- CLI exposes **29 commands** from [src/cli.ts](https://github.com/ybotok/loam/blob/main/src/cli.ts),
25
- and the suite stands at **174 test files**. Those four counts are deliberately stated OUTSIDE the
24
+ CLI exposes **30 commands** from [src/cli.ts](https://github.com/ybotok/loam/blob/main/src/cli.ts),
25
+ and the suite stands at **190 test files**. Those four counts are deliberately stated OUTSIDE the
26
26
  dated snapshot below: each derives from the tree in one readdir, so
27
27
  [test/docs-facts.test.ts](https://github.com/ybotok/loam/blob/main/test/docs-facts.test.ts) grades
28
28
  them live and this paragraph cannot quietly trail the code the way its predecessor did.
@@ -128,10 +128,57 @@ Closed since the 2026-08-18 assessment, each with the commit or commit range tha
128
128
  `main`. [CHANGELOG.md](CHANGELOG.md) is the user-facing record; the full item texts — required
129
129
  changes, exit criteria, and what each review surfaced — are in this file's history (`git show
130
130
  5cd3942:ROADMAP.md`). The four 2026-09-03 problem-report entries that follow — the extending model
131
- and the report ordinal, which open the list — landed together in `f751909`, one change built as
132
- four disjoint workstreams and gated as one; the three before them — the edgeless brief, the
133
- intra-service use case, and the styling paragraph under the generated views — landed together in
134
- `0eaa101` the same way.
131
+ and the report ordinal, the pair opening the 2026-09-04 group — landed together in `f751909`, one
132
+ change built as four disjoint workstreams and gated as one; the three before them — the edgeless
133
+ brief, the intra-service use case, and the styling paragraph under the generated views — landed
134
+ together in `0eaa101` the same way.
135
+
136
+ #### The work packet — the verify checklist read forwards
137
+
138
+ **Landed 2026-09-21.** loam could already say what a feature PROMISES (`loam verify`'s checklist)
139
+ and what to BUILD (`loam delta`), and nothing joined the two into the question an agent actually
140
+ opens a session with: which promise is still open, at which step, and what fact closes it. The
141
+ artifact a team reaches for to answer it is a `tasks.md` — the one document this project refuses,
142
+ because a task list authored beside a spec is a second mutable state that drifts the moment the
143
+ spec moves. That refusal (SCHEMA's "Deliberate limits of the workflow surface") is unchanged; what
144
+ this item settles is that the question was never the problem, only the file.
145
+
146
+ **What landed.** A read-only `loam tasks <FEAT> [--service <id>] [--next] [--json]`, and a
147
+ `loam_tasks` MCP tool beside it, projecting one work unit per verify-checklist claim under the
148
+ claim's own id — so the thing to do and the answer that closes it are one identity — plus a unit
149
+ of kind requirement.described for an ADDED or MODIFIED requirement with no scenario at all. Each
150
+ unit reports the step it waits on in `at` (`describe`, `generate`, `implement`, `attested`), and a
151
+ unit is retired by exactly one fact: a claim recorded `confirmed` in a `verification.yaml` that is
152
+ not stale against the current checklist. An agent-attested scenario deliberately stays on the list
153
+ at `attested`. `frontier` is the first ten open units, providers before consumers on the exact token
154
+ join and never on prose, and the order is advice rather than a lock; `--next` is the single leaf
155
+ packet — scenario verbatim, digest, the check that closes it, the follow-up command — that an
156
+ orchestrator hands one coding agent. Nothing is written to disk on any path, and no stable code was
157
+ minted: every fact in the payload is a projection of state other commands already grade. CHANGELOG
158
+ has every flag and payload key; SCHEMA's "The same checklist read forwards" has the unit model and
159
+ the done rule.
160
+
161
+ **Deliberately NOT built, each with its reason.** None of these is a gap nobody noticed.
162
+
163
+ - **`--results` refinement against a live red/green run** — it needs the report readers re-exposed
164
+ read-only, which is a seam rather than a flag.
165
+ - **A status rung for tasks in `loam status`'s `next[]`** — that is a new stable `next.*` code, and
166
+ minting one is a separate decision on a frozen surface.
167
+ - **Removal-direction units** — a retirement's consumers are answered in prose by the consumer
168
+ scans today, and a unit would be a second account of the same walk.
169
+ - **Obligation-coverage units** — `covers()` never checks that a scenario exists, so a unit derived
170
+ from an obligation would assert work nothing grades.
171
+ - **A `size.phrasesOwed` figure from `loam steps`** — the step inventory is a report about a
172
+ service's whole suite, not about one feature's units, and joining them would put a fleet-wide
173
+ number inside a per-feature packet.
174
+ - **A Jira (or any tracker) export protocol** — that is an agent workflow over `--json` and stays
175
+ one: an HTTP call from loam is the network dependency the product does not have.
176
+
177
+ **Exit criteria**, each answerable by one run rather than by a reading: a unit leaves the list only
178
+ when a confirmed claim in a non-stale record retires it, and an attested scenario is still on the
179
+ list at `attested`; the frontier's provider-before-consumer order comes from the exact operation
180
+ token join and from nowhere else; and a run writes no byte and mints no code, so the projection
181
+ cannot be behind the documents it projected.
135
182
 
136
183
  #### One model, many documents — a service model may extend the fleet map
137
184
 
@@ -696,6 +743,35 @@ item gets promoted — it went from here to `## Now` and from there to
696
743
  five-file-capped package, so a new non-ok code forces a split-module commit before any behaviour
697
744
  can land, and that split should be chosen for a seam rather than for a code. Promote when a second
698
745
  fleet reports a flow that rendered and was graded by nothing.
746
+ - **What the closed `flows-dynamic-views` branch had and main still lacks.** The branch drew
747
+ cross-service journeys as fleet-level dynamic views before main grew its own use-case axis; it was
748
+ closed as superseded on 2026-10-10, its one piece main lacked outright — suites, the participant
749
+ union a test stand needs — was ported onto that axis (`#suite-<name>`, `loam list suites`), and its
750
+ reference implementation stays reachable at the tag `archive/flows-dynamic-views` — commit
751
+ `d90b6f9`, the closed branch's head, which is the name to use where the tag was never fetched
752
+ (`git show d90b6f9:<path>`). Five things remain, and each waits for the same evidence — pilot
753
+ teams actually writing tagged use cases — because each would freeze a code, a grammar or a
754
+ generated file, and the two checks among them are advisory heuristics:
755
+ - **Per-view outcome counting against scenarios** — a view's `alt`/`opt`/`try` arms summed (not
756
+ multiplied) and compared with the scenarios covering it (it would be spelled
757
+ usecase.outcomes-uncovered, warn). `core/c4/parsed/dynamic-views.ts` flattens the block tree
758
+ it would need, and the count says how many outcomes lack a scenario, never which. Waits for
759
+ flows with branches being written and a team asking which outcomes go untested.
760
+ - **A feature-scope warning for a `#FEAT` cross-service edge no journey traverses** (it would be
761
+ spelled usecase.edge-unrepresented, adopt-gated on the fleet having a tagged use case). Main sees
762
+ only the removal direction (`diff.op-removed-consumed`). Waits for a fleet whose journeys are
763
+ kept at all — on one with none it is noise.
764
+ - **`Covers: view:<id>`** — a join from an arch-axis requirement to a journey that needs no
765
+ capability axis. It runs the opposite way to `#req-` (two answers to "what covers this flow"),
766
+ and a bare view id can now be stolen by a service-local view of the same name. Waits for
767
+ evidence that legacy teams will not write `capabilities/` — the one case where main has no way
768
+ to join a cross-service flow to a runner-verified arch-level outcome.
769
+ - **Generated per-suite views** (a `flow-groups.likec4`, a sync verb, a staleness code) —
770
+ rendering only. Waits for a team asking to SEE a suite rather than list it.
771
+ - **Changing an existing journey through a feature** (replace by view id, with a conflict
772
+ warning). Main declined it on purpose — the feature route is create-only and an existing flow is
773
+ edited in the pull request — and it waits for concurrent journey edits conflicting more often
774
+ than review absorbs.
699
775
  - **Landscape scaling:** retain one landscape while conflicts are exceptional, and half of what
700
776
  this row once asked for arrived on 2026-09-04. Per-service internals now live in
701
777
  `services/<svc>/model.likec4` by default: `loam archive` routes a delta's fqn-spelled interior