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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1256) hide show
  1. package/CHANGELOG.md +5992 -82
  2. package/COMPARISON.md +168 -63
  3. package/CONTRIBUTING.md +121 -0
  4. package/MIGRATING-from-OpenSpec.md +238 -55
  5. package/QUICKSTART.md +302 -0
  6. package/README.md +653 -144
  7. package/ROADMAP.md +1035 -0
  8. package/SCHEMA.md +3916 -263
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +927 -0
  11. package/dist/cli.js +133 -21
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +204 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +309 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +74 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/closing.js +42 -0
  20. package/dist/commands/archive/closing.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
  22. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  24. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  25. package/dist/commands/archive/plan/contracts/openapi.js +193 -0
  26. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  28. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  29. package/dist/commands/archive/plan/document/head.js +151 -0
  30. package/dist/commands/archive/plan/document/head.js.map +1 -0
  31. package/dist/commands/archive/plan/document/links.js +284 -0
  32. package/dist/commands/archive/plan/document/links.js.map +1 -0
  33. package/dist/commands/archive/plan/document/run.js +136 -0
  34. package/dist/commands/archive/plan/document/run.js.map +1 -0
  35. package/dist/commands/archive/plan/gate.js +319 -0
  36. package/dist/commands/archive/plan/gate.js.map +1 -0
  37. package/dist/commands/archive/plan/landscape.js +298 -0
  38. package/dist/commands/archive/plan/landscape.js.map +1 -0
  39. package/dist/commands/archive/plan/model/extending.js +85 -0
  40. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  41. package/dist/commands/archive/plan/refusal.js +106 -0
  42. package/dist/commands/archive/plan/refusal.js.map +1 -0
  43. package/dist/commands/archive/plan/specs.js +318 -0
  44. package/dist/commands/archive/plan/specs.js.map +1 -0
  45. package/dist/commands/archive/plan/state.js +30 -0
  46. package/dist/commands/archive/plan/state.js.map +1 -0
  47. package/dist/commands/archive/run.js +355 -0
  48. package/dist/commands/archive/run.js.map +1 -0
  49. package/dist/commands/archive/shipped.js +49 -0
  50. package/dist/commands/archive/shipped.js.map +1 -0
  51. package/dist/commands/context/context.js +166 -0
  52. package/dist/commands/context/context.js.map +1 -0
  53. package/dist/commands/context/print.js +305 -0
  54. package/dist/commands/context/print.js.map +1 -0
  55. package/dist/commands/delta/delta.js +367 -0
  56. package/dist/commands/delta/delta.js.map +1 -0
  57. package/dist/commands/delta/print.js +221 -0
  58. package/dist/commands/delta/print.js.map +1 -0
  59. package/dist/commands/dependencies.js +6 -8
  60. package/dist/commands/dependencies.js.map +1 -1
  61. package/dist/commands/diff/diff.js +86 -0
  62. package/dist/commands/diff/diff.js.map +1 -0
  63. package/dist/commands/diff/print.js +38 -0
  64. package/dist/commands/diff/print.js.map +1 -0
  65. package/dist/commands/doctor.js +65 -5
  66. package/dist/commands/doctor.js.map +1 -1
  67. package/dist/commands/explain/explain.js +227 -0
  68. package/dist/commands/explain/explain.js.map +1 -0
  69. package/dist/commands/explore.js +39 -28
  70. package/dist/commands/explore.js.map +1 -1
  71. package/dist/commands/gate/gate.js +152 -0
  72. package/dist/commands/gate/gate.js.map +1 -0
  73. package/dist/commands/gate/print.js +66 -0
  74. package/dist/commands/gate/print.js.map +1 -0
  75. package/dist/commands/gherkin/commit.js +105 -0
  76. package/dist/commands/gherkin/commit.js.map +1 -0
  77. package/dist/commands/gherkin/gherkin.js +262 -0
  78. package/dist/commands/gherkin/gherkin.js.map +1 -0
  79. package/dist/commands/gherkin/reconcile.js +146 -0
  80. package/dist/commands/gherkin/reconcile.js.map +1 -0
  81. package/dist/commands/gherkin/render.js +77 -0
  82. package/dist/commands/gherkin/render.js.map +1 -0
  83. package/dist/commands/init/example.js +204 -0
  84. package/dist/commands/init/example.js.map +1 -0
  85. package/dist/commands/init/first-hour.js +72 -0
  86. package/dist/commands/init/first-hour.js.map +1 -0
  87. package/dist/commands/{init.js → init/init.js} +142 -71
  88. package/dist/commands/init/init.js.map +1 -0
  89. package/dist/commands/init/mcp.js +131 -0
  90. package/dist/commands/init/mcp.js.map +1 -0
  91. package/dist/commands/init/options.js +78 -0
  92. package/dist/commands/init/options.js.map +1 -0
  93. package/dist/commands/instructions.js +72 -14
  94. package/dist/commands/instructions.js.map +1 -1
  95. package/dist/commands/list/campaign/campaign.js +63 -0
  96. package/dist/commands/list/campaign/campaign.js.map +1 -0
  97. package/dist/commands/list/campaign/owners.js +65 -0
  98. package/dist/commands/list/campaign/owners.js.map +1 -0
  99. package/dist/commands/list/json.js +155 -0
  100. package/dist/commands/list/json.js.map +1 -0
  101. package/dist/commands/list/list.js +358 -0
  102. package/dist/commands/list/list.js.map +1 -0
  103. package/dist/commands/list/print.js +344 -0
  104. package/dist/commands/list/print.js.map +1 -0
  105. package/dist/commands/list/review.js +120 -0
  106. package/dist/commands/list/review.js.map +1 -0
  107. package/dist/commands/list/suites/suites.js +140 -0
  108. package/dist/commands/list/suites/suites.js.map +1 -0
  109. package/dist/commands/list/views.js +108 -0
  110. package/dist/commands/list/views.js.map +1 -0
  111. package/dist/commands/mcp/dispatch.js +238 -0
  112. package/dist/commands/mcp/dispatch.js.map +1 -0
  113. package/dist/commands/mcp/mcp.js +75 -0
  114. package/dist/commands/mcp/mcp.js.map +1 -0
  115. package/dist/commands/mcp/serve.js +55 -0
  116. package/dist/commands/mcp/serve.js.map +1 -0
  117. package/dist/commands/migrate-openspec/materialize/active.js +175 -0
  118. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  119. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  120. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  121. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  122. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  123. package/dist/commands/migrate-openspec/materialize/stage.js +143 -0
  124. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  125. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  126. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  127. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  128. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  129. package/dist/commands/migrate-openspec/openspec/decisions.js +86 -0
  130. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  131. package/dist/commands/migrate-openspec/openspec/error.js +18 -0
  132. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  133. package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
  134. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  135. package/dist/commands/migrate-openspec/openspec/paths.js +40 -0
  136. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  137. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  138. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  139. package/dist/commands/migrate-openspec/print.js +89 -0
  140. package/dist/commands/migrate-openspec/print.js.map +1 -0
  141. package/dist/commands/new/capability-template.js +118 -0
  142. package/dist/commands/new/capability-template.js.map +1 -0
  143. package/dist/commands/new/commit.js +62 -0
  144. package/dist/commands/new/commit.js.map +1 -0
  145. package/dist/commands/new/modifies.js +206 -0
  146. package/dist/commands/new/modifies.js.map +1 -0
  147. package/dist/commands/new/new.js +328 -0
  148. package/dist/commands/new/new.js.map +1 -0
  149. package/dist/commands/new/templates.js +279 -0
  150. package/dist/commands/new/templates.js.map +1 -0
  151. package/dist/commands/open.js +199 -0
  152. package/dist/commands/open.js.map +1 -0
  153. package/dist/commands/policy/format.js +152 -0
  154. package/dist/commands/policy/format.js.map +1 -0
  155. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +38 -11
  156. package/dist/commands/policy/gate.js.map +1 -0
  157. package/dist/commands/rebase/edit.js +106 -0
  158. package/dist/commands/rebase/edit.js.map +1 -0
  159. package/dist/commands/rebase/living.js +185 -0
  160. package/dist/commands/rebase/living.js.map +1 -0
  161. package/dist/commands/rebase/plan.js +245 -0
  162. package/dist/commands/rebase/plan.js.map +1 -0
  163. package/dist/commands/rebase/rebase.js +300 -0
  164. package/dist/commands/rebase/rebase.js.map +1 -0
  165. package/dist/commands/seed/commit.js +221 -0
  166. package/dist/commands/seed/commit.js.map +1 -0
  167. package/dist/commands/seed/plan.js +278 -0
  168. package/dist/commands/seed/plan.js.map +1 -0
  169. package/dist/commands/seed/seed.js +174 -0
  170. package/dist/commands/seed/seed.js.map +1 -0
  171. package/dist/commands/show/feature.js +182 -0
  172. package/dist/commands/show/feature.js.map +1 -0
  173. package/dist/commands/show/introduced.js +157 -0
  174. package/dist/commands/show/introduced.js.map +1 -0
  175. package/dist/commands/show/marks.js +53 -0
  176. package/dist/commands/show/marks.js.map +1 -0
  177. package/dist/commands/show/service.js +239 -0
  178. package/dist/commands/show/service.js.map +1 -0
  179. package/dist/commands/show/show.js +87 -0
  180. package/dist/commands/show/show.js.map +1 -0
  181. package/dist/commands/status/fleet-next.js +90 -0
  182. package/dist/commands/status/fleet-next.js.map +1 -0
  183. package/dist/commands/status/json.js +47 -0
  184. package/dist/commands/status/json.js.map +1 -0
  185. package/dist/commands/status/print.js +209 -0
  186. package/dist/commands/status/print.js.map +1 -0
  187. package/dist/commands/status/status.js +115 -0
  188. package/dist/commands/status/status.js.map +1 -0
  189. package/dist/commands/steps/steps.js +269 -0
  190. package/dist/commands/steps/steps.js.map +1 -0
  191. package/dist/commands/subsystem/edit.js +192 -0
  192. package/dist/commands/subsystem/edit.js.map +1 -0
  193. package/dist/commands/subsystem/move.js +325 -0
  194. package/dist/commands/subsystem/move.js.map +1 -0
  195. package/dist/commands/subsystem/query.js +113 -0
  196. package/dist/commands/subsystem/query.js.map +1 -0
  197. package/dist/commands/subsystem/subsystem.js +98 -0
  198. package/dist/commands/subsystem/subsystem.js.map +1 -0
  199. package/dist/commands/subsystem/sync.js +318 -0
  200. package/dist/commands/subsystem/sync.js.map +1 -0
  201. package/dist/commands/subsystem/txn/exclude.js +132 -0
  202. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  203. package/dist/commands/subsystem/txn/links.js +128 -0
  204. package/dist/commands/subsystem/txn/links.js.map +1 -0
  205. package/dist/commands/subsystem/txn/report.js +174 -0
  206. package/dist/commands/subsystem/txn/report.js.map +1 -0
  207. package/dist/commands/subsystem/txn/txn.js +196 -0
  208. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  209. package/dist/commands/subsystem/txn/views.js +249 -0
  210. package/dist/commands/subsystem/txn/views.js.map +1 -0
  211. package/dist/commands/tasks/actions.js +107 -0
  212. package/dist/commands/tasks/actions.js.map +1 -0
  213. package/dist/commands/tasks/render.js +253 -0
  214. package/dist/commands/tasks/render.js.map +1 -0
  215. package/dist/commands/tasks/tasks.js +119 -0
  216. package/dist/commands/tasks/tasks.js.map +1 -0
  217. package/dist/commands/unarchive/manifest.js +176 -0
  218. package/dist/commands/unarchive/manifest.js.map +1 -0
  219. package/dist/commands/unarchive/restore.js +254 -0
  220. package/dist/commands/unarchive/restore.js.map +1 -0
  221. package/dist/commands/unarchive/unarchive.js +59 -0
  222. package/dist/commands/unarchive/unarchive.js.map +1 -0
  223. package/dist/commands/validate/arch-coverage.js +245 -0
  224. package/dist/commands/validate/arch-coverage.js.map +1 -0
  225. package/dist/commands/validate/checks/fleet-shape.js +204 -0
  226. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  227. package/dist/commands/validate/checks/health-deps.js +58 -0
  228. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  229. package/dist/commands/validate/checks/introduced.js +102 -0
  230. package/dist/commands/validate/checks/introduced.js.map +1 -0
  231. package/dist/commands/validate/checks/requirements.js +264 -0
  232. package/dist/commands/validate/checks/requirements.js.map +1 -0
  233. package/dist/commands/validate/checks/sources.js +85 -0
  234. package/dist/commands/validate/checks/sources.js.map +1 -0
  235. package/dist/commands/validate/coverage/covers-after.js +105 -0
  236. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  237. package/dist/commands/validate/feature.js +222 -0
  238. package/dist/commands/validate/feature.js.map +1 -0
  239. package/dist/commands/validate/fleet/census.js +93 -0
  240. package/dist/commands/validate/fleet/census.js.map +1 -0
  241. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  242. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  243. package/dist/commands/validate/fleet/landscape.js +371 -0
  244. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  245. package/dist/commands/validate/fleet/load.js +118 -0
  246. package/dist/commands/validate/fleet/load.js.map +1 -0
  247. package/dist/commands/validate/fleet/map/attest.js +98 -0
  248. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  249. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  250. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  251. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  252. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  253. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  254. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  255. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  256. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  257. package/dist/commands/validate/fleet/obligations.js +266 -0
  258. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  259. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  260. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  261. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  262. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  263. package/dist/commands/validate/fleet/scorecard/print.js +71 -0
  264. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  265. package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
  266. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  267. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  268. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  269. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  270. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  271. package/dist/commands/validate/fleet/views/ids.js +75 -0
  272. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  273. package/dist/commands/validate/fleet/views/projects.js +278 -0
  274. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  275. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  276. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  277. package/dist/commands/validate/fleet/views/stale.js +52 -0
  278. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  279. package/dist/commands/validate/links/corpus.js +89 -0
  280. package/dist/commands/validate/links/corpus.js.map +1 -0
  281. package/dist/commands/validate/links/glossary.js +75 -0
  282. package/dist/commands/validate/links/glossary.js.map +1 -0
  283. package/dist/commands/validate/render/repeats.js +63 -0
  284. package/dist/commands/validate/render/repeats.js.map +1 -0
  285. package/dist/commands/validate/render/rollups.js +115 -0
  286. package/dist/commands/validate/render/rollups.js.map +1 -0
  287. package/dist/commands/validate/render/text.js +199 -0
  288. package/dist/commands/validate/render/text.js.map +1 -0
  289. package/dist/commands/validate/report.js +145 -0
  290. package/dist/commands/validate/report.js.map +1 -0
  291. package/dist/commands/validate/scope.js +113 -0
  292. package/dist/commands/validate/scope.js.map +1 -0
  293. package/dist/commands/validate/service/api.js +252 -0
  294. package/dist/commands/validate/service/api.js.map +1 -0
  295. package/dist/commands/validate/service/contracts/generated.js +134 -0
  296. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  297. package/dist/commands/validate/service/events/events.js +241 -0
  298. package/dist/commands/validate/service/events/events.js.map +1 -0
  299. package/dist/commands/validate/service/events/message-producers.js +77 -0
  300. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  301. package/dist/commands/validate/service/evidence-pins.js +177 -0
  302. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  303. package/dist/commands/validate/service/model/diverged.js +226 -0
  304. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  305. package/dist/commands/validate/service/model/grade.js +163 -0
  306. package/dist/commands/validate/service/model/grade.js.map +1 -0
  307. package/dist/commands/validate/service/service.js +310 -0
  308. package/dist/commands/validate/service/service.js.map +1 -0
  309. package/dist/commands/validate/service/specs.js +279 -0
  310. package/dist/commands/validate/service/specs.js.map +1 -0
  311. package/dist/commands/validate/service/spine.js +148 -0
  312. package/dist/commands/validate/service/spine.js.map +1 -0
  313. package/dist/commands/validate/service/usecases/tags.js +113 -0
  314. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  315. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  316. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  317. package/dist/commands/validate/validate.js +363 -0
  318. package/dist/commands/validate/validate.js.map +1 -0
  319. package/dist/commands/verify/cross/diff.js +178 -0
  320. package/dist/commands/verify/cross/diff.js.map +1 -0
  321. package/dist/commands/verify/evidence/contract.js +32 -0
  322. package/dist/commands/verify/evidence/contract.js.map +1 -0
  323. package/dist/commands/verify/evidence/pins.js +52 -0
  324. package/dist/commands/verify/evidence/pins.js.map +1 -0
  325. package/dist/commands/verify/evidence/read.js +81 -0
  326. package/dist/commands/verify/evidence/read.js.map +1 -0
  327. package/dist/commands/verify/frozen.js +263 -0
  328. package/dist/commands/verify/frozen.js.map +1 -0
  329. package/dist/commands/verify/record.js +278 -0
  330. package/dist/commands/verify/record.js.map +1 -0
  331. package/dist/commands/verify/report.js +206 -0
  332. package/dist/commands/verify/report.js.map +1 -0
  333. package/dist/commands/verify/results.js +328 -0
  334. package/dist/commands/verify/results.js.map +1 -0
  335. package/dist/commands/verify/verify.js +220 -0
  336. package/dist/commands/verify/verify.js.map +1 -0
  337. package/dist/commands/vouch/contract.js +11 -0
  338. package/dist/commands/vouch/contract.js.map +1 -0
  339. package/dist/commands/vouch/pack/contract.js +2 -0
  340. package/dist/commands/vouch/pack/contract.js.map +1 -0
  341. package/dist/commands/vouch/pack/pack.js +266 -0
  342. package/dist/commands/vouch/pack/pack.js.map +1 -0
  343. package/dist/commands/vouch/pack/print.js +266 -0
  344. package/dist/commands/vouch/pack/print.js.map +1 -0
  345. package/dist/commands/vouch/pack/sections.js +141 -0
  346. package/dist/commands/vouch/pack/sections.js.map +1 -0
  347. package/dist/commands/vouch/prompt/confirm.js +46 -0
  348. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  349. package/dist/commands/vouch/report.js +101 -0
  350. package/dist/commands/vouch/report.js.map +1 -0
  351. package/dist/commands/vouch/run.js +230 -0
  352. package/dist/commands/vouch/run.js.map +1 -0
  353. package/dist/commands/vouch/sample/plan.js +111 -0
  354. package/dist/commands/vouch/sample/plan.js.map +1 -0
  355. package/dist/commands/vouch/sample/print.js +109 -0
  356. package/dist/commands/vouch/sample/print.js.map +1 -0
  357. package/dist/commands/vouch/vet/verify.js +155 -0
  358. package/dist/commands/vouch/vet/verify.js.map +1 -0
  359. package/dist/commands/vouch/vouch.js +169 -0
  360. package/dist/commands/vouch/vouch.js.map +1 -0
  361. package/dist/core/agent/agents-md/command-map.js +299 -0
  362. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  363. package/dist/core/agent/agents-md/map/explain.js +46 -0
  364. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  365. package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
  366. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  367. package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
  368. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  369. package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
  370. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  371. package/dist/core/agent/agents-md/map/mcp.js +44 -0
  372. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  373. package/dist/core/agent/agents-md/map/status.js +78 -0
  374. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  375. package/dist/core/agent/agents-md/map/subsystem.js +104 -0
  376. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  377. package/dist/core/agent/agents-md/map/usecases.js +138 -0
  378. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  379. package/dist/core/agent/agents-md/refusals.js +273 -0
  380. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  381. package/dist/core/agent/agents-md.js +203 -0
  382. package/dist/core/agent/agents-md.js.map +1 -0
  383. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -0
  384. package/dist/core/agent/agents-stamp.js.map +1 -0
  385. package/dist/core/agent/contract.js +2 -0
  386. package/dist/core/agent/contract.js.map +1 -0
  387. package/dist/core/agent/protocol.js +193 -0
  388. package/dist/core/agent/protocol.js.map +1 -0
  389. package/dist/core/agent/scaffold.js +254 -0
  390. package/dist/core/agent/scaffold.js.map +1 -0
  391. package/dist/core/agent/support/report.js +144 -0
  392. package/dist/core/agent/support/report.js.map +1 -0
  393. package/dist/core/agent/tools/dialects.js +151 -0
  394. package/dist/core/agent/tools/dialects.js.map +1 -0
  395. package/dist/core/agent/tools/registry.js +193 -0
  396. package/dist/core/agent/tools/registry.js.map +1 -0
  397. package/dist/core/agent/workflows/adopt.js +280 -0
  398. package/dist/core/agent/workflows/adopt.js.map +1 -0
  399. package/dist/core/agent/workflows/check.js +373 -0
  400. package/dist/core/agent/workflows/check.js.map +1 -0
  401. package/dist/core/agent/workflows/closing.js +323 -0
  402. package/dist/core/agent/workflows/closing.js.map +1 -0
  403. package/dist/core/agent/workflows/feature.js +220 -0
  404. package/dist/core/agent/workflows/feature.js.map +1 -0
  405. package/dist/core/agent/workflows/implement.js +188 -0
  406. package/dist/core/agent/workflows/implement.js.map +1 -0
  407. package/dist/core/agent/workflows/reference/authoring.js +311 -0
  408. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  409. package/dist/core/agent/workflows/reference/codes.js +67 -0
  410. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  411. package/dist/core/agent/workflows/reference/done-check.js +210 -0
  412. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  413. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  414. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  415. package/dist/core/agent/workflows/reference/reference.js +19 -0
  416. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  417. package/dist/core/agent/workflows/reference/spine.js +338 -0
  418. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  419. package/dist/core/asyncapi/baseline/plan.js +43 -0
  420. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  421. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  422. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  423. package/dist/core/asyncapi/depth.js +164 -0
  424. package/dist/core/asyncapi/depth.js.map +1 -0
  425. package/dist/core/asyncapi/digest.js +146 -0
  426. package/dist/core/asyncapi/digest.js.map +1 -0
  427. package/dist/core/asyncapi/merge/components.js +92 -0
  428. package/dist/core/asyncapi/merge/components.js.map +1 -0
  429. package/dist/core/asyncapi/merge/error.js +38 -0
  430. package/dist/core/asyncapi/merge/error.js.map +1 -0
  431. package/dist/core/asyncapi/merge/markers.js +290 -0
  432. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  433. package/dist/core/asyncapi/merge/merge.js +195 -0
  434. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  435. package/dist/core/asyncapi/merge/pin.js +83 -0
  436. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  437. package/dist/core/asyncapi/model.js +11 -0
  438. package/dist/core/asyncapi/model.js.map +1 -0
  439. package/dist/core/asyncapi/producers.js +50 -0
  440. package/dist/core/asyncapi/producers.js.map +1 -0
  441. package/dist/core/asyncapi/read.js +263 -0
  442. package/dist/core/asyncapi/read.js.map +1 -0
  443. package/dist/core/brief/brief.js +285 -0
  444. package/dist/core/brief/brief.js.map +1 -0
  445. package/dist/core/brief/checks.js +385 -0
  446. package/dist/core/brief/checks.js.map +1 -0
  447. package/dist/core/brief/landscape.js +273 -0
  448. package/dist/core/brief/landscape.js.map +1 -0
  449. package/dist/core/brief/map/extend.js +84 -0
  450. package/dist/core/brief/map/extend.js.map +1 -0
  451. package/dist/core/brief/map/owed.js +266 -0
  452. package/dist/core/brief/map/owed.js.map +1 -0
  453. package/dist/core/brief/targets.js +304 -0
  454. package/dist/core/brief/targets.js.map +1 -0
  455. package/dist/core/brief/unchecked.js +58 -0
  456. package/dist/core/brief/unchecked.js.map +1 -0
  457. package/dist/core/c4/arch.js +190 -0
  458. package/dist/core/c4/arch.js.map +1 -0
  459. package/dist/core/c4/direction/direction.js +114 -0
  460. package/dist/core/c4/direction/direction.js.map +1 -0
  461. package/dist/core/c4/likec4.js +243 -0
  462. package/dist/core/c4/likec4.js.map +1 -0
  463. package/dist/core/c4/locate/unlocated.js +150 -0
  464. package/dist/core/c4/locate/unlocated.js.map +1 -0
  465. package/dist/core/c4/parsed/deployment.js +160 -0
  466. package/dist/core/c4/parsed/deployment.js.map +1 -0
  467. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  468. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  469. package/dist/core/c4/parsed/specification.js +78 -0
  470. package/dist/core/c4/parsed/specification.js.map +1 -0
  471. package/dist/core/c4/parsed/values.js +110 -0
  472. package/dist/core/c4/parsed/values.js.map +1 -0
  473. package/dist/core/c4/parsed/view-ids.js +113 -0
  474. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  475. package/dist/core/c4/prefetch/fleet.js +134 -0
  476. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  477. package/dist/core/c4/project/architecture.js +161 -0
  478. package/dist/core/c4/project/architecture.js.map +1 -0
  479. package/dist/core/c4/project/batch.js +140 -0
  480. package/dist/core/c4/project/batch.js.map +1 -0
  481. package/dist/core/c4/project/documents.js +89 -0
  482. package/dist/core/c4/project/documents.js.map +1 -0
  483. package/dist/core/c4/project/load.js +219 -0
  484. package/dist/core/c4/project/load.js.map +1 -0
  485. package/dist/core/c4/project/staged.js +277 -0
  486. package/dist/core/c4/project/staged.js.map +1 -0
  487. package/dist/core/c4/resolve/attested.js +0 -0
  488. package/dist/core/c4/resolve/attested.js.map +1 -0
  489. package/dist/core/c4/resolve/external.js +51 -0
  490. package/dist/core/c4/resolve/external.js.map +1 -0
  491. package/dist/core/c4/resolve/service.js +174 -0
  492. package/dist/core/c4/resolve/service.js.map +1 -0
  493. package/dist/core/c4/resolve/steps.js +290 -0
  494. package/dist/core/c4/resolve/steps.js.map +1 -0
  495. package/dist/core/c4/resolve/systems.js +154 -0
  496. package/dist/core/c4/resolve/systems.js.map +1 -0
  497. package/dist/core/c4/root-project/exclude.js +352 -0
  498. package/dist/core/c4/root-project/exclude.js.map +1 -0
  499. package/dist/core/c4/seed/fleet-file.js +201 -0
  500. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  501. package/dist/core/c4/seed/items.js +91 -0
  502. package/dist/core/c4/seed/items.js.map +1 -0
  503. package/dist/core/c4/seed/stamp.js +48 -0
  504. package/dist/core/c4/seed/stamp.js.map +1 -0
  505. package/dist/core/c4/seed/template.js +173 -0
  506. package/dist/core/c4/seed/template.js.map +1 -0
  507. package/dist/core/c4/service-model/created/models.js +96 -0
  508. package/dist/core/c4/service-model/created/models.js.map +1 -0
  509. package/dist/core/c4/service-model/documents.js +47 -0
  510. package/dist/core/c4/service-model/documents.js.map +1 -0
  511. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  512. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  513. package/dist/core/c4/service-model/load.js +165 -0
  514. package/dist/core/c4/service-model/load.js.map +1 -0
  515. package/dist/core/c4/service-model/renderer.js +128 -0
  516. package/dist/core/c4/service-model/renderer.js.map +1 -0
  517. package/dist/core/c4/service-model/shape.js +106 -0
  518. package/dist/core/c4/service-model/shape.js.map +1 -0
  519. package/dist/core/c4/service-model/slice.js +188 -0
  520. package/dist/core/c4/service-model/slice.js.map +1 -0
  521. package/dist/core/c4/source-mask.js +369 -0
  522. package/dist/core/c4/source-mask.js.map +1 -0
  523. package/dist/core/c4/source-scan.js +308 -0
  524. package/dist/core/c4/source-scan.js.map +1 -0
  525. package/dist/core/c4/splice/authored-source.js +167 -0
  526. package/dist/core/c4/splice/authored-source.js.map +1 -0
  527. package/dist/core/c4/splice/contract.js +30 -0
  528. package/dist/core/c4/splice/contract.js.map +1 -0
  529. package/dist/core/c4/splice/delta-blocks.js +126 -0
  530. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  531. package/dist/core/c4/splice/identity/declared.js +87 -0
  532. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  533. package/dist/core/c4/splice/identity/edges.js +73 -0
  534. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  535. package/dist/core/c4/splice/identity/existing.js +80 -0
  536. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  537. package/dist/core/c4/splice/identity/interior.js +80 -0
  538. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  539. package/dist/core/c4/splice/identity/owner.js +50 -0
  540. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  541. package/dist/core/c4/splice/landscape-merge.js +337 -0
  542. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  543. package/dist/core/c4/splice/model/merge.js +151 -0
  544. package/dist/core/c4/splice/model/merge.js.map +1 -0
  545. package/dist/core/c4/splice/placement.js +298 -0
  546. package/dist/core/c4/splice/placement.js.map +1 -0
  547. package/dist/core/c4/splice/text/spot.js +131 -0
  548. package/dist/core/c4/splice/text/spot.js.map +1 -0
  549. package/dist/core/c4/workspace.js +166 -0
  550. package/dist/core/c4/workspace.js.map +1 -0
  551. package/dist/core/capabilities/authoring/notes.js +141 -0
  552. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  553. package/dist/core/capabilities/capabilities.js +124 -0
  554. package/dist/core/capabilities/capabilities.js.map +1 -0
  555. package/dist/core/capabilities/delta/doc.js +47 -0
  556. package/dist/core/capabilities/delta/doc.js.map +1 -0
  557. package/dist/core/capabilities/delta/overlay.js +129 -0
  558. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  559. package/dist/core/capabilities/delta/summary.js +57 -0
  560. package/dist/core/capabilities/delta/summary.js.map +1 -0
  561. package/dist/core/capabilities/delta/tree.js +43 -0
  562. package/dist/core/capabilities/delta/tree.js.map +1 -0
  563. package/dist/core/capabilities/delta/uncovered.js +222 -0
  564. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  565. package/dist/core/capabilities/findings.js +338 -0
  566. package/dist/core/capabilities/findings.js.map +1 -0
  567. package/dist/core/capabilities/realizes/findings.js +174 -0
  568. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  569. package/dist/core/capabilities/realizes/join.js +123 -0
  570. package/dist/core/capabilities/realizes/join.js.map +1 -0
  571. package/dist/core/capabilities/rollup.js +205 -0
  572. package/dist/core/capabilities/rollup.js.map +1 -0
  573. package/dist/core/capabilities/tree.js +104 -0
  574. package/dist/core/capabilities/tree.js.map +1 -0
  575. package/dist/core/capabilities/usecase-join.js +267 -0
  576. package/dist/core/capabilities/usecase-join.js.map +1 -0
  577. package/dist/core/coherence/authoring/scaffold.js +185 -0
  578. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  579. package/dist/core/coherence/authoring/sentinels.js +75 -0
  580. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  581. package/dist/core/coherence/calls/called.js +52 -0
  582. package/dist/core/coherence/calls/called.js.map +1 -0
  583. package/dist/core/coherence/coherence.js +332 -0
  584. package/dist/core/coherence/coherence.js.map +1 -0
  585. package/dist/core/coherence/consumed/operations.js +70 -0
  586. package/dist/core/coherence/consumed/operations.js.map +1 -0
  587. package/dist/core/coherence/consumed/refusal.js +38 -0
  588. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  589. package/dist/core/coherence/covers/health.js +85 -0
  590. package/dist/core/coherence/covers/health.js.map +1 -0
  591. package/dist/core/coherence/declared.js +295 -0
  592. package/dist/core/coherence/declared.js.map +1 -0
  593. package/dist/core/coherence/events/declared.js +191 -0
  594. package/dist/core/coherence/events/declared.js.map +1 -0
  595. package/dist/core/coherence/events/events.js +335 -0
  596. package/dist/core/coherence/events/events.js.map +1 -0
  597. package/dist/core/coherence/events/grades.js +189 -0
  598. package/dist/core/coherence/events/grades.js.map +1 -0
  599. package/dist/core/coherence/events/lookups.js +63 -0
  600. package/dist/core/coherence/events/lookups.js.map +1 -0
  601. package/dist/core/coherence/events/produced.js +100 -0
  602. package/dist/core/coherence/events/produced.js.map +1 -0
  603. package/dist/core/coherence/living.js +198 -0
  604. package/dist/core/coherence/living.js.map +1 -0
  605. package/dist/core/coherence/lookups.js +95 -0
  606. package/dist/core/coherence/lookups.js.map +1 -0
  607. package/dist/core/coherence/pending.js +39 -0
  608. package/dist/core/coherence/pending.js.map +1 -0
  609. package/dist/core/coherence/retired/archived.js +285 -0
  610. package/dist/core/coherence/retired/archived.js.map +1 -0
  611. package/dist/core/coherence/retired/event-pair.js +62 -0
  612. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  613. package/dist/core/coherence/retired/merged.js +79 -0
  614. package/dist/core/coherence/retired/merged.js.map +1 -0
  615. package/dist/core/coherence/retired/retirement.js +49 -0
  616. package/dist/core/coherence/retired/retirement.js.map +1 -0
  617. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  618. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  619. package/dist/core/coherence/retired/revival/revived.js +297 -0
  620. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  621. package/dist/core/conflict-markers.js +60 -0
  622. package/dist/core/conflict-markers.js.map +1 -0
  623. package/dist/core/consumers/after.js +113 -0
  624. package/dist/core/consumers/after.js.map +1 -0
  625. package/dist/core/consumers/consumers.js +296 -0
  626. package/dist/core/consumers/consumers.js.map +1 -0
  627. package/dist/core/consumers/current.js +211 -0
  628. package/dist/core/consumers/current.js.map +1 -0
  629. package/dist/core/consumers/scan.js +46 -0
  630. package/dist/core/consumers/scan.js.map +1 -0
  631. package/dist/core/consumers/state.js +27 -0
  632. package/dist/core/consumers/state.js.map +1 -0
  633. package/dist/core/delta/claims.js +73 -0
  634. package/dist/core/delta/claims.js.map +1 -0
  635. package/dist/core/delta/delta.js +341 -0
  636. package/dist/core/delta/delta.js.map +1 -0
  637. package/dist/core/delta/document.js +177 -0
  638. package/dist/core/delta/document.js.map +1 -0
  639. package/dist/core/delta/scope.js +48 -0
  640. package/dist/core/delta/scope.js.map +1 -0
  641. package/dist/core/delta/select.js +237 -0
  642. package/dist/core/delta/select.js.map +1 -0
  643. package/dist/core/dependencies/dependencies.js +141 -0
  644. package/dist/core/dependencies/dependencies.js.map +1 -0
  645. package/dist/core/dependencies/facts.js +165 -0
  646. package/dist/core/dependencies/facts.js.map +1 -0
  647. package/dist/core/dependencies/fanin.js +88 -0
  648. package/dist/core/dependencies/fanin.js.map +1 -0
  649. package/dist/core/dependencies/graph.js +106 -0
  650. package/dist/core/dependencies/graph.js.map +1 -0
  651. package/dist/core/deployment/delta.js +191 -0
  652. package/dist/core/deployment/delta.js.map +1 -0
  653. package/dist/core/deployment/objects.js +145 -0
  654. package/dist/core/deployment/objects.js.map +1 -0
  655. package/dist/core/diff/base-git.js +230 -0
  656. package/dist/core/diff/base-git.js.map +1 -0
  657. package/dist/core/diff/base-state.js +237 -0
  658. package/dist/core/diff/base-state.js.map +1 -0
  659. package/dist/core/diff/joins.js +136 -0
  660. package/dist/core/diff/joins.js.map +1 -0
  661. package/dist/core/diff/scope/changed-paths.js +204 -0
  662. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  663. package/dist/core/diff/scope/edges.js +82 -0
  664. package/dist/core/diff/scope/edges.js.map +1 -0
  665. package/dist/core/diff/semantic.js +312 -0
  666. package/dist/core/diff/semantic.js.map +1 -0
  667. package/dist/core/docs.js +37 -85
  668. package/dist/core/docs.js.map +1 -1
  669. package/dist/core/doctor/agents.js +238 -0
  670. package/dist/core/doctor/agents.js.map +1 -0
  671. package/dist/core/doctor/config.js +139 -0
  672. package/dist/core/doctor/config.js.map +1 -0
  673. package/dist/core/doctor/doctor.js +355 -0
  674. package/dist/core/doctor/doctor.js.map +1 -0
  675. package/dist/core/doctor/report.js +13 -0
  676. package/dist/core/doctor/report.js.map +1 -0
  677. package/dist/core/doctor/reports/scan.js +242 -0
  678. package/dist/core/doctor/reports/scan.js.map +1 -0
  679. package/dist/core/doctor/residue.js +110 -0
  680. package/dist/core/doctor/residue.js.map +1 -0
  681. package/dist/core/document/apply.js +224 -0
  682. package/dist/core/document/apply.js.map +1 -0
  683. package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -2
  684. package/dist/core/document/frontmatter.js.map +1 -0
  685. package/dist/core/document/grammar/directives.js +143 -0
  686. package/dist/core/document/grammar/directives.js.map +1 -0
  687. package/dist/core/document/parse.js +286 -0
  688. package/dist/core/document/parse.js.map +1 -0
  689. package/dist/core/document/scenarios.js +238 -0
  690. package/dist/core/document/scenarios.js.map +1 -0
  691. package/dist/core/document/spec.js +234 -0
  692. package/dist/core/document/spec.js.map +1 -0
  693. package/dist/core/{config.js → envelope/config.js} +89 -18
  694. package/dist/core/envelope/config.js.map +1 -0
  695. package/dist/core/envelope/json.js +209 -0
  696. package/dist/core/envelope/json.js.map +1 -0
  697. package/dist/core/{version.js → envelope/version.js} +3 -3
  698. package/dist/core/envelope/version.js.map +1 -0
  699. package/dist/core/explain/families.js +180 -0
  700. package/dist/core/explain/families.js.map +1 -0
  701. package/dist/core/explain/fix-tables.js +178 -0
  702. package/dist/core/explain/fix-tables.js.map +1 -0
  703. package/dist/core/explain/lookup.js +194 -0
  704. package/dist/core/explain/lookup.js.map +1 -0
  705. package/dist/core/explain/refusals.js +49 -0
  706. package/dist/core/explain/refusals.js.map +1 -0
  707. package/dist/core/explain/terms/documents.js +227 -0
  708. package/dist/core/explain/terms/documents.js.map +1 -0
  709. package/dist/core/explain/terms/done-check.js +144 -0
  710. package/dist/core/explain/terms/done-check.js.map +1 -0
  711. package/dist/core/explain/terms/entry.js +14 -0
  712. package/dist/core/explain/terms/entry.js.map +1 -0
  713. package/dist/core/explain/terms/stages.js +71 -0
  714. package/dist/core/explain/terms/stages.js.map +1 -0
  715. package/dist/core/explain/terms/tasks.js +97 -0
  716. package/dist/core/explain/terms/tasks.js.map +1 -0
  717. package/dist/core/explain/terms.js +103 -0
  718. package/dist/core/explain/terms.js.map +1 -0
  719. package/dist/core/explore/describe.js +105 -0
  720. package/dist/core/explore/describe.js.map +1 -0
  721. package/dist/core/explore/explore.js +204 -0
  722. package/dist/core/explore/explore.js.map +1 -0
  723. package/dist/core/fleet-context.js +174 -146
  724. package/dist/core/fleet-context.js.map +1 -1
  725. package/dist/core/gate/checks.js +208 -0
  726. package/dist/core/gate/checks.js.map +1 -0
  727. package/dist/core/gate/partners.js +246 -0
  728. package/dist/core/gate/partners.js.map +1 -0
  729. package/dist/core/gate/report.js +47 -0
  730. package/dist/core/gate/report.js.map +1 -0
  731. package/dist/core/gate/verification.js +176 -0
  732. package/dist/core/gate/verification.js.map +1 -0
  733. package/dist/core/gherkin/digest.js +60 -0
  734. package/dist/core/gherkin/digest.js.map +1 -0
  735. package/dist/core/gherkin/emit.js +177 -0
  736. package/dist/core/gherkin/emit.js.map +1 -0
  737. package/dist/core/gherkin/read.js +76 -0
  738. package/dist/core/gherkin/read.js.map +1 -0
  739. package/dist/core/gherkin/stale.js +210 -0
  740. package/dist/core/gherkin/stale.js.map +1 -0
  741. package/dist/core/gherkin/stamp.js +77 -0
  742. package/dist/core/gherkin/stamp.js.map +1 -0
  743. package/dist/core/gherkin/steps/catalogue.js +154 -0
  744. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  745. package/dist/core/gherkin/steps/inventory.js +98 -0
  746. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  747. package/dist/core/gherkin/steps/phrase.js +72 -0
  748. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  749. package/dist/core/glossary/delta.js +109 -0
  750. package/dist/core/glossary/delta.js.map +1 -0
  751. package/dist/core/glossary/tree.js +73 -0
  752. package/dist/core/glossary/tree.js.map +1 -0
  753. package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -0
  754. package/dist/core/kernel/concurrency.js.map +1 -0
  755. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  756. package/dist/core/kernel/document-bytes.js.map +1 -0
  757. package/dist/core/kernel/fences.js +42 -0
  758. package/dist/core/kernel/fences.js.map +1 -0
  759. package/dist/core/kernel/ids/capability.js +72 -0
  760. package/dist/core/kernel/ids/capability.js.map +1 -0
  761. package/dist/core/kernel/ids/dirs.js +33 -0
  762. package/dist/core/kernel/ids/dirs.js.map +1 -0
  763. package/dist/core/kernel/ids/feature.js +75 -0
  764. package/dist/core/kernel/ids/feature.js.map +1 -0
  765. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  766. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  767. package/dist/core/kernel/ids/service.js +156 -0
  768. package/dist/core/kernel/ids/service.js.map +1 -0
  769. package/dist/core/kernel/ids/subsystem.js +63 -0
  770. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  771. package/dist/core/{path-safety.js → kernel/path-safety.js} +56 -4
  772. package/dist/core/kernel/path-safety.js.map +1 -0
  773. package/dist/core/{records.js → kernel/records.js} +11 -0
  774. package/dist/core/kernel/records.js.map +1 -0
  775. package/dist/core/links/backlinks.js +66 -0
  776. package/dist/core/links/backlinks.js.map +1 -0
  777. package/dist/core/links/case.js +74 -0
  778. package/dist/core/links/case.js.map +1 -0
  779. package/dist/core/links/corpus.js +118 -0
  780. package/dist/core/links/corpus.js.map +1 -0
  781. package/dist/core/links/findings.js +110 -0
  782. package/dist/core/links/findings.js.map +1 -0
  783. package/dist/core/links/parse.js +265 -0
  784. package/dist/core/links/parse.js.map +1 -0
  785. package/dist/core/mcp/argv.js +212 -0
  786. package/dist/core/mcp/argv.js.map +1 -0
  787. package/dist/core/mcp/author-tools.js +73 -0
  788. package/dist/core/mcp/author-tools.js.map +1 -0
  789. package/dist/core/mcp/framing.js +46 -0
  790. package/dist/core/mcp/framing.js.map +1 -0
  791. package/dist/core/mcp/protocol.js +280 -0
  792. package/dist/core/mcp/protocol.js.map +1 -0
  793. package/dist/core/mcp/tools.js +324 -0
  794. package/dist/core/mcp/tools.js.map +1 -0
  795. package/dist/core/obligations/obligations.js +106 -0
  796. package/dist/core/obligations/obligations.js.map +1 -0
  797. package/dist/core/openapi/baseline/gate.js +207 -0
  798. package/dist/core/openapi/baseline/gate.js.map +1 -0
  799. package/dist/core/openapi/baseline/plan.js +142 -0
  800. package/dist/core/openapi/baseline/plan.js.map +1 -0
  801. package/dist/core/openapi/baseline/record.js +174 -0
  802. package/dist/core/openapi/baseline/record.js.map +1 -0
  803. package/dist/core/openapi/contract-text.js +33 -0
  804. package/dist/core/openapi/contract-text.js.map +1 -0
  805. package/dist/core/openapi/contract-tree.js +301 -0
  806. package/dist/core/openapi/contract-tree.js.map +1 -0
  807. package/dist/core/openapi/depth.js +136 -0
  808. package/dist/core/openapi/depth.js.map +1 -0
  809. package/dist/core/openapi/digest.js +239 -0
  810. package/dist/core/openapi/digest.js.map +1 -0
  811. package/dist/core/{openapi.js → openapi/doc.js} +54 -108
  812. package/dist/core/openapi/doc.js.map +1 -0
  813. package/dist/core/openapi/merge/components.js +199 -0
  814. package/dist/core/openapi/merge/components.js.map +1 -0
  815. package/dist/core/openapi/merge/error.js +16 -0
  816. package/dist/core/openapi/merge/error.js.map +1 -0
  817. package/dist/core/openapi/merge/markers.js +204 -0
  818. package/dist/core/openapi/merge/markers.js.map +1 -0
  819. package/dist/core/openapi/merge/merge.js +232 -0
  820. package/dist/core/openapi/merge/merge.js.map +1 -0
  821. package/dist/core/openapi/merge/pin.js +110 -0
  822. package/dist/core/openapi/merge/pin.js.map +1 -0
  823. package/dist/core/openspec/decide/capabilities.js +244 -0
  824. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  825. package/dist/core/openspec/decide/dispositions.js +63 -0
  826. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  827. package/dist/core/openspec/decide/renames.js +179 -0
  828. package/dist/core/openspec/decide/renames.js.map +1 -0
  829. package/dist/core/openspec/decide/verdict.js +84 -0
  830. package/dist/core/openspec/decide/verdict.js.map +1 -0
  831. package/dist/core/openspec/inventory.js +220 -0
  832. package/dist/core/openspec/inventory.js.map +1 -0
  833. package/dist/core/openspec/model/mapping.js +78 -0
  834. package/dist/core/openspec/model/mapping.js.map +1 -0
  835. package/dist/core/openspec/model/model.js +70 -0
  836. package/dist/core/openspec/model/model.js.map +1 -0
  837. package/dist/core/openspec/scan/changes.js +241 -0
  838. package/dist/core/openspec/scan/changes.js.map +1 -0
  839. package/dist/core/openspec/scan/config.js +191 -0
  840. package/dist/core/openspec/scan/config.js.map +1 -0
  841. package/dist/core/openspec/scan/shape.js +304 -0
  842. package/dist/core/openspec/scan/shape.js.map +1 -0
  843. package/dist/core/openspec/scan/walk.js +116 -0
  844. package/dist/core/openspec/scan/walk.js.map +1 -0
  845. package/dist/core/openspec/scan/workspace.js +71 -0
  846. package/dist/core/openspec/scan/workspace.js.map +1 -0
  847. package/dist/core/owners/codeowners.js +141 -0
  848. package/dist/core/owners/codeowners.js.map +1 -0
  849. package/dist/core/pack/features.js +120 -0
  850. package/dist/core/pack/features.js.map +1 -0
  851. package/dist/core/pack/joins.js +112 -0
  852. package/dist/core/pack/joins.js.map +1 -0
  853. package/dist/core/pack/living.js +157 -0
  854. package/dist/core/pack/living.js.map +1 -0
  855. package/dist/core/pack/pack.js +120 -0
  856. package/dist/core/pack/pack.js.map +1 -0
  857. package/dist/core/permissions/permissions.js +87 -0
  858. package/dist/core/permissions/permissions.js.map +1 -0
  859. package/dist/core/projection/api.js +84 -0
  860. package/dist/core/projection/api.js.map +1 -0
  861. package/dist/core/projection/arch-slice.js +63 -0
  862. package/dist/core/projection/arch-slice.js.map +1 -0
  863. package/dist/core/projection/events.js +34 -0
  864. package/dist/core/projection/events.js.map +1 -0
  865. package/dist/core/projection/introduced.js +14 -0
  866. package/dist/core/projection/introduced.js.map +1 -0
  867. package/dist/core/provenance/findings.js +244 -0
  868. package/dist/core/provenance/findings.js.map +1 -0
  869. package/dist/core/provenance/git.js +201 -0
  870. package/dist/core/provenance/git.js.map +1 -0
  871. package/dist/core/provenance/gitq/moves.js +139 -0
  872. package/dist/core/provenance/gitq/moves.js.map +1 -0
  873. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  874. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  875. package/dist/core/provenance/sample/scope.js +238 -0
  876. package/dist/core/provenance/sample/scope.js.map +1 -0
  877. package/dist/core/provenance/sample/sections.js +61 -0
  878. package/dist/core/provenance/sample/sections.js.map +1 -0
  879. package/dist/core/provenance/sources.js +280 -0
  880. package/dist/core/provenance/sources.js.map +1 -0
  881. package/dist/core/provenance/stamp.js +220 -0
  882. package/dist/core/provenance/stamp.js.map +1 -0
  883. package/dist/core/provenance/walk.js +157 -0
  884. package/dist/core/provenance/walk.js.map +1 -0
  885. package/dist/core/repo/authored/paths.js +210 -0
  886. package/dist/core/repo/authored/paths.js.map +1 -0
  887. package/dist/core/repo/entries.js +126 -0
  888. package/dist/core/repo/entries.js.map +1 -0
  889. package/dist/core/repo/paths.js +322 -0
  890. package/dist/core/repo/paths.js.map +1 -0
  891. package/dist/core/repo/repo.js +308 -0
  892. package/dist/core/repo/repo.js.map +1 -0
  893. package/dist/core/repo/service-target.js +153 -0
  894. package/dist/core/repo/service-target.js.map +1 -0
  895. package/dist/core/repo/state.js +58 -0
  896. package/dist/core/repo/state.js.map +1 -0
  897. package/dist/core/repo/tree/find.js +61 -0
  898. package/dist/core/repo/tree/find.js.map +1 -0
  899. package/dist/core/repo/tree/fs.js +90 -0
  900. package/dist/core/repo/tree/fs.js.map +1 -0
  901. package/dist/core/repo/tree/marker.js +61 -0
  902. package/dist/core/repo/tree/marker.js.map +1 -0
  903. package/dist/core/repo/tree/render/body.js +258 -0
  904. package/dist/core/repo/tree/render/body.js.map +1 -0
  905. package/dist/core/repo/tree/render/projects.js +182 -0
  906. package/dist/core/repo/tree/render/projects.js.map +1 -0
  907. package/dist/core/repo/tree/render/service/header.js +125 -0
  908. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  909. package/dist/core/repo/tree/render/service/peers.js +28 -0
  910. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  911. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  912. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  913. package/dist/core/repo/tree/render/service/views.js +78 -0
  914. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  915. package/dist/core/repo/tree/render/stale.js +42 -0
  916. package/dist/core/repo/tree/render/stale.js.map +1 -0
  917. package/dist/core/repo/tree/render/text.js +84 -0
  918. package/dist/core/repo/tree/render/text.js.map +1 -0
  919. package/dist/core/repo/tree/render/views.js +293 -0
  920. package/dist/core/repo/tree/render/views.js.map +1 -0
  921. package/dist/core/repo/tree/walk.js +255 -0
  922. package/dist/core/repo/tree/walk.js.map +1 -0
  923. package/dist/core/results.js +146 -14
  924. package/dist/core/results.js.map +1 -1
  925. package/dist/core/scaffold/landscape.js +239 -0
  926. package/dist/core/scaffold/landscape.js.map +1 -0
  927. package/dist/core/scaffold/legacy.js +271 -0
  928. package/dist/core/scaffold/legacy.js.map +1 -0
  929. package/dist/core/scaffold/readme.js +84 -0
  930. package/dist/core/scaffold/readme.js.map +1 -0
  931. package/dist/core/staging/commit.js +252 -0
  932. package/dist/core/staging/commit.js.map +1 -0
  933. package/dist/core/staging/interrupted.js +96 -0
  934. package/dist/core/staging/interrupted.js.map +1 -0
  935. package/dist/core/staging/lock.js +268 -0
  936. package/dist/core/staging/lock.js.map +1 -0
  937. package/dist/core/staging/recovery/finding.js +35 -0
  938. package/dist/core/staging/recovery/finding.js.map +1 -0
  939. package/dist/core/staging/recovery/intent.js +95 -0
  940. package/dist/core/staging/recovery/intent.js.map +1 -0
  941. package/dist/core/staging/recovery/recover.js +204 -0
  942. package/dist/core/staging/recovery/recover.js.map +1 -0
  943. package/dist/core/staging/recovery/residue.js +62 -0
  944. package/dist/core/staging/recovery/residue.js.map +1 -0
  945. package/dist/core/staging/snapshot/manifest.js +188 -0
  946. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  947. package/dist/core/staging/snapshot/snapshot.js +196 -0
  948. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  949. package/dist/core/staging/txn/forward.js +181 -0
  950. package/dist/core/staging/txn/forward.js.map +1 -0
  951. package/dist/core/staging/txn/journal.js +139 -0
  952. package/dist/core/staging/txn/journal.js.map +1 -0
  953. package/dist/core/staging/txn/transaction.js +75 -0
  954. package/dist/core/staging/txn/transaction.js.map +1 -0
  955. package/dist/core/staging/writes.js +113 -0
  956. package/dist/core/staging/writes.js.map +1 -0
  957. package/dist/core/status/actions/execution.js +60 -0
  958. package/dist/core/status/actions/execution.js.map +1 -0
  959. package/dist/core/status/contracts.js +126 -0
  960. package/dist/core/status/contracts.js.map +1 -0
  961. package/dist/core/status/feature/artifacts.js +196 -0
  962. package/dist/core/status/feature/artifacts.js.map +1 -0
  963. package/dist/core/status/feature/feature.js +214 -0
  964. package/dist/core/status/feature/feature.js.map +1 -0
  965. package/dist/core/status/feature/next.js +163 -0
  966. package/dist/core/status/feature/next.js.map +1 -0
  967. package/dist/core/status/feature/state.js +21 -0
  968. package/dist/core/status/feature/state.js.map +1 -0
  969. package/dist/core/status/feature/words.js +96 -0
  970. package/dist/core/status/feature/words.js.map +1 -0
  971. package/dist/core/status/fleet/fleet.js +216 -0
  972. package/dist/core/status/fleet/fleet.js.map +1 -0
  973. package/dist/core/status/fleet/next.js +302 -0
  974. package/dist/core/status/fleet/next.js.map +1 -0
  975. package/dist/core/status/interrupted.js +97 -0
  976. package/dist/core/status/interrupted.js.map +1 -0
  977. package/dist/core/status/report.js +31 -0
  978. package/dist/core/status/report.js.map +1 -0
  979. package/dist/core/status/scan.js +41 -0
  980. package/dist/core/status/scan.js.map +1 -0
  981. package/dist/core/status/verification.js +216 -0
  982. package/dist/core/status/verification.js.map +1 -0
  983. package/dist/core/tasks/packet.js +199 -0
  984. package/dist/core/tasks/packet.js.map +1 -0
  985. package/dist/core/tasks/record.js +43 -0
  986. package/dist/core/tasks/record.js.map +1 -0
  987. package/dist/core/tasks/sources.js +181 -0
  988. package/dist/core/tasks/sources.js.map +1 -0
  989. package/dist/core/tasks/stamps.js +76 -0
  990. package/dist/core/tasks/stamps.js.map +1 -0
  991. package/dist/core/tasks/unit.js +0 -0
  992. package/dist/core/tasks/unit.js.map +1 -0
  993. package/dist/core/usecases/capability.js +166 -0
  994. package/dist/core/usecases/capability.js.map +1 -0
  995. package/dist/core/usecases/delta/claims.js +140 -0
  996. package/dist/core/usecases/delta/claims.js.map +1 -0
  997. package/dist/core/usecases/delta/flows.js +101 -0
  998. package/dist/core/usecases/delta/flows.js.map +1 -0
  999. package/dist/core/usecases/delta/modified.js +315 -0
  1000. package/dist/core/usecases/delta/modified.js.map +1 -0
  1001. package/dist/core/usecases/delta/overlay.js +76 -0
  1002. package/dist/core/usecases/delta/overlay.js.map +1 -0
  1003. package/dist/core/usecases/fleet.js +296 -0
  1004. package/dist/core/usecases/fleet.js.map +1 -0
  1005. package/dist/core/usecases/grade/capability-tag.js +93 -0
  1006. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  1007. package/dist/core/usecases/grade/feature.js +88 -0
  1008. package/dist/core/usecases/grade/feature.js.map +1 -0
  1009. package/dist/core/usecases/grade/requirement-tag.js +94 -0
  1010. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  1011. package/dist/core/usecases/grade/steps.js +266 -0
  1012. package/dist/core/usecases/grade/steps.js.map +1 -0
  1013. package/dist/core/usecases/grade/usecases.js +112 -0
  1014. package/dist/core/usecases/grade/usecases.js.map +1 -0
  1015. package/dist/core/usecases/operations.js +123 -0
  1016. package/dist/core/usecases/operations.js.map +1 -0
  1017. package/dist/core/usecases/place.js +44 -0
  1018. package/dist/core/usecases/place.js.map +1 -0
  1019. package/dist/core/usecases/service/exclude.js +119 -0
  1020. package/dist/core/usecases/service/exclude.js.map +1 -0
  1021. package/dist/core/usecases/service/flows.js +164 -0
  1022. package/dist/core/usecases/service/flows.js.map +1 -0
  1023. package/dist/core/usecases/suites/participants.js +83 -0
  1024. package/dist/core/usecases/suites/participants.js.map +1 -0
  1025. package/dist/core/usecases/suites/suites.js +45 -0
  1026. package/dist/core/usecases/suites/suites.js.map +1 -0
  1027. package/dist/core/usecases/touch.js +101 -0
  1028. package/dist/core/usecases/touch.js.map +1 -0
  1029. package/dist/core/verify/answers.js +180 -0
  1030. package/dist/core/verify/answers.js.map +1 -0
  1031. package/dist/core/verify/build.js +170 -0
  1032. package/dist/core/verify/build.js.map +1 -0
  1033. package/dist/core/verify/checklist.js +259 -0
  1034. package/dist/core/verify/checklist.js.map +1 -0
  1035. package/dist/core/verify/claims/identity.js +61 -0
  1036. package/dist/core/verify/claims/identity.js.map +1 -0
  1037. package/dist/core/verify/cross/diff.js +97 -0
  1038. package/dist/core/verify/cross/diff.js.map +1 -0
  1039. package/dist/core/verify/evidence/contract.js +169 -0
  1040. package/dist/core/verify/evidence/contract.js.map +1 -0
  1041. package/dist/core/verify/location.js +67 -0
  1042. package/dist/core/verify/location.js.map +1 -0
  1043. package/dist/core/verify/pins/lint.js +158 -0
  1044. package/dist/core/verify/pins/lint.js.map +1 -0
  1045. package/dist/core/verify/pins/pin.js +95 -0
  1046. package/dist/core/verify/pins/pin.js.map +1 -0
  1047. package/dist/core/verify/read/file.js +224 -0
  1048. package/dist/core/verify/read/file.js.map +1 -0
  1049. package/dist/core/verify/read/shape.js +169 -0
  1050. package/dist/core/verify/read/shape.js.map +1 -0
  1051. package/dist/core/verify/read/union.js +105 -0
  1052. package/dist/core/verify/read/union.js.map +1 -0
  1053. package/dist/core/verify/record.js +165 -0
  1054. package/dist/core/verify/record.js.map +1 -0
  1055. package/dist/core/verify/store/commit.js +99 -0
  1056. package/dist/core/verify/store/commit.js.map +1 -0
  1057. package/dist/core/verify/store/render.js +61 -0
  1058. package/dist/core/verify/store/render.js.map +1 -0
  1059. package/dist/core/vocabulary/health.js +91 -0
  1060. package/dist/core/vocabulary/health.js.map +1 -0
  1061. package/dist/core/vocabulary/issue.js +59 -0
  1062. package/dist/core/vocabulary/issue.js.map +1 -0
  1063. package/dist/core/vocabulary/maturity.js +216 -0
  1064. package/dist/core/vocabulary/maturity.js.map +1 -0
  1065. package/dist/core/vocabulary/report.js +90 -0
  1066. package/dist/core/vocabulary/report.js.map +1 -0
  1067. package/dist/core/vocabulary/steps.js +266 -0
  1068. package/dist/core/vocabulary/steps.js.map +1 -0
  1069. package/dist/core/workspace/discover.js +239 -0
  1070. package/dist/core/workspace/discover.js.map +1 -0
  1071. package/dist/core/workspace/render.js +52 -0
  1072. package/dist/core/workspace/render.js.map +1 -0
  1073. package/examples/README.md +232 -0
  1074. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  1075. package/examples/docs/architecture/capabilities.yaml +31 -0
  1076. package/examples/docs/architecture/landscape.likec4 +336 -0
  1077. package/examples/docs/architecture/obligations.yaml +23 -0
  1078. package/examples/docs/architecture/permissions.yaml +50 -0
  1079. package/examples/docs/architecture/services.likec4 +70 -0
  1080. package/examples/docs/architecture/subsystems.likec4 +18 -0
  1081. package/examples/docs/architecture/usecases/order-notification.likec4 +74 -0
  1082. package/examples/docs/capabilities/checkout/spec.md +55 -0
  1083. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  1084. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  1085. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  1086. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  1087. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  1088. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  1089. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +132 -0
  1090. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  1091. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  1092. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  1093. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  1094. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  1095. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +31 -0
  1096. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  1097. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  1098. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  1099. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  1100. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  1101. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  1102. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  1103. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  1104. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  1105. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  1106. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +73 -0
  1107. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  1108. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  1109. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  1110. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  1111. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  1112. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  1113. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  1114. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  1115. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  1116. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  1117. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  1118. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  1119. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  1120. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  1121. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  1122. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  1123. package/examples/docs/glossary/order.md +15 -0
  1124. package/examples/docs/glossary/payments/authorization.md +14 -0
  1125. package/examples/docs/likec4.config.json +8 -0
  1126. package/examples/docs/loam.json +3 -0
  1127. package/examples/docs/services/checkout-web/model.likec4 +92 -0
  1128. package/examples/docs/services/checkout-web/spec.md +91 -0
  1129. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  1130. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  1131. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  1132. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  1133. package/examples/docs/services/order-service/arch.spec.md +134 -0
  1134. package/examples/docs/services/order-service/asyncapi.yaml +109 -0
  1135. package/examples/docs/services/order-service/health.yaml +57 -0
  1136. package/examples/docs/services/order-service/model.likec4 +126 -0
  1137. package/examples/docs/services/order-service/openapi.yaml +257 -0
  1138. package/examples/docs/services/order-service/runbook.md +62 -0
  1139. package/examples/docs/services/order-service/spec.md +134 -0
  1140. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  1141. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  1142. package/examples/docs/services/payment-service/arch.spec.md +76 -0
  1143. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  1144. package/examples/docs/services/payment-service/health.yaml +39 -0
  1145. package/examples/docs/services/payment-service/model.likec4 +68 -0
  1146. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  1147. package/examples/docs/services/payment-service/runbook.md +37 -0
  1148. package/examples/docs/services/payment-service/spec.md +88 -0
  1149. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  1150. package/examples/docs/services/platform/identity-service/arch.spec.md +120 -0
  1151. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  1152. package/examples/docs/services/platform/identity-service/model.likec4 +81 -0
  1153. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  1154. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  1155. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  1156. package/examples/docs/services/platform/notification-service/asyncapi.yaml +200 -0
  1157. package/examples/docs/services/platform/notification-service/health.yaml +40 -0
  1158. package/examples/docs/services/platform/notification-service/model.likec4 +97 -0
  1159. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  1160. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  1161. package/examples/docs/services/platform/subsystem.yaml +2 -0
  1162. package/examples/fleet.yaml +57 -0
  1163. package/package.json +19 -6
  1164. package/dist/commands/adopt.js +0 -240
  1165. package/dist/commands/adopt.js.map +0 -1
  1166. package/dist/commands/archive.js +0 -1313
  1167. package/dist/commands/archive.js.map +0 -1
  1168. package/dist/commands/delta.js +0 -388
  1169. package/dist/commands/delta.js.map +0 -1
  1170. package/dist/commands/docs-repo-gate.js.map +0 -1
  1171. package/dist/commands/format.js +0 -17
  1172. package/dist/commands/format.js.map +0 -1
  1173. package/dist/commands/gherkin.js +0 -309
  1174. package/dist/commands/gherkin.js.map +0 -1
  1175. package/dist/commands/init.js.map +0 -1
  1176. package/dist/commands/list.js +0 -295
  1177. package/dist/commands/list.js.map +0 -1
  1178. package/dist/commands/migrate-openspec.js +0 -950
  1179. package/dist/commands/migrate-openspec.js.map +0 -1
  1180. package/dist/commands/new.js +0 -413
  1181. package/dist/commands/new.js.map +0 -1
  1182. package/dist/commands/rebase.js +0 -356
  1183. package/dist/commands/rebase.js.map +0 -1
  1184. package/dist/commands/show.js +0 -320
  1185. package/dist/commands/show.js.map +0 -1
  1186. package/dist/commands/status.js +0 -262
  1187. package/dist/commands/status.js.map +0 -1
  1188. package/dist/commands/unarchive.js +0 -317
  1189. package/dist/commands/unarchive.js.map +0 -1
  1190. package/dist/commands/validate.js +0 -1773
  1191. package/dist/commands/validate.js.map +0 -1
  1192. package/dist/commands/verify.js +0 -775
  1193. package/dist/commands/verify.js.map +0 -1
  1194. package/dist/commands/vouch.js +0 -421
  1195. package/dist/commands/vouch.js.map +0 -1
  1196. package/dist/core/agent.js +0 -2173
  1197. package/dist/core/agent.js.map +0 -1
  1198. package/dist/core/agents-stamp.js.map +0 -1
  1199. package/dist/core/arch.js +0 -130
  1200. package/dist/core/arch.js.map +0 -1
  1201. package/dist/core/asyncapi.js +0 -253
  1202. package/dist/core/asyncapi.js.map +0 -1
  1203. package/dist/core/brief.js +0 -755
  1204. package/dist/core/brief.js.map +0 -1
  1205. package/dist/core/coherence.js +0 -577
  1206. package/dist/core/coherence.js.map +0 -1
  1207. package/dist/core/concurrency.js.map +0 -1
  1208. package/dist/core/config.js.map +0 -1
  1209. package/dist/core/delta.js +0 -476
  1210. package/dist/core/delta.js.map +0 -1
  1211. package/dist/core/dependencies.js +0 -356
  1212. package/dist/core/dependencies.js.map +0 -1
  1213. package/dist/core/doctor.js +0 -596
  1214. package/dist/core/doctor.js.map +0 -1
  1215. package/dist/core/document-bytes.js.map +0 -1
  1216. package/dist/core/explore.js +0 -225
  1217. package/dist/core/explore.js.map +0 -1
  1218. package/dist/core/frontmatter.js.map +0 -1
  1219. package/dist/core/gherkin.js +0 -463
  1220. package/dist/core/gherkin.js.map +0 -1
  1221. package/dist/core/health.js +0 -67
  1222. package/dist/core/health.js.map +0 -1
  1223. package/dist/core/ids.js +0 -122
  1224. package/dist/core/ids.js.map +0 -1
  1225. package/dist/core/issue.js +0 -9
  1226. package/dist/core/issue.js.map +0 -1
  1227. package/dist/core/json.js +0 -74
  1228. package/dist/core/json.js.map +0 -1
  1229. package/dist/core/likec4.js +0 -489
  1230. package/dist/core/likec4.js.map +0 -1
  1231. package/dist/core/maturity.js +0 -66
  1232. package/dist/core/maturity.js.map +0 -1
  1233. package/dist/core/openapi-merge.js +0 -552
  1234. package/dist/core/openapi-merge.js.map +0 -1
  1235. package/dist/core/openapi.js.map +0 -1
  1236. package/dist/core/openspec-inventory.js +0 -1440
  1237. package/dist/core/openspec-inventory.js.map +0 -1
  1238. package/dist/core/path-safety.js.map +0 -1
  1239. package/dist/core/provenance.js +0 -787
  1240. package/dist/core/provenance.js.map +0 -1
  1241. package/dist/core/records.js.map +0 -1
  1242. package/dist/core/repo.js +0 -438
  1243. package/dist/core/repo.js.map +0 -1
  1244. package/dist/core/report.js +0 -47
  1245. package/dist/core/report.js.map +0 -1
  1246. package/dist/core/spec.js +0 -505
  1247. package/dist/core/spec.js.map +0 -1
  1248. package/dist/core/staging.js +0 -890
  1249. package/dist/core/staging.js.map +0 -1
  1250. package/dist/core/status.js +0 -1132
  1251. package/dist/core/status.js.map +0 -1
  1252. package/dist/core/steps.js +0 -72
  1253. package/dist/core/steps.js.map +0 -1
  1254. package/dist/core/verify.js +0 -807
  1255. package/dist/core/verify.js.map +0 -1
  1256. package/dist/core/version.js.map +0 -1
