@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,123 @@
1
+ /**
2
+ * Does this spec still describe the code it points at?
3
+ *
4
+ * One spec, read against the sources it declares. It answers only about what it
5
+ * could check, and says which sources it skipped — a vouch over a spec whose
6
+ * sources could not be read would be the claim this command exists to prevent.
7
+ */
8
+ import { listField, parseFrontmatter } from "../../../core/document/frontmatter.js";
9
+ import { missingSources, patternSources, unsafeSources } from "../../../core/provenance/sources.js";
10
+ import { emptySourcesMessage, sourcesDigest } from "../../../core/provenance/stamp.js";
11
+ import { NotUtf8Error, readUtf8 } from "../../../core/staging/writes.js";
12
+ /**
13
+ * "There is no living spec here", in one sentence.
14
+ *
15
+ * Three callers reach this state independently — the stamp (`../run.ts`), the
16
+ * reading list (`../sample/plan.ts`) and the reading pack (`../pack/pack.ts`)
17
+ * — and two of them carried a comment promising to keep the wording identical
18
+ * to the third, which is a promise nothing could enforce. It lives in the leaf
19
+ * all three already import, because the failure this repo has actually shipped
20
+ * is four copies of an enumeration `catch` that looked identical for years
21
+ * while a fix landed in one of them: a `--sample` run refusing a missing spec
22
+ * with older advice than a bare run gives is the same defect, one flag wide.
23
+ */
24
+ export function noLivingSpecMessage(specPath, service) {
25
+ return `No living spec at ${specPath}. Run \`loam adopt\` for '${service}' first.`;
26
+ }
27
+ /**
28
+ * The per-file half of the refusal discipline: everything vouch cannot verify
29
+ * about ONE spec file, checked the same way for spec.md and arch.spec.md.
30
+ */
31
+ export async function verifySpec(req, path, file) {
32
+ // Through readUtf8, so the round trip below is exact: the stamp is computed
33
+ // from `raw` and the race check compares `Buffer.from(raw)` against the bytes
34
+ // on disk, which only agree if the file decoded without substitutions. A
35
+ // non-UTF-8 spec is refused by name rather than stamped as verified with
36
+ // every undecodable byte replaced. Refused HERE rather than left to the CLI's
37
+ // top-level handler, which would report a diagnosable state as `internal`.
38
+ // What it replaces is a diagnosis that was worse than none: a UTF-16 spec
39
+ // decoded to a document with no frontmatter loam could find, so vouch refused
40
+ // it as `sources-absent` — "names no sources" — over a file whose `sources:`
41
+ // line is right there.
42
+ let raw;
43
+ try {
44
+ raw = await readUtf8(path);
45
+ }
46
+ catch (err) {
47
+ if (!(err instanceof NotUtf8Error))
48
+ throw err;
49
+ return {
50
+ ok: false,
51
+ code: "repository-unavailable",
52
+ message: `${req.service}: ${file} cannot be vouched for — ${err.message}`,
53
+ };
54
+ }
55
+ const fm = parseFrontmatter(raw);
56
+ // Before any sources reasoning: a header that does not parse hides whatever
57
+ // fields the author wrote, so "names no sources" would be a false diagnosis —
58
+ // and if the file ever reached the stamp, withFrontmatterFields' rule for
59
+ // unreadable headers is replace-don't-merge, which would silently discard the
60
+ // author's owner/service/sources lines. Refuse before the write path can see
61
+ // the file. The code stays `sources-absent` — for vouch's purposes the
62
+ // sources ARE unreadable-hence-absent, and the message carries the real
63
+ // diagnosis — rather than minting a new ErrorCode for one refusal.
64
+ if (fm.malformed) {
65
+ return {
66
+ ok: false,
67
+ code: "sources-absent",
68
+ message: `${req.service}: ${file} has a frontmatter block that cannot be read as YAML — ` +
69
+ `its fields (\`sources\` included) are unreadable, and stamping would rewrite the header wholesale, ` +
70
+ `losing what the author wrote. Fix the YAML between the \`---\` fences ` +
71
+ `(\`loam validate\` reports it as \`frontmatter.malformed\`), then re-run.`,
72
+ };
73
+ }
74
+ const sources = listField(fm, "sources");
75
+ if (sources.length === 0) {
76
+ return {
77
+ ok: false,
78
+ code: "sources-absent",
79
+ message: `${req.service}: ${file} names no sources — there is nothing to vouch it against. Add \`sources:\` naming the code it was written from.`,
80
+ };
81
+ }
82
+ // spec.md's refusals predate the second axis and keep their exact wording;
83
+ // where they did not name the file, only the newer axis adds it.
84
+ const label = file === "spec.md" ? req.service : `${req.service}: ${file}`;
85
+ // Before the existence check: a pattern is not a path that "does not exist",
86
+ // it is an entry loam no longer reads at all, and the refusal has to say so.
87
+ const patterns = patternSources(sources);
88
+ if (patterns.length > 0) {
89
+ return {
90
+ ok: false,
91
+ code: "sources-path-missing",
92
+ message: `${label}: ${patterns.length} source(s) are glob patterns — ${patterns.join(", ")}. Patterns are no longer supported: name files or directories (a directory already covers everything beneath it). A stamp over a pattern would vouch for a file set nobody can be sure of.`,
93
+ };
94
+ }
95
+ const unsafe = unsafeSources(req.repoDir, sources);
96
+ if (unsafe.length > 0) {
97
+ return {
98
+ ok: false,
99
+ code: "sources-path-missing",
100
+ message: `${label}: ${unsafe.length} source(s) escape the service repo — ${unsafe.join(", ")}. Sources must be relative paths contained by this repository, including through symlinks; vouch will not hash files outside it.`,
101
+ };
102
+ }
103
+ const missing = missingSources(req.repoDir, sources);
104
+ if (missing.length > 0) {
105
+ return {
106
+ ok: false,
107
+ code: "sources-path-missing",
108
+ message: `${label}: ${missing.length} source(s) do not exist — ${missing.join(", ")}. Vouching now would stamp a claim about code that is not there.`,
109
+ };
110
+ }
111
+ const { digest, index, skipped } = await sourcesDigest(req.repoDir, sources);
112
+ if (index.length === 0) {
113
+ // A directory that exists but holds no files — or only ones the walk leaves
114
+ // out: dot-entries, `node_modules`, anything the repository itself ignores.
115
+ // The paths "resolve", but a digest over nothing never changes, so the stamp
116
+ // would read as current forever. The sentence comes from provenance/stamp.ts so
117
+ // that `loam validate` can grade the same state in the same words instead of
118
+ // going green on a document this command refuses.
119
+ return { ok: false, code: "sources-absent", message: emptySourcesMessage(label, sources) };
120
+ }
121
+ return { ok: true, path, file, raw, sources, digest, index, skipped };
122
+ }
123
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../../src/commands/vouch/vet/verify.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Does this spec still describe the code it points at?\n *\n * One spec, read against the sources it declares. It answers only about what it\n * could check, and says which sources it skipped — a vouch over a spec whose\n * sources could not be read would be the claim this command exists to prevent.\n */\nimport { listField, parseFrontmatter } from \"../../../core/document/frontmatter.js\";\nimport type { PathableService } from \"../../../core/kernel/ids/service.js\";\nimport { missingSources, patternSources, unsafeSources } from \"../../../core/provenance/sources.js\";\nimport { emptySourcesMessage, sourcesDigest, type SourceIndexEntry } from \"../../../core/provenance/stamp.js\";\nimport type { SkippedSource } from \"../../../core/provenance/walk.js\";\nimport { NotUtf8Error, readUtf8 } from \"../../../core/staging/writes.js\";\n\nexport interface VerifiedSpec {\n ok: true;\n path: string;\n file: string;\n /** The file exactly as read — what the stamp is applied to. */\n raw: string;\n sources: string[];\n digest: string;\n /** Per-file shas, in digest order — what `sources_files` is stamped from. */\n index: SourceIndexEntry[];\n skipped: SkippedSource[];\n}\n\n/**\n * The two facts the vetting reads — not the whole VouchRequest, because the\n * reading pack (`../pack/pack.ts`) asks the same questions with no date or\n * identity to offer: a pack stamps nothing.\n */\nexport interface SpecVetting {\n service: PathableService;\n repoDir: string;\n}\n\n/**\n * The refusal half, spelled here rather than imported from `../contract.ts`:\n * this module is a LEAF two sibling consumers share — `run.ts` (the stamp) and\n * `pack/pack.ts` (the worklist) — which is why it lives in its own package,\n * and an import from the vouch package above it would close the exact\n * package-graph cycle the move exists to avoid. The codes are a subset of\n * VouchOutcome's refusal codes, so run.ts returns one of these unchanged.\n */\nexport interface SpecRefusal {\n ok: false;\n code: \"sources-absent\" | \"sources-path-missing\" | \"repository-unavailable\";\n message: string;\n}\n\n/**\n * \"There is no living spec here\", in one sentence.\n *\n * Three callers reach this state independently — the stamp (`../run.ts`), the\n * reading list (`../sample/plan.ts`) and the reading pack (`../pack/pack.ts`)\n * — and two of them carried a comment promising to keep the wording identical\n * to the third, which is a promise nothing could enforce. It lives in the leaf\n * all three already import, because the failure this repo has actually shipped\n * is four copies of an enumeration `catch` that looked identical for years\n * while a fix landed in one of them: a `--sample` run refusing a missing spec\n * with older advice than a bare run gives is the same defect, one flag wide.\n */\nexport function noLivingSpecMessage(specPath: string, service: string): string {\n return `No living spec at ${specPath}. Run \\`loam adopt\\` for '${service}' first.`;\n}\n\n/**\n * The per-file half of the refusal discipline: everything vouch cannot verify\n * about ONE spec file, checked the same way for spec.md and arch.spec.md.\n */\nexport async function verifySpec(\n req: SpecVetting,\n path: string,\n file: string,\n): Promise<VerifiedSpec | SpecRefusal> {\n // Through readUtf8, so the round trip below is exact: the stamp is computed\n // from `raw` and the race check compares `Buffer.from(raw)` against the bytes\n // on disk, which only agree if the file decoded without substitutions. A\n // non-UTF-8 spec is refused by name rather than stamped as verified with\n // every undecodable byte replaced. Refused HERE rather than left to the CLI's\n // top-level handler, which would report a diagnosable state as `internal`.\n // What it replaces is a diagnosis that was worse than none: a UTF-16 spec\n // decoded to a document with no frontmatter loam could find, so vouch refused\n // it as `sources-absent` — \"names no sources\" — over a file whose `sources:`\n // line is right there.\n let raw: string;\n try {\n raw = await readUtf8(path);\n } catch (err) {\n if (!(err instanceof NotUtf8Error)) throw err;\n return {\n ok: false,\n code: \"repository-unavailable\",\n message: `${req.service}: ${file} cannot be vouched for — ${err.message}`,\n };\n }\n const fm = parseFrontmatter(raw);\n // Before any sources reasoning: a header that does not parse hides whatever\n // fields the author wrote, so \"names no sources\" would be a false diagnosis —\n // and if the file ever reached the stamp, withFrontmatterFields' rule for\n // unreadable headers is replace-don't-merge, which would silently discard the\n // author's owner/service/sources lines. Refuse before the write path can see\n // the file. The code stays `sources-absent` — for vouch's purposes the\n // sources ARE unreadable-hence-absent, and the message carries the real\n // diagnosis — rather than minting a new ErrorCode for one refusal.\n if (fm.malformed) {\n return {\n ok: false,\n code: \"sources-absent\",\n message:\n `${req.service}: ${file} has a frontmatter block that cannot be read as YAML — ` +\n `its fields (\\`sources\\` included) are unreadable, and stamping would rewrite the header wholesale, ` +\n `losing what the author wrote. Fix the YAML between the \\`---\\` fences ` +\n `(\\`loam validate\\` reports it as \\`frontmatter.malformed\\`), then re-run.`,\n };\n }\n const sources = listField(fm, \"sources\");\n if (sources.length === 0) {\n return {\n ok: false,\n code: \"sources-absent\",\n message: `${req.service}: ${file} names no sources — there is nothing to vouch it against. Add \\`sources:\\` naming the code it was written from.`,\n };\n }\n\n // spec.md's refusals predate the second axis and keep their exact wording;\n // where they did not name the file, only the newer axis adds it.\n const label = file === \"spec.md\" ? req.service : `${req.service}: ${file}`;\n\n // Before the existence check: a pattern is not a path that \"does not exist\",\n // it is an entry loam no longer reads at all, and the refusal has to say so.\n const patterns = patternSources(sources);\n if (patterns.length > 0) {\n return {\n ok: false,\n code: \"sources-path-missing\",\n message: `${label}: ${patterns.length} source(s) are glob patterns — ${patterns.join(\", \")}. Patterns are no longer supported: name files or directories (a directory already covers everything beneath it). A stamp over a pattern would vouch for a file set nobody can be sure of.`,\n };\n }\n\n const unsafe = unsafeSources(req.repoDir, sources);\n if (unsafe.length > 0) {\n return {\n ok: false,\n code: \"sources-path-missing\",\n message: `${label}: ${unsafe.length} source(s) escape the service repo — ${unsafe.join(\", \")}. Sources must be relative paths contained by this repository, including through symlinks; vouch will not hash files outside it.`,\n };\n }\n\n const missing = missingSources(req.repoDir, sources);\n if (missing.length > 0) {\n return {\n ok: false,\n code: \"sources-path-missing\",\n message: `${label}: ${missing.length} source(s) do not exist — ${missing.join(\", \")}. Vouching now would stamp a claim about code that is not there.`,\n };\n }\n\n const { digest, index, skipped } = await sourcesDigest(req.repoDir, sources);\n if (index.length === 0) {\n // A directory that exists but holds no files — or only ones the walk leaves\n // out: dot-entries, `node_modules`, anything the repository itself ignores.\n // The paths \"resolve\", but a digest over nothing never changes, so the stamp\n // would read as current forever. The sentence comes from provenance/stamp.ts so\n // that `loam validate` can grade the same state in the same words instead of\n // going green on a document this command refuses.\n return { ok: false, code: \"sources-absent\", message: emptySourcesMessage(label, sources) };\n }\n return { ok: true, path, file, raw, sources, digest, index, skipped };\n}\n"]}
@@ -0,0 +1,176 @@
1
+ import { loadConfig } from "../../core/envelope/config.js";
2
+ import { fail, NO_SERVICE_MESSAGE, reportNoConfig } from "../../core/envelope/json.js";
3
+ import { gitIdentity } from "../../core/provenance/git.js";
4
+ import { today } from "../../core/provenance/stamp.js";
5
+ import { serviceTreePathOf } from "../../core/repo/service-target.js";
6
+ import { runPack } from "./pack/print.js";
7
+ import { confirmVouch } from "./prompt/confirm.js";
8
+ import { emitStampJson, printStamp } from "./report.js";
9
+ import { vouch } from "./run.js";
10
+ import { buildSamplePlan } from "./sample/plan.js";
11
+ import { printReadingList } from "./sample/print.js";
12
+ export function registerVouch(program) {
13
+ program
14
+ .command("vouch")
15
+ .description("Vouch for a service's living specs: stamp spec.md, and arch.spec.md when present, verified against the code they describe")
16
+ .option("--service <id>", "service to vouch for (defaults to the configured service)")
17
+ .option("--yes", "skip the confirmation — required when stdin is not a terminal, and still records `vouched_by`")
18
+ .option("--pack", "print the re-vouch reading pack — the doc-body diff since the last vouch, the source files that moved, and the sections already covered — then exit without vouching; read-only, nothing is stamped")
19
+ .option("--sample <n>", "vouch after reading a deterministic sample of <n> sections per spec file — the stamp records `vouch_scope: sampled`, `loam list` shows `vouched (sampled)`, and `loam validate` reports `sources.sampled-vouch` until a full vouch clears it")
20
+ .option("--json", "emit the machine contract instead of the human view")
21
+ .action(async (opts) => {
22
+ const json = opts.json === true;
23
+ const loaded = await loadConfig();
24
+ if (loaded.kind !== "loaded") {
25
+ reportNoConfig(json, loaded);
26
+ return;
27
+ }
28
+ const config = loaded.config;
29
+ const service = opts.service ?? config.service;
30
+ if (service === undefined) {
31
+ return fail(json, "invalid-option", NO_SERVICE_MESSAGE);
32
+ }
33
+ // Vouching hashes the code the doc was written from, so it can only run
34
+ // where that code is. From anywhere else the paths are someone else's.
35
+ //
36
+ // TWO conditions, two codes, and the split is the whole point. Both used
37
+ // to answer `invalid-option`, whose `loam explain` row says the
38
+ // invocation itself is wrong — contradictory flags, a mistyped one, a
39
+ // value that cannot be right. Here the invocation is perfectly correct
40
+ // and the REPOSITORY is the wrong one, so that code sent a user whose
41
+ // flags were fine off to re-read their flags, and left CI and agents
42
+ // unable to tell "run this in the service repo" from "you typed the flag
43
+ // wrong". `loam verify --record --service` already draws exactly this
44
+ // line for exactly this reason (see commands/verify/verify.ts); vouch
45
+ // and gherkin now answer the same pair, so a caller branching on
46
+ // `error.code` gets one answer from all three. The messages are
47
+ // unchanged — only the code moved.
48
+ if (config.service === undefined) {
49
+ return fail(json, "repository-unavailable", `Cannot vouch for '${service}' from here: this is not a service repo. \`sources\` resolve against the service's own repo — run it there.`);
50
+ }
51
+ if (config.service !== service) {
52
+ return fail(json, "service-mismatch", `Cannot vouch for '${service}' from here: this repo is '${config.service}'. \`sources\` resolve against the service's own repo — run it there.`);
53
+ }
54
+ // The repo root, not the cwd — see the comment on `repoDir` below; the
55
+ // identity has to be asked of the same directory the sources resolve in,
56
+ // or a subdirectory with its own git config would answer for it.
57
+ const repoDir = config.root ?? process.cwd();
58
+ // The flag's own grammar, before anything is read or hashed: `--sample`
59
+ // decides what the run CLAIMS, so a value nobody can read must not reach
60
+ // a stamp. Whole numbers only, and at least one — `0` is a vouch that
61
+ // read nothing, and there is already a way to record that (do not
62
+ // vouch). Checked before `--pack` below so a typo is refused the same
63
+ // way in both modes.
64
+ let sampleSize;
65
+ if (opts.sample !== undefined) {
66
+ if (!/^\d+$/.test(opts.sample.trim()) || Number(opts.sample) < 1) {
67
+ return fail(json, "invalid-option", `--sample expects a positive whole number of sections; got '${opts.sample}'. ` +
68
+ "Nothing was read and nothing was stamped.");
69
+ }
70
+ sampleSize = Number(opts.sample);
71
+ }
72
+ // The reading pack: read-only, so it runs BEFORE — and instead of —
73
+ // every write-path gate below (identity, TTY, `--yes`, lock, journal),
74
+ // which all defend the stamp; pack/pack.ts's banner carries the full
75
+ // reasoning. It runs AFTER the wrong-repo gate above on purpose: the
76
+ // source delta resolves `sources` here. `--yes` does not compose — it
77
+ // is the unattended stamp, and a pack that stamped would defeat the
78
+ // read it just prescribed.
79
+ if (opts.pack === true) {
80
+ if (opts.yes === true) {
81
+ return fail(json, "invalid-option", "--pack is the reading list and --yes is the unattended stamp; a pack that immediately " +
82
+ `stamped would defeat the read it just prescribed. Run --pack, read it, then \`loam vouch --service ${service}\`.`);
83
+ }
84
+ // `--sample` composes with the pack instead of conflicting with it:
85
+ // the pack is the reading list, and a sampled vouch's reading list is
86
+ // the sample. Passing it here makes the pack print the sections the
87
+ // subsequent `loam vouch --sample <n>` will stamp for — the same
88
+ // derivation from the same seed, so the two cannot prescribe
89
+ // different documents.
90
+ return runPack({ docsDir: config.docsDir, service: config.service, repoDir, json, sample: sampleSize });
91
+ }
92
+ // Who. Before any reading, because a run that cannot name a person has
93
+ // nothing to offer at the end of it and should not spend a digest finding
94
+ // that out.
95
+ const vouchedBy = await gitIdentity(repoDir);
96
+ if (vouchedBy === null) {
97
+ return fail(json, "vouch-unattributable", `Cannot vouch for '${service}': git names no \`user.email\` in ${repoDir}, so the stamp would ` +
98
+ "record a claim with nobody behind it — which is the one thing `status: verified` must not mean. " +
99
+ "Set it (`git config user.email you@example.com`) and re-run.");
100
+ }
101
+ // Whether a person is actually here. `vouch` is the only command in loam
102
+ // whose output is a claim about a HUMAN act — every other check is
103
+ // internal consistency, which fluent prose satisfies — and it used to run
104
+ // unattended, unattributed, twice in a row, stamping `verified` both
105
+ // times. Meanwhile the generated skill files pre-approved `Bash(loam:*)`,
106
+ // so the same agent that wrote the draft was permitted to promote it.
107
+ // That inverts loam's own argument about test evidence: an agent must not
108
+ // be able to SAY a scenario is tested, and it must not be able to say a
109
+ // spec matches the code either. The allowlist no longer covers this
110
+ // command (core/agent/tools/dialects.ts), and nothing but a terminal or an explicit
111
+ // `--yes` gets past here.
112
+ const attended = opts.yes === true;
113
+ if (!attended) {
114
+ if (process.stdin.isTTY !== true) {
115
+ return fail(json, "vouch-unattended", `Cannot vouch for '${service}' with nothing on the other end of stdin: this command records that ` +
116
+ "a PERSON read the code and says the document matches it, and nobody was asked. Run it from a " +
117
+ "terminal, or pass --yes to state that you are standing behind it anyway — `vouched_by` records " +
118
+ `${vouchedBy} either way.`);
119
+ }
120
+ // `--json` and a prompt do not compose: the envelope is one JSON
121
+ // document on stdout, and a question printed beside it is not parseable
122
+ // by the consumer that asked for it. A JSON caller is a program, so it
123
+ // gets the same answer a pipe does — say so with --yes.
124
+ if (json) {
125
+ return fail(json, "vouch-unattended", `Cannot vouch for '${service}' in --json mode without --yes: the confirmation is a question for a ` +
126
+ "person, and it cannot be asked on a stream whose whole contract is one JSON document.");
127
+ }
128
+ }
129
+ // The reading list is built BEFORE the question and AFTER the attendance
130
+ // gates: a run that cannot ask anybody anything must not spend two
131
+ // source-tree digests finding that out, and a person must not be asked
132
+ // to confirm a sample nobody has shown them. Every refusal a vouch can
133
+ // raise about these documents fires in here, so it lands before the read
134
+ // rather than after it.
135
+ let sample;
136
+ if (sampleSize !== undefined) {
137
+ const built = await buildSamplePlan({ docsDir: config.docsDir, service: config.service, repoDir, n: sampleSize });
138
+ if (!built.ok)
139
+ return fail(json, built.code, built.message);
140
+ sample = built.plan;
141
+ if (!json)
142
+ printReadingList(sample, service);
143
+ }
144
+ const servicePath = await serviceTreePathOf(config.docsDir, service);
145
+ if (!attended && !(await confirmVouch({ service, vouchedBy, docsDir: config.docsDir, servicePath, sample }))) {
146
+ return fail(json, "vouch-declined", `Nothing was stamped for '${service}'.`);
147
+ }
148
+ const outcome = await vouch({
149
+ docsDir: config.docsDir,
150
+ // The guard above proved `service` IS `config.service`, and only the
151
+ // latter carries the parse (`loam.json`'s `service` field is validated
152
+ // at load). Same string, but only one spelling is pathable.
153
+ service: config.service,
154
+ vouchedBy,
155
+ // The repo root, not the cwd. `sources:` are spelled relative to the
156
+ // repository — that is what they mean in the frontmatter and what
157
+ // `loam validate` resolves them against — so vouching from a
158
+ // subdirectory used to report every real source as missing
159
+ // (`sources-path-missing`) and refuse the stamp. `config.root` is the
160
+ // directory loam.json was found in, which is the only definition of
161
+ // "this repo" that does not move with the caller.
162
+ repoDir,
163
+ today: today(new Date()),
164
+ // Absent for an ordinary vouch, which is what makes an ordinary vouch
165
+ // CLEAR a prior sample's scope rather than leave it standing.
166
+ ...(sample === undefined ? {} : { sample }),
167
+ });
168
+ if (!outcome.ok)
169
+ return fail(json, outcome.code, outcome.message);
170
+ const report = { service, docsDir: config.docsDir, outcome, ...(sample === undefined ? {} : { sample }) };
171
+ if (json)
172
+ return emitStampJson(report);
173
+ printStamp(report);
174
+ });
175
+ }
176
+ //# sourceMappingURL=vouch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vouch.js","sourceRoot":"","sources":["../../../src/commands/vouch/vouch.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig } from \"../../core/envelope/config.js\";\nimport { fail, NO_SERVICE_MESSAGE, reportNoConfig } from \"../../core/envelope/json.js\";\nimport { gitIdentity } from \"../../core/provenance/git.js\";\nimport { today } from \"../../core/provenance/stamp.js\";\nimport { serviceTreePathOf } from \"../../core/repo/service-target.js\";\nimport { runPack } from \"./pack/print.js\";\nimport { confirmVouch } from \"./prompt/confirm.js\";\nimport { emitStampJson, printStamp } from \"./report.js\";\nimport { vouch } from \"./run.js\";\nimport { buildSamplePlan, type SamplePlan } from \"./sample/plan.js\";\nimport { printReadingList } from \"./sample/print.js\";\n\n/**\n * `loam vouch` — the human act SCHEMA.md has always described as \"promote draft\n * -> verified\".\n *\n * Everything else loam checks is internal consistency, and an agent writing\n * fluent prose satisfies all of it. This is the one command that records a\n * person: they read the code, they say the document matches it, and loam stamps\n * a digest of what they read — and a digest of the document they read it\n * against, so neither side can move quietly. From then on `loam validate` can\n * tell the difference between a document nobody has checked, one that still\n * matches the code, one the code has moved out from under, and one whose own\n * prose changed after the stamp.\n *\n * \"Records a person\" was, for two releases, a thing this file said and did not\n * do. There was no `vouched_by`, no identity of any kind and no interactive\n * gate, so an agent could run it twice unattended and stamp `verified` both\n * times — while the skill files loam generates pre-approved `Bash(loam:*)`,\n * which meant the agent that wrote the draft was permitted to promote it. Three\n * things close that, and none of them is a signature: the stamp carries git's\n * `user.email` (`vouched_by`), the run refuses without a terminal or an explicit\n * `--yes`, and the generated allowlist names loam's read-only and authoring\n * verbs one by one instead of all of them (core/agent/tools/dialects.ts). What that buys is\n * attribution and a deliberate act, not proof — git config is a text file. A\n * reviewer can now ask a named person what they read, which is the question\n * `status: verified` was silently answering with nobody.\n *\n * The stamp is only worth what it claims, so vouch refuses everything it cannot\n * actually verify — a frontmatter block that will not parse (whose fields\n * nobody can read, and whose rewrite would lose the author's lines), a spec\n * with no sources, a glob pattern (no longer supported), a source that is\n * gone, a directory holding no files, or a repo that is not this service's —\n * and refuses without writing anything.\n *\n * \"The document\" is every spec-axis file the service has: spec.md always, and\n * arch.spec.md beside it when present — same frontmatter conventions, same\n * stamp, one vouch. The refusal discipline is per file but the vouch is\n * all-or-nothing per service: one unverifiable file refuses the whole run, so\n * a `verified` service never means \"half-stamped\".\n */\n\ninterface VouchOptions {\n service?: string;\n yes?: boolean;\n pack?: boolean;\n /** `--sample <n>` as typed — a string until it is proved to be a whole number. */\n sample?: string;\n json?: boolean;\n}\n\nexport function registerVouch(program: Command): void {\n program\n .command(\"vouch\")\n .description(\n \"Vouch for a service's living specs: stamp spec.md, and arch.spec.md when present, verified against the code they describe\",\n )\n .option(\"--service <id>\", \"service to vouch for (defaults to the configured service)\")\n .option(\n \"--yes\",\n \"skip the confirmation — required when stdin is not a terminal, and still records `vouched_by`\",\n )\n .option(\n \"--pack\",\n \"print the re-vouch reading pack — the doc-body diff since the last vouch, the source files that moved, and the sections already covered — then exit without vouching; read-only, nothing is stamped\",\n )\n .option(\n \"--sample <n>\",\n \"vouch after reading a deterministic sample of <n> sections per spec file — the stamp records `vouch_scope: sampled`, `loam list` shows `vouched (sampled)`, and `loam validate` reports `sources.sampled-vouch` until a full vouch clears it\",\n )\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .action(async (opts: VouchOptions) => {\n const json = opts.json === true;\n\n const loaded = await loadConfig();\n if (loaded.kind !== \"loaded\") {\n reportNoConfig(json, loaded);\n return;\n }\n const config = loaded.config;\n\n const service = opts.service ?? config.service;\n if (service === undefined) {\n return fail(json, \"invalid-option\", NO_SERVICE_MESSAGE);\n }\n // Vouching hashes the code the doc was written from, so it can only run\n // where that code is. From anywhere else the paths are someone else's.\n //\n // TWO conditions, two codes, and the split is the whole point. Both used\n // to answer `invalid-option`, whose `loam explain` row says the\n // invocation itself is wrong — contradictory flags, a mistyped one, a\n // value that cannot be right. Here the invocation is perfectly correct\n // and the REPOSITORY is the wrong one, so that code sent a user whose\n // flags were fine off to re-read their flags, and left CI and agents\n // unable to tell \"run this in the service repo\" from \"you typed the flag\n // wrong\". `loam verify --record --service` already draws exactly this\n // line for exactly this reason (see commands/verify/verify.ts); vouch\n // and gherkin now answer the same pair, so a caller branching on\n // `error.code` gets one answer from all three. The messages are\n // unchanged — only the code moved.\n if (config.service === undefined) {\n return fail(\n json,\n \"repository-unavailable\",\n `Cannot vouch for '${service}' from here: this is not a service repo. \\`sources\\` resolve against the service's own repo — run it there.`,\n );\n }\n if (config.service !== service) {\n return fail(\n json,\n \"service-mismatch\",\n `Cannot vouch for '${service}' from here: this repo is '${config.service}'. \\`sources\\` resolve against the service's own repo — run it there.`,\n );\n }\n\n // The repo root, not the cwd — see the comment on `repoDir` below; the\n // identity has to be asked of the same directory the sources resolve in,\n // or a subdirectory with its own git config would answer for it.\n const repoDir = config.root ?? process.cwd();\n\n // The flag's own grammar, before anything is read or hashed: `--sample`\n // decides what the run CLAIMS, so a value nobody can read must not reach\n // a stamp. Whole numbers only, and at least one — `0` is a vouch that\n // read nothing, and there is already a way to record that (do not\n // vouch). Checked before `--pack` below so a typo is refused the same\n // way in both modes.\n let sampleSize: number | undefined;\n if (opts.sample !== undefined) {\n if (!/^\\d+$/.test(opts.sample.trim()) || Number(opts.sample) < 1) {\n return fail(\n json,\n \"invalid-option\",\n `--sample expects a positive whole number of sections; got '${opts.sample}'. ` +\n \"Nothing was read and nothing was stamped.\",\n );\n }\n sampleSize = Number(opts.sample);\n }\n\n // The reading pack: read-only, so it runs BEFORE — and instead of —\n // every write-path gate below (identity, TTY, `--yes`, lock, journal),\n // which all defend the stamp; pack/pack.ts's banner carries the full\n // reasoning. It runs AFTER the wrong-repo gate above on purpose: the\n // source delta resolves `sources` here. `--yes` does not compose — it\n // is the unattended stamp, and a pack that stamped would defeat the\n // read it just prescribed.\n if (opts.pack === true) {\n if (opts.yes === true) {\n return fail(\n json,\n \"invalid-option\",\n \"--pack is the reading list and --yes is the unattended stamp; a pack that immediately \" +\n `stamped would defeat the read it just prescribed. Run --pack, read it, then \\`loam vouch --service ${service}\\`.`,\n );\n }\n // `--sample` composes with the pack instead of conflicting with it:\n // the pack is the reading list, and a sampled vouch's reading list is\n // the sample. Passing it here makes the pack print the sections the\n // subsequent `loam vouch --sample <n>` will stamp for — the same\n // derivation from the same seed, so the two cannot prescribe\n // different documents.\n return runPack({ docsDir: config.docsDir, service: config.service, repoDir, json, sample: sampleSize });\n }\n\n // Who. Before any reading, because a run that cannot name a person has\n // nothing to offer at the end of it and should not spend a digest finding\n // that out.\n const vouchedBy = await gitIdentity(repoDir);\n if (vouchedBy === null) {\n return fail(\n json,\n \"vouch-unattributable\",\n `Cannot vouch for '${service}': git names no \\`user.email\\` in ${repoDir}, so the stamp would ` +\n \"record a claim with nobody behind it — which is the one thing `status: verified` must not mean. \" +\n \"Set it (`git config user.email you@example.com`) and re-run.\",\n );\n }\n\n // Whether a person is actually here. `vouch` is the only command in loam\n // whose output is a claim about a HUMAN act — every other check is\n // internal consistency, which fluent prose satisfies — and it used to run\n // unattended, unattributed, twice in a row, stamping `verified` both\n // times. Meanwhile the generated skill files pre-approved `Bash(loam:*)`,\n // so the same agent that wrote the draft was permitted to promote it.\n // That inverts loam's own argument about test evidence: an agent must not\n // be able to SAY a scenario is tested, and it must not be able to say a\n // spec matches the code either. The allowlist no longer covers this\n // command (core/agent/tools/dialects.ts), and nothing but a terminal or an explicit\n // `--yes` gets past here.\n const attended = opts.yes === true;\n if (!attended) {\n if (process.stdin.isTTY !== true) {\n return fail(\n json,\n \"vouch-unattended\",\n `Cannot vouch for '${service}' with nothing on the other end of stdin: this command records that ` +\n \"a PERSON read the code and says the document matches it, and nobody was asked. Run it from a \" +\n \"terminal, or pass --yes to state that you are standing behind it anyway — `vouched_by` records \" +\n `${vouchedBy} either way.`,\n );\n }\n // `--json` and a prompt do not compose: the envelope is one JSON\n // document on stdout, and a question printed beside it is not parseable\n // by the consumer that asked for it. A JSON caller is a program, so it\n // gets the same answer a pipe does — say so with --yes.\n if (json) {\n return fail(\n json,\n \"vouch-unattended\",\n `Cannot vouch for '${service}' in --json mode without --yes: the confirmation is a question for a ` +\n \"person, and it cannot be asked on a stream whose whole contract is one JSON document.\",\n );\n }\n }\n\n // The reading list is built BEFORE the question and AFTER the attendance\n // gates: a run that cannot ask anybody anything must not spend two\n // source-tree digests finding that out, and a person must not be asked\n // to confirm a sample nobody has shown them. Every refusal a vouch can\n // raise about these documents fires in here, so it lands before the read\n // rather than after it.\n let sample: SamplePlan | undefined;\n if (sampleSize !== undefined) {\n const built = await buildSamplePlan({ docsDir: config.docsDir, service: config.service, repoDir, n: sampleSize });\n if (!built.ok) return fail(json, built.code, built.message);\n sample = built.plan;\n if (!json) printReadingList(sample, service);\n }\n const servicePath = await serviceTreePathOf(config.docsDir, service);\n if (!attended && !(await confirmVouch({ service, vouchedBy, docsDir: config.docsDir, servicePath, sample }))) {\n return fail(json, \"vouch-declined\", `Nothing was stamped for '${service}'.`);\n }\n\n const outcome = await vouch({\n docsDir: config.docsDir,\n // The guard above proved `service` IS `config.service`, and only the\n // latter carries the parse (`loam.json`'s `service` field is validated\n // at load). Same string, but only one spelling is pathable.\n service: config.service,\n vouchedBy,\n // The repo root, not the cwd. `sources:` are spelled relative to the\n // repository — that is what they mean in the frontmatter and what\n // `loam validate` resolves them against — so vouching from a\n // subdirectory used to report every real source as missing\n // (`sources-path-missing`) and refuse the stamp. `config.root` is the\n // directory loam.json was found in, which is the only definition of\n // \"this repo\" that does not move with the caller.\n repoDir,\n today: today(new Date()),\n // Absent for an ordinary vouch, which is what makes an ordinary vouch\n // CLEAR a prior sample's scope rather than leave it standing.\n ...(sample === undefined ? {} : { sample }),\n });\n if (!outcome.ok) return fail(json, outcome.code, outcome.message);\n\n const report = { service, docsDir: config.docsDir, outcome, ...(sample === undefined ? {} : { sample }) };\n if (json) return emitStampJson(report);\n printStamp(report);\n });\n}\n"]}
@@ -0,0 +1,220 @@
1
+ /**
2
+ * The document's opening arc: what the docs repo HOLDS — the layout, how its
3
+ * documents link to each other, the glossary, architectural obligations, and
4
+ * the `loam.json` wiring every repository commits.
5
+ *
6
+ * The three sections that used to close this file — the architecture spec
7
+ * axis, the generated Gherkin suite, and the frontmatter/vouch chain — are now
8
+ * the `loam-authoring` reference page (../workflows/reference/authoring.ts),
9
+ * printed by `loam instructions loam-authoring` rather than written into
10
+ * AGENTS.md. They are grammars consulted while writing ONE document, and the
11
+ * file they were in is auto-loaded on every session by hosts that truncate it
12
+ * silently; ./command-map.ts's header carries the measurement that decided it.
13
+ * What is left here is what an agent must know before it can form a question
14
+ * at all.
15
+ *
16
+ * One section of the AGENTS.md template. ../agents-md.ts assembles the
17
+ * document by PLAIN CONCATENATION — no join separator — so every section
18
+ * starts at the first character of its opening line and ends with the newline
19
+ * that closes its last one. Keep that shape when editing, or two sections glue
20
+ * onto one line in every docs repo loam scaffolds from now on.
21
+ */
22
+ export const ARTIFACTS = `# Working in this docs repo
23
+
24
+ This is a **loam** docs repo: the shared source of truth for a governed software
25
+ system — its architecture, requirements, contracts and evidence. Everything here
26
+ is plain files. \`loam\` reads and writes them; delete \`loam\` and the docs remain.
27
+
28
+ **The bar this artifact set aims at is reproducibility**: a reader should be able
29
+ to answer, from these files alone — what each governed boundary exposes, what it
30
+ reaches, what shapes it exchanges, how it is run, and what pages whom —
31
+ without opening the code. \`loam validate\` grades form and joins, never depth:
32
+ green means the files agree with each other, and the bar is what "done" is
33
+ measured against — a thin baseline that validates is thin, not done.
34
+
35
+ ## Layout
36
+
37
+ \`\`\`
38
+ architecture/landscape.likec4 the living C4 model of the whole system
39
+ architecture/permissions.yaml optional system-wide authorization vocabulary
40
+ architecture/obligations.yaml optional ARCHITECTURAL obligations (#obl-<name> on the map)
41
+ architecture/adrs/NNNN-*.md optional SYSTEM-level decisions (MADR) — only their links are graded
42
+ glossary/<term>.md optional domain vocabulary — one file per term, nesting allowed
43
+ services/<svc>/
44
+ model.likec4 this governed boundary's C4
45
+ spec.md its living requirements (current state)
46
+ arch.spec.md its living ARCHITECTURE requirements (outbox, retries, alerts)
47
+ openapi.yaml its API contract
48
+ asyncapi.yaml its AsyncAPI 3 event contract
49
+ adrs/ runbook.md health.yaml why it is like this, how to run it
50
+ features/<FEAT>/ a change in flight
51
+ intent.md why, in business terms
52
+ delta.likec4 the architecture change, tagged #<FEAT>
53
+ specs/<svc>/spec.md the requirement change for one governed boundary
54
+ specs/<svc>/arch.spec.md the architectural requirement change, same delta grammar
55
+ specs/<svc>/openapi.yaml the endpoints this feature adds
56
+ specs/<svc>/asyncapi.yaml the event-contract delta (optional; a complete AsyncAPI 3 document)
57
+ verification.yaml what was checked once the code was built
58
+ features/archive/<FEAT>/ shipped changes — the evolution history
59
+ \`\`\`
60
+
61
+ ## Linking between documents
62
+
63
+ Documents here link to each other with **standard markdown links**, and the
64
+ target is a relative path to the file:
65
+
66
+ \`\`\`markdown
67
+ [0001 — transactional outbox](../../architecture/adrs/0001-transactional-outbox.md)
68
+ \`\`\`
69
+
70
+ Two reasons, and the second is the one that decides it. A markdown link renders
71
+ as a link in pull-request review, which is where these documents are actually
72
+ read, while \`[[0001 transactional outbox]]\` renders there as the literal
73
+ brackets somebody typed. And its target is a real relative path, so "does this
74
+ link resolve" is a filesystem question with a yes-or-no answer — where resolving
75
+ a wikilink means reimplementing Obsidian's shortest-unique-path search across the
76
+ whole repo, which is guessing, and loam refuses and names rather than guessing.
77
+
78
+ You lose nothing by it. Obsidian reads a repo written this way with no
79
+ integration at all — graph view, backlinks and search all work on markdown links
80
+ — and its per-vault \`Use [[Wikilinks]]\` setting turns OFF, after which its own
81
+ autocomplete and rename-tracking produce markdown links too. The authoring
82
+ comfort is a toggle in somebody's editor, not a decision this repo carries.
83
+
84
+ **\`loam validate\` resolves these links** (\`link.unresolved\`, error): a relative
85
+ target that names nothing is a broken join, reported once per document with
86
+ every bad link and its line. A link here is a **join**, not decoration — a
87
+ requirement that names a term wants that term's document linked, and an ADR that
88
+ supersedes another wants to say which, the same kind of relationship
89
+ \`Operations:\` and \`Covers:\` already state.
90
+
91
+ Three things are deliberately NOT graded, so write them freely: a target outside
92
+ this repository (\`../../some-service/README.md\` — that tree may not be checked
93
+ out beside these documents), a link to a heading (\`#section\`), and any link
94
+ inside a fenced code block or an inline code span, which is how a document shows
95
+ the convention without being convicted for it.
96
+
97
+ CASE **is** graded, and deliberately: \`[Order](Order.md)\` beside a file called
98
+ \`order.md\` resolves on Windows and macOS and 404s on GitHub and every Linux
99
+ runner, so the message names the stored spelling on all of them alike.
100
+
101
+ ## The glossary — the system's domain words
102
+
103
+ \`glossary/<term>.md\`, one file per term, nesting allowed
104
+ (\`glossary/payments/authorization.md\` is the term \`payments/authorization\`). There is
105
+ no \`glossary.yaml\`: a definition is prose, and the DIRECTORY is the list. The
106
+ directory's existence is the opt-in — a system without one hears nothing.
107
+
108
+ **A term is checkable because a link is a join.** Cite it from the document that
109
+ uses the word — a requirement, a capability document, a feature's intent — with an
110
+ ordinary relative link:
111
+
112
+ \`\`\`markdown
113
+ An [Order](../../glossary/order.md) is what a customer has confirmed.
114
+ \`\`\`
115
+
116
+ A citation that does not resolve is \`link.unresolved\` like any other; a term nothing
117
+ outside \`glossary/\` cites is \`glossary.unlinked\` (warn). Terms citing each other is
118
+ normal and does NOT count as adoption — a glossary is a network of definitions, and
119
+ two terms defining each other say nothing about whether the system uses either word.
120
+ \`loam list glossary\` prints every term with the documents that cite it.
121
+
122
+ **A feature may bring a new word with it**: write it at
123
+ \`features/<FEAT>/glossary/<term>.md\` and \`loam archive\` copies it into \`glossary/\`,
124
+ \`loam unarchive\` takes it back out. This route is CREATE-ONLY — a term the living
125
+ glossary already defines is \`glossary.term-exists\`, which \`--approve\` does not
126
+ override, because the merge is a whole-file copy and would replace an authored
127
+ definition wholesale. To CHANGE a definition, edit \`glossary/<term>.md\` directly in
128
+ the same pull request, where git produces an ordinary conflict.
129
+
130
+ Cite the new word at its FUTURE living path (\`../../../../glossary/order.md\` from a
131
+ \`specs/<svc>/\` delta) — that link resolves while the feature is in flight, and the
132
+ merge re-expresses it from wherever the text lands, so it keeps resolving afterwards.
133
+
134
+ Write the definition for a reader who knows the business and not this system: what the
135
+ word means, and what it is NOT (an order is not a cart). Never which service owns it —
136
+ that is the system map's question and it changes.
137
+
138
+
139
+ ## Architectural obligations — what the architect hands the team
140
+
141
+ An architect has always had one checked channel here: an edge carrying
142
+ \`metadata { op 'authorizePayment' }\` obliges the provider to define that operationId,
143
+ or \`spine.op-undefined\` fails the gate. Obligations are the same handoff for the rules
144
+ that VARY — an outbox on this publisher and not that one, a circuit breaker on two
145
+ edges out of five — and they are three separate things on purpose:
146
+
147
+ - an **ADR** in \`architecture/adrs/\` says WHAT was decided, as thin or as thick as the
148
+ decision needs;
149
+ - a **\`#obl-<name>\` tag** on an element or an edge in \`architecture/landscape.likec4\`
150
+ says WHERE it applies, so one ADR governs three edges and not the fourth without the
151
+ document forking;
152
+ - **\`architecture/obligations.yaml\`** declares the names, so a mistyped tag is an error
153
+ rather than a word nobody notices.
154
+
155
+ \`\`\`yaml
156
+ obligations:
157
+ outbox:
158
+ description: Publishers write the event and the state change in one transaction.
159
+ adr: architecture/adrs/0001-transactional-outbox.md # relative to the docs repo root
160
+ \`\`\`
161
+
162
+ **Your side of it is \`Covers:\`**. A tagged object with no living requirement covering it
163
+ is \`obligation.uncovered\` (warn), and the finding names the service, the object and the
164
+ exact line to write — \`Covers: <element>\` or \`Covers: <source> -> <target>\` in that
165
+ service's \`arch.spec.md\`, with a scenario that proves it. An id is its own tag suffix,
166
+ so it may hold letters, digits, \`_\` and \`-\` only.
167
+
168
+ ## \`loam.json\` — the wiring, in every repo
169
+
170
+ A governed system is **N + 1 repositories**: this docs repo, and one per governed
171
+ implementation boundary. Paths and commands call that boundary a \`service\`; it
172
+ may be a modular monolith, a network service, a CLI or a worker. Every repo
173
+ commits its own \`loam.json\`, so an agent, human or CI runner can find the rest
174
+ of the system. There is no global config; without a \`loam.json\`, commands refuse
175
+ with \`no-config\` rather than guessing.
176
+
177
+ \`\`\`json
178
+ { "docsDir": "../docs-repo", "service": "payment-service", "gherkinDir": "features" }
179
+ \`\`\`
180
+
181
+ - \`docsDir\` — where the docs repo is, **stored exactly as it was passed** and
182
+ resolved against the directory holding the \`loam.json\`. So \`../docs-repo\`
183
+ keeps working on every machine that checks the repos out side by side, which
184
+ is the point of committing the file. An absolute path is a warning
185
+ (\`doctor.docs-absolute\`): it resolves only on the machine that ran \`loam init\`.
186
+ The docs repo's own \`loam.json\` says \`"docsDir": "."\`.
187
+ - \`service\` — the canonical id of the governed boundary THIS repo contains, i.e. the
188
+ \`services/<id>/\` directory it is allowed to speak for. \`loam vouch\`,
189
+ \`loam gherkin\` and \`loam verify --service\` when writing with \`--record\`,
190
+ \`--results\` or \`--contract-results\` bind to it; without it they refuse
191
+ (\`repository-unavailable\`) rather than write another boundary's documents
192
+ from a repo that is not that boundary's. A read-only verify checklist needs no
193
+ binding and works from the docs repo.
194
+ - \`gherkinDir\` — optional, default \`features\`: the directory \`loam gherkin\`
195
+ writes its own \`loam/\` subtree into.
196
+ - \`agentTools\` — optional: the agent tools \`loam init\` has written command and
197
+ skill files for here, accumulated across runs. Written by \`init\`, read by
198
+ \`loam doctor\`; nothing else depends on it, and a config without it loads.
199
+
200
+ **Step 0 of everything below, once per repo:**
201
+
202
+ \`\`\`sh
203
+ loam init --docs ../docs-repo --service payment-service # in EACH service repo
204
+ loam doctor # before you trust any of it
205
+ \`\`\`
206
+
207
+ \`loam init --docs <dir>\` **joins** an existing docs repo; creating a new one
208
+ takes \`--create\`, so a mistyped path cannot quietly scaffold a second source of
209
+ truth beside the real one. \`loam doctor\` is the read-only preflight: it reads
210
+ loam.json defensively, resolves \`docsDir\`, probes access, checks \`services/\` and
211
+ the system map, and reports the service binding — run it first when anything
212
+ behaves as though the system were empty.
213
+
214
+ **Living vs delta.** \`services/<svc>/spec.md\` is the complete current state.
215
+ \`features/<FEAT>/specs/<svc>/spec.md\` is a diff against it, reviewed as a diff, with
216
+ requirements grouped under \`## ADDED\`, \`## MODIFIED\` or \`## REMOVED Requirements\`.
217
+ \`loam archive\` folds the delta into the living state.
218
+
219
+ `;
220
+ //# sourceMappingURL=artifacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../../../src/core/agent/agents-md/artifacts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqMxB,CAAC","sourcesContent":["/**\n * The document's opening arc: what the docs repo HOLDS — the layout, how its\n * documents link to each other, the glossary, architectural obligations, and\n * the `loam.json` wiring every repository commits.\n *\n * The three sections that used to close this file — the architecture spec\n * axis, the generated Gherkin suite, and the frontmatter/vouch chain — are now\n * the `loam-authoring` reference page (../workflows/reference/authoring.ts),\n * printed by `loam instructions loam-authoring` rather than written into\n * AGENTS.md. They are grammars consulted while writing ONE document, and the\n * file they were in is auto-loaded on every session by hosts that truncate it\n * silently; ./command-map.ts's header carries the measurement that decided it.\n * What is left here is what an agent must know before it can form a question\n * at all.\n *\n * One section of the AGENTS.md template. ../agents-md.ts assembles the\n * document by PLAIN CONCATENATION — no join separator — so every section\n * starts at the first character of its opening line and ends with the newline\n * that closes its last one. Keep that shape when editing, or two sections glue\n * onto one line in every docs repo loam scaffolds from now on.\n */\nexport const ARTIFACTS = `# Working in this docs repo\n\nThis is a **loam** docs repo: the shared source of truth for a governed software\nsystem — its architecture, requirements, contracts and evidence. Everything here\nis plain files. \\`loam\\` reads and writes them; delete \\`loam\\` and the docs remain.\n\n**The bar this artifact set aims at is reproducibility**: a reader should be able\nto answer, from these files alone — what each governed boundary exposes, what it\nreaches, what shapes it exchanges, how it is run, and what pages whom —\nwithout opening the code. \\`loam validate\\` grades form and joins, never depth:\ngreen means the files agree with each other, and the bar is what \"done\" is\nmeasured against — a thin baseline that validates is thin, not done.\n\n## Layout\n\n\\`\\`\\`\narchitecture/landscape.likec4 the living C4 model of the whole system\narchitecture/permissions.yaml optional system-wide authorization vocabulary\narchitecture/obligations.yaml optional ARCHITECTURAL obligations (#obl-<name> on the map)\narchitecture/adrs/NNNN-*.md optional SYSTEM-level decisions (MADR) — only their links are graded\nglossary/<term>.md optional domain vocabulary — one file per term, nesting allowed\nservices/<svc>/\n model.likec4 this governed boundary's C4\n spec.md its living requirements (current state)\n arch.spec.md its living ARCHITECTURE requirements (outbox, retries, alerts)\n openapi.yaml its API contract\n asyncapi.yaml its AsyncAPI 3 event contract\n adrs/ runbook.md health.yaml why it is like this, how to run it\nfeatures/<FEAT>/ a change in flight\n intent.md why, in business terms\n delta.likec4 the architecture change, tagged #<FEAT>\n specs/<svc>/spec.md the requirement change for one governed boundary\n specs/<svc>/arch.spec.md the architectural requirement change, same delta grammar\n specs/<svc>/openapi.yaml the endpoints this feature adds\n specs/<svc>/asyncapi.yaml the event-contract delta (optional; a complete AsyncAPI 3 document)\n verification.yaml what was checked once the code was built\nfeatures/archive/<FEAT>/ shipped changes — the evolution history\n\\`\\`\\`\n\n## Linking between documents\n\nDocuments here link to each other with **standard markdown links**, and the\ntarget is a relative path to the file:\n\n\\`\\`\\`markdown\n[0001 — transactional outbox](../../architecture/adrs/0001-transactional-outbox.md)\n\\`\\`\\`\n\nTwo reasons, and the second is the one that decides it. A markdown link renders\nas a link in pull-request review, which is where these documents are actually\nread, while \\`[[0001 transactional outbox]]\\` renders there as the literal\nbrackets somebody typed. And its target is a real relative path, so \"does this\nlink resolve\" is a filesystem question with a yes-or-no answer — where resolving\na wikilink means reimplementing Obsidian's shortest-unique-path search across the\nwhole repo, which is guessing, and loam refuses and names rather than guessing.\n\nYou lose nothing by it. Obsidian reads a repo written this way with no\nintegration at all — graph view, backlinks and search all work on markdown links\n— and its per-vault \\`Use [[Wikilinks]]\\` setting turns OFF, after which its own\nautocomplete and rename-tracking produce markdown links too. The authoring\ncomfort is a toggle in somebody's editor, not a decision this repo carries.\n\n**\\`loam validate\\` resolves these links** (\\`link.unresolved\\`, error): a relative\ntarget that names nothing is a broken join, reported once per document with\nevery bad link and its line. A link here is a **join**, not decoration — a\nrequirement that names a term wants that term's document linked, and an ADR that\nsupersedes another wants to say which, the same kind of relationship\n\\`Operations:\\` and \\`Covers:\\` already state.\n\nThree things are deliberately NOT graded, so write them freely: a target outside\nthis repository (\\`../../some-service/README.md\\` — that tree may not be checked\nout beside these documents), a link to a heading (\\`#section\\`), and any link\ninside a fenced code block or an inline code span, which is how a document shows\nthe convention without being convicted for it.\n\nCASE **is** graded, and deliberately: \\`[Order](Order.md)\\` beside a file called\n\\`order.md\\` resolves on Windows and macOS and 404s on GitHub and every Linux\nrunner, so the message names the stored spelling on all of them alike.\n\n## The glossary — the system's domain words\n\n\\`glossary/<term>.md\\`, one file per term, nesting allowed\n(\\`glossary/payments/authorization.md\\` is the term \\`payments/authorization\\`). There is\nno \\`glossary.yaml\\`: a definition is prose, and the DIRECTORY is the list. The\ndirectory's existence is the opt-in — a system without one hears nothing.\n\n**A term is checkable because a link is a join.** Cite it from the document that\nuses the word — a requirement, a capability document, a feature's intent — with an\nordinary relative link:\n\n\\`\\`\\`markdown\nAn [Order](../../glossary/order.md) is what a customer has confirmed.\n\\`\\`\\`\n\nA citation that does not resolve is \\`link.unresolved\\` like any other; a term nothing\noutside \\`glossary/\\` cites is \\`glossary.unlinked\\` (warn). Terms citing each other is\nnormal and does NOT count as adoption — a glossary is a network of definitions, and\ntwo terms defining each other say nothing about whether the system uses either word.\n\\`loam list glossary\\` prints every term with the documents that cite it.\n\n**A feature may bring a new word with it**: write it at\n\\`features/<FEAT>/glossary/<term>.md\\` and \\`loam archive\\` copies it into \\`glossary/\\`,\n\\`loam unarchive\\` takes it back out. This route is CREATE-ONLY — a term the living\nglossary already defines is \\`glossary.term-exists\\`, which \\`--approve\\` does not\noverride, because the merge is a whole-file copy and would replace an authored\ndefinition wholesale. To CHANGE a definition, edit \\`glossary/<term>.md\\` directly in\nthe same pull request, where git produces an ordinary conflict.\n\nCite the new word at its FUTURE living path (\\`../../../../glossary/order.md\\` from a\n\\`specs/<svc>/\\` delta) — that link resolves while the feature is in flight, and the\nmerge re-expresses it from wherever the text lands, so it keeps resolving afterwards.\n\nWrite the definition for a reader who knows the business and not this system: what the\nword means, and what it is NOT (an order is not a cart). Never which service owns it —\nthat is the system map's question and it changes.\n\n\n## Architectural obligations — what the architect hands the team\n\nAn architect has always had one checked channel here: an edge carrying\n\\`metadata { op 'authorizePayment' }\\` obliges the provider to define that operationId,\nor \\`spine.op-undefined\\` fails the gate. Obligations are the same handoff for the rules\nthat VARY — an outbox on this publisher and not that one, a circuit breaker on two\nedges out of five — and they are three separate things on purpose:\n\n- an **ADR** in \\`architecture/adrs/\\` says WHAT was decided, as thin or as thick as the\n decision needs;\n- a **\\`#obl-<name>\\` tag** on an element or an edge in \\`architecture/landscape.likec4\\`\n says WHERE it applies, so one ADR governs three edges and not the fourth without the\n document forking;\n- **\\`architecture/obligations.yaml\\`** declares the names, so a mistyped tag is an error\n rather than a word nobody notices.\n\n\\`\\`\\`yaml\nobligations:\n outbox:\n description: Publishers write the event and the state change in one transaction.\n adr: architecture/adrs/0001-transactional-outbox.md # relative to the docs repo root\n\\`\\`\\`\n\n**Your side of it is \\`Covers:\\`**. A tagged object with no living requirement covering it\nis \\`obligation.uncovered\\` (warn), and the finding names the service, the object and the\nexact line to write — \\`Covers: <element>\\` or \\`Covers: <source> -> <target>\\` in that\nservice's \\`arch.spec.md\\`, with a scenario that proves it. An id is its own tag suffix,\nso it may hold letters, digits, \\`_\\` and \\`-\\` only.\n\n## \\`loam.json\\` — the wiring, in every repo\n\nA governed system is **N + 1 repositories**: this docs repo, and one per governed\nimplementation boundary. Paths and commands call that boundary a \\`service\\`; it\nmay be a modular monolith, a network service, a CLI or a worker. Every repo\ncommits its own \\`loam.json\\`, so an agent, human or CI runner can find the rest\nof the system. There is no global config; without a \\`loam.json\\`, commands refuse\nwith \\`no-config\\` rather than guessing.\n\n\\`\\`\\`json\n{ \"docsDir\": \"../docs-repo\", \"service\": \"payment-service\", \"gherkinDir\": \"features\" }\n\\`\\`\\`\n\n- \\`docsDir\\` — where the docs repo is, **stored exactly as it was passed** and\n resolved against the directory holding the \\`loam.json\\`. So \\`../docs-repo\\`\n keeps working on every machine that checks the repos out side by side, which\n is the point of committing the file. An absolute path is a warning\n (\\`doctor.docs-absolute\\`): it resolves only on the machine that ran \\`loam init\\`.\n The docs repo's own \\`loam.json\\` says \\`\"docsDir\": \".\"\\`.\n- \\`service\\` — the canonical id of the governed boundary THIS repo contains, i.e. the\n \\`services/<id>/\\` directory it is allowed to speak for. \\`loam vouch\\`,\n \\`loam gherkin\\` and \\`loam verify --service\\` when writing with \\`--record\\`,\n \\`--results\\` or \\`--contract-results\\` bind to it; without it they refuse\n (\\`repository-unavailable\\`) rather than write another boundary's documents\n from a repo that is not that boundary's. A read-only verify checklist needs no\n binding and works from the docs repo.\n- \\`gherkinDir\\` — optional, default \\`features\\`: the directory \\`loam gherkin\\`\n writes its own \\`loam/\\` subtree into.\n- \\`agentTools\\` — optional: the agent tools \\`loam init\\` has written command and\n skill files for here, accumulated across runs. Written by \\`init\\`, read by\n \\`loam doctor\\`; nothing else depends on it, and a config without it loads.\n\n**Step 0 of everything below, once per repo:**\n\n\\`\\`\\`sh\nloam init --docs ../docs-repo --service payment-service # in EACH service repo\nloam doctor # before you trust any of it\n\\`\\`\\`\n\n\\`loam init --docs <dir>\\` **joins** an existing docs repo; creating a new one\ntakes \\`--create\\`, so a mistyped path cannot quietly scaffold a second source of\ntruth beside the real one. \\`loam doctor\\` is the read-only preflight: it reads\nloam.json defensively, resolves \\`docsDir\\`, probes access, checks \\`services/\\` and\nthe system map, and reports the service binding — run it first when anything\nbehaves as though the system were empty.\n\n**Living vs delta.** \\`services/<svc>/spec.md\\` is the complete current state.\n\\`features/<FEAT>/specs/<svc>/spec.md\\` is a diff against it, reviewed as a diff, with\nrequirements grouped under \\`## ADDED\\`, \\`## MODIFIED\\` or \\`## REMOVED Requirements\\`.\n\\`loam archive\\` folds the delta into the living state.\n\n`;\n"]}