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

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 (1036) hide show
  1. package/CHANGELOG.md +2635 -86
  2. package/COMPARISON.md +80 -63
  3. package/CONTRIBUTING.md +84 -0
  4. package/MIGRATING-from-OpenSpec.md +213 -54
  5. package/QUICKSTART.md +125 -0
  6. package/README.md +450 -150
  7. package/ROADMAP.md +599 -0
  8. package/SCHEMA.md +2355 -256
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +701 -0
  11. package/dist/cli.js +113 -19
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +209 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +268 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +77 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/openapi.js +159 -0
  22. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  23. package/dist/commands/archive/plan/gate.js +323 -0
  24. package/dist/commands/archive/plan/gate.js.map +1 -0
  25. package/dist/commands/archive/plan/landscape.js +180 -0
  26. package/dist/commands/archive/plan/landscape.js.map +1 -0
  27. package/dist/commands/archive/plan/refusal.js +111 -0
  28. package/dist/commands/archive/plan/refusal.js.map +1 -0
  29. package/dist/commands/archive/plan/specs.js +237 -0
  30. package/dist/commands/archive/plan/specs.js.map +1 -0
  31. package/dist/commands/archive/plan/state.js +27 -0
  32. package/dist/commands/archive/plan/state.js.map +1 -0
  33. package/dist/commands/archive/run.js +252 -0
  34. package/dist/commands/archive/run.js.map +1 -0
  35. package/dist/commands/context/context.js +99 -0
  36. package/dist/commands/context/context.js.map +1 -0
  37. package/dist/commands/context/print.js +283 -0
  38. package/dist/commands/context/print.js.map +1 -0
  39. package/dist/commands/delta/delta.js +279 -0
  40. package/dist/commands/delta/delta.js.map +1 -0
  41. package/dist/commands/delta/print.js +205 -0
  42. package/dist/commands/delta/print.js.map +1 -0
  43. package/dist/commands/dependencies.js +9 -7
  44. package/dist/commands/dependencies.js.map +1 -1
  45. package/dist/commands/diff/diff.js +93 -0
  46. package/dist/commands/diff/diff.js.map +1 -0
  47. package/dist/commands/diff/print.js +38 -0
  48. package/dist/commands/diff/print.js.map +1 -0
  49. package/dist/commands/doctor.js +5 -4
  50. package/dist/commands/doctor.js.map +1 -1
  51. package/dist/commands/explain/explain.js +151 -0
  52. package/dist/commands/explain/explain.js.map +1 -0
  53. package/dist/commands/explore.js +29 -24
  54. package/dist/commands/explore.js.map +1 -1
  55. package/dist/commands/gate/gate.js +115 -0
  56. package/dist/commands/gate/gate.js.map +1 -0
  57. package/dist/commands/gate/print.js +54 -0
  58. package/dist/commands/gate/print.js.map +1 -0
  59. package/dist/commands/gherkin/commit.js +146 -0
  60. package/dist/commands/gherkin/commit.js.map +1 -0
  61. package/dist/commands/gherkin/gherkin.js +246 -0
  62. package/dist/commands/gherkin/gherkin.js.map +1 -0
  63. package/dist/commands/gherkin/reconcile.js +149 -0
  64. package/dist/commands/gherkin/reconcile.js.map +1 -0
  65. package/dist/commands/gherkin/render.js +77 -0
  66. package/dist/commands/gherkin/render.js.map +1 -0
  67. package/dist/commands/init/example.js +204 -0
  68. package/dist/commands/init/example.js.map +1 -0
  69. package/dist/commands/init/first-hour.js +28 -0
  70. package/dist/commands/init/first-hour.js.map +1 -0
  71. package/dist/commands/{init.js → init/init.js} +146 -71
  72. package/dist/commands/init/init.js.map +1 -0
  73. package/dist/commands/init/mcp.js +131 -0
  74. package/dist/commands/init/mcp.js.map +1 -0
  75. package/dist/commands/init/options.js +78 -0
  76. package/dist/commands/init/options.js.map +1 -0
  77. package/dist/commands/instructions.js +72 -14
  78. package/dist/commands/instructions.js.map +1 -1
  79. package/dist/commands/list/campaign/campaign.js +65 -0
  80. package/dist/commands/list/campaign/campaign.js.map +1 -0
  81. package/dist/commands/list/campaign/owners.js +65 -0
  82. package/dist/commands/list/campaign/owners.js.map +1 -0
  83. package/dist/commands/list/json.js +157 -0
  84. package/dist/commands/list/json.js.map +1 -0
  85. package/dist/commands/list/list.js +343 -0
  86. package/dist/commands/list/list.js.map +1 -0
  87. package/dist/commands/list/print.js +301 -0
  88. package/dist/commands/list/print.js.map +1 -0
  89. package/dist/commands/list/review.js +120 -0
  90. package/dist/commands/list/review.js.map +1 -0
  91. package/dist/commands/list/views.js +105 -0
  92. package/dist/commands/list/views.js.map +1 -0
  93. package/dist/commands/mcp/dispatch.js +183 -0
  94. package/dist/commands/mcp/dispatch.js.map +1 -0
  95. package/dist/commands/mcp/mcp.js +34 -0
  96. package/dist/commands/mcp/mcp.js.map +1 -0
  97. package/dist/commands/mcp/serve.js +55 -0
  98. package/dist/commands/mcp/serve.js.map +1 -0
  99. package/dist/commands/migrate-openspec/materialize/active.js +170 -0
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  101. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  102. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  103. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  104. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  105. package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
  106. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  107. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  108. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  109. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  110. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  111. package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
  112. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  113. package/dist/commands/migrate-openspec/openspec/error.js +19 -0
  114. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  115. package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
  116. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  117. package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
  118. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  119. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  120. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  121. package/dist/commands/migrate-openspec/print.js +89 -0
  122. package/dist/commands/migrate-openspec/print.js.map +1 -0
  123. package/dist/commands/new/commit.js +76 -0
  124. package/dist/commands/new/commit.js.map +1 -0
  125. package/dist/commands/new/new.js +283 -0
  126. package/dist/commands/new/new.js.map +1 -0
  127. package/dist/commands/new/templates.js +355 -0
  128. package/dist/commands/new/templates.js.map +1 -0
  129. package/dist/commands/open.js +203 -0
  130. package/dist/commands/open.js.map +1 -0
  131. package/dist/commands/policy/format.js +152 -0
  132. package/dist/commands/policy/format.js.map +1 -0
  133. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
  134. package/dist/commands/policy/gate.js.map +1 -0
  135. package/dist/commands/rebase/edit.js +106 -0
  136. package/dist/commands/rebase/edit.js.map +1 -0
  137. package/dist/commands/rebase/living.js +185 -0
  138. package/dist/commands/rebase/living.js.map +1 -0
  139. package/dist/commands/rebase/plan.js +245 -0
  140. package/dist/commands/rebase/plan.js.map +1 -0
  141. package/dist/commands/rebase/rebase.js +275 -0
  142. package/dist/commands/rebase/rebase.js.map +1 -0
  143. package/dist/commands/seed/commit.js +192 -0
  144. package/dist/commands/seed/commit.js.map +1 -0
  145. package/dist/commands/seed/plan.js +133 -0
  146. package/dist/commands/seed/plan.js.map +1 -0
  147. package/dist/commands/seed/seed.js +172 -0
  148. package/dist/commands/seed/seed.js.map +1 -0
  149. package/dist/commands/show/feature.js +178 -0
  150. package/dist/commands/show/feature.js.map +1 -0
  151. package/dist/commands/show/marks.js +24 -0
  152. package/dist/commands/show/marks.js.map +1 -0
  153. package/dist/commands/{show.js → show/service.js} +63 -152
  154. package/dist/commands/show/service.js.map +1 -0
  155. package/dist/commands/show/show.js +77 -0
  156. package/dist/commands/show/show.js.map +1 -0
  157. package/dist/commands/status/json.js +45 -0
  158. package/dist/commands/status/json.js.map +1 -0
  159. package/dist/commands/status/print.js +157 -0
  160. package/dist/commands/status/print.js.map +1 -0
  161. package/dist/commands/status/status.js +119 -0
  162. package/dist/commands/status/status.js.map +1 -0
  163. package/dist/commands/steps/steps.js +189 -0
  164. package/dist/commands/steps/steps.js.map +1 -0
  165. package/dist/commands/subsystem/edit.js +192 -0
  166. package/dist/commands/subsystem/edit.js.map +1 -0
  167. package/dist/commands/subsystem/move.js +265 -0
  168. package/dist/commands/subsystem/move.js.map +1 -0
  169. package/dist/commands/subsystem/query.js +115 -0
  170. package/dist/commands/subsystem/query.js.map +1 -0
  171. package/dist/commands/subsystem/subsystem.js +101 -0
  172. package/dist/commands/subsystem/subsystem.js.map +1 -0
  173. package/dist/commands/subsystem/sync.js +103 -0
  174. package/dist/commands/subsystem/sync.js.map +1 -0
  175. package/dist/commands/subsystem/txn/txn.js +94 -0
  176. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  177. package/dist/commands/subsystem/txn/views.js +70 -0
  178. package/dist/commands/subsystem/txn/views.js.map +1 -0
  179. package/dist/commands/unarchive/manifest.js +160 -0
  180. package/dist/commands/unarchive/manifest.js.map +1 -0
  181. package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
  182. package/dist/commands/unarchive/restore.js.map +1 -0
  183. package/dist/commands/unarchive/unarchive.js +67 -0
  184. package/dist/commands/unarchive/unarchive.js.map +1 -0
  185. package/dist/commands/validate/arch-coverage.js +204 -0
  186. package/dist/commands/validate/arch-coverage.js.map +1 -0
  187. package/dist/commands/validate/checks/fleet-shape.js +296 -0
  188. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  189. package/dist/commands/validate/checks/health-deps.js +55 -0
  190. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  191. package/dist/commands/validate/checks/requirements.js +254 -0
  192. package/dist/commands/validate/checks/requirements.js.map +1 -0
  193. package/dist/commands/validate/checks/sources.js +76 -0
  194. package/dist/commands/validate/checks/sources.js.map +1 -0
  195. package/dist/commands/validate/checks/vocabulary.js +31 -0
  196. package/dist/commands/validate/checks/vocabulary.js.map +1 -0
  197. package/dist/commands/validate/feature.js +216 -0
  198. package/dist/commands/validate/feature.js.map +1 -0
  199. package/dist/commands/validate/fleet/census.js +69 -0
  200. package/dist/commands/validate/fleet/census.js.map +1 -0
  201. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  202. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  203. package/dist/commands/validate/fleet/landscape.js +353 -0
  204. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  205. package/dist/commands/validate/fleet/load.js +52 -0
  206. package/dist/commands/validate/fleet/load.js.map +1 -0
  207. package/dist/commands/validate/fleet/obligations.js +270 -0
  208. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  209. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  210. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  211. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  212. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  213. package/dist/commands/validate/fleet/scorecard/print.js +63 -0
  214. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  215. package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
  216. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  217. package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
  218. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
  219. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  220. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  221. package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
  222. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
  223. package/dist/commands/validate/fleet/usecases/steps.js +197 -0
  224. package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
  225. package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
  226. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
  227. package/dist/commands/validate/fleet/views/ids.js +40 -0
  228. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  229. package/dist/commands/validate/fleet/views/stale.js +59 -0
  230. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  231. package/dist/commands/validate/links/corpus.js +92 -0
  232. package/dist/commands/validate/links/corpus.js.map +1 -0
  233. package/dist/commands/validate/links/glossary.js +75 -0
  234. package/dist/commands/validate/links/glossary.js.map +1 -0
  235. package/dist/commands/validate/report.js +269 -0
  236. package/dist/commands/validate/report.js.map +1 -0
  237. package/dist/commands/validate/service/api.js +338 -0
  238. package/dist/commands/validate/service/api.js.map +1 -0
  239. package/dist/commands/validate/service/events/events.js +219 -0
  240. package/dist/commands/validate/service/events/events.js.map +1 -0
  241. package/dist/commands/validate/service/events/message-producers.js +77 -0
  242. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  243. package/dist/commands/validate/service/evidence-pins.js +131 -0
  244. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  245. package/dist/commands/validate/service/service.js +251 -0
  246. package/dist/commands/validate/service/service.js.map +1 -0
  247. package/dist/commands/validate/service/specs.js +251 -0
  248. package/dist/commands/validate/service/specs.js.map +1 -0
  249. package/dist/commands/validate/service/spine.js +113 -0
  250. package/dist/commands/validate/service/spine.js.map +1 -0
  251. package/dist/commands/validate/validate.js +338 -0
  252. package/dist/commands/validate/validate.js.map +1 -0
  253. package/dist/commands/verify/cross/diff.js +182 -0
  254. package/dist/commands/verify/cross/diff.js.map +1 -0
  255. package/dist/commands/verify/evidence/contract.js +32 -0
  256. package/dist/commands/verify/evidence/contract.js.map +1 -0
  257. package/dist/commands/verify/evidence/pins.js +52 -0
  258. package/dist/commands/verify/evidence/pins.js.map +1 -0
  259. package/dist/commands/verify/evidence/read.js +72 -0
  260. package/dist/commands/verify/evidence/read.js.map +1 -0
  261. package/dist/commands/verify/frozen.js +241 -0
  262. package/dist/commands/verify/frozen.js.map +1 -0
  263. package/dist/commands/verify/record.js +226 -0
  264. package/dist/commands/verify/record.js.map +1 -0
  265. package/dist/commands/verify/report.js +223 -0
  266. package/dist/commands/verify/report.js.map +1 -0
  267. package/dist/commands/verify/results.js +246 -0
  268. package/dist/commands/verify/results.js.map +1 -0
  269. package/dist/commands/verify/verify.js +217 -0
  270. package/dist/commands/verify/verify.js.map +1 -0
  271. package/dist/commands/vouch/contract.js +11 -0
  272. package/dist/commands/vouch/contract.js.map +1 -0
  273. package/dist/commands/vouch/pack/contract.js +2 -0
  274. package/dist/commands/vouch/pack/contract.js.map +1 -0
  275. package/dist/commands/vouch/pack/pack.js +266 -0
  276. package/dist/commands/vouch/pack/pack.js.map +1 -0
  277. package/dist/commands/vouch/pack/print.js +271 -0
  278. package/dist/commands/vouch/pack/print.js.map +1 -0
  279. package/dist/commands/vouch/pack/sections.js +142 -0
  280. package/dist/commands/vouch/pack/sections.js.map +1 -0
  281. package/dist/commands/vouch/prompt/confirm.js +46 -0
  282. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  283. package/dist/commands/vouch/report.js +101 -0
  284. package/dist/commands/vouch/report.js.map +1 -0
  285. package/dist/commands/vouch/run.js +285 -0
  286. package/dist/commands/vouch/run.js.map +1 -0
  287. package/dist/commands/vouch/sample/plan.js +125 -0
  288. package/dist/commands/vouch/sample/plan.js.map +1 -0
  289. package/dist/commands/vouch/sample/print.js +109 -0
  290. package/dist/commands/vouch/sample/print.js.map +1 -0
  291. package/dist/commands/vouch/vet/verify.js +123 -0
  292. package/dist/commands/vouch/vet/verify.js.map +1 -0
  293. package/dist/commands/vouch/vouch.js +176 -0
  294. package/dist/commands/vouch/vouch.js.map +1 -0
  295. package/dist/core/agent/agents-md/artifacts.js +220 -0
  296. package/dist/core/agent/agents-md/artifacts.js.map +1 -0
  297. package/dist/core/agent/agents-md/command-map.js +324 -0
  298. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  299. package/dist/core/agent/agents-md/cycle.js +165 -0
  300. package/dist/core/agent/agents-md/cycle.js.map +1 -0
  301. package/dist/core/agent/agents-md/map/explain.js +34 -0
  302. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  303. package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
  304. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  305. package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
  306. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  307. package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
  308. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  309. package/dist/core/agent/agents-md/map/mcp.js +41 -0
  310. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  311. package/dist/core/agent/agents-md/map/status.js +62 -0
  312. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  313. package/dist/core/agent/agents-md/map/subsystem.js +32 -0
  314. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  315. package/dist/core/agent/agents-md/map/usecases.js +60 -0
  316. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  317. package/dist/core/agent/agents-md/refusals.js +246 -0
  318. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  319. package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
  320. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
  321. package/dist/core/agent/agents-md/spine.js +40 -0
  322. package/dist/core/agent/agents-md/spine.js.map +1 -0
  323. package/dist/core/agent/agents-md.js +170 -0
  324. package/dist/core/agent/agents-md.js.map +1 -0
  325. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +50 -0
  326. package/dist/core/agent/agents-stamp.js.map +1 -0
  327. package/dist/core/agent/contract.js +2 -0
  328. package/dist/core/agent/contract.js.map +1 -0
  329. package/dist/core/agent/protocol.js +193 -0
  330. package/dist/core/agent/protocol.js.map +1 -0
  331. package/dist/core/agent/scaffold.js +259 -0
  332. package/dist/core/agent/scaffold.js.map +1 -0
  333. package/dist/core/agent/support/report.js +103 -0
  334. package/dist/core/agent/support/report.js.map +1 -0
  335. package/dist/core/agent/tools/dialects.js +150 -0
  336. package/dist/core/agent/tools/dialects.js.map +1 -0
  337. package/dist/core/agent/tools/registry.js +228 -0
  338. package/dist/core/agent/tools/registry.js.map +1 -0
  339. package/dist/core/agent/workflows/adopt.js +133 -0
  340. package/dist/core/agent/workflows/adopt.js.map +1 -0
  341. package/dist/core/agent/workflows/check.js +337 -0
  342. package/dist/core/agent/workflows/check.js.map +1 -0
  343. package/dist/core/agent/workflows/closing.js +262 -0
  344. package/dist/core/agent/workflows/closing.js.map +1 -0
  345. package/dist/core/agent/workflows/feature.js +105 -0
  346. package/dist/core/agent/workflows/feature.js.map +1 -0
  347. package/dist/core/agent/workflows/implement.js +105 -0
  348. package/dist/core/agent/workflows/implement.js.map +1 -0
  349. package/dist/core/agent/workflows/reference/authoring.js +209 -0
  350. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  351. package/dist/core/agent/workflows/reference/codes.js +65 -0
  352. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  353. package/dist/core/agent/workflows/reference/done-check.js +188 -0
  354. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  355. package/dist/core/agent/workflows/reference/reference.js +16 -0
  356. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  357. package/dist/core/agent/workflows/reference/spine.js +297 -0
  358. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  359. package/dist/core/asyncapi/baseline/plan.js +110 -0
  360. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  361. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  362. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  363. package/dist/core/asyncapi/depth.js +164 -0
  364. package/dist/core/asyncapi/depth.js.map +1 -0
  365. package/dist/core/asyncapi/digest.js +141 -0
  366. package/dist/core/asyncapi/digest.js.map +1 -0
  367. package/dist/core/asyncapi/merge/components.js +91 -0
  368. package/dist/core/asyncapi/merge/components.js.map +1 -0
  369. package/dist/core/asyncapi/merge/error.js +33 -0
  370. package/dist/core/asyncapi/merge/error.js.map +1 -0
  371. package/dist/core/asyncapi/merge/markers.js +308 -0
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  373. package/dist/core/asyncapi/merge/merge.js +215 -0
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  375. package/dist/core/asyncapi/merge/pin.js +107 -0
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  377. package/dist/core/asyncapi/model.js +11 -0
  378. package/dist/core/asyncapi/model.js.map +1 -0
  379. package/dist/core/asyncapi/producers.js +50 -0
  380. package/dist/core/asyncapi/producers.js.map +1 -0
  381. package/dist/core/{asyncapi.js → asyncapi/read.js} +95 -109
  382. package/dist/core/asyncapi/read.js.map +1 -0
  383. package/dist/core/brief/brief.js +225 -0
  384. package/dist/core/brief/brief.js.map +1 -0
  385. package/dist/core/brief/checks.js +250 -0
  386. package/dist/core/brief/checks.js.map +1 -0
  387. package/dist/core/brief/landscape.js +194 -0
  388. package/dist/core/brief/landscape.js.map +1 -0
  389. package/dist/core/brief/targets.js +226 -0
  390. package/dist/core/brief/targets.js.map +1 -0
  391. package/dist/core/brief/unchecked.js +48 -0
  392. package/dist/core/brief/unchecked.js.map +1 -0
  393. package/dist/core/c4/arch.js +174 -0
  394. package/dist/core/c4/arch.js.map +1 -0
  395. package/dist/core/c4/likec4.js +90 -0
  396. package/dist/core/c4/likec4.js.map +1 -0
  397. package/dist/core/c4/parsed/deployment.js +158 -0
  398. package/dist/core/c4/parsed/deployment.js.map +1 -0
  399. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  400. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  401. package/dist/core/c4/parsed/specification.js +78 -0
  402. package/dist/core/c4/parsed/specification.js.map +1 -0
  403. package/dist/core/c4/parsed/values.js +57 -0
  404. package/dist/core/c4/parsed/values.js.map +1 -0
  405. package/dist/core/c4/parsed/view-ids.js +75 -0
  406. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  407. package/dist/core/c4/project/architecture.js +45 -0
  408. package/dist/core/c4/project/architecture.js.map +1 -0
  409. package/dist/core/c4/project/documents.js +58 -0
  410. package/dist/core/c4/project/documents.js.map +1 -0
  411. package/dist/core/c4/project/load.js +187 -0
  412. package/dist/core/c4/project/load.js.map +1 -0
  413. package/dist/core/c4/project/staged.js +220 -0
  414. package/dist/core/c4/project/staged.js.map +1 -0
  415. package/dist/core/c4/resolve/service.js +159 -0
  416. package/dist/core/c4/resolve/service.js.map +1 -0
  417. package/dist/core/c4/resolve/steps.js +144 -0
  418. package/dist/core/c4/resolve/steps.js.map +1 -0
  419. package/dist/core/c4/seed/fleet-file.js +201 -0
  420. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  421. package/dist/core/c4/seed/items.js +91 -0
  422. package/dist/core/c4/seed/items.js.map +1 -0
  423. package/dist/core/c4/seed/stamp.js +48 -0
  424. package/dist/core/c4/seed/stamp.js.map +1 -0
  425. package/dist/core/c4/seed/template.js +109 -0
  426. package/dist/core/c4/seed/template.js.map +1 -0
  427. package/dist/core/c4/source-mask.js +82 -0
  428. package/dist/core/c4/source-mask.js.map +1 -0
  429. package/dist/core/c4/source-scan.js +227 -0
  430. package/dist/core/c4/source-scan.js.map +1 -0
  431. package/dist/core/c4/splice/authored-source.js +101 -0
  432. package/dist/core/c4/splice/authored-source.js.map +1 -0
  433. package/dist/core/c4/splice/contract.js +10 -0
  434. package/dist/core/c4/splice/contract.js.map +1 -0
  435. package/dist/core/c4/splice/delta-blocks.js +139 -0
  436. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  437. package/dist/core/c4/splice/identity/edges.js +36 -0
  438. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  439. package/dist/core/c4/splice/landscape-merge.js +269 -0
  440. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  441. package/dist/core/c4/splice/placement.js +194 -0
  442. package/dist/core/c4/splice/placement.js.map +1 -0
  443. package/dist/core/c4/workspace.js +174 -0
  444. package/dist/core/c4/workspace.js.map +1 -0
  445. package/dist/core/capabilities/authoring/notes.js +141 -0
  446. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  447. package/dist/core/capabilities/capabilities.js +124 -0
  448. package/dist/core/capabilities/capabilities.js.map +1 -0
  449. package/dist/core/capabilities/delta/doc.js +50 -0
  450. package/dist/core/capabilities/delta/doc.js.map +1 -0
  451. package/dist/core/capabilities/delta/overlay.js +129 -0
  452. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  453. package/dist/core/capabilities/delta/summary.js +57 -0
  454. package/dist/core/capabilities/delta/summary.js.map +1 -0
  455. package/dist/core/capabilities/delta/tree.js +43 -0
  456. package/dist/core/capabilities/delta/tree.js.map +1 -0
  457. package/dist/core/capabilities/delta/uncovered.js +222 -0
  458. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  459. package/dist/core/capabilities/findings.js +342 -0
  460. package/dist/core/capabilities/findings.js.map +1 -0
  461. package/dist/core/capabilities/realizes/findings.js +181 -0
  462. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  463. package/dist/core/capabilities/realizes/join.js +143 -0
  464. package/dist/core/capabilities/realizes/join.js.map +1 -0
  465. package/dist/core/capabilities/rollup.js +199 -0
  466. package/dist/core/capabilities/rollup.js.map +1 -0
  467. package/dist/core/capabilities/tree.js +126 -0
  468. package/dist/core/capabilities/tree.js.map +1 -0
  469. package/dist/core/capabilities/usecase-join.js +277 -0
  470. package/dist/core/capabilities/usecase-join.js.map +1 -0
  471. package/dist/core/coherence/authoring/scaffold.js +177 -0
  472. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  473. package/dist/core/coherence/authoring/sentinels.js +74 -0
  474. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  475. package/dist/core/coherence/coherence.js +287 -0
  476. package/dist/core/coherence/coherence.js.map +1 -0
  477. package/dist/core/coherence/declared.js +269 -0
  478. package/dist/core/coherence/declared.js.map +1 -0
  479. package/dist/core/coherence/events/declared.js +206 -0
  480. package/dist/core/coherence/events/declared.js.map +1 -0
  481. package/dist/core/coherence/events/events.js +204 -0
  482. package/dist/core/coherence/events/events.js.map +1 -0
  483. package/dist/core/coherence/events/grades.js +166 -0
  484. package/dist/core/coherence/events/grades.js.map +1 -0
  485. package/dist/core/coherence/events/lookups.js +122 -0
  486. package/dist/core/coherence/events/lookups.js.map +1 -0
  487. package/dist/core/coherence/events/merged.js +40 -0
  488. package/dist/core/coherence/events/merged.js.map +1 -0
  489. package/dist/core/coherence/living.js +198 -0
  490. package/dist/core/coherence/living.js.map +1 -0
  491. package/dist/core/coherence/lookups.js +155 -0
  492. package/dist/core/coherence/lookups.js.map +1 -0
  493. package/dist/core/coherence/pending.js +39 -0
  494. package/dist/core/coherence/pending.js.map +1 -0
  495. package/dist/core/conflict-markers.js +60 -0
  496. package/dist/core/conflict-markers.js.map +1 -0
  497. package/dist/core/delta/claims.js +73 -0
  498. package/dist/core/delta/claims.js.map +1 -0
  499. package/dist/core/delta/delta.js +296 -0
  500. package/dist/core/delta/delta.js.map +1 -0
  501. package/dist/core/delta/document.js +177 -0
  502. package/dist/core/delta/document.js.map +1 -0
  503. package/dist/core/delta/scope.js +48 -0
  504. package/dist/core/delta/scope.js.map +1 -0
  505. package/dist/core/delta/select.js +237 -0
  506. package/dist/core/delta/select.js.map +1 -0
  507. package/dist/core/dependencies/dependencies.js +141 -0
  508. package/dist/core/dependencies/dependencies.js.map +1 -0
  509. package/dist/core/dependencies/facts.js +165 -0
  510. package/dist/core/dependencies/facts.js.map +1 -0
  511. package/dist/core/dependencies/fanin.js +88 -0
  512. package/dist/core/dependencies/fanin.js.map +1 -0
  513. package/dist/core/dependencies/graph.js +106 -0
  514. package/dist/core/dependencies/graph.js.map +1 -0
  515. package/dist/core/deployment/delta.js +188 -0
  516. package/dist/core/deployment/delta.js.map +1 -0
  517. package/dist/core/deployment/objects.js +145 -0
  518. package/dist/core/deployment/objects.js.map +1 -0
  519. package/dist/core/diff/base-git.js +148 -0
  520. package/dist/core/diff/base-git.js.map +1 -0
  521. package/dist/core/diff/base-state.js +209 -0
  522. package/dist/core/diff/base-state.js.map +1 -0
  523. package/dist/core/diff/current-state.js +96 -0
  524. package/dist/core/diff/current-state.js.map +1 -0
  525. package/dist/core/diff/scope/changed-paths.js +188 -0
  526. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  527. package/dist/core/diff/semantic.js +243 -0
  528. package/dist/core/diff/semantic.js.map +1 -0
  529. package/dist/core/diff/victims.js +247 -0
  530. package/dist/core/diff/victims.js.map +1 -0
  531. package/dist/core/docs.js +7 -64
  532. package/dist/core/docs.js.map +1 -1
  533. package/dist/core/doctor/agents.js +222 -0
  534. package/dist/core/doctor/agents.js.map +1 -0
  535. package/dist/core/doctor/config.js +135 -0
  536. package/dist/core/doctor/config.js.map +1 -0
  537. package/dist/core/doctor/doctor.js +275 -0
  538. package/dist/core/doctor/doctor.js.map +1 -0
  539. package/dist/core/doctor/report.js +13 -0
  540. package/dist/core/doctor/report.js.map +1 -0
  541. package/dist/core/doctor/residue.js +110 -0
  542. package/dist/core/doctor/residue.js.map +1 -0
  543. package/dist/core/document/apply.js +77 -0
  544. package/dist/core/document/apply.js.map +1 -0
  545. package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
  546. package/dist/core/document/frontmatter.js.map +1 -0
  547. package/dist/core/document/grammar/directives.js +143 -0
  548. package/dist/core/document/grammar/directives.js.map +1 -0
  549. package/dist/core/document/parse.js +263 -0
  550. package/dist/core/document/parse.js.map +1 -0
  551. package/dist/core/document/scenarios.js +221 -0
  552. package/dist/core/document/scenarios.js.map +1 -0
  553. package/dist/core/document/spec.js +241 -0
  554. package/dist/core/document/spec.js.map +1 -0
  555. package/dist/core/{config.js → envelope/config.js} +79 -18
  556. package/dist/core/envelope/config.js.map +1 -0
  557. package/dist/core/envelope/json.js +175 -0
  558. package/dist/core/envelope/json.js.map +1 -0
  559. package/dist/core/{version.js → envelope/version.js} +3 -3
  560. package/dist/core/envelope/version.js.map +1 -0
  561. package/dist/core/explain/families.js +175 -0
  562. package/dist/core/explain/families.js.map +1 -0
  563. package/dist/core/explain/fix-tables.js +178 -0
  564. package/dist/core/explain/fix-tables.js.map +1 -0
  565. package/dist/core/explain/lookup.js +181 -0
  566. package/dist/core/explain/lookup.js.map +1 -0
  567. package/dist/core/explain/refusals.js +49 -0
  568. package/dist/core/explain/refusals.js.map +1 -0
  569. package/dist/core/explain/terms.js +144 -0
  570. package/dist/core/explain/terms.js.map +1 -0
  571. package/dist/core/explore/describe.js +105 -0
  572. package/dist/core/explore/describe.js.map +1 -0
  573. package/dist/core/{explore.js → explore/explore.js} +50 -101
  574. package/dist/core/explore/explore.js.map +1 -0
  575. package/dist/core/fleet-context.js +120 -78
  576. package/dist/core/fleet-context.js.map +1 -1
  577. package/dist/core/gate/checks.js +201 -0
  578. package/dist/core/gate/checks.js.map +1 -0
  579. package/dist/core/gate/partners.js +205 -0
  580. package/dist/core/gate/partners.js.map +1 -0
  581. package/dist/core/gate/report.js +47 -0
  582. package/dist/core/gate/report.js.map +1 -0
  583. package/dist/core/gate/verification.js +113 -0
  584. package/dist/core/gate/verification.js.map +1 -0
  585. package/dist/core/gherkin/digest.js +60 -0
  586. package/dist/core/gherkin/digest.js.map +1 -0
  587. package/dist/core/gherkin/emit.js +177 -0
  588. package/dist/core/gherkin/emit.js.map +1 -0
  589. package/dist/core/gherkin/read.js +76 -0
  590. package/dist/core/gherkin/read.js.map +1 -0
  591. package/dist/core/gherkin/stale.js +234 -0
  592. package/dist/core/gherkin/stale.js.map +1 -0
  593. package/dist/core/gherkin/stamp.js +77 -0
  594. package/dist/core/gherkin/stamp.js.map +1 -0
  595. package/dist/core/gherkin/steps/catalogue.js +154 -0
  596. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  597. package/dist/core/gherkin/steps/inventory.js +98 -0
  598. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  599. package/dist/core/gherkin/steps/phrase.js +72 -0
  600. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  601. package/dist/core/glossary/delta.js +106 -0
  602. package/dist/core/glossary/delta.js.map +1 -0
  603. package/dist/core/glossary/tree.js +86 -0
  604. package/dist/core/glossary/tree.js.map +1 -0
  605. package/dist/core/kernel/concurrency.js.map +1 -0
  606. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  607. package/dist/core/kernel/document-bytes.js.map +1 -0
  608. package/dist/core/kernel/fences.js +42 -0
  609. package/dist/core/kernel/fences.js.map +1 -0
  610. package/dist/core/kernel/ids/capability.js +72 -0
  611. package/dist/core/kernel/ids/capability.js.map +1 -0
  612. package/dist/core/kernel/ids/dirs.js +33 -0
  613. package/dist/core/kernel/ids/dirs.js.map +1 -0
  614. package/dist/core/kernel/ids/feature.js +75 -0
  615. package/dist/core/kernel/ids/feature.js.map +1 -0
  616. package/dist/core/kernel/ids/service.js +156 -0
  617. package/dist/core/kernel/ids/service.js.map +1 -0
  618. package/dist/core/kernel/ids/subsystem.js +63 -0
  619. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  620. package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
  621. package/dist/core/kernel/path-safety.js.map +1 -0
  622. package/dist/core/kernel/records.js.map +1 -0
  623. package/dist/core/links/backlinks.js +68 -0
  624. package/dist/core/links/backlinks.js.map +1 -0
  625. package/dist/core/links/case.js +74 -0
  626. package/dist/core/links/case.js.map +1 -0
  627. package/dist/core/links/corpus.js +104 -0
  628. package/dist/core/links/corpus.js.map +1 -0
  629. package/dist/core/links/findings.js +110 -0
  630. package/dist/core/links/findings.js.map +1 -0
  631. package/dist/core/links/parse.js +236 -0
  632. package/dist/core/links/parse.js.map +1 -0
  633. package/dist/core/mcp/argv.js +111 -0
  634. package/dist/core/mcp/argv.js.map +1 -0
  635. package/dist/core/mcp/author-tools.js +72 -0
  636. package/dist/core/mcp/author-tools.js.map +1 -0
  637. package/dist/core/mcp/framing.js +46 -0
  638. package/dist/core/mcp/framing.js.map +1 -0
  639. package/dist/core/mcp/protocol.js +280 -0
  640. package/dist/core/mcp/protocol.js.map +1 -0
  641. package/dist/core/mcp/tools.js +314 -0
  642. package/dist/core/mcp/tools.js.map +1 -0
  643. package/dist/core/obligations/obligations.js +106 -0
  644. package/dist/core/obligations/obligations.js.map +1 -0
  645. package/dist/core/openapi/baseline/gate.js +166 -0
  646. package/dist/core/openapi/baseline/gate.js.map +1 -0
  647. package/dist/core/openapi/baseline/plan.js +112 -0
  648. package/dist/core/openapi/baseline/plan.js.map +1 -0
  649. package/dist/core/openapi/baseline/record.js +175 -0
  650. package/dist/core/openapi/baseline/record.js.map +1 -0
  651. package/dist/core/openapi/depth.js +122 -0
  652. package/dist/core/openapi/depth.js.map +1 -0
  653. package/dist/core/openapi/digest.js +189 -0
  654. package/dist/core/openapi/digest.js.map +1 -0
  655. package/dist/core/{openapi.js → openapi/doc.js} +44 -106
  656. package/dist/core/openapi/doc.js.map +1 -0
  657. package/dist/core/openapi/merge/components.js +234 -0
  658. package/dist/core/openapi/merge/components.js.map +1 -0
  659. package/dist/core/openapi/merge/error.js +26 -0
  660. package/dist/core/openapi/merge/error.js.map +1 -0
  661. package/dist/core/openapi/merge/markers.js +208 -0
  662. package/dist/core/openapi/merge/markers.js.map +1 -0
  663. package/dist/core/openapi/merge/merge.js +256 -0
  664. package/dist/core/openapi/merge/merge.js.map +1 -0
  665. package/dist/core/openapi/merge/pin.js +128 -0
  666. package/dist/core/openapi/merge/pin.js.map +1 -0
  667. package/dist/core/openspec/decide/capabilities.js +244 -0
  668. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  669. package/dist/core/openspec/decide/dispositions.js +63 -0
  670. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  671. package/dist/core/openspec/decide/renames.js +179 -0
  672. package/dist/core/openspec/decide/renames.js.map +1 -0
  673. package/dist/core/openspec/decide/verdict.js +84 -0
  674. package/dist/core/openspec/decide/verdict.js.map +1 -0
  675. package/dist/core/openspec/inventory.js +221 -0
  676. package/dist/core/openspec/inventory.js.map +1 -0
  677. package/dist/core/openspec/model/mapping.js +76 -0
  678. package/dist/core/openspec/model/mapping.js.map +1 -0
  679. package/dist/core/openspec/model/model.js +65 -0
  680. package/dist/core/openspec/model/model.js.map +1 -0
  681. package/dist/core/openspec/scan/changes.js +235 -0
  682. package/dist/core/openspec/scan/changes.js.map +1 -0
  683. package/dist/core/openspec/scan/config.js +200 -0
  684. package/dist/core/openspec/scan/config.js.map +1 -0
  685. package/dist/core/openspec/scan/shape.js +260 -0
  686. package/dist/core/openspec/scan/shape.js.map +1 -0
  687. package/dist/core/openspec/scan/walk.js +133 -0
  688. package/dist/core/openspec/scan/walk.js.map +1 -0
  689. package/dist/core/openspec/scan/workspace.js +71 -0
  690. package/dist/core/openspec/scan/workspace.js.map +1 -0
  691. package/dist/core/owners/codeowners.js +141 -0
  692. package/dist/core/owners/codeowners.js.map +1 -0
  693. package/dist/core/pack/features.js +120 -0
  694. package/dist/core/pack/features.js.map +1 -0
  695. package/dist/core/pack/joins.js +112 -0
  696. package/dist/core/pack/joins.js.map +1 -0
  697. package/dist/core/pack/living.js +137 -0
  698. package/dist/core/pack/living.js.map +1 -0
  699. package/dist/core/pack/pack.js +76 -0
  700. package/dist/core/pack/pack.js.map +1 -0
  701. package/dist/core/permissions/permissions.js +87 -0
  702. package/dist/core/permissions/permissions.js.map +1 -0
  703. package/dist/core/projection/api.js +84 -0
  704. package/dist/core/projection/api.js.map +1 -0
  705. package/dist/core/projection/arch-slice.js +63 -0
  706. package/dist/core/projection/arch-slice.js.map +1 -0
  707. package/dist/core/projection/events.js +34 -0
  708. package/dist/core/projection/events.js.map +1 -0
  709. package/dist/core/provenance/findings.js +208 -0
  710. package/dist/core/provenance/findings.js.map +1 -0
  711. package/dist/core/provenance/git.js +225 -0
  712. package/dist/core/provenance/git.js.map +1 -0
  713. package/dist/core/provenance/gitq/moves.js +182 -0
  714. package/dist/core/provenance/gitq/moves.js.map +1 -0
  715. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  716. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  717. package/dist/core/provenance/sample/scope.js +238 -0
  718. package/dist/core/provenance/sample/scope.js.map +1 -0
  719. package/dist/core/provenance/sample/sections.js +61 -0
  720. package/dist/core/provenance/sample/sections.js.map +1 -0
  721. package/dist/core/provenance/sources.js +263 -0
  722. package/dist/core/provenance/sources.js.map +1 -0
  723. package/dist/core/provenance/stamp.js +232 -0
  724. package/dist/core/provenance/stamp.js.map +1 -0
  725. package/dist/core/provenance/walk.js +157 -0
  726. package/dist/core/provenance/walk.js.map +1 -0
  727. package/dist/core/repo/authored/paths.js +210 -0
  728. package/dist/core/repo/authored/paths.js.map +1 -0
  729. package/dist/core/repo/entries.js +126 -0
  730. package/dist/core/repo/entries.js.map +1 -0
  731. package/dist/core/repo/paths.js +277 -0
  732. package/dist/core/repo/paths.js.map +1 -0
  733. package/dist/core/repo/repo.js +248 -0
  734. package/dist/core/repo/repo.js.map +1 -0
  735. package/dist/core/repo/service-target.js +153 -0
  736. package/dist/core/repo/service-target.js.map +1 -0
  737. package/dist/core/repo/state.js +58 -0
  738. package/dist/core/repo/state.js.map +1 -0
  739. package/dist/core/repo/tree/find.js +52 -0
  740. package/dist/core/repo/tree/find.js.map +1 -0
  741. package/dist/core/repo/tree/fs.js +64 -0
  742. package/dist/core/repo/tree/fs.js.map +1 -0
  743. package/dist/core/repo/tree/marker.js +61 -0
  744. package/dist/core/repo/tree/marker.js.map +1 -0
  745. package/dist/core/repo/tree/views.js +172 -0
  746. package/dist/core/repo/tree/views.js.map +1 -0
  747. package/dist/core/repo/tree/walk.js +234 -0
  748. package/dist/core/repo/tree/walk.js.map +1 -0
  749. package/dist/core/results.js +99 -2
  750. package/dist/core/results.js.map +1 -1
  751. package/dist/core/scaffold/landscape.js +131 -0
  752. package/dist/core/scaffold/landscape.js.map +1 -0
  753. package/dist/core/scaffold/readme.js +84 -0
  754. package/dist/core/scaffold/readme.js.map +1 -0
  755. package/dist/core/staging/commit.js +241 -0
  756. package/dist/core/staging/commit.js.map +1 -0
  757. package/dist/core/staging/interrupted.js +96 -0
  758. package/dist/core/staging/interrupted.js.map +1 -0
  759. package/dist/core/staging/lock.js +206 -0
  760. package/dist/core/staging/lock.js.map +1 -0
  761. package/dist/core/staging/recovery/finding.js +35 -0
  762. package/dist/core/staging/recovery/finding.js.map +1 -0
  763. package/dist/core/staging/recovery/intent.js +98 -0
  764. package/dist/core/staging/recovery/intent.js.map +1 -0
  765. package/dist/core/staging/recovery/recover.js +126 -0
  766. package/dist/core/staging/recovery/recover.js.map +1 -0
  767. package/dist/core/staging/recovery/residue.js +62 -0
  768. package/dist/core/staging/recovery/residue.js.map +1 -0
  769. package/dist/core/staging/snapshot.js +202 -0
  770. package/dist/core/staging/snapshot.js.map +1 -0
  771. package/dist/core/staging/txn/forward.js +171 -0
  772. package/dist/core/staging/txn/forward.js.map +1 -0
  773. package/dist/core/staging/txn/journal.js +139 -0
  774. package/dist/core/staging/txn/journal.js.map +1 -0
  775. package/dist/core/staging/txn/transaction.js +75 -0
  776. package/dist/core/staging/txn/transaction.js.map +1 -0
  777. package/dist/core/staging/writes.js +113 -0
  778. package/dist/core/staging/writes.js.map +1 -0
  779. package/dist/core/status/actions/execution.js +49 -0
  780. package/dist/core/status/actions/execution.js.map +1 -0
  781. package/dist/core/status/contracts.js +102 -0
  782. package/dist/core/status/contracts.js.map +1 -0
  783. package/dist/core/status/feature/artifacts.js +196 -0
  784. package/dist/core/status/feature/artifacts.js.map +1 -0
  785. package/dist/core/status/feature/feature.js +207 -0
  786. package/dist/core/status/feature/feature.js.map +1 -0
  787. package/dist/core/status/feature/next.js +150 -0
  788. package/dist/core/status/feature/next.js.map +1 -0
  789. package/dist/core/status/feature/state.js +21 -0
  790. package/dist/core/status/feature/state.js.map +1 -0
  791. package/dist/core/status/fleet/fleet.js +197 -0
  792. package/dist/core/status/fleet/fleet.js.map +1 -0
  793. package/dist/core/status/fleet/next.js +207 -0
  794. package/dist/core/status/fleet/next.js.map +1 -0
  795. package/dist/core/status/interrupted.js +97 -0
  796. package/dist/core/status/interrupted.js.map +1 -0
  797. package/dist/core/status/report.js +31 -0
  798. package/dist/core/status/report.js.map +1 -0
  799. package/dist/core/status/scan.js +41 -0
  800. package/dist/core/status/scan.js.map +1 -0
  801. package/dist/core/status/verification.js +201 -0
  802. package/dist/core/status/verification.js.map +1 -0
  803. package/dist/core/usecases/capability.js +169 -0
  804. package/dist/core/usecases/capability.js.map +1 -0
  805. package/dist/core/usecases/delta/claims.js +116 -0
  806. package/dist/core/usecases/delta/claims.js.map +1 -0
  807. package/dist/core/usecases/delta/flows.js +103 -0
  808. package/dist/core/usecases/delta/flows.js.map +1 -0
  809. package/dist/core/usecases/delta/overlay.js +72 -0
  810. package/dist/core/usecases/delta/overlay.js.map +1 -0
  811. package/dist/core/usecases/fleet.js +137 -0
  812. package/dist/core/usecases/fleet.js.map +1 -0
  813. package/dist/core/usecases/operations.js +111 -0
  814. package/dist/core/usecases/operations.js.map +1 -0
  815. package/dist/core/usecases/place.js +44 -0
  816. package/dist/core/usecases/place.js.map +1 -0
  817. package/dist/core/usecases/touch.js +101 -0
  818. package/dist/core/usecases/touch.js.map +1 -0
  819. package/dist/core/verify/answers.js +173 -0
  820. package/dist/core/verify/answers.js.map +1 -0
  821. package/dist/core/verify/build.js +150 -0
  822. package/dist/core/verify/build.js.map +1 -0
  823. package/dist/core/verify/checklist.js +201 -0
  824. package/dist/core/verify/checklist.js.map +1 -0
  825. package/dist/core/verify/claims/identity.js +61 -0
  826. package/dist/core/verify/claims/identity.js.map +1 -0
  827. package/dist/core/verify/cross/diff.js +97 -0
  828. package/dist/core/verify/cross/diff.js.map +1 -0
  829. package/dist/core/verify/evidence/contract.js +169 -0
  830. package/dist/core/verify/evidence/contract.js.map +1 -0
  831. package/dist/core/verify/file.js +257 -0
  832. package/dist/core/verify/file.js.map +1 -0
  833. package/dist/core/verify/pins/lint.js +157 -0
  834. package/dist/core/verify/pins/lint.js.map +1 -0
  835. package/dist/core/verify/pins/pin.js +95 -0
  836. package/dist/core/verify/pins/pin.js.map +1 -0
  837. package/dist/core/verify/record.js +142 -0
  838. package/dist/core/verify/record.js.map +1 -0
  839. package/dist/core/verify/store/commit.js +89 -0
  840. package/dist/core/verify/store/commit.js.map +1 -0
  841. package/dist/core/verify/store/render.js +57 -0
  842. package/dist/core/verify/store/render.js.map +1 -0
  843. package/dist/core/vocabulary/health.js +91 -0
  844. package/dist/core/vocabulary/health.js.map +1 -0
  845. package/dist/core/vocabulary/issue.js +58 -0
  846. package/dist/core/vocabulary/issue.js.map +1 -0
  847. package/dist/core/vocabulary/maturity.js +145 -0
  848. package/dist/core/vocabulary/maturity.js.map +1 -0
  849. package/dist/core/{report.js → vocabulary/report.js} +30 -2
  850. package/dist/core/vocabulary/report.js.map +1 -0
  851. package/dist/core/vocabulary/steps.js +266 -0
  852. package/dist/core/vocabulary/steps.js.map +1 -0
  853. package/dist/core/workspace/discover.js +239 -0
  854. package/dist/core/workspace/discover.js.map +1 -0
  855. package/dist/core/workspace/render.js +52 -0
  856. package/dist/core/workspace/render.js.map +1 -0
  857. package/examples/README.md +189 -0
  858. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  859. package/examples/docs/architecture/capabilities.yaml +31 -0
  860. package/examples/docs/architecture/landscape.likec4 +280 -0
  861. package/examples/docs/architecture/obligations.yaml +23 -0
  862. package/examples/docs/architecture/permissions.yaml +50 -0
  863. package/examples/docs/architecture/subsystems.likec4 +11 -0
  864. package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
  865. package/examples/docs/capabilities/checkout/spec.md +55 -0
  866. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  867. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  868. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  869. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  870. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  871. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  872. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
  873. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  874. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  875. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  876. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  877. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  878. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
  879. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  880. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  881. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  882. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  883. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  884. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  885. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  886. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  887. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  888. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  889. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
  890. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  891. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  892. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  893. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  894. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  895. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  896. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  897. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  898. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  899. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  900. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  901. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  902. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  903. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  904. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  905. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  906. package/examples/docs/glossary/order.md +15 -0
  907. package/examples/docs/glossary/payments/authorization.md +14 -0
  908. package/examples/docs/likec4.config.json +9 -0
  909. package/examples/docs/loam.json +3 -0
  910. package/examples/docs/services/checkout-web/model.likec4 +109 -0
  911. package/examples/docs/services/checkout-web/spec.md +91 -0
  912. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  913. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  914. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  915. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  916. package/examples/docs/services/order-service/arch.spec.md +127 -0
  917. package/examples/docs/services/order-service/asyncapi.yaml +108 -0
  918. package/examples/docs/services/order-service/health.yaml +57 -0
  919. package/examples/docs/services/order-service/model.likec4 +138 -0
  920. package/examples/docs/services/order-service/openapi.yaml +257 -0
  921. package/examples/docs/services/order-service/runbook.md +62 -0
  922. package/examples/docs/services/order-service/spec.md +134 -0
  923. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  924. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  925. package/examples/docs/services/payment-service/arch.spec.md +73 -0
  926. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  927. package/examples/docs/services/payment-service/health.yaml +39 -0
  928. package/examples/docs/services/payment-service/model.likec4 +67 -0
  929. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  930. package/examples/docs/services/payment-service/runbook.md +37 -0
  931. package/examples/docs/services/payment-service/spec.md +88 -0
  932. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  933. package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
  934. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  935. package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
  936. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  937. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  938. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  939. package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
  940. package/examples/docs/services/platform/notification-service/health.yaml +35 -0
  941. package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
  942. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  943. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  944. package/examples/docs/services/platform/subsystem.yaml +2 -0
  945. package/examples/fleet.yaml +57 -0
  946. package/package.json +19 -6
  947. package/dist/commands/adopt.js +0 -240
  948. package/dist/commands/adopt.js.map +0 -1
  949. package/dist/commands/archive.js +0 -1313
  950. package/dist/commands/archive.js.map +0 -1
  951. package/dist/commands/delta.js +0 -388
  952. package/dist/commands/delta.js.map +0 -1
  953. package/dist/commands/docs-repo-gate.js.map +0 -1
  954. package/dist/commands/format.js +0 -17
  955. package/dist/commands/format.js.map +0 -1
  956. package/dist/commands/gherkin.js +0 -309
  957. package/dist/commands/gherkin.js.map +0 -1
  958. package/dist/commands/init.js.map +0 -1
  959. package/dist/commands/list.js +0 -295
  960. package/dist/commands/list.js.map +0 -1
  961. package/dist/commands/migrate-openspec.js +0 -950
  962. package/dist/commands/migrate-openspec.js.map +0 -1
  963. package/dist/commands/new.js +0 -413
  964. package/dist/commands/new.js.map +0 -1
  965. package/dist/commands/rebase.js +0 -356
  966. package/dist/commands/rebase.js.map +0 -1
  967. package/dist/commands/show.js.map +0 -1
  968. package/dist/commands/status.js +0 -262
  969. package/dist/commands/status.js.map +0 -1
  970. package/dist/commands/unarchive.js.map +0 -1
  971. package/dist/commands/validate.js +0 -1773
  972. package/dist/commands/validate.js.map +0 -1
  973. package/dist/commands/verify.js +0 -775
  974. package/dist/commands/verify.js.map +0 -1
  975. package/dist/commands/vouch.js +0 -421
  976. package/dist/commands/vouch.js.map +0 -1
  977. package/dist/core/agent.js +0 -2173
  978. package/dist/core/agent.js.map +0 -1
  979. package/dist/core/agents-stamp.js.map +0 -1
  980. package/dist/core/arch.js +0 -130
  981. package/dist/core/arch.js.map +0 -1
  982. package/dist/core/asyncapi.js.map +0 -1
  983. package/dist/core/brief.js +0 -755
  984. package/dist/core/brief.js.map +0 -1
  985. package/dist/core/coherence.js +0 -577
  986. package/dist/core/coherence.js.map +0 -1
  987. package/dist/core/concurrency.js.map +0 -1
  988. package/dist/core/config.js.map +0 -1
  989. package/dist/core/delta.js +0 -476
  990. package/dist/core/delta.js.map +0 -1
  991. package/dist/core/dependencies.js +0 -356
  992. package/dist/core/dependencies.js.map +0 -1
  993. package/dist/core/doctor.js +0 -596
  994. package/dist/core/doctor.js.map +0 -1
  995. package/dist/core/document-bytes.js.map +0 -1
  996. package/dist/core/explore.js.map +0 -1
  997. package/dist/core/frontmatter.js.map +0 -1
  998. package/dist/core/gherkin.js +0 -463
  999. package/dist/core/gherkin.js.map +0 -1
  1000. package/dist/core/health.js +0 -67
  1001. package/dist/core/health.js.map +0 -1
  1002. package/dist/core/ids.js +0 -122
  1003. package/dist/core/ids.js.map +0 -1
  1004. package/dist/core/issue.js +0 -9
  1005. package/dist/core/issue.js.map +0 -1
  1006. package/dist/core/json.js +0 -74
  1007. package/dist/core/json.js.map +0 -1
  1008. package/dist/core/likec4.js +0 -489
  1009. package/dist/core/likec4.js.map +0 -1
  1010. package/dist/core/maturity.js +0 -66
  1011. package/dist/core/maturity.js.map +0 -1
  1012. package/dist/core/openapi-merge.js +0 -552
  1013. package/dist/core/openapi-merge.js.map +0 -1
  1014. package/dist/core/openapi.js.map +0 -1
  1015. package/dist/core/openspec-inventory.js +0 -1440
  1016. package/dist/core/openspec-inventory.js.map +0 -1
  1017. package/dist/core/path-safety.js.map +0 -1
  1018. package/dist/core/provenance.js +0 -787
  1019. package/dist/core/provenance.js.map +0 -1
  1020. package/dist/core/records.js.map +0 -1
  1021. package/dist/core/repo.js +0 -438
  1022. package/dist/core/repo.js.map +0 -1
  1023. package/dist/core/report.js.map +0 -1
  1024. package/dist/core/spec.js +0 -505
  1025. package/dist/core/spec.js.map +0 -1
  1026. package/dist/core/staging.js +0 -890
  1027. package/dist/core/staging.js.map +0 -1
  1028. package/dist/core/status.js +0 -1132
  1029. package/dist/core/status.js.map +0 -1
  1030. package/dist/core/steps.js +0 -72
  1031. package/dist/core/steps.js.map +0 -1
  1032. package/dist/core/verify.js +0 -807
  1033. package/dist/core/verify.js.map +0 -1
  1034. package/dist/core/version.js.map +0 -1
  1035. /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
  1036. /package/dist/core/{records.js → kernel/records.js} +0 -0
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Writing the answers down.
3
+ *
4
+ * The one command in loam that takes somebody's word for something, so every
5
+ * refusal here is about whose word is on the file. The legacy all-at-once form
6
+ * run over a federated record does not merge and does not migrate — it would
7
+ * erase every other service's commit-bound attestation, invisibly, because what
8
+ * replaces it is a well-formed and plausible record.
9
+ */
10
+ import { readFile } from "node:fs/promises";
11
+ import { resolve } from "node:path";
12
+ import { emitJson, fail, repoPath } from "../../core/envelope/json.js";
13
+ import { today } from "../../core/provenance/stamp.js";
14
+ import { runnerAnswers } from "../../core/results.js";
15
+ import { checkAnswers } from "../../core/verify/answers.js";
16
+ import { buildFederatedVerification, buildVerification, } from "../../core/verify/build.js";
17
+ import {} from "../../core/verify/checklist.js";
18
+ import { contractAnswers } from "../../core/verify/evidence/contract.js";
19
+ import { commitVerification } from "../../core/verify/store/commit.js";
20
+ import { tallyRecord, verificationPath, verificationVerdict, } from "../../core/verify/record.js";
21
+ import { plural, sayDiscarded, sayRecovered } from "../policy/format.js";
22
+ import { readContractResults } from "./evidence/contract.js";
23
+ import { claimTokens, pinAnswers } from "./evidence/pins.js";
24
+ import { readResults, repositoryCommit, validateServiceEvidence } from "./results.js";
25
+ import { contestedNotices, contestedOperationNotices, contractReportLine, noticesFor, reportLine } from "./frozen.js";
26
+ import {} from "./report.js";
27
+ export async function record(target, checklist, attestor, opts) {
28
+ const { docsDir, featureDir, json } = target;
29
+ const { service, repoDir, previous } = attestor;
30
+ // The legacy all-at-once form answers the WHOLE checklist on one repository's
31
+ // word and writes a schema-1 record — no attestations, no commits. Run over a
32
+ // federated record it does not merge and it does not migrate: it erases every
33
+ // other service's commit-bound attestation, and the erasure is invisible
34
+ // afterwards because what replaces it is a well-formed, plausible record. So
35
+ // it refuses, and names the repositories whose word is on the file.
36
+ const attested = previous?.verification.schema === 2 ? (previous.verification.attestations ?? []) : [];
37
+ if (service === undefined && attested.length > 0) {
38
+ const services = [...new Set(attested.map((a) => a.service))].sort();
39
+ return fail(json, "record-federated", `${repoPath(docsDir, verificationPath(featureDir))} is a federated record: ${plural(services.length, "service")} (${services.join(", ")}) have attested claims against their own git commits. ` +
40
+ "Recording without --service would replace all of it with one unattested answer set. " +
41
+ `Record this service's claims from its own repo instead: \`loam verify ${checklist.feature} --record answers.json --service <svc>\`.`);
42
+ }
43
+ const scopedClaims = service === undefined ? checklist.claims : checklist.claims.filter((claim) => claim.subject === service);
44
+ if (service !== undefined && scopedClaims.length === 0) {
45
+ return fail(json, "unknown-service", `The current ${checklist.feature} checklist has no claims owned by service '${service}'.`);
46
+ }
47
+ // The mechanical halves: with --results, every scenario.tested claim is the
48
+ // cucumber report's to answer — matched by digest, confirmed only by a green
49
+ // run — and with --contract-results, every api.exposes claim is the contract
50
+ // report's, matched by operationId under the same ownership discipline. A
51
+ // partial suite leaves its unexercised claims unconfirmed rather than
52
+ // agent-attestable in the same run: silence must not read as checked, and
53
+ // the escape is a --record run without the flag.
54
+ const runnerClaims = opts.results === undefined ? [] : scopedClaims.filter((c) => c.kind === "scenario.tested");
55
+ const contractClaims = opts.contractResults === undefined ? [] : scopedClaims.filter((c) => c.kind === "api.exposes");
56
+ const agentClaims = scopedClaims.filter((c) => (opts.results === undefined || c.kind !== "scenario.tested") &&
57
+ (opts.contractResults === undefined || c.kind !== "api.exposes"));
58
+ let fromRunner = [];
59
+ let fromContract = [];
60
+ const reports = {};
61
+ if (opts.results !== undefined) {
62
+ // A federated record attests for THIS repository, so its report has to be a
63
+ // file inside it — see evidence/read.ts.
64
+ const read = await readResults(opts.results, service === undefined ? undefined : repoDir);
65
+ if (!read.ok)
66
+ return fail(json, read.code, read.message);
67
+ reports.results = read.report;
68
+ fromRunner = runnerAnswers(runnerClaims, read.scenarios, read.report.path);
69
+ }
70
+ if (opts.contractResults !== undefined) {
71
+ // Same resolution rules as the cucumber report, same refusal code: the two
72
+ // pins make the same promise about the same repository.
73
+ const read = await readContractResults(opts.contractResults, service === undefined ? undefined : repoDir);
74
+ if (!read.ok)
75
+ return fail(json, read.code, read.message);
76
+ reports.contract = read.report;
77
+ fromContract = contractAnswers(contractClaims, read.runs, read.report.path);
78
+ }
79
+ // The agent's half — exactly what no report owns. A mechanical flag alone is
80
+ // legal only when the reports own the whole checklist: anything left over
81
+ // refuses with the ids, the same discipline as a claim with no answer.
82
+ let raw = [];
83
+ if (opts.record !== undefined) {
84
+ try {
85
+ // The one path that stays cwd-relative, and deliberately: the answer set
86
+ // is a file the caller just wrote and hands to the command, not part of
87
+ // the repository being attested. Nothing on the record points at it.
88
+ raw = JSON.parse(await readFile(resolve(process.cwd(), opts.record), "utf8"));
89
+ }
90
+ catch (err) {
91
+ return fail(json, "answers-unreadable", `Cannot read ${opts.record}: ${err instanceof Error ? err.message : String(err)}`);
92
+ }
93
+ }
94
+ else if (agentClaims.length > 0 && (opts.results !== undefined || opts.contractResults !== undefined)) {
95
+ const owns = [
96
+ ...(opts.results === undefined ? [] : ["--results answers only the scenario.tested claims"]),
97
+ ...(opts.contractResults === undefined ? [] : ["--contract-results answers only the api.exposes claims"]),
98
+ ].join(" and ");
99
+ return fail(json, "answers-mismatch", `${owns}; ${agentClaims.length} claim(s) have no answer: ` +
100
+ `${agentClaims.map((c) => c.id).join(", ")}. Record them with --record <answers.json> alongside.`);
101
+ }
102
+ const checked = checkAnswers(agentClaims, raw, opts.results === undefined && opts.contractResults === undefined
103
+ ? undefined
104
+ : new Set([...runnerClaims, ...contractClaims].map((c) => c.id)), { feature: checklist.feature, ...(service === undefined ? {} : { service }) });
105
+ if (!checked.ok)
106
+ return fail(json, checked.code, checked.message);
107
+ let serviceCommit;
108
+ let answers = [...fromRunner, ...fromContract, ...checked.answers];
109
+ let pinNotice = null;
110
+ if (service !== undefined) {
111
+ const commit = await repositoryCommit(repoDir);
112
+ if (!commit.ok)
113
+ return fail(json, "repository-unavailable", commit.message);
114
+ serviceCommit = commit.commit;
115
+ // All halves, one validator. The runner's evidence used to skip it
116
+ // entirely: `--results` minted confirmations whose evidence strings nothing
117
+ // ever checked, in the one mode that promises every answer is bound to this
118
+ // repository at this commit. The same pass stamps each agent citation's
119
+ // evidence pin and scans its blob for the claim's token (evidence/pins.ts).
120
+ const evidence = await validateServiceEvidence(answers, { repoDir, commit: serviceCommit }, reports, claimTokens(scopedClaims));
121
+ if (!evidence.ok)
122
+ return fail(json, "answers-unevidenced", evidence.message);
123
+ ({ answers, notice: pinNotice } = pinAnswers(answers, evidence, serviceCommit));
124
+ }
125
+ const recorded = today(new Date());
126
+ let verification;
127
+ let discarded = [];
128
+ if (service === undefined) {
129
+ verification = buildVerification(checklist, answers, recorded, reports);
130
+ }
131
+ else {
132
+ // The docs side of the pin, and it is ASKED FOR rather than required: a
133
+ // docs repo is not obliged to be a git checkout, and the attestation simply
134
+ // carries no `docsCommit` when git cannot answer. Failing the record over
135
+ // it would refuse a working fleet for a field that is optional by design.
136
+ const docsHead = await repositoryCommit(docsDir);
137
+ const built = buildFederatedVerification(checklist, {
138
+ service,
139
+ recorded,
140
+ commit: serviceCommit,
141
+ reports,
142
+ ...(docsHead.ok ? { docsCommit: docsHead.commit } : {}),
143
+ }, answers, previous?.verification ?? null);
144
+ verification = built.verification;
145
+ discarded = built.discarded;
146
+ }
147
+ // Staged, compared against the locked read's bytes, swapped in by one
148
+ // rename — see core/verify/store/commit.ts for what each refusal means.
149
+ const committed = await commitVerification(featureDir, verification, previous?.raw ?? null, docsDir);
150
+ if (!committed.ok)
151
+ return fail(json, committed.code, committed.message);
152
+ const path = committed.path;
153
+ const unconfirmed = verification.claims.filter((c) => c.verdict === "unconfirmed");
154
+ // The same judgment read mode makes (see report): the record just written IS
155
+ // the current checklist's answer, so `stale` is false by construction and the
156
+ // remaining question is whether every claim was confirmed — and, now, by
157
+ // whom. Counted from the claims, not from the summary this same call wrote.
158
+ // Without these fields an agent that recorded all-confirmed answers would
159
+ // have to re-run verify just to learn the state it created.
160
+ const tally = tallyRecord(verification);
161
+ const verdict = verificationVerdict(tally);
162
+ const verified = verdict === "verified";
163
+ const notices = [
164
+ ...noticesFor(verification.claims, verification.feature),
165
+ ...contestedNotices(runnerClaims),
166
+ ...contestedOperationNotices(contractClaims),
167
+ ...(pinNotice === null ? [] : [pinNotice]),
168
+ ];
169
+ if (json) {
170
+ emitJson({
171
+ command: "verify",
172
+ feature: verification.feature,
173
+ path: repoPath(docsDir, path),
174
+ ...(target.recovered == null ? {} : { recovered: target.recovered }),
175
+ digest: verification.checklist,
176
+ verified,
177
+ verdict,
178
+ attested: tally.attested,
179
+ recorded: verification.recorded,
180
+ summary: verification.summary,
181
+ ...(verification.attestations === undefined ? {} : { attestations: verification.attestations }),
182
+ ...(reports.results === undefined ? {} : { report: reports.results }),
183
+ ...(reports.contract === undefined ? {} : { contractReport: reports.contract }),
184
+ unconfirmed: unconfirmed.map((c) => ({ id: c.id, claim: c.claim, ...(c.note === undefined ? {} : { note: c.note }) })),
185
+ ...(discarded.length === 0 ? {} : { discarded }),
186
+ ...(notices.length === 0 ? {} : { notices }),
187
+ });
188
+ return;
189
+ }
190
+ if (target.recovered != null)
191
+ console.log(`${sayRecovered(target.recovered)}\n`);
192
+ console.log(`${verification.feature} verification recorded — ${repoPath(docsDir, path)}\n`);
193
+ console.log(` ${tally.confirmed} of ${plural(tally.claims, "claim")} confirmed with evidence.`);
194
+ if (reports.results !== undefined) {
195
+ console.log(` ${plural(fromRunner.length, "scenario claim")} answered by the test runner (${opts.results}).`);
196
+ console.log(` Report read: ${reportLine(reports.results)}.`);
197
+ }
198
+ if (reports.contract !== undefined) {
199
+ console.log(` ${plural(fromContract.length, "api.exposes claim")} answered by the contract test run (${opts.contractResults}).`);
200
+ console.log(` Contract report read: ${contractReportLine(reports.contract)}.`);
201
+ }
202
+ if (opts.record !== undefined && (reports.results !== undefined || reports.contract !== undefined)) {
203
+ console.log(` ${plural(checked.answers.length, "claim")} answered by ${opts.record}.`);
204
+ }
205
+ if (service !== undefined) {
206
+ const attestation = verification.attestations?.find((item) => item.service === service);
207
+ if (attestation !== undefined) {
208
+ console.log(` ${service} attested at git commit ${attestation.commit}.`);
209
+ }
210
+ }
211
+ for (const c of unconfirmed) {
212
+ console.log(` ✗ ${c.claim}${c.note === undefined ? "" : ` — ${c.note}`}`);
213
+ }
214
+ sayDiscarded(discarded, repoPath(docsDir, verificationPath(featureDir)), verification.feature);
215
+ console.log("");
216
+ for (const notice of notices)
217
+ console.log(` ⚠ ${notice.code}: ${notice.message}`);
218
+ console.log(tally.unanswered > 0
219
+ ? ` Partial federation — ${plural(tally.unanswered, "claim")} remain unanswered for their owning service repositories.`
220
+ : verdict === "attested"
221
+ ? " Recorded as attested, not verified: the record travels into features/archive/ saying so."
222
+ : unconfirmed.length === 0
223
+ ? " The record travels with the feature into features/archive/."
224
+ : " Recorded as it stands. Nothing gates on this — it is what a reviewer reads later, so leave it true.");
225
+ }
226
+ //# sourceMappingURL=record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../../src/commands/verify/record.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Writing the answers down.\n *\n * The one command in loam that takes somebody's word for something, so every\n * refusal here is about whose word is on the file. The legacy all-at-once form\n * run over a federated record does not merge and does not migrate — it would\n * erase every other service's commit-bound attestation, invisibly, because what\n * replaces it is a well-formed and plausible record.\n */\nimport { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { emitJson, fail, repoPath } from \"../../core/envelope/json.js\";\nimport { today } from \"../../core/provenance/stamp.js\";\nimport { runnerAnswers } from \"../../core/results.js\";\nimport { checkAnswers, type Answer } from \"../../core/verify/answers.js\";\nimport {\n buildFederatedVerification,\n buildVerification,\n type DiscardedAnswer,\n} from \"../../core/verify/build.js\";\nimport { type Checklist } from \"../../core/verify/checklist.js\";\nimport { contractAnswers } from \"../../core/verify/evidence/contract.js\";\nimport { commitVerification } from \"../../core/verify/store/commit.js\";\nimport {\n tallyRecord,\n type ConsumedReports,\n type Verification,\n type VerifyNotice,\n verificationPath,\n verificationVerdict,\n} from \"../../core/verify/record.js\";\nimport { plural, sayDiscarded, sayRecovered } from \"../policy/format.js\";\nimport { readContractResults } from \"./evidence/contract.js\";\nimport { claimTokens, pinAnswers } from \"./evidence/pins.js\";\nimport { readResults, repositoryCommit, validateServiceEvidence } from \"./results.js\";\nimport { contestedNotices, contestedOperationNotices, contractReportLine, noticesFor, reportLine } from \"./frozen.js\";\nimport { type VerifyTarget } from \"./report.js\";\n\n/** The flags `loam verify --record` reads. */\nexport interface VerifyOptions {\n record?: string;\n results?: string;\n contractResults?: string;\n /** `--diff-answers a.json b.json` — the read-only cross-examination lens\n * (./cross/diff.ts): both files validate against the current checklist and\n * nothing is written. verify.ts refuses recording combinations and arity ≠ 2. */\n diffAnswers?: string[];\n service?: string;\n json?: boolean;\n}\n\n/**\n * The repository whose word this record is taking, for which service, and over\n * which existing record.\n *\n * `previous` belongs here rather than beside it: every refusal in this function\n * is about whether THIS attestor may write over what that record already says,\n * so the two are never asked about separately.\n */\nexport interface Attestor {\n /** Undefined in the legacy all-at-once form, which answers for every service. */\n service: string | undefined;\n repoDir: string;\n /**\n * The existing record as ONE read — the parse the merge consumes and the\n * exact bytes it was parsed from — or null when there was no record. One\n * field rather than a `Verification` beside a `Buffer` because the two are\n * meaningless apart: a pre-image from any other read would let the commit\n * vouch for a document the merge never saw, and as separate fields that\n * inconsistent pair is representable and compiles.\n */\n previous: { verification: Verification; raw: Buffer } | null;\n}\n\nexport async function record(\n target: VerifyTarget,\n checklist: Checklist,\n attestor: Attestor,\n opts: VerifyOptions,\n): Promise<void> {\n const { docsDir, featureDir, json } = target;\n const { service, repoDir, previous } = attestor;\n // The legacy all-at-once form answers the WHOLE checklist on one repository's\n // word and writes a schema-1 record — no attestations, no commits. Run over a\n // federated record it does not merge and it does not migrate: it erases every\n // other service's commit-bound attestation, and the erasure is invisible\n // afterwards because what replaces it is a well-formed, plausible record. So\n // it refuses, and names the repositories whose word is on the file.\n const attested = previous?.verification.schema === 2 ? (previous.verification.attestations ?? []) : [];\n if (service === undefined && attested.length > 0) {\n const services = [...new Set(attested.map((a) => a.service))].sort();\n return fail(\n json,\n \"record-federated\",\n `${repoPath(docsDir, verificationPath(featureDir))} is a federated record: ${plural(services.length, \"service\")} (${services.join(\", \")}) have attested claims against their own git commits. ` +\n \"Recording without --service would replace all of it with one unattested answer set. \" +\n `Record this service's claims from its own repo instead: \\`loam verify ${checklist.feature} --record answers.json --service <svc>\\`.`,\n );\n }\n\n const scopedClaims =\n service === undefined ? checklist.claims : checklist.claims.filter((claim) => claim.subject === service);\n if (service !== undefined && scopedClaims.length === 0) {\n return fail(\n json,\n \"unknown-service\",\n `The current ${checklist.feature} checklist has no claims owned by service '${service}'.`,\n );\n }\n\n // The mechanical halves: with --results, every scenario.tested claim is the\n // cucumber report's to answer — matched by digest, confirmed only by a green\n // run — and with --contract-results, every api.exposes claim is the contract\n // report's, matched by operationId under the same ownership discipline. A\n // partial suite leaves its unexercised claims unconfirmed rather than\n // agent-attestable in the same run: silence must not read as checked, and\n // the escape is a --record run without the flag.\n const runnerClaims =\n opts.results === undefined ? [] : scopedClaims.filter((c) => c.kind === \"scenario.tested\");\n const contractClaims =\n opts.contractResults === undefined ? [] : scopedClaims.filter((c) => c.kind === \"api.exposes\");\n const agentClaims = scopedClaims.filter(\n (c) =>\n (opts.results === undefined || c.kind !== \"scenario.tested\") &&\n (opts.contractResults === undefined || c.kind !== \"api.exposes\"),\n );\n\n let fromRunner: Answer[] = [];\n let fromContract: Answer[] = [];\n const reports: ConsumedReports = {};\n if (opts.results !== undefined) {\n // A federated record attests for THIS repository, so its report has to be a\n // file inside it — see evidence/read.ts.\n const read = await readResults(opts.results, service === undefined ? undefined : repoDir);\n if (!read.ok) return fail(json, read.code, read.message);\n reports.results = read.report;\n fromRunner = runnerAnswers(runnerClaims, read.scenarios, read.report.path);\n }\n if (opts.contractResults !== undefined) {\n // Same resolution rules as the cucumber report, same refusal code: the two\n // pins make the same promise about the same repository.\n const read = await readContractResults(opts.contractResults, service === undefined ? undefined : repoDir);\n if (!read.ok) return fail(json, read.code, read.message);\n reports.contract = read.report;\n fromContract = contractAnswers(contractClaims, read.runs, read.report.path);\n }\n\n // The agent's half — exactly what no report owns. A mechanical flag alone is\n // legal only when the reports own the whole checklist: anything left over\n // refuses with the ids, the same discipline as a claim with no answer.\n let raw: unknown = [];\n if (opts.record !== undefined) {\n try {\n // The one path that stays cwd-relative, and deliberately: the answer set\n // is a file the caller just wrote and hands to the command, not part of\n // the repository being attested. Nothing on the record points at it.\n raw = JSON.parse(await readFile(resolve(process.cwd(), opts.record), \"utf8\"));\n } catch (err) {\n return fail(\n json,\n \"answers-unreadable\",\n `Cannot read ${opts.record}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n } else if (agentClaims.length > 0 && (opts.results !== undefined || opts.contractResults !== undefined)) {\n const owns = [\n ...(opts.results === undefined ? [] : [\"--results answers only the scenario.tested claims\"]),\n ...(opts.contractResults === undefined ? [] : [\"--contract-results answers only the api.exposes claims\"]),\n ].join(\" and \");\n return fail(\n json,\n \"answers-mismatch\",\n `${owns}; ${agentClaims.length} claim(s) have no answer: ` +\n `${agentClaims.map((c) => c.id).join(\", \")}. Record them with --record <answers.json> alongside.`,\n );\n }\n\n const checked = checkAnswers(\n agentClaims,\n raw,\n opts.results === undefined && opts.contractResults === undefined\n ? undefined\n : new Set([...runnerClaims, ...contractClaims].map((c) => c.id)),\n { feature: checklist.feature, ...(service === undefined ? {} : { service }) },\n );\n if (!checked.ok) return fail(json, checked.code, checked.message);\n\n let serviceCommit: string | undefined;\n let answers = [...fromRunner, ...fromContract, ...checked.answers];\n let pinNotice: VerifyNotice | null = null;\n if (service !== undefined) {\n const commit = await repositoryCommit(repoDir);\n if (!commit.ok) return fail(json, \"repository-unavailable\", commit.message);\n serviceCommit = commit.commit;\n // All halves, one validator. The runner's evidence used to skip it\n // entirely: `--results` minted confirmations whose evidence strings nothing\n // ever checked, in the one mode that promises every answer is bound to this\n // repository at this commit. The same pass stamps each agent citation's\n // evidence pin and scans its blob for the claim's token (evidence/pins.ts).\n const evidence = await validateServiceEvidence(answers, { repoDir, commit: serviceCommit }, reports, claimTokens(scopedClaims));\n if (!evidence.ok) return fail(json, \"answers-unevidenced\", evidence.message);\n ({ answers, notice: pinNotice } = pinAnswers(answers, evidence, serviceCommit));\n }\n\n const recorded = today(new Date());\n let verification: Verification;\n let discarded: DiscardedAnswer[] = [];\n if (service === undefined) {\n verification = buildVerification(checklist, answers, recorded, reports);\n } else {\n // The docs side of the pin, and it is ASKED FOR rather than required: a\n // docs repo is not obliged to be a git checkout, and the attestation simply\n // carries no `docsCommit` when git cannot answer. Failing the record over\n // it would refuse a working fleet for a field that is optional by design.\n const docsHead = await repositoryCommit(docsDir);\n const built = buildFederatedVerification(\n checklist,\n {\n service,\n recorded,\n commit: serviceCommit!,\n reports,\n ...(docsHead.ok ? { docsCommit: docsHead.commit } : {}),\n },\n answers,\n previous?.verification ?? null,\n );\n verification = built.verification;\n discarded = built.discarded;\n }\n // Staged, compared against the locked read's bytes, swapped in by one\n // rename — see core/verify/store/commit.ts for what each refusal means.\n const committed = await commitVerification(featureDir, verification, previous?.raw ?? null, docsDir);\n if (!committed.ok) return fail(json, committed.code, committed.message);\n const path = committed.path;\n const unconfirmed = verification.claims.filter((c) => c.verdict === \"unconfirmed\");\n\n // The same judgment read mode makes (see report): the record just written IS\n // the current checklist's answer, so `stale` is false by construction and the\n // remaining question is whether every claim was confirmed — and, now, by\n // whom. Counted from the claims, not from the summary this same call wrote.\n // Without these fields an agent that recorded all-confirmed answers would\n // have to re-run verify just to learn the state it created.\n const tally = tallyRecord(verification);\n const verdict = verificationVerdict(tally);\n const verified = verdict === \"verified\";\n const notices = [\n ...noticesFor(verification.claims, verification.feature),\n ...contestedNotices(runnerClaims),\n ...contestedOperationNotices(contractClaims),\n ...(pinNotice === null ? [] : [pinNotice]),\n ];\n\n if (json) {\n emitJson({\n command: \"verify\",\n feature: verification.feature,\n path: repoPath(docsDir, path),\n ...(target.recovered == null ? {} : { recovered: target.recovered }),\n digest: verification.checklist,\n verified,\n verdict,\n attested: tally.attested,\n recorded: verification.recorded,\n summary: verification.summary,\n ...(verification.attestations === undefined ? {} : { attestations: verification.attestations }),\n ...(reports.results === undefined ? {} : { report: reports.results }),\n ...(reports.contract === undefined ? {} : { contractReport: reports.contract }),\n unconfirmed: unconfirmed.map((c) => ({ id: c.id, claim: c.claim, ...(c.note === undefined ? {} : { note: c.note }) })),\n ...(discarded.length === 0 ? {} : { discarded }),\n ...(notices.length === 0 ? {} : { notices }),\n });\n return;\n }\n\n if (target.recovered != null) console.log(`${sayRecovered(target.recovered)}\\n`);\n console.log(`${verification.feature} verification recorded — ${repoPath(docsDir, path)}\\n`);\n console.log(` ${tally.confirmed} of ${plural(tally.claims, \"claim\")} confirmed with evidence.`);\n if (reports.results !== undefined) {\n console.log(` ${plural(fromRunner.length, \"scenario claim\")} answered by the test runner (${opts.results}).`);\n console.log(` Report read: ${reportLine(reports.results)}.`);\n }\n if (reports.contract !== undefined) {\n console.log(` ${plural(fromContract.length, \"api.exposes claim\")} answered by the contract test run (${opts.contractResults}).`);\n console.log(` Contract report read: ${contractReportLine(reports.contract)}.`);\n }\n if (opts.record !== undefined && (reports.results !== undefined || reports.contract !== undefined)) {\n console.log(` ${plural(checked.answers.length, \"claim\")} answered by ${opts.record}.`);\n }\n if (service !== undefined) {\n const attestation = verification.attestations?.find((item) => item.service === service);\n if (attestation !== undefined) {\n console.log(` ${service} attested at git commit ${attestation.commit}.`);\n }\n }\n for (const c of unconfirmed) {\n console.log(` ✗ ${c.claim}${c.note === undefined ? \"\" : ` — ${c.note}`}`);\n }\n\n sayDiscarded(discarded, repoPath(docsDir, verificationPath(featureDir)), verification.feature);\n console.log(\"\");\n for (const notice of notices) console.log(` ⚠ ${notice.code}: ${notice.message}`);\n console.log(\n tally.unanswered > 0\n ? ` Partial federation — ${plural(tally.unanswered, \"claim\")} remain unanswered for their owning service repositories.`\n : verdict === \"attested\"\n ? \" Recorded as attested, not verified: the record travels into features/archive/ saying so.\"\n : unconfirmed.length === 0\n ? \" The record travels with the feature into features/archive/.\"\n : \" Recorded as it stands. Nothing gates on this — it is what a reviewer reads later, so leave it true.\",\n );\n}\n"]}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * The done-check as an answer: every claim, its verdict, and who said so.
3
+ *
4
+ * The per-claim rows are computed once and both surfaces read them — `--json`
5
+ * and the terminal cannot disagree about a count, which is the failure this
6
+ * shape prevents. The federation note is here rather than at the call sites
7
+ * because a federated record answers per SERVICE and a reader looking at one
8
+ * lens has to be told which of the others have not answered yet.
9
+ */
10
+ import { emitJson, repoPath } from "../../core/envelope/json.js";
11
+ import {} from "../../core/staging/interrupted.js";
12
+ import {} from "../../core/verify/answers.js";
13
+ import {} from "../../core/verify/checklist.js";
14
+ import {} from "../../core/verify/pins/pin.js";
15
+ import { openClaimsNotice, tallyAnswers, verificationPath, verificationVerdict, } from "../../core/verify/record.js";
16
+ import { EXPLAIN_FOOTER, plural } from "../policy/format.js";
17
+ import { answeredMark, contestedNotices, contractReportLine, forkedChecklistNotices, MARK, noticesFor, reportLine } from "./frozen.js";
18
+ export function statuses(checklist, claims, recorded) {
19
+ const subjects = new Map(checklist.claims.map((claim) => [claim.id, claim.subject]));
20
+ const attested = recorded?.schema !== 2
21
+ ? null
22
+ : new Set((recorded.attestations ?? []).flatMap((attestation) => attestation.claims.filter((id) => subjects.get(id) === attestation.service)));
23
+ const byId = new Map((recorded?.claims ?? [])
24
+ .filter((claim) => attested === null || attested.has(claim.id))
25
+ .map((claim) => [claim.id, claim]));
26
+ return claims.map((c) => {
27
+ const answer = byId.get(c.id);
28
+ return {
29
+ id: c.id,
30
+ kind: c.kind,
31
+ subject: c.subject,
32
+ claim: c.claim,
33
+ verdict: answer?.verdict ?? "unanswered",
34
+ ...(answer?.answered_by === undefined ? {} : { answered_by: answer.answered_by }),
35
+ evidence: answer?.evidence ?? [],
36
+ ...(answer?.note === undefined ? {} : { note: answer.note }),
37
+ ...(answer?.evidence_pins === undefined ? {} : { evidence_pins: answer.evidence_pins }),
38
+ };
39
+ });
40
+ }
41
+ export function report(target, checklist, recorded, scope = {}) {
42
+ const { docsDir, featureDir, json } = target;
43
+ const lens = scope.lens;
44
+ const owners = [...new Set(checklist.claims.map((c) => c.subject))].sort();
45
+ const scoped = lens === undefined ? checklist.claims : checklist.claims.filter((c) => c.subject === lens);
46
+ const claims = statuses(checklist, scoped, recorded);
47
+ const count = (v) => claims.filter((c) => c.verdict === v).length;
48
+ const summary = {
49
+ claims: claims.length,
50
+ confirmed: count("confirmed"),
51
+ unconfirmed: count("unconfirmed"),
52
+ unanswered: count("unanswered"),
53
+ };
54
+ // A record that answers a different question set is not an answer to this one,
55
+ // however complete it looks — so staleness disqualifies it as a whole.
56
+ const stale = recorded !== null && recorded.checklist !== checklist.digest;
57
+ const tally = tallyAnswers(claims);
58
+ const verdict = verificationVerdict(tally, stale);
59
+ // `verified` keeps its name and its type, and loses its old meaning: a
60
+ // scenario claim on an agent's word is answered, not run, so it no longer
61
+ // reads the same as a green suite. `verdict` carries the distinction.
62
+ const verified = verdict === "verified";
63
+ // Contest is derivable from the checklist alone, so the read view says it
64
+ // too: an agent looking at what it owes should learn that a second service
65
+ // answers the same claim BEFORE it runs a suite whose report cannot be
66
+ // attributed. Always from the whole checklist, never the lens — a shared
67
+ // digest is a fact about the feature, and a narrowed view is the one place it
68
+ // would otherwise be invisible.
69
+ // The open-claims honesty line only where a record EXISTS: with none, the
70
+ // surface already says "Not verified", and not-started is not partial.
71
+ const open = recorded === null ? null : openClaimsNotice(tally, checklist.feature);
72
+ const notices = [
73
+ ...noticesFor(claims, checklist.feature),
74
+ ...(open === null ? [] : [open]),
75
+ ...contestedNotices(checklist.claims),
76
+ ...forkedChecklistNotices(recorded, checklist.digest),
77
+ ];
78
+ if (json) {
79
+ emitJson({
80
+ command: "verify",
81
+ feature: checklist.feature,
82
+ path: repoPath(docsDir, featureDir),
83
+ digest: checklist.digest,
84
+ // Named only when narrowed, so a consumer can never mistake a service's
85
+ // verdict for the feature's.
86
+ ...(lens === undefined ? {} : { service: lens, checklistClaims: checklist.claims.length }),
87
+ verified,
88
+ verdict,
89
+ attested: tally.attested,
90
+ summary,
91
+ services: owners,
92
+ recorded: recorded === null
93
+ ? null
94
+ : {
95
+ path: repoPath(docsDir, verificationPath(featureDir)),
96
+ recorded: recorded.recorded,
97
+ checklist: recorded.checklist,
98
+ stale,
99
+ ...(recorded.attestations === undefined ? {} : { attestations: recorded.attestations }),
100
+ ...(recorded.report === undefined ? {} : { report: recorded.report }),
101
+ ...(recorded.contractReport === undefined ? {} : { contractReport: recorded.contractReport }),
102
+ },
103
+ claims,
104
+ ...(notices.length === 0 ? {} : { notices }),
105
+ });
106
+ return;
107
+ }
108
+ const scopeNote = lens === undefined ? "" : ` owned by ${lens} (of ${plural(checklist.claims.length, "claim")} on the checklist)`;
109
+ console.log(`${checklist.feature} — ${plural(claims.length, "claim")}${scopeNote} derived from ${repoPath(docsDir, featureDir)}\n`);
110
+ if (claims.length === 0) {
111
+ console.log(lens === undefined
112
+ ? " Nothing to check: this feature's delta, specs and openapi promise nothing yet."
113
+ : ` No claim on this checklist is owned by '${lens}'.${owners.length > 0 ? ` The services that own claims here are ${owners.join(", ")}.` : ""}`);
114
+ return;
115
+ }
116
+ for (const c of claims) {
117
+ console.log(` ${MARK[c.verdict]} ${c.id} [${c.subject}] ${c.claim}${answeredMark(c)}`);
118
+ for (const e of c.evidence)
119
+ console.log(` ${e}`);
120
+ if (c.note !== undefined)
121
+ console.log(` note: ${c.note}`);
122
+ }
123
+ console.log("");
124
+ if (recorded === null) {
125
+ console.log(` Not verified — no ${repoPath(docsDir, verificationPath(featureDir))}.`);
126
+ }
127
+ else {
128
+ console.log(` Recorded ${recorded.recorded} — ${summary.confirmed} confirmed, ${summary.unconfirmed} unconfirmed, ${summary.unanswered} unanswered.`);
129
+ if (stale) {
130
+ console.log(" STALE: the feature changed after this was recorded. Answer the claims above again.");
131
+ }
132
+ for (const attestation of recorded.attestations ?? []) {
133
+ console.log(` Attested by ${attestation.service} at ${attestation.commit.slice(0, 12)} (${attestation.recorded}, ${plural(attestation.claims.length, "claim")}).`);
134
+ if (attestation.report !== undefined)
135
+ console.log(` from ${reportLine(attestation.report)}`);
136
+ if (attestation.contractReport !== undefined) {
137
+ console.log(` from ${contractReportLine(attestation.contractReport)}`);
138
+ }
139
+ }
140
+ if (recorded.report !== undefined)
141
+ console.log(` Answered from ${reportLine(recorded.report)}.`);
142
+ if (recorded.contractReport !== undefined) {
143
+ console.log(` Contract report read: ${contractReportLine(recorded.contractReport)}.`);
144
+ }
145
+ }
146
+ // The notice's code LEADS the line here, where validate's findings now carry
147
+ // theirs in a trailing `(code)` — and the two shapes are deliberate, not
148
+ // drift. A notice is one line and its code is its subject, so it reads as a
149
+ // label; a finding is one of hundreds in a report whose subject is the
150
+ // message, so its code is an aside. Appending a second copy to satisfy the
151
+ // one-shape instinct would print `⚠ verify.claims-open: … (verify.claims-open)`,
152
+ // and the leading form is also the one the frozen post-archive view prints
153
+ // (frozen.ts) — a live record and a shipped one must not describe the same
154
+ // notice two ways. Either way the code is on screen, which is the whole of
155
+ // what EXPLAIN_FOOTER below needs to be true.
156
+ for (const notice of notices)
157
+ console.log(` ⚠ ${notice.code}: ${notice.message}`);
158
+ // An attested record has answered every question — telling it to "answer each
159
+ // claim" would send an agent round a loop it has already run. The notice
160
+ // above names the one thing left, which is a test run.
161
+ if (verdict === "unverified") {
162
+ console.log("\n Answer each claim, then record the answers:\n");
163
+ console.log(' [{ "id": "<claim id>", "verdict": "confirmed", "evidence": ["src/x.ts:42"] }]');
164
+ console.log(`\n loam verify ${checklist.feature} --record answers.json${recordSuffix(scope, owners)}`);
165
+ for (const line of federationNote(scope, owners))
166
+ console.log(line);
167
+ console.log("\n A claim you cannot show evidence for is `unconfirmed` — say why in `note`.");
168
+ }
169
+ // APPENDED, as format.ts promises — the report's last line, never a wedge
170
+ // between the notices and the recording instructions that follow them. It
171
+ // follows printed notice codes only: claim marks carry no code to look up,
172
+ // and the frozen post-archive view (frozen.ts) stays without it on purpose,
173
+ // because shipped history is not a fix-it surface.
174
+ if (notices.length > 0)
175
+ console.log(`\n${EXPLAIN_FOOTER}`);
176
+ }
177
+ /**
178
+ * The `--service` the printed form should carry. It comes from loam.json, never
179
+ * from the checklist: the only attestation this repository can make is its own,
180
+ * and a hint naming a service that lives somewhere else is a hint that fails.
181
+ */
182
+ export function recordSuffix(scope, owners) {
183
+ if (scope.bound !== undefined)
184
+ return ` --service ${scope.bound}`;
185
+ return owners.length > 1 || scope.lens !== undefined ? " --service <svc>" : "";
186
+ }
187
+ /** Why the form above has a `--service` on it — the one place federation is taught. */
188
+ export function federationNote(scope, owners) {
189
+ if (scope.bound !== undefined) {
190
+ const others = owners.filter((s) => s !== scope.bound);
191
+ return [
192
+ "",
193
+ ` This repository is ${scope.bound}, so it attests only ${scope.bound}'s claims, bound to its git HEAD.`,
194
+ ...(others.length === 0
195
+ ? []
196
+ : [` The claims owned by ${others.join(", ")} are recorded the same way from those repositories.`]),
197
+ ];
198
+ }
199
+ if (owners.length > 1 || scope.lens !== undefined) {
200
+ return [
201
+ "",
202
+ ` This checklist spans ${plural(owners.length, "service")} (${owners.join(", ")}) — each attests its own claims`,
203
+ " from its own repository, where loam.json names that service.",
204
+ ];
205
+ }
206
+ return [];
207
+ }
208
+ /**
209
+ * The frozen view: an archived feature's record, verbatim. No checklist is
210
+ * derived and no staleness is judged — there is nothing current to judge
211
+ * against, and pretending otherwise is how a true record reads as a lie.
212
+ * `frozen` is the marker a consumer branches on.
213
+ *
214
+ * The verdict is recounted from `claims[]`, never taken from `summary`: this is
215
+ * the post-ship verdict on a feature nobody can re-derive a checklist for, so a
216
+ * record whose counts had drifted from its own answers reported a shipped
217
+ * feature as fully confirmed. (A record that contradicts itself never reaches
218
+ * here — `readVerificationState` refuses it — so the recount and the summary
219
+ * agree; the recount is what says WHY.) No record at all is reported as exactly
220
+ * that, with `summary: null`, not zero claims, which would falsely say the
221
+ * feature promised nothing.
222
+ */
223
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/commands/verify/report.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The done-check as an answer: every claim, its verdict, and who said so.\n *\n * The per-claim rows are computed once and both surfaces read them — `--json`\n * and the terminal cannot disagree about a count, which is the failure this\n * shape prevents. The federation note is here rather than at the call sites\n * because a federated record answers per SERVICE and a reader looking at one\n * lens has to be told which of the others have not answered yet.\n */\nimport { emitJson, repoPath } from \"../../core/envelope/json.js\";\nimport { type CommitRecovery } from \"../../core/staging/interrupted.js\";\nimport { type AnsweredBy } from \"../../core/verify/answers.js\";\nimport { type Checklist } from \"../../core/verify/checklist.js\";\nimport { type EvidencePin } from \"../../core/verify/pins/pin.js\";\nimport {\n openClaimsNotice,\n tallyAnswers,\n type Verification,\n verificationPath,\n verificationVerdict,\n} from \"../../core/verify/record.js\";\nimport { EXPLAIN_FOOTER, plural } from \"../policy/format.js\";\nimport { answeredMark, contestedNotices, contractReportLine, forkedChecklistNotices, MARK, noticesFor, reportLine } from \"./frozen.js\";\n\nexport interface ClaimStatus {\n id: string;\n kind: string;\n subject: string;\n claim: string;\n verdict: \"confirmed\" | \"unconfirmed\" | \"unanswered\";\n answered_by?: AnsweredBy;\n evidence: string[];\n note?: string;\n /** The recorded pins, passed through where the record carries them — additive payload key. */\n evidence_pins?: EvidencePin[];\n}\n\nexport function statuses(checklist: Checklist, claims: Checklist[\"claims\"], recorded: Verification | null): ClaimStatus[] {\n const subjects = new Map(checklist.claims.map((claim) => [claim.id, claim.subject]));\n const attested =\n recorded?.schema !== 2\n ? null\n : new Set(\n (recorded.attestations ?? []).flatMap((attestation) =>\n attestation.claims.filter((id) => subjects.get(id) === attestation.service),\n ),\n );\n const byId = new Map(\n (recorded?.claims ?? [])\n .filter((claim) => attested === null || attested.has(claim.id))\n .map((claim) => [claim.id, claim]),\n );\n return claims.map((c) => {\n const answer = byId.get(c.id);\n return {\n id: c.id,\n kind: c.kind,\n subject: c.subject,\n claim: c.claim,\n verdict: answer?.verdict ?? \"unanswered\",\n ...(answer?.answered_by === undefined ? {} : { answered_by: answer.answered_by }),\n evidence: answer?.evidence ?? [],\n ...(answer?.note === undefined ? {} : { note: answer.note }),\n ...(answer?.evidence_pins === undefined ? {} : { evidence_pins: answer.evidence_pins }),\n };\n });\n}\n\n/**\n * The read view.\n *\n * `lens` is `--service`: the same checklist, narrowed to the claims that\n * service's code answers. It exists because in a ten-repo fleet the whole\n * checklist is never one repository's business, and an agent that cannot ask\n * \"what do I still owe on FEAT-1?\" answers the question by guessing. Narrowing\n * narrows the verdict too — `verified` then means \"every claim owned by this\n * service is confirmed\", which is why the payload names the service it applied.\n *\n * `bound` is loam.json's `service` — what this repository says it is. It only\n * shapes the footer, and it is the whole of how federation is discoverable:\n * the recording form printed here is the one that will actually work from here.\n */\n/**\n * Which feature is being reported on, and in what voice.\n *\n * Three of these travelled as loose strings beside two booleans through every\n * reporting path. They are one thing — the target of this run — and a record\n * makes the `--json` flag impossible to transpose with a lens name, which is\n * what the positional form allowed.\n */\nexport interface VerifyTarget {\n docsDir: string;\n featureDir: string;\n json: boolean;\n /**\n * Non-null when the record path first rolled a predecessor's interrupted\n * commit forward under its lock. Only `record` reports it; the read path\n * never recovers, so it never carries one.\n */\n recovered?: CommitRecovery | null;\n}\n\nexport function report(\n target: VerifyTarget,\n checklist: Checklist,\n recorded: Verification | null,\n scope: { lens?: string; bound?: string } = {},\n): void {\n const { docsDir, featureDir, json } = target;\n const lens = scope.lens;\n const owners = [...new Set(checklist.claims.map((c) => c.subject))].sort();\n const scoped = lens === undefined ? checklist.claims : checklist.claims.filter((c) => c.subject === lens);\n const claims = statuses(checklist, scoped, recorded);\n const count = (v: string): number => claims.filter((c) => c.verdict === v).length;\n const summary = {\n claims: claims.length,\n confirmed: count(\"confirmed\"),\n unconfirmed: count(\"unconfirmed\"),\n unanswered: count(\"unanswered\"),\n };\n // A record that answers a different question set is not an answer to this one,\n // however complete it looks — so staleness disqualifies it as a whole.\n const stale = recorded !== null && recorded.checklist !== checklist.digest;\n const tally = tallyAnswers(claims);\n const verdict = verificationVerdict(tally, stale);\n // `verified` keeps its name and its type, and loses its old meaning: a\n // scenario claim on an agent's word is answered, not run, so it no longer\n // reads the same as a green suite. `verdict` carries the distinction.\n const verified = verdict === \"verified\";\n // Contest is derivable from the checklist alone, so the read view says it\n // too: an agent looking at what it owes should learn that a second service\n // answers the same claim BEFORE it runs a suite whose report cannot be\n // attributed. Always from the whole checklist, never the lens — a shared\n // digest is a fact about the feature, and a narrowed view is the one place it\n // would otherwise be invisible.\n // The open-claims honesty line only where a record EXISTS: with none, the\n // surface already says \"Not verified\", and not-started is not partial.\n const open = recorded === null ? null : openClaimsNotice(tally, checklist.feature);\n const notices = [\n ...noticesFor(claims, checklist.feature),\n ...(open === null ? [] : [open]),\n ...contestedNotices(checklist.claims),\n ...forkedChecklistNotices(recorded, checklist.digest),\n ];\n\n if (json) {\n emitJson({\n command: \"verify\",\n feature: checklist.feature,\n path: repoPath(docsDir, featureDir),\n digest: checklist.digest,\n // Named only when narrowed, so a consumer can never mistake a service's\n // verdict for the feature's.\n ...(lens === undefined ? {} : { service: lens, checklistClaims: checklist.claims.length }),\n verified,\n verdict,\n attested: tally.attested,\n summary,\n services: owners,\n recorded:\n recorded === null\n ? null\n : {\n path: repoPath(docsDir, verificationPath(featureDir)),\n recorded: recorded.recorded,\n checklist: recorded.checklist,\n stale,\n ...(recorded.attestations === undefined ? {} : { attestations: recorded.attestations }),\n ...(recorded.report === undefined ? {} : { report: recorded.report }),\n ...(recorded.contractReport === undefined ? {} : { contractReport: recorded.contractReport }),\n },\n claims,\n ...(notices.length === 0 ? {} : { notices }),\n });\n return;\n }\n\n const scopeNote =\n lens === undefined ? \"\" : ` owned by ${lens} (of ${plural(checklist.claims.length, \"claim\")} on the checklist)`;\n console.log(\n `${checklist.feature} — ${plural(claims.length, \"claim\")}${scopeNote} derived from ${repoPath(docsDir, featureDir)}\\n`,\n );\n if (claims.length === 0) {\n console.log(\n lens === undefined\n ? \" Nothing to check: this feature's delta, specs and openapi promise nothing yet.\"\n : ` No claim on this checklist is owned by '${lens}'.${owners.length > 0 ? ` The services that own claims here are ${owners.join(\", \")}.` : \"\"}`,\n );\n return;\n }\n for (const c of claims) {\n console.log(` ${MARK[c.verdict]} ${c.id} [${c.subject}] ${c.claim}${answeredMark(c)}`);\n for (const e of c.evidence) console.log(` ${e}`);\n if (c.note !== undefined) console.log(` note: ${c.note}`);\n }\n\n console.log(\"\");\n if (recorded === null) {\n console.log(` Not verified — no ${repoPath(docsDir, verificationPath(featureDir))}.`);\n } else {\n console.log(\n ` Recorded ${recorded.recorded} — ${summary.confirmed} confirmed, ${summary.unconfirmed} unconfirmed, ${summary.unanswered} unanswered.`,\n );\n if (stale) {\n console.log(\" STALE: the feature changed after this was recorded. Answer the claims above again.\");\n }\n for (const attestation of recorded.attestations ?? []) {\n console.log(\n ` Attested by ${attestation.service} at ${attestation.commit.slice(0, 12)} (${attestation.recorded}, ${plural(attestation.claims.length, \"claim\")}).`,\n );\n if (attestation.report !== undefined) console.log(` from ${reportLine(attestation.report)}`);\n if (attestation.contractReport !== undefined) {\n console.log(` from ${contractReportLine(attestation.contractReport)}`);\n }\n }\n if (recorded.report !== undefined) console.log(` Answered from ${reportLine(recorded.report)}.`);\n if (recorded.contractReport !== undefined) {\n console.log(` Contract report read: ${contractReportLine(recorded.contractReport)}.`);\n }\n }\n // The notice's code LEADS the line here, where validate's findings now carry\n // theirs in a trailing `(code)` — and the two shapes are deliberate, not\n // drift. A notice is one line and its code is its subject, so it reads as a\n // label; a finding is one of hundreds in a report whose subject is the\n // message, so its code is an aside. Appending a second copy to satisfy the\n // one-shape instinct would print `⚠ verify.claims-open: … (verify.claims-open)`,\n // and the leading form is also the one the frozen post-archive view prints\n // (frozen.ts) — a live record and a shipped one must not describe the same\n // notice two ways. Either way the code is on screen, which is the whole of\n // what EXPLAIN_FOOTER below needs to be true.\n for (const notice of notices) console.log(` ⚠ ${notice.code}: ${notice.message}`);\n // An attested record has answered every question — telling it to \"answer each\n // claim\" would send an agent round a loop it has already run. The notice\n // above names the one thing left, which is a test run.\n if (verdict === \"unverified\") {\n console.log(\"\\n Answer each claim, then record the answers:\\n\");\n console.log(' [{ \"id\": \"<claim id>\", \"verdict\": \"confirmed\", \"evidence\": [\"src/x.ts:42\"] }]');\n console.log(`\\n loam verify ${checklist.feature} --record answers.json${recordSuffix(scope, owners)}`);\n for (const line of federationNote(scope, owners)) console.log(line);\n console.log(\"\\n A claim you cannot show evidence for is `unconfirmed` — say why in `note`.\");\n }\n // APPENDED, as format.ts promises — the report's last line, never a wedge\n // between the notices and the recording instructions that follow them. It\n // follows printed notice codes only: claim marks carry no code to look up,\n // and the frozen post-archive view (frozen.ts) stays without it on purpose,\n // because shipped history is not a fix-it surface.\n if (notices.length > 0) console.log(`\\n${EXPLAIN_FOOTER}`);\n}\n\n/**\n * The `--service` the printed form should carry. It comes from loam.json, never\n * from the checklist: the only attestation this repository can make is its own,\n * and a hint naming a service that lives somewhere else is a hint that fails.\n */\nexport function recordSuffix(scope: { lens?: string; bound?: string }, owners: string[]): string {\n if (scope.bound !== undefined) return ` --service ${scope.bound}`;\n return owners.length > 1 || scope.lens !== undefined ? \" --service <svc>\" : \"\";\n}\n\n/** Why the form above has a `--service` on it — the one place federation is taught. */\nexport function federationNote(scope: { lens?: string; bound?: string }, owners: string[]): string[] {\n if (scope.bound !== undefined) {\n const others = owners.filter((s) => s !== scope.bound);\n return [\n \"\",\n ` This repository is ${scope.bound}, so it attests only ${scope.bound}'s claims, bound to its git HEAD.`,\n ...(others.length === 0\n ? []\n : [` The claims owned by ${others.join(\", \")} are recorded the same way from those repositories.`]),\n ];\n }\n if (owners.length > 1 || scope.lens !== undefined) {\n return [\n \"\",\n ` This checklist spans ${plural(owners.length, \"service\")} (${owners.join(\", \")}) — each attests its own claims`,\n \" from its own repository, where loam.json names that service.\",\n ];\n }\n return [];\n}\n\n/**\n * The frozen view: an archived feature's record, verbatim. No checklist is\n * derived and no staleness is judged — there is nothing current to judge\n * against, and pretending otherwise is how a true record reads as a lie.\n * `frozen` is the marker a consumer branches on.\n *\n * The verdict is recounted from `claims[]`, never taken from `summary`: this is\n * the post-ship verdict on a feature nobody can re-derive a checklist for, so a\n * record whose counts had drifted from its own answers reported a shipped\n * feature as fully confirmed. (A record that contradicts itself never reaches\n * here — `readVerificationState` refuses it — so the recount and the summary\n * agree; the recount is what says WHY.) No record at all is reported as exactly\n * that, with `summary: null`, not zero claims, which would falsely say the\n * feature promised nothing.\n */\n"]}