@@ -0,0 +1,328 @@
1
+ /**
2
+ * The cucumber report, and the repository it has to be evidence FROM.
3
+ *
4
+ * A results file is only evidence if it describes the commit the attestation
5
+ * names, so reading it and checking the repository are one subject: the git
6
+ * helpers below are here because they answer the same question — is this
7
+ * working tree the one the report was produced from.
8
+ */
9
+ import { execFile } from "node:child_process";
10
+ import { readFile, stat } from "node:fs/promises";
11
+ import { resolvePortableFileInside } from "../../core/kernel/path-safety.js";
12
+ import { GIT_TIMEOUT_MS } from "../../core/provenance/git.js";
13
+ import { isScenarioReport, readCucumberReport, readScenarioReport } from "../../core/results.js";
14
+ import {} from "../../core/verify/answers.js";
15
+ import { citedLine, pinnedDigest, sourceLines } from "../../core/verify/pins/pin.js";
16
+ import {} from "../../core/verify/record.js";
17
+ import {} from "./evidence/pins.js";
18
+ import { readReportArtifact } from "./evidence/read.js";
19
+ /**
20
+ * The two shapes `--results` reads, named wherever a file is refused for being
21
+ * neither — a fleet whose runner has no cucumber formatter learns here that
22
+ * the runner-neutral shape exists, rather than from a parse error.
23
+ */
24
+ const RESULTS_SHAPES = "--results reads two JSON shapes: a cucumber JSON report (cucumber-js --format json, cucumber-jvm, behave, " +
25
+ "SpecFlow/Reqnroll, pytest-bdd --cucumberjson and godog's cucumber formatter all write one), or loam's runner-neutral " +
26
+ '{"loamScenarioReport": 1, "results": [{"digest": "<16 hex>", "status": "passed"}]} — the shape a JUnit, pytest, ' +
27
+ "Vitest or house runner's report is adapted into, keyed by each scenario's @loam-digest tag.";
28
+ /**
29
+ * The report as an artifact, not merely as a parse. The resolve/read/digest
30
+ * plumbing lives in `./evidence/read.ts`, shared with `--contract-results`:
31
+ * the bytes are digested and the file's mtime read, because loam cannot prove
32
+ * a JSON file came from executing this commit and should stop implying
33
+ * otherwise. It can say precisely which file it consumed, and that goes on
34
+ * the record.
35
+ */
36
+ export async function readResults(spelled, repoDir) {
37
+ const artifact = await readReportArtifact(spelled, repoDir, "test report", RESULTS_SHAPES);
38
+ if (!artifact.ok)
39
+ return artifact;
40
+ // The reader is chosen by MARKER, before either shape has validated
41
+ // anything. A file declaring `loamScenarioReport` must be graded as that
42
+ // shape even when it is malformed — falling through to the cucumber parser
43
+ // would tell an author their report is not a cucumber array, which is true,
44
+ // useless, and hides the actual mistake.
45
+ const parsed = isScenarioReport(artifact.doc)
46
+ ? readScenarioReport(artifact.doc, spelled)
47
+ : readCucumberReport(artifact.doc, spelled);
48
+ if (!parsed.ok)
49
+ return { ok: false, code: "answers-unreadable", message: parsed.message };
50
+ return {
51
+ ok: true,
52
+ scenarios: parsed.scenarios,
53
+ report: {
54
+ path: artifact.spelled,
55
+ digest: artifact.digest,
56
+ mtime: artifact.mtime,
57
+ scenarios: parsed.scenarios.length,
58
+ },
59
+ };
60
+ }
61
+ /**
62
+ * In federated mode, a confirmation is accepted only when its evidence holds up
63
+ * in this repository: an agent's `file:line` resolves to a real line that is
64
+ * unchanged at the attested commit, and each runner's evidence names the report
65
+ * loam just read — the cucumber report for `runner`, the contract report for
66
+ * `external-runner`. The legacy all-at-once form binds to no commit, so it gets
67
+ * only the first half of that — {@link validateLocalEvidence}.
68
+ *
69
+ * The same pass now STAMPS what it validated: one `EvidencePin` per agent
70
+ * citation, built where `committedFile`'s blob is already in hand (zero new
71
+ * git calls), and one `TokenMiss` per citation whose blob does not contain the
72
+ * claim's token (`tokens`, claim id → the literal the claim asserts). Runner
73
+ * and contract answers get no pins — their evidence names a report entry, not
74
+ * a file — and the legacy all-at-once form never calls this validator, so it
75
+ * stamps nothing.
76
+ */
77
+ export async function validateServiceEvidence(answers, binding, reports, tokens) {
78
+ const { repoDir, commit } = binding;
79
+ const err = (message) => ({ ok: false, message });
80
+ const pins = new Map();
81
+ const tokenMisses = [];
82
+ for (const report of [reports.results, reports.contract]) {
83
+ if (report === undefined)
84
+ continue;
85
+ // Most reports are build output and untracked, and `git diff` is quiet on
86
+ // those — nothing here invents a rule for them. One the repository DOES
87
+ // carry has to match the commit being attested, like any other file the
88
+ // evidence rests on. Both reports independently: each is its own file
89
+ // making its own claim about this commit.
90
+ const clean = await git(repoDir, ["diff", "--quiet", commit, "--", report.path]);
91
+ if (clean.code !== 0) {
92
+ // Only `1` is git ANSWERING — "that file differs". Every other non-zero
93
+ // code is git failing to answer at all: no git on PATH, a fork that never
94
+ // happened, a child killed by a CI timeout or the OOM killer. Testing for
95
+ // `1` alone made those silently pass the check, so the one run that most
96
+ // needs the binding — the one where the machine is falling over — is the
97
+ // one that would mint an attestation whose report was never bound to the
98
+ // commit. An unanswered check is not a passed one, so the unknown refuses
99
+ // on the same terms as the known, and `clean.stderr` carries whatever
100
+ // account of itself the child managed to leave.
101
+ return err(clean.code === 1
102
+ ? `The test report '${report.path}' is committed to this repository and differs from ${commit.slice(0, 12)} — commit it or attest the commit it belongs to.`
103
+ : `Cannot tell whether the test report '${report.path}' is bound to ${commit.slice(0, 12)} — git could not be run to completion: ${clean.stderr || "git diff failed"}`);
104
+ }
105
+ }
106
+ for (const answer of answers) {
107
+ if (answer.verdict !== "confirmed")
108
+ continue;
109
+ if (answer.answered_by === "runner" || answer.answered_by === "external-runner") {
110
+ // A runner's evidence is an entry inside its report, not a file:line in
111
+ // the source — there is nothing to resolve. What must hold is that it
112
+ // names THAT report: an answer pointing anywhere else is not this run's.
113
+ const report = answer.answered_by === "runner" ? reports.results : reports.contract;
114
+ const stray = answer.evidence.filter((e) => report === undefined || !e.startsWith(`${report.path}: `));
115
+ if (stray.length > 0) {
116
+ return err(`Claim ${answer.id} has runner evidence ${stray.map((e) => `'${e}'`).join(", ")} that does not name the report loam read.`);
117
+ }
118
+ continue;
119
+ }
120
+ for (const evidence of answer.evidence) {
121
+ const cited = await resolveCitation(repoDir, answer.id, evidence);
122
+ if (!cited.ok)
123
+ return err(cited.message);
124
+ const { relativePath, line } = cited;
125
+ try {
126
+ const committed = await committedFile(repoDir, commit, relativePath);
127
+ if (!committed.ok) {
128
+ return err(`Claim ${answer.id} has evidence '${evidence}' that is not bound to ${commit.slice(0, 12)}: ${committed.message}`);
129
+ }
130
+ // The pin, built from the blob just fetched. `citedLine` is undefined
131
+ // exactly when the line is past the committed file's end — the refusal
132
+ // this validator already owed — so the bounds check and the pinned
133
+ // text can never disagree about where lines fall.
134
+ const text = citedLine(committed.source, line);
135
+ if (text === undefined) {
136
+ const committedLines = sourceLines(committed.source).length;
137
+ return err(`Claim ${answer.id} has evidence '${evidence}', but '${relativePath}' has only ${committedLines} line(s) at ${commit.slice(0, 12)}.`);
138
+ }
139
+ // The token scan happens here, per citation, because the blob is in
140
+ // hand and record time is when the answerer can still re-read what
141
+ // they cited. Substring, never a parse: the claim asserts a literal.
142
+ // A blob that does NOT contain the token is warned once (the notice
143
+ // built from `tokenMisses`) and the pin then omits the token — see
144
+ // EvidencePin.token for why re-litigating a never-there token at
145
+ // every later validate would be a false sentence with no repair.
146
+ const token = tokens.get(answer.id);
147
+ const held = token !== undefined && committed.source.includes(token);
148
+ if (token !== undefined && !held)
149
+ tokenMisses.push({ id: answer.id, evidence, token });
150
+ const list = pins.get(answer.id) ?? [];
151
+ list.push({
152
+ path: relativePath,
153
+ line,
154
+ file_sha256: pinnedDigest(committed.source),
155
+ text,
156
+ ...(held && token !== undefined ? { token } : {}),
157
+ });
158
+ pins.set(answer.id, list);
159
+ }
160
+ catch (cause) {
161
+ return err(`Claim ${answer.id} has unreadable evidence '${evidence}': ${cause instanceof Error ? cause.message : String(cause)}`);
162
+ }
163
+ }
164
+ }
165
+ return { ok: true, pins, tokenMisses };
166
+ }
167
+ /**
168
+ * One `file:line` citation, resolved in the working tree: canonical form, a
169
+ * path that stays inside the repository, a regular file, and a line that
170
+ * exists. What both recording forms owe every agent citation before anything
171
+ * else — the federated form then binds it to the attested commit.
172
+ */
173
+ async function resolveCitation(repoDir, id, evidence) {
174
+ const err = (message) => ({ ok: false, message });
175
+ const match = /^(.+):([1-9]\d*)$/.exec(evidence);
176
+ if (match === null) {
177
+ return err(`Claim ${id} has evidence '${evidence}' — evidence must be a canonical relative file:line.`);
178
+ }
179
+ const relativePath = match[1];
180
+ const line = Number(match[2]);
181
+ let absolutePath;
182
+ try {
183
+ absolutePath = resolvePortableFileInside(repoDir, relativePath, `evidence for ${id}`);
184
+ }
185
+ catch (cause) {
186
+ return err(`Claim ${id} has unsafe evidence '${evidence}': ${cause instanceof Error ? cause.message : String(cause)}`);
187
+ }
188
+ try {
189
+ // Absence named in the repository's own spelling: the stat's ENOENT
190
+ // carries the absolute path of whatever machine ran this, which tells the
191
+ // reader nothing the citation did not.
192
+ const info = await stat(absolutePath).catch((cause) => {
193
+ if (cause.code === "ENOENT")
194
+ return null;
195
+ throw cause;
196
+ });
197
+ if (info === null)
198
+ return err(`Claim ${id} has evidence '${evidence}', but '${relativePath}' does not exist in this repository.`);
199
+ if (!info.isFile())
200
+ return err(`Claim ${id} has evidence '${evidence}', but '${relativePath}' is not a regular file.`);
201
+ const lines = sourceLines(await readFile(absolutePath, "utf8")).length;
202
+ if (line > lines)
203
+ return err(`Claim ${id} has evidence '${evidence}', but '${relativePath}' has only ${lines} line(s).`);
204
+ }
205
+ catch (cause) {
206
+ return err(`Claim ${id} has unreadable evidence '${evidence}': ${cause instanceof Error ? cause.message : String(cause)}`);
207
+ }
208
+ return { ok: true, relativePath, line };
209
+ }
210
+ /**
211
+ * The all-at-once form's evidence check: every agent citation must resolve to a
212
+ * real line of a real file in THIS repository. The form binds to no commit, so
213
+ * there is nothing to pin and no blob to compare — but it used to check
214
+ * nothing at all, and accepted `src/foo.py:1` for a file that did not exist
215
+ * while printing `verified`, in the same release whose `--service` form refused
216
+ * exactly that citation. The commit binding is the federated form's addition,
217
+ * not the difference between checked and unchecked.
218
+ *
219
+ * A CITATION is what is checked, and only a citation: an entry shaped like a
220
+ * `path:line` (see {@link citesALine}). The all-at-once form has always taken
221
+ * other evidence — "manual QA by Alice", a CI run's URL, `README.md` with no
222
+ * line — and still records it as it stands; holding every entry to the
223
+ * `file:line` grammar refused all of that with `answers-unevidenced`, which
224
+ * was never the defect. What a `path:line` claims is checkable, so it is
225
+ * checked; prose claims nothing a file can contradict. The federated form
226
+ * keeps its stricter contract — every agent entry a `file:line` bound to the
227
+ * attested commit — because its whole promise is that binding.
228
+ */
229
+ export async function validateLocalEvidence(answers, repoDir) {
230
+ for (const answer of answers) {
231
+ if (answer.verdict !== "confirmed" || answer.answered_by === "runner" || answer.answered_by === "external-runner")
232
+ continue;
233
+ for (const evidence of answer.evidence.filter(citesALine)) {
234
+ const cited = await resolveCitation(repoDir, answer.id, evidence);
235
+ if (!cited.ok)
236
+ return cited;
237
+ }
238
+ }
239
+ return { ok: true };
240
+ }
241
+ /**
242
+ * Is this evidence entry shaped like a `path:line` — something that names a
243
+ * line of a file and can therefore be wrong about it? One token (no
244
+ * whitespace: prose such as "checked at 10:30" is not a citation), not a URL
245
+ * (`https://ci.example:8443` ends in a number too), ending in `:<digits>`.
246
+ * Deliberately wider than `resolveCitation`'s canonical form: `src/x.py:0` and
247
+ * `../x.py:3` are citations, badly made, and must be refused rather than
248
+ * waved through as prose.
249
+ */
250
+ function citesALine(evidence) {
251
+ return /^\S+:\d+$/.test(evidence) && !/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(evidence);
252
+ }
253
+ /** Require the evidence blob to exist at HEAD and have no uncommitted edits. */
254
+ export async function committedFile(repoDir, commit, path) {
255
+ const clean = await git(repoDir, ["diff", "--quiet", commit, "--", path]);
256
+ if (clean.code !== 0) {
257
+ return {
258
+ ok: false,
259
+ message: clean.code === 1 ? `'${path}' has uncommitted changes` : clean.stderr || "git diff failed",
260
+ };
261
+ }
262
+ const blob = await git(repoDir, ["show", `${commit}:${path}`]);
263
+ if (blob.code !== 0) {
264
+ return { ok: false, message: blob.stderr || `'${path}' is not tracked by that commit` };
265
+ }
266
+ return { ok: true, source: blob.stdout };
267
+ }
268
+ /**
269
+ * How long one git question may take, and how much it may say. Both bounds
270
+ * exist because every call in this module now runs while `loam verify --record`
271
+ * HOLDS the docs lock: a `git rev-parse` blocked on a credential-helper prompt
272
+ * used to hang this process forever with the lock in hand, wedging every
273
+ * archive, rebase and record in the fleet behind a live pid that
274
+ * `breakStaleLock` rightly refuses to break. The timeout IS
275
+ * `core/provenance/git.ts`'s (imported, so the two cannot drift); the cap is
276
+ * sized for `git show` of a source file an attestation cites (the default
277
+ * 1 MiB refused sound evidence the moment a generated client crossed it), not
278
+ * for arbitrary blobs.
279
+ *
280
+ * Not `gitText` itself: its answer carries no signal, so a child killed by
281
+ * the deadline and one killed from outside would read alike, and the
282
+ * deadline's own message below is the one that names the fix.
283
+ */
284
+ const GIT_MAX_OUTPUT_BYTES = 64 * 1024 * 1024;
285
+ function git(repoDir, args) {
286
+ return new Promise((done) => {
287
+ execFile("git", ["-C", repoDir, ...args], { encoding: "utf8", timeout: GIT_TIMEOUT_MS, maxBuffer: GIT_MAX_OUTPUT_BYTES }, (error, stdout, stderr) => {
288
+ done({
289
+ // `error.code` is an exit status only when it is a number: a spawn
290
+ // failure reports an errno string ("ENOENT") and a signal-killed child
291
+ // reports none at all. Folding those onto 1 would state that `git diff`
292
+ // found a difference — a Ctrl-C or an OOM kill during
293
+ // `loam verify --record` would read as an uncommitted edit and refuse
294
+ // a sound attestation. -1 is not a status git assigns, so both diff
295
+ // sites fall to their stderr-carrying arm and say what happened.
296
+ code: error === null ? 0 : typeof error.code === "number" ? error.code : -1,
297
+ stdout,
298
+ // A child that never ran writes nothing to stderr, so its only account
299
+ // of itself is on the error; without this the refusal would name no
300
+ // cause at all. A child WE killed gets its account written for it: the
301
+ // deadline exists for a git blocked on a credential-helper prompt, and
302
+ // the raw "Command failed: git …" says nothing about a deadline — the
303
+ // operator re-runs, waits the same 10 s, and reads the same message,
304
+ // with the actual fix (GIT_TERMINAL_PROMPT=0, or the helper) never
305
+ // reachable from it.
306
+ stderr: error !== null && error.killed && error.signal !== null
307
+ ? `git did not answer within ${GIT_TIMEOUT_MS / 1000}s and was stopped — a prompt or a hung remote; GIT_TERMINAL_PROMPT=0 disables credential prompts`
308
+ : stderr.trim() || (error === null ? "" : error.message),
309
+ });
310
+ });
311
+ });
312
+ }
313
+ /** Resolve HEAD without a shell, so repository paths remain data, never code. */
314
+ export async function repositoryCommit(repoDir) {
315
+ const result = await git(repoDir, ["rev-parse", "--verify", "HEAD^{commit}"]);
316
+ if (result.code !== 0) {
317
+ return {
318
+ ok: false,
319
+ message: `Federated verification requires a git repository with a committed HEAD: ${result.stderr || "git rev-parse failed"}`,
320
+ };
321
+ }
322
+ const commit = result.stdout.trim();
323
+ if (!/^[0-9a-f]{40,64}$/i.test(commit)) {
324
+ return { ok: false, message: `Git returned an invalid HEAD commit '${commit}'.` };
325
+ }
326
+ return { ok: true, commit };
327
+ }
328
+ //# sourceMappingURL=results.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"results.js","sourceRoot":"","sources":["../../../src/commands/verify/results.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The cucumber report, and the repository it has to be evidence FROM.\n *\n * A results file is only evidence if it describes the commit the attestation\n * names, so reading it and checking the repository are one subject: the git\n * helpers below are here because they answer the same question — is this\n * working tree the one the report was produced from.\n */\nimport { execFile } from \"node:child_process\";\nimport { readFile, stat } from \"node:fs/promises\";\nimport { resolvePortableFileInside } from \"../../core/kernel/path-safety.js\";\nimport { GIT_TIMEOUT_MS } from \"../../core/provenance/git.js\";\nimport { isScenarioReport, readCucumberReport, readScenarioReport, type ReportScenario } from \"../../core/results.js\";\nimport { type Answer } from \"../../core/verify/answers.js\";\nimport { citedLine, pinnedDigest, sourceLines, type EvidencePin } from \"../../core/verify/pins/pin.js\";\nimport { type ConsumedReport, type ConsumedReports } from \"../../core/verify/record.js\";\nimport { type EvidencePins, type TokenMiss } from \"./evidence/pins.js\";\nimport { readReportArtifact } from \"./evidence/read.js\";\n\nexport type ResultsRead =\n | { ok: true; report: ConsumedReport; scenarios: ReportScenario[] }\n | { ok: false; code: \"answers-unreadable\"; message: string };\n\n/**\n * The two shapes `--results` reads, named wherever a file is refused for being\n * neither — a fleet whose runner has no cucumber formatter learns here that\n * the runner-neutral shape exists, rather than from a parse error.\n */\nconst RESULTS_SHAPES =\n \"--results reads two JSON shapes: a cucumber JSON report (cucumber-js --format json, cucumber-jvm, behave, \" +\n \"SpecFlow/Reqnroll, pytest-bdd --cucumberjson and godog's cucumber formatter all write one), or loam's runner-neutral \" +\n '{\"loamScenarioReport\": 1, \"results\": [{\"digest\": \"<16 hex>\", \"status\": \"passed\"}]} — the shape a JUnit, pytest, ' +\n \"Vitest or house runner's report is adapted into, keyed by each scenario's @loam-digest tag.\";\n\n/**\n * The report as an artifact, not merely as a parse. The resolve/read/digest\n * plumbing lives in `./evidence/read.ts`, shared with `--contract-results`:\n * the bytes are digested and the file's mtime read, because loam cannot prove\n * a JSON file came from executing this commit and should stop implying\n * otherwise. It can say precisely which file it consumed, and that goes on\n * the record.\n */\nexport async function readResults(spelled: string, repoDir: string | undefined): Promise<ResultsRead> {\n const artifact = await readReportArtifact(spelled, repoDir, \"test report\", RESULTS_SHAPES);\n if (!artifact.ok) return artifact;\n // The reader is chosen by MARKER, before either shape has validated\n // anything. A file declaring `loamScenarioReport` must be graded as that\n // shape even when it is malformed — falling through to the cucumber parser\n // would tell an author their report is not a cucumber array, which is true,\n // useless, and hides the actual mistake.\n const parsed = isScenarioReport(artifact.doc)\n ? readScenarioReport(artifact.doc, spelled)\n : readCucumberReport(artifact.doc, spelled);\n if (!parsed.ok) return { ok: false, code: \"answers-unreadable\", message: parsed.message };\n return {\n ok: true,\n scenarios: parsed.scenarios,\n report: {\n path: artifact.spelled,\n digest: artifact.digest,\n mtime: artifact.mtime,\n scenarios: parsed.scenarios.length,\n },\n };\n}\n\n/**\n * The repository an attestation binds to and the commit it binds at — two\n * values only ever asked about together, so they travel as one and the\n * inconsistent pair (this repo, that commit) stops being representable.\n */\nexport interface AttestationBinding {\n repoDir: string;\n commit: string;\n}\n\nexport type ServiceEvidenceCheck =\n /** Every citation held up; `pins`/`tokenMisses` are the stamp and the honesty it computed en route. */\n | ({ ok: true } & EvidencePins)\n | { ok: false; message: string };\n\n/**\n * In federated mode, a confirmation is accepted only when its evidence holds up\n * in this repository: an agent's `file:line` resolves to a real line that is\n * unchanged at the attested commit, and each runner's evidence names the report\n * loam just read — the cucumber report for `runner`, the contract report for\n * `external-runner`. The legacy all-at-once form binds to no commit, so it gets\n * only the first half of that — {@link validateLocalEvidence}.\n *\n * The same pass now STAMPS what it validated: one `EvidencePin` per agent\n * citation, built where `committedFile`'s blob is already in hand (zero new\n * git calls), and one `TokenMiss` per citation whose blob does not contain the\n * claim's token (`tokens`, claim id → the literal the claim asserts). Runner\n * and contract answers get no pins — their evidence names a report entry, not\n * a file — and the legacy all-at-once form never calls this validator, so it\n * stamps nothing.\n */\nexport async function validateServiceEvidence(\n answers: Answer[],\n binding: AttestationBinding,\n reports: ConsumedReports,\n tokens: ReadonlyMap<string, string>,\n): Promise<ServiceEvidenceCheck> {\n const { repoDir, commit } = binding;\n const err = (message: string): ServiceEvidenceCheck => ({ ok: false, message });\n const pins = new Map<string, EvidencePin[]>();\n const tokenMisses: TokenMiss[] = [];\n for (const report of [reports.results, reports.contract]) {\n if (report === undefined) continue;\n // Most reports are build output and untracked, and `git diff` is quiet on\n // those — nothing here invents a rule for them. One the repository DOES\n // carry has to match the commit being attested, like any other file the\n // evidence rests on. Both reports independently: each is its own file\n // making its own claim about this commit.\n const clean = await git(repoDir, [\"diff\", \"--quiet\", commit, \"--\", report.path]);\n if (clean.code !== 0) {\n // Only `1` is git ANSWERING — \"that file differs\". Every other non-zero\n // code is git failing to answer at all: no git on PATH, a fork that never\n // happened, a child killed by a CI timeout or the OOM killer. Testing for\n // `1` alone made those silently pass the check, so the one run that most\n // needs the binding — the one where the machine is falling over — is the\n // one that would mint an attestation whose report was never bound to the\n // commit. An unanswered check is not a passed one, so the unknown refuses\n // on the same terms as the known, and `clean.stderr` carries whatever\n // account of itself the child managed to leave.\n return err(\n clean.code === 1\n ? `The test report '${report.path}' is committed to this repository and differs from ${commit.slice(0, 12)} — commit it or attest the commit it belongs to.`\n : `Cannot tell whether the test report '${report.path}' is bound to ${commit.slice(0, 12)} — git could not be run to completion: ${clean.stderr || \"git diff failed\"}`,\n );\n }\n }\n for (const answer of answers) {\n if (answer.verdict !== \"confirmed\") continue;\n if (answer.answered_by === \"runner\" || answer.answered_by === \"external-runner\") {\n // A runner's evidence is an entry inside its report, not a file:line in\n // the source — there is nothing to resolve. What must hold is that it\n // names THAT report: an answer pointing anywhere else is not this run's.\n const report = answer.answered_by === \"runner\" ? reports.results : reports.contract;\n const stray = answer.evidence.filter((e) => report === undefined || !e.startsWith(`${report.path}: `));\n if (stray.length > 0) {\n return err(`Claim ${answer.id} has runner evidence ${stray.map((e) => `'${e}'`).join(\", \")} that does not name the report loam read.`);\n }\n continue;\n }\n for (const evidence of answer.evidence) {\n const cited = await resolveCitation(repoDir, answer.id, evidence);\n if (!cited.ok) return err(cited.message);\n const { relativePath, line } = cited;\n try {\n const committed = await committedFile(repoDir, commit, relativePath);\n if (!committed.ok) {\n return err(`Claim ${answer.id} has evidence '${evidence}' that is not bound to ${commit.slice(0, 12)}: ${committed.message}`);\n }\n // The pin, built from the blob just fetched. `citedLine` is undefined\n // exactly when the line is past the committed file's end — the refusal\n // this validator already owed — so the bounds check and the pinned\n // text can never disagree about where lines fall.\n const text = citedLine(committed.source, line);\n if (text === undefined) {\n const committedLines = sourceLines(committed.source).length;\n return err(`Claim ${answer.id} has evidence '${evidence}', but '${relativePath}' has only ${committedLines} line(s) at ${commit.slice(0, 12)}.`);\n }\n // The token scan happens here, per citation, because the blob is in\n // hand and record time is when the answerer can still re-read what\n // they cited. Substring, never a parse: the claim asserts a literal.\n // A blob that does NOT contain the token is warned once (the notice\n // built from `tokenMisses`) and the pin then omits the token — see\n // EvidencePin.token for why re-litigating a never-there token at\n // every later validate would be a false sentence with no repair.\n const token = tokens.get(answer.id);\n const held = token !== undefined && committed.source.includes(token);\n if (token !== undefined && !held) tokenMisses.push({ id: answer.id, evidence, token });\n const list = pins.get(answer.id) ?? [];\n list.push({\n path: relativePath,\n line,\n file_sha256: pinnedDigest(committed.source),\n text,\n ...(held && token !== undefined ? { token } : {}),\n });\n pins.set(answer.id, list);\n } catch (cause) {\n return err(`Claim ${answer.id} has unreadable evidence '${evidence}': ${cause instanceof Error ? cause.message : String(cause)}`);\n }\n }\n }\n return { ok: true, pins, tokenMisses };\n}\n\ntype Citation = { ok: true; relativePath: string; line: number } | { ok: false; message: string };\n\n/**\n * One `file:line` citation, resolved in the working tree: canonical form, a\n * path that stays inside the repository, a regular file, and a line that\n * exists. What both recording forms owe every agent citation before anything\n * else — the federated form then binds it to the attested commit.\n */\nasync function resolveCitation(repoDir: string, id: string, evidence: string): Promise<Citation> {\n const err = (message: string): Citation => ({ ok: false, message });\n const match = /^(.+):([1-9]\\d*)$/.exec(evidence);\n if (match === null) {\n return err(`Claim ${id} has evidence '${evidence}' — evidence must be a canonical relative file:line.`);\n }\n const relativePath = match[1]!;\n const line = Number(match[2]);\n let absolutePath: string;\n try {\n absolutePath = resolvePortableFileInside(repoDir, relativePath, `evidence for ${id}`);\n } catch (cause) {\n return err(`Claim ${id} has unsafe evidence '${evidence}': ${cause instanceof Error ? cause.message : String(cause)}`);\n }\n try {\n // Absence named in the repository's own spelling: the stat's ENOENT\n // carries the absolute path of whatever machine ran this, which tells the\n // reader nothing the citation did not.\n const info = await stat(absolutePath).catch((cause: NodeJS.ErrnoException) => {\n if (cause.code === \"ENOENT\") return null;\n throw cause;\n });\n if (info === null) return err(`Claim ${id} has evidence '${evidence}', but '${relativePath}' does not exist in this repository.`);\n if (!info.isFile()) return err(`Claim ${id} has evidence '${evidence}', but '${relativePath}' is not a regular file.`);\n const lines = sourceLines(await readFile(absolutePath, \"utf8\")).length;\n if (line > lines) return err(`Claim ${id} has evidence '${evidence}', but '${relativePath}' has only ${lines} line(s).`);\n } catch (cause) {\n return err(`Claim ${id} has unreadable evidence '${evidence}': ${cause instanceof Error ? cause.message : String(cause)}`);\n }\n return { ok: true, relativePath, line };\n}\n\n/**\n * The all-at-once form's evidence check: every agent citation must resolve to a\n * real line of a real file in THIS repository. The form binds to no commit, so\n * there is nothing to pin and no blob to compare — but it used to check\n * nothing at all, and accepted `src/foo.py:1` for a file that did not exist\n * while printing `verified`, in the same release whose `--service` form refused\n * exactly that citation. The commit binding is the federated form's addition,\n * not the difference between checked and unchecked.\n *\n * A CITATION is what is checked, and only a citation: an entry shaped like a\n * `path:line` (see {@link citesALine}). The all-at-once form has always taken\n * other evidence — \"manual QA by Alice\", a CI run's URL, `README.md` with no\n * line — and still records it as it stands; holding every entry to the\n * `file:line` grammar refused all of that with `answers-unevidenced`, which\n * was never the defect. What a `path:line` claims is checkable, so it is\n * checked; prose claims nothing a file can contradict. The federated form\n * keeps its stricter contract — every agent entry a `file:line` bound to the\n * attested commit — because its whole promise is that binding.\n */\nexport async function validateLocalEvidence(answers: Answer[], repoDir: string): Promise<{ ok: true } | { ok: false; message: string }> {\n for (const answer of answers) {\n if (answer.verdict !== \"confirmed\" || answer.answered_by === \"runner\" || answer.answered_by === \"external-runner\") continue;\n for (const evidence of answer.evidence.filter(citesALine)) {\n const cited = await resolveCitation(repoDir, answer.id, evidence);\n if (!cited.ok) return cited;\n }\n }\n return { ok: true };\n}\n\n/**\n * Is this evidence entry shaped like a `path:line` — something that names a\n * line of a file and can therefore be wrong about it? One token (no\n * whitespace: prose such as \"checked at 10:30\" is not a citation), not a URL\n * (`https://ci.example:8443` ends in a number too), ending in `:<digits>`.\n * Deliberately wider than `resolveCitation`'s canonical form: `src/x.py:0` and\n * `../x.py:3` are citations, badly made, and must be refused rather than\n * waved through as prose.\n */\nfunction citesALine(evidence: string): boolean {\n return /^\\S+:\\d+$/.test(evidence) && !/^[A-Za-z][A-Za-z0-9+.-]*:\\/\\//.test(evidence);\n}\n\ntype CommitResult = { ok: true; commit: string } | { ok: false; message: string };\ntype CommittedFileResult = { ok: true; source: string } | { ok: false; message: string };\n\n/** Require the evidence blob to exist at HEAD and have no uncommitted edits. */\nexport async function committedFile(repoDir: string, commit: string, path: string): Promise<CommittedFileResult> {\n const clean = await git(repoDir, [\"diff\", \"--quiet\", commit, \"--\", path]);\n if (clean.code !== 0) {\n return {\n ok: false,\n message: clean.code === 1 ? `'${path}' has uncommitted changes` : clean.stderr || \"git diff failed\",\n };\n }\n const blob = await git(repoDir, [\"show\", `${commit}:${path}`]);\n if (blob.code !== 0) {\n return { ok: false, message: blob.stderr || `'${path}' is not tracked by that commit` };\n }\n return { ok: true, source: blob.stdout };\n}\n\ninterface GitResult {\n /**\n * Git's own exit status, or `-1` for \"git could not be run to completion\" —\n * no git on PATH, a spawn failure, a child killed by a signal (the deadline\n * below included), or output past the declared cap. Callers read specific\n * meaning into small numbers (`1` from `git diff --quiet` is \"that file\n * differs\"), so a run that never reached an exit status must not borrow one\n * of them.\n */\n code: number;\n stdout: string;\n stderr: string;\n}\n\n/**\n * How long one git question may take, and how much it may say. Both bounds\n * exist because every call in this module now runs while `loam verify --record`\n * HOLDS the docs lock: a `git rev-parse` blocked on a credential-helper prompt\n * used to hang this process forever with the lock in hand, wedging every\n * archive, rebase and record in the fleet behind a live pid that\n * `breakStaleLock` rightly refuses to break. The timeout IS\n * `core/provenance/git.ts`'s (imported, so the two cannot drift); the cap is\n * sized for `git show` of a source file an attestation cites (the default\n * 1 MiB refused sound evidence the moment a generated client crossed it), not\n * for arbitrary blobs.\n *\n * Not `gitText` itself: its answer carries no signal, so a child killed by\n * the deadline and one killed from outside would read alike, and the\n * deadline's own message below is the one that names the fix.\n */\nconst GIT_MAX_OUTPUT_BYTES = 64 * 1024 * 1024;\n\nfunction git(repoDir: string, args: string[]): Promise<GitResult> {\n return new Promise((done) => {\n execFile(\n \"git\",\n [\"-C\", repoDir, ...args],\n { encoding: \"utf8\", timeout: GIT_TIMEOUT_MS, maxBuffer: GIT_MAX_OUTPUT_BYTES },\n (error, stdout, stderr) => {\n done({\n // `error.code` is an exit status only when it is a number: a spawn\n // failure reports an errno string (\"ENOENT\") and a signal-killed child\n // reports none at all. Folding those onto 1 would state that `git diff`\n // found a difference — a Ctrl-C or an OOM kill during\n // `loam verify --record` would read as an uncommitted edit and refuse\n // a sound attestation. -1 is not a status git assigns, so both diff\n // sites fall to their stderr-carrying arm and say what happened.\n code: error === null ? 0 : typeof error.code === \"number\" ? error.code : -1,\n stdout,\n // A child that never ran writes nothing to stderr, so its only account\n // of itself is on the error; without this the refusal would name no\n // cause at all. A child WE killed gets its account written for it: the\n // deadline exists for a git blocked on a credential-helper prompt, and\n // the raw \"Command failed: git …\" says nothing about a deadline — the\n // operator re-runs, waits the same 10 s, and reads the same message,\n // with the actual fix (GIT_TERMINAL_PROMPT=0, or the helper) never\n // reachable from it.\n stderr:\n error !== null && error.killed && error.signal !== null\n ? `git did not answer within ${GIT_TIMEOUT_MS / 1000}s and was stopped — a prompt or a hung remote; GIT_TERMINAL_PROMPT=0 disables credential prompts`\n : stderr.trim() || (error === null ? \"\" : error.message),\n });\n });\n });\n}\n\n/** Resolve HEAD without a shell, so repository paths remain data, never code. */\nexport async function repositoryCommit(repoDir: string): Promise<CommitResult> {\n const result = await git(repoDir, [\"rev-parse\", \"--verify\", \"HEAD^{commit}\"]);\n if (result.code !== 0) {\n return {\n ok: false,\n message: `Federated verification requires a git repository with a committed HEAD: ${result.stderr || \"git rev-parse failed\"}`,\n };\n }\n const commit = result.stdout.trim();\n if (!/^[0-9a-f]{40,64}$/i.test(commit)) {\n return { ok: false, message: `Git returned an invalid HEAD commit '${commit}'.` };\n }\n return { ok: true, commit };\n}\n"]}
@@ -0,0 +1,220 @@
1
+ import { configOrRefuse, fail, repoPath } from "../../core/envelope/json.js";
2
+ import { missingFeatureMessage, resolveFeature } from "../../core/repo/repo.js";
3
+ import {} from "../../core/staging/interrupted.js";
4
+ import { LOCK_WAIT_MS } from "../../core/staging/lock.js";
5
+ import { openCommitWindow } from "../../core/staging/recovery/recover.js";
6
+ import { docsRepoReady } from "../policy/gate.js";
7
+ import { featureChecklist } from "../../core/verify/checklist.js";
8
+ import { readVerificationState } from "../../core/verify/read/file.js";
9
+ import { report } from "./report.js";
10
+ import { reportFrozen } from "./frozen.js";
11
+ import { record } from "./record.js";
12
+ import {} from "./record.js";
13
+ import { diffAnswers } from "./cross/diff.js";
14
+ export function registerVerify(program) {
15
+ program
16
+ .command("verify")
17
+ .argument("<featureId>", "feature id, e.g. FEAT-101")
18
+ .description("Check a feature against its own promises: derive the claims, record the answers with evidence")
19
+ .option("--record <file>", "record a JSON answer set against the current checklist")
20
+ .option("--results <file>", "answer the scenario.tested claims mechanically from a test report: cucumber JSON, or loam's runner-neutral loamScenarioReport JSON for any other runner")
21
+ .option("--contract-results <file>", "answer the api.exposes claims mechanically from an API contract-test report (loam's generic contract-results JSON)")
22
+ .option("--diff-answers <files...>", "cross-examine two independent answer sets against the current checklist (reads only, writes nothing)")
23
+ .option("--service <id>", "record only this service's claims, bound to the current repository commit")
24
+ .option("--json", "emit the machine contract instead of the human view")
25
+ .action(async (featureId, opts) => {
26
+ const json = opts.json === true;
27
+ const config = await configOrRefuse(json);
28
+ if (config === null)
29
+ return;
30
+ const { docsDir } = config;
31
+ const recording = opts.record !== undefined || opts.results !== undefined || opts.contractResults !== undefined;
32
+ // --diff-answers is a third READ form (see the WRITING/READING split
33
+ // below): it validates two answer sets against the same checklist and
34
+ // writes nothing, so combining it with any recording flag is a
35
+ // contradiction refused up front — before the binding, before the lock —
36
+ // rather than a mode silently picked between the two.
37
+ let diffFiles = null;
38
+ if (opts.diffAnswers !== undefined) {
39
+ if (recording) {
40
+ return fail(json, "invalid-option", "--diff-answers is a read-only cross-examination: it validates both files and writes nothing, " +
41
+ "so it cannot be combined with --record, --results or --contract-results. " +
42
+ "Diff first, then record the answer set you stand behind.");
43
+ }
44
+ // Commander's variadic form consumes arguments until the next --flag,
45
+ // so a featureId placed AFTER the flag arrives here as a third file —
46
+ // this refusal is what turns that mistake into a sentence instead of a
47
+ // diff of the wrong files.
48
+ const [a, b] = opts.diffAnswers;
49
+ if (opts.diffAnswers.length !== 2 || a === undefined || b === undefined) {
50
+ return fail(json, "invalid-option", "--diff-answers takes exactly two answer files: --diff-answers a.json b.json");
51
+ }
52
+ diffFiles = { a, b };
53
+ }
54
+ // WRITING is bound to the repository; READING is not. An attestation
55
+ // pins claims to this repo's git HEAD and to file:line evidence inside
56
+ // it, so writing (--record, --results or --contract-results) with
57
+ // `--service X` may only run where loam.json says this repo IS X —
58
+ // vouch's and gherkin's refusal, for vouch's reason: from anywhere
59
+ // else, that repository is somebody else's. Reading takes
60
+ // `--service` as a pure lens (which claims are checkout-web's, and what
61
+ // has it said?) and needs no binding at all, because it writes nothing.
62
+ if (recording && opts.service !== undefined) {
63
+ if (config.service === undefined) {
64
+ return fail(json, "repository-unavailable", `Cannot attest for '${opts.service}' from here: this is not a service repo — loam.json declares no \`service\`. ` +
65
+ `A federated attestation binds the answers to this repository's git HEAD and to evidence inside it, so the repository has to say which service it is. ` +
66
+ `Add "service": "${opts.service}" to loam.json, or record it from that service's own repo.`);
67
+ }
68
+ if (config.service !== opts.service) {
69
+ return fail(json, "service-mismatch", `This repository is configured as service '${config.service}', so it cannot attest claims for '${opts.service}'.`);
70
+ }
71
+ }
72
+ // Before the lock, because the lock is a file INSIDE the docs repo: a
73
+ // `docsDir` pointing at nothing used to surface as the lock file's own
74
+ // ENOENT — an `internal` where the read side of this same command names
75
+ // the misconfiguration. "docs", not "services", in BOTH modes — and that
76
+ // is a pinned contract, not looseness: the legacy all-at-once form
77
+ // records against a features-only docs repo with no `services/` at all,
78
+ // and it has always exited 0 there. The cost is real and accepted: a
79
+ // typo'd `docsDir` pointing at some existing non-docs directory gets a
80
+ // `.loam-lock` created and removed inside it. The gate above only
81
+ // guarantees the directory exists.
82
+ if (!docsRepoReady(json, docsDir, "docs"))
83
+ return;
84
+ // A record is a merge over the docs repo, so recording takes the docs
85
+ // lock — the same one archive, unarchive and rebase hold — and takes it
86
+ // HERE, before the feature is even resolved. Behind the lock, an archive
87
+ // can rename this feature's directory into features/archive/ at any
88
+ // moment; a feature resolved before the lock could have its record
89
+ // written into the pre-move path, a file nothing will ever read again.
90
+ // The waiting form rather than archive's refuse-fast one, because two
91
+ // recorders for different services of one feature are both supposed to
92
+ // land: the second waits out the first's sub-second window and merges
93
+ // over what it left. Reading stays lock-free — it writes nothing.
94
+ //
95
+ // A journal under the lock means the last writer never finished. The
96
+ // record's own authoritative read is about to happen; reading it over
97
+ // a half-commit would merge against bytes no run ever produced — the
98
+ // last docs-repo writer that could still silently treat a half-commit
99
+ // as healthy. That refusal must release the lock like every other path
100
+ // out, and once did not; `openCommitWindow` releases it before it answers.
101
+ let releaseLock = null;
102
+ let recovered = null;
103
+ if (recording) {
104
+ const opened = await openCommitWindow(docsDir, LOCK_WAIT_MS);
105
+ if (!opened.ok)
106
+ return fail(json, opened.code, opened.message);
107
+ releaseLock = opened.release;
108
+ recovered = opened.recovered;
109
+ }
110
+ try {
111
+ // Archived features resolve too: a shipped feature's verification is worth
112
+ // reading back, and it travelled into the archive with everything else.
113
+ const feature = await resolveFeature(docsDir, featureId, "include");
114
+ if (!feature) {
115
+ // repo.ts's sentence, not a second copy of it. Resolving with "include"
116
+ // means the archived branch inside it cannot fire here — an archived
117
+ // feature resolves — so the text is exactly what it was; what changes is
118
+ // that a reworded miss message can no longer leave this one behind.
119
+ return fail(json, "unknown-target", await missingFeatureMessage(docsDir, featureId));
120
+ }
121
+ // The cross-examination lens leaves BEFORE the record is read below:
122
+ // it never consumes verification.yaml, and the moment a
123
+ // cross-examination is most needed is exactly when the record on disk
124
+ // is too damaged to read and somebody is about to re-record over it —
125
+ // the record-unreadable refusal must not bar the one command that
126
+ // would inform that re-recording. The archived refusal still applies,
127
+ // with the recording branch's code and reason: there is no current
128
+ // checklist to answer, so the wrong thing is the option, not the
129
+ // answer sets.
130
+ if (diffFiles !== null) {
131
+ if (feature.archived) {
132
+ return fail(json, "invalid-option", `${feature.id} is archived — there is no current checklist to answer, so there is nothing to cross-examine; its record is frozen history. \`loam unarchive ${feature.id}\` first if the claims really need re-answering.`);
133
+ }
134
+ await diffAnswers({ docsDir, featureDir: feature.dir, json }, await featureChecklist(docsDir, feature.dir, feature.id), diffFiles, { lens: opts.service });
135
+ return;
136
+ }
137
+ // Before anything else: a record file that exists but will not read
138
+ // is a refusal, not an absence. It holds somebody's answers and — in a
139
+ // fleet — other repositories' attestations; treating it as "not verified"
140
+ // let the next --record silently overwrite all of it, and made the read
141
+ // view say "no record" about a file sitting right there.
142
+ //
143
+ // The path is the one FILE that failed, and the advice is that file's:
144
+ // the record is several files now, and the recipe that is safe for a
145
+ // service's own attestation file (delete it, record that service again)
146
+ // is the one that erases a fleet's evidence when the file is the shared
147
+ // one-file record — which is what this refusal used to tell everyone,
148
+ // and what a miscounted record's "record again" looped back into.
149
+ //
150
+ // An in-flight feature's checklist is derived FIRST, because which of
151
+ // those files count depends on it: a record kept as per-service files
152
+ // answers the question being asked now, and only the caller knows what
153
+ // that is (`core/verify/read/union.ts`). Read without it, a service
154
+ // that recorded the current checklist could lose a same-day tie to one
155
+ // that recorded an older one, and this view called the whole record
156
+ // stale. An archived feature derives nothing — see below.
157
+ const checklist = feature.archived ? null : await featureChecklist(docsDir, feature.dir, feature.id);
158
+ const existing = await readVerificationState(feature.dir, checklist?.digest);
159
+ if (existing.state === "unreadable") {
160
+ return fail(json, "record-unreadable", `${repoPath(docsDir, existing.path)} exists but cannot be read as a verification record: ${existing.reason}. ` +
161
+ `${existing.advice} loam will not overwrite a record it could not read.`);
162
+ }
163
+ const recorded = existing.state === "ok" ? existing.verification : null;
164
+ // But an archived feature never gets a re-derived checklist — see the
165
+ // header. Its record is frozen history, and --record / --results refuse
166
+ // alike: the code is `invalid-option` rather than `answers-mismatch`
167
+ // because the answers were never compared to anything — there is no
168
+ // current checklist to answer, so the wrong thing here is the option,
169
+ // not the answer set. (`checklist` is null exactly when the feature is
170
+ // archived — the test is spelled on it so the compiler knows the
171
+ // in-flight path below has one.)
172
+ if (checklist === null) {
173
+ if (recording) {
174
+ return fail(json, "invalid-option", `${feature.id} is archived — its verification is history now. \`loam unarchive ${feature.id}\` first if the answers really need to change.`);
175
+ }
176
+ reportFrozen({ docsDir, featureDir: feature.dir, json }, feature.id, recorded);
177
+ return;
178
+ }
179
+ if (recording) {
180
+ // Standing in a service repo, `--service` is what the repo already
181
+ // says: omitting it must not fall back to the legacy all-at-once form,
182
+ // which claims the whole fleet's checklist on this one repo's word.
183
+ //
184
+ // The repo root, not the cwd — `vouch`'s and `gherkin`'s reason. An
185
+ // attestation names a commit and rests on evidence resolved inside
186
+ // "this repository", and `config.root` is the directory loam.json was
187
+ // actually found in. Off `process.cwd()`, running from a subdirectory
188
+ // silently changed all three: evidence resolved against the
189
+ // subdirectory, `--results` had to live in it, and `git rev-parse` ran
190
+ // there — a submodule or nested checkout under it would have named
191
+ // somebody else's commit on this repository's attestation.
192
+ //
193
+ // `config.service` and not `opts.service ?? config.service`, though
194
+ // the two are the same value: the binding refusal above lets a
195
+ // recording `--service` through only when it EQUALS the configured
196
+ // service. Taking the configured one keeps its brand — loam.json's
197
+ // reader validated it against the id grammar — and that brand is
198
+ // what `serviceRecordPath` demands before it joins the id into a
199
+ // file name. The raw flag never reaches the join.
200
+ await record({ docsDir, featureDir: feature.dir, json, recovered }, checklist, {
201
+ service: config.service,
202
+ repoDir: config.root ?? process.cwd(),
203
+ previous: existing.state === "ok" ? { verification: existing.verification, files: existing.files } : null,
204
+ }, opts);
205
+ return;
206
+ }
207
+ report({ docsDir, featureDir: feature.dir, json }, checklist, recorded, {
208
+ lens: opts.service,
209
+ bound: config.service,
210
+ });
211
+ }
212
+ finally {
213
+ // Released on every path out — a refusal that kept the lock would turn
214
+ // one bad answer set into a wedged docs repo for everyone else.
215
+ if (releaseLock !== null)
216
+ await releaseLock();
217
+ }
218
+ });
219
+ }
220
+ //# sourceMappingURL=verify.js.map