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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1026) hide show
  1. package/CHANGELOG.md +2570 -61
  2. package/COMPARISON.md +80 -63
  3. package/CONTRIBUTING.md +84 -0
  4. package/MIGRATING-from-OpenSpec.md +213 -54
  5. package/QUICKSTART.md +125 -0
  6. package/README.md +450 -150
  7. package/ROADMAP.md +494 -0
  8. package/SCHEMA.md +2362 -245
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +701 -0
  11. package/dist/cli.js +113 -19
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +209 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +268 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +77 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/openapi.js +159 -0
  22. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  23. package/dist/commands/archive/plan/gate.js +317 -0
  24. package/dist/commands/archive/plan/gate.js.map +1 -0
  25. package/dist/commands/archive/plan/landscape.js +161 -0
  26. package/dist/commands/archive/plan/landscape.js.map +1 -0
  27. package/dist/commands/archive/plan/refusal.js +111 -0
  28. package/dist/commands/archive/plan/refusal.js.map +1 -0
  29. package/dist/commands/archive/plan/specs.js +237 -0
  30. package/dist/commands/archive/plan/specs.js.map +1 -0
  31. package/dist/commands/archive/plan/state.js +27 -0
  32. package/dist/commands/archive/plan/state.js.map +1 -0
  33. package/dist/commands/archive/run.js +251 -0
  34. package/dist/commands/archive/run.js.map +1 -0
  35. package/dist/commands/context/context.js +99 -0
  36. package/dist/commands/context/context.js.map +1 -0
  37. package/dist/commands/context/print.js +283 -0
  38. package/dist/commands/context/print.js.map +1 -0
  39. package/dist/commands/delta/delta.js +279 -0
  40. package/dist/commands/delta/delta.js.map +1 -0
  41. package/dist/commands/delta/print.js +205 -0
  42. package/dist/commands/delta/print.js.map +1 -0
  43. package/dist/commands/dependencies.js +9 -7
  44. package/dist/commands/dependencies.js.map +1 -1
  45. package/dist/commands/diff/diff.js +93 -0
  46. package/dist/commands/diff/diff.js.map +1 -0
  47. package/dist/commands/diff/print.js +38 -0
  48. package/dist/commands/diff/print.js.map +1 -0
  49. package/dist/commands/doctor.js +5 -4
  50. package/dist/commands/doctor.js.map +1 -1
  51. package/dist/commands/explain/explain.js +151 -0
  52. package/dist/commands/explain/explain.js.map +1 -0
  53. package/dist/commands/explore.js +29 -24
  54. package/dist/commands/explore.js.map +1 -1
  55. package/dist/commands/gate/gate.js +115 -0
  56. package/dist/commands/gate/gate.js.map +1 -0
  57. package/dist/commands/gate/print.js +54 -0
  58. package/dist/commands/gate/print.js.map +1 -0
  59. package/dist/commands/gherkin/commit.js +146 -0
  60. package/dist/commands/gherkin/commit.js.map +1 -0
  61. package/dist/commands/gherkin/gherkin.js +246 -0
  62. package/dist/commands/gherkin/gherkin.js.map +1 -0
  63. package/dist/commands/gherkin/reconcile.js +149 -0
  64. package/dist/commands/gherkin/reconcile.js.map +1 -0
  65. package/dist/commands/gherkin/render.js +77 -0
  66. package/dist/commands/gherkin/render.js.map +1 -0
  67. package/dist/commands/init/example.js +204 -0
  68. package/dist/commands/init/example.js.map +1 -0
  69. package/dist/commands/init/first-hour.js +28 -0
  70. package/dist/commands/init/first-hour.js.map +1 -0
  71. package/dist/commands/{init.js → init/init.js} +146 -71
  72. package/dist/commands/init/init.js.map +1 -0
  73. package/dist/commands/init/mcp.js +131 -0
  74. package/dist/commands/init/mcp.js.map +1 -0
  75. package/dist/commands/init/options.js +78 -0
  76. package/dist/commands/init/options.js.map +1 -0
  77. package/dist/commands/instructions.js +82 -14
  78. package/dist/commands/instructions.js.map +1 -1
  79. package/dist/commands/list/campaign/campaign.js +65 -0
  80. package/dist/commands/list/campaign/campaign.js.map +1 -0
  81. package/dist/commands/list/campaign/owners.js +65 -0
  82. package/dist/commands/list/campaign/owners.js.map +1 -0
  83. package/dist/commands/list/json.js +157 -0
  84. package/dist/commands/list/json.js.map +1 -0
  85. package/dist/commands/list/list.js +343 -0
  86. package/dist/commands/list/list.js.map +1 -0
  87. package/dist/commands/list/print.js +301 -0
  88. package/dist/commands/list/print.js.map +1 -0
  89. package/dist/commands/list/review.js +120 -0
  90. package/dist/commands/list/review.js.map +1 -0
  91. package/dist/commands/list/views.js +105 -0
  92. package/dist/commands/list/views.js.map +1 -0
  93. package/dist/commands/mcp/dispatch.js +183 -0
  94. package/dist/commands/mcp/dispatch.js.map +1 -0
  95. package/dist/commands/mcp/mcp.js +34 -0
  96. package/dist/commands/mcp/mcp.js.map +1 -0
  97. package/dist/commands/mcp/serve.js +55 -0
  98. package/dist/commands/mcp/serve.js.map +1 -0
  99. package/dist/commands/migrate-openspec/materialize/active.js +170 -0
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  101. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  102. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  103. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  104. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  105. package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
  106. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  107. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  108. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  109. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  110. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  111. package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
  112. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  113. package/dist/commands/migrate-openspec/openspec/error.js +19 -0
  114. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  115. package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
  116. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  117. package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
  118. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  119. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  120. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  121. package/dist/commands/migrate-openspec/print.js +89 -0
  122. package/dist/commands/migrate-openspec/print.js.map +1 -0
  123. package/dist/commands/new/commit.js +76 -0
  124. package/dist/commands/new/commit.js.map +1 -0
  125. package/dist/commands/new/new.js +283 -0
  126. package/dist/commands/new/new.js.map +1 -0
  127. package/dist/commands/new/templates.js +355 -0
  128. package/dist/commands/new/templates.js.map +1 -0
  129. package/dist/commands/open.js +203 -0
  130. package/dist/commands/open.js.map +1 -0
  131. package/dist/commands/policy/format.js +152 -0
  132. package/dist/commands/policy/format.js.map +1 -0
  133. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
  134. package/dist/commands/policy/gate.js.map +1 -0
  135. package/dist/commands/rebase/edit.js +106 -0
  136. package/dist/commands/rebase/edit.js.map +1 -0
  137. package/dist/commands/rebase/living.js +185 -0
  138. package/dist/commands/rebase/living.js.map +1 -0
  139. package/dist/commands/rebase/plan.js +245 -0
  140. package/dist/commands/rebase/plan.js.map +1 -0
  141. package/dist/commands/rebase/rebase.js +275 -0
  142. package/dist/commands/rebase/rebase.js.map +1 -0
  143. package/dist/commands/seed/commit.js +192 -0
  144. package/dist/commands/seed/commit.js.map +1 -0
  145. package/dist/commands/seed/plan.js +133 -0
  146. package/dist/commands/seed/plan.js.map +1 -0
  147. package/dist/commands/seed/seed.js +172 -0
  148. package/dist/commands/seed/seed.js.map +1 -0
  149. package/dist/commands/show/feature.js +178 -0
  150. package/dist/commands/show/feature.js.map +1 -0
  151. package/dist/commands/show/marks.js +24 -0
  152. package/dist/commands/show/marks.js.map +1 -0
  153. package/dist/commands/{show.js → show/service.js} +63 -152
  154. package/dist/commands/show/service.js.map +1 -0
  155. package/dist/commands/show/show.js +77 -0
  156. package/dist/commands/show/show.js.map +1 -0
  157. package/dist/commands/status/json.js +45 -0
  158. package/dist/commands/status/json.js.map +1 -0
  159. package/dist/commands/status/print.js +157 -0
  160. package/dist/commands/status/print.js.map +1 -0
  161. package/dist/commands/status/status.js +119 -0
  162. package/dist/commands/status/status.js.map +1 -0
  163. package/dist/commands/steps/steps.js +189 -0
  164. package/dist/commands/steps/steps.js.map +1 -0
  165. package/dist/commands/subsystem/edit.js +192 -0
  166. package/dist/commands/subsystem/edit.js.map +1 -0
  167. package/dist/commands/subsystem/move.js +265 -0
  168. package/dist/commands/subsystem/move.js.map +1 -0
  169. package/dist/commands/subsystem/query.js +115 -0
  170. package/dist/commands/subsystem/query.js.map +1 -0
  171. package/dist/commands/subsystem/subsystem.js +101 -0
  172. package/dist/commands/subsystem/subsystem.js.map +1 -0
  173. package/dist/commands/subsystem/sync.js +103 -0
  174. package/dist/commands/subsystem/sync.js.map +1 -0
  175. package/dist/commands/subsystem/txn/txn.js +94 -0
  176. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  177. package/dist/commands/subsystem/txn/views.js +70 -0
  178. package/dist/commands/subsystem/txn/views.js.map +1 -0
  179. package/dist/commands/unarchive/manifest.js +160 -0
  180. package/dist/commands/unarchive/manifest.js.map +1 -0
  181. package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
  182. package/dist/commands/unarchive/restore.js.map +1 -0
  183. package/dist/commands/unarchive/unarchive.js +67 -0
  184. package/dist/commands/unarchive/unarchive.js.map +1 -0
  185. package/dist/commands/validate/arch-coverage.js +194 -0
  186. package/dist/commands/validate/arch-coverage.js.map +1 -0
  187. package/dist/commands/validate/checks/fleet-shape.js +296 -0
  188. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  189. package/dist/commands/validate/checks/health-deps.js +55 -0
  190. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  191. package/dist/commands/validate/checks/requirements.js +254 -0
  192. package/dist/commands/validate/checks/requirements.js.map +1 -0
  193. package/dist/commands/validate/checks/sources.js +76 -0
  194. package/dist/commands/validate/checks/sources.js.map +1 -0
  195. package/dist/commands/validate/checks/vocabulary.js +31 -0
  196. package/dist/commands/validate/checks/vocabulary.js.map +1 -0
  197. package/dist/commands/validate/feature.js +216 -0
  198. package/dist/commands/validate/feature.js.map +1 -0
  199. package/dist/commands/validate/fleet/census.js +69 -0
  200. package/dist/commands/validate/fleet/census.js.map +1 -0
  201. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  202. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  203. package/dist/commands/validate/fleet/landscape.js +353 -0
  204. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  205. package/dist/commands/validate/fleet/load.js +52 -0
  206. package/dist/commands/validate/fleet/load.js.map +1 -0
  207. package/dist/commands/validate/fleet/obligations.js +236 -0
  208. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  209. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  210. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  211. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  212. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  213. package/dist/commands/validate/fleet/scorecard/print.js +63 -0
  214. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  215. package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
  216. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  217. package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
  218. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
  219. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  220. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  221. package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
  222. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
  223. package/dist/commands/validate/fleet/usecases/steps.js +197 -0
  224. package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
  225. package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
  226. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
  227. package/dist/commands/validate/fleet/views/ids.js +40 -0
  228. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  229. package/dist/commands/validate/fleet/views/stale.js +59 -0
  230. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  231. package/dist/commands/validate/links/corpus.js +92 -0
  232. package/dist/commands/validate/links/corpus.js.map +1 -0
  233. package/dist/commands/validate/links/glossary.js +75 -0
  234. package/dist/commands/validate/links/glossary.js.map +1 -0
  235. package/dist/commands/validate/report.js +269 -0
  236. package/dist/commands/validate/report.js.map +1 -0
  237. package/dist/commands/validate/service/api.js +338 -0
  238. package/dist/commands/validate/service/api.js.map +1 -0
  239. package/dist/commands/validate/service/events/events.js +219 -0
  240. package/dist/commands/validate/service/events/events.js.map +1 -0
  241. package/dist/commands/validate/service/events/message-producers.js +77 -0
  242. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  243. package/dist/commands/validate/service/evidence-pins.js +131 -0
  244. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  245. package/dist/commands/validate/service/service.js +250 -0
  246. package/dist/commands/validate/service/service.js.map +1 -0
  247. package/dist/commands/validate/service/specs.js +219 -0
  248. package/dist/commands/validate/service/specs.js.map +1 -0
  249. package/dist/commands/validate/service/spine.js +113 -0
  250. package/dist/commands/validate/service/spine.js.map +1 -0
  251. package/dist/commands/validate/validate.js +338 -0
  252. package/dist/commands/validate/validate.js.map +1 -0
  253. package/dist/commands/verify/cross/diff.js +182 -0
  254. package/dist/commands/verify/cross/diff.js.map +1 -0
  255. package/dist/commands/verify/evidence/contract.js +32 -0
  256. package/dist/commands/verify/evidence/contract.js.map +1 -0
  257. package/dist/commands/verify/evidence/pins.js +52 -0
  258. package/dist/commands/verify/evidence/pins.js.map +1 -0
  259. package/dist/commands/verify/evidence/read.js +72 -0
  260. package/dist/commands/verify/evidence/read.js.map +1 -0
  261. package/dist/commands/verify/frozen.js +241 -0
  262. package/dist/commands/verify/frozen.js.map +1 -0
  263. package/dist/commands/verify/record.js +226 -0
  264. package/dist/commands/verify/record.js.map +1 -0
  265. package/dist/commands/verify/report.js +223 -0
  266. package/dist/commands/verify/report.js.map +1 -0
  267. package/dist/commands/verify/results.js +246 -0
  268. package/dist/commands/verify/results.js.map +1 -0
  269. package/dist/commands/verify/verify.js +217 -0
  270. package/dist/commands/verify/verify.js.map +1 -0
  271. package/dist/commands/vouch/contract.js +11 -0
  272. package/dist/commands/vouch/contract.js.map +1 -0
  273. package/dist/commands/vouch/pack/contract.js +2 -0
  274. package/dist/commands/vouch/pack/contract.js.map +1 -0
  275. package/dist/commands/vouch/pack/pack.js +266 -0
  276. package/dist/commands/vouch/pack/pack.js.map +1 -0
  277. package/dist/commands/vouch/pack/print.js +271 -0
  278. package/dist/commands/vouch/pack/print.js.map +1 -0
  279. package/dist/commands/vouch/pack/sections.js +142 -0
  280. package/dist/commands/vouch/pack/sections.js.map +1 -0
  281. package/dist/commands/vouch/prompt/confirm.js +46 -0
  282. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  283. package/dist/commands/vouch/report.js +101 -0
  284. package/dist/commands/vouch/report.js.map +1 -0
  285. package/dist/commands/vouch/run.js +285 -0
  286. package/dist/commands/vouch/run.js.map +1 -0
  287. package/dist/commands/vouch/sample/plan.js +125 -0
  288. package/dist/commands/vouch/sample/plan.js.map +1 -0
  289. package/dist/commands/vouch/sample/print.js +109 -0
  290. package/dist/commands/vouch/sample/print.js.map +1 -0
  291. package/dist/commands/vouch/vet/verify.js +123 -0
  292. package/dist/commands/vouch/vet/verify.js.map +1 -0
  293. package/dist/commands/vouch/vouch.js +176 -0
  294. package/dist/commands/vouch/vouch.js.map +1 -0
  295. package/dist/core/agent/agents-md/artifacts.js +220 -0
  296. package/dist/core/agent/agents-md/artifacts.js.map +1 -0
  297. package/dist/core/agent/agents-md/command-map.js +324 -0
  298. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  299. package/dist/core/agent/agents-md/cycle.js +165 -0
  300. package/dist/core/agent/agents-md/cycle.js.map +1 -0
  301. package/dist/core/agent/agents-md/map/explain.js +34 -0
  302. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  303. package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
  304. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  305. package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
  306. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  307. package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
  308. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  309. package/dist/core/agent/agents-md/map/mcp.js +41 -0
  310. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  311. package/dist/core/agent/agents-md/map/status.js +62 -0
  312. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  313. package/dist/core/agent/agents-md/map/subsystem.js +32 -0
  314. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  315. package/dist/core/agent/agents-md/map/usecases.js +60 -0
  316. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  317. package/dist/core/agent/agents-md/refusals.js +246 -0
  318. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  319. package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
  320. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
  321. package/dist/core/agent/agents-md/spine.js +40 -0
  322. package/dist/core/agent/agents-md/spine.js.map +1 -0
  323. package/dist/core/agent/agents-md.js +170 -0
  324. package/dist/core/agent/agents-md.js.map +1 -0
  325. package/dist/core/agent/agents-stamp.js +155 -0
  326. package/dist/core/agent/agents-stamp.js.map +1 -0
  327. package/dist/core/agent/contract.js +2 -0
  328. package/dist/core/agent/contract.js.map +1 -0
  329. package/dist/core/agent/protocol.js +193 -0
  330. package/dist/core/agent/protocol.js.map +1 -0
  331. package/dist/core/agent/scaffold.js +259 -0
  332. package/dist/core/agent/scaffold.js.map +1 -0
  333. package/dist/core/agent/support/report.js +103 -0
  334. package/dist/core/agent/support/report.js.map +1 -0
  335. package/dist/core/agent/tools/dialects.js +150 -0
  336. package/dist/core/agent/tools/dialects.js.map +1 -0
  337. package/dist/core/agent/tools/registry.js +228 -0
  338. package/dist/core/agent/tools/registry.js.map +1 -0
  339. package/dist/core/agent/workflows/adopt.js +133 -0
  340. package/dist/core/agent/workflows/adopt.js.map +1 -0
  341. package/dist/core/agent/workflows/check.js +334 -0
  342. package/dist/core/agent/workflows/check.js.map +1 -0
  343. package/dist/core/agent/workflows/closing.js +262 -0
  344. package/dist/core/agent/workflows/closing.js.map +1 -0
  345. package/dist/core/agent/workflows/feature.js +105 -0
  346. package/dist/core/agent/workflows/feature.js.map +1 -0
  347. package/dist/core/agent/workflows/implement.js +105 -0
  348. package/dist/core/agent/workflows/implement.js.map +1 -0
  349. package/dist/core/agent/workflows/reference/authoring.js +209 -0
  350. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  351. package/dist/core/agent/workflows/reference/codes.js +65 -0
  352. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  353. package/dist/core/agent/workflows/reference/done-check.js +188 -0
  354. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  355. package/dist/core/agent/workflows/reference/reference.js +16 -0
  356. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  357. package/dist/core/agent/workflows/reference/spine.js +297 -0
  358. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  359. package/dist/core/asyncapi/baseline/plan.js +110 -0
  360. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  361. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  362. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  363. package/dist/core/asyncapi/depth.js +164 -0
  364. package/dist/core/asyncapi/depth.js.map +1 -0
  365. package/dist/core/asyncapi/digest.js +141 -0
  366. package/dist/core/asyncapi/digest.js.map +1 -0
  367. package/dist/core/asyncapi/merge/components.js +91 -0
  368. package/dist/core/asyncapi/merge/components.js.map +1 -0
  369. package/dist/core/asyncapi/merge/error.js +33 -0
  370. package/dist/core/asyncapi/merge/error.js.map +1 -0
  371. package/dist/core/asyncapi/merge/markers.js +308 -0
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  373. package/dist/core/asyncapi/merge/merge.js +215 -0
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  375. package/dist/core/asyncapi/merge/pin.js +107 -0
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  377. package/dist/core/asyncapi/model.js +11 -0
  378. package/dist/core/asyncapi/model.js.map +1 -0
  379. package/dist/core/asyncapi/producers.js +50 -0
  380. package/dist/core/asyncapi/producers.js.map +1 -0
  381. package/dist/core/asyncapi/read.js +239 -0
  382. package/dist/core/asyncapi/read.js.map +1 -0
  383. package/dist/core/brief/brief.js +225 -0
  384. package/dist/core/brief/brief.js.map +1 -0
  385. package/dist/core/brief/checks.js +250 -0
  386. package/dist/core/brief/checks.js.map +1 -0
  387. package/dist/core/brief/landscape.js +194 -0
  388. package/dist/core/brief/landscape.js.map +1 -0
  389. package/dist/core/brief/targets.js +226 -0
  390. package/dist/core/brief/targets.js.map +1 -0
  391. package/dist/core/brief/unchecked.js +47 -0
  392. package/dist/core/brief/unchecked.js.map +1 -0
  393. package/dist/core/c4/arch.js +282 -0
  394. package/dist/core/c4/arch.js.map +1 -0
  395. package/dist/core/c4/likec4.js +88 -0
  396. package/dist/core/c4/likec4.js.map +1 -0
  397. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  398. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  399. package/dist/core/c4/parsed/specification.js +78 -0
  400. package/dist/core/c4/parsed/specification.js.map +1 -0
  401. package/dist/core/c4/parsed/values.js +57 -0
  402. package/dist/core/c4/parsed/values.js.map +1 -0
  403. package/dist/core/c4/parsed/view-ids.js +75 -0
  404. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  405. package/dist/core/c4/project/architecture.js +45 -0
  406. package/dist/core/c4/project/architecture.js.map +1 -0
  407. package/dist/core/c4/project/documents.js +58 -0
  408. package/dist/core/c4/project/documents.js.map +1 -0
  409. package/dist/core/c4/project/load.js +183 -0
  410. package/dist/core/c4/project/load.js.map +1 -0
  411. package/dist/core/c4/resolve/service.js +113 -0
  412. package/dist/core/c4/resolve/service.js.map +1 -0
  413. package/dist/core/c4/seed/fleet-file.js +201 -0
  414. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  415. package/dist/core/c4/seed/items.js +91 -0
  416. package/dist/core/c4/seed/items.js.map +1 -0
  417. package/dist/core/c4/seed/stamp.js +48 -0
  418. package/dist/core/c4/seed/stamp.js.map +1 -0
  419. package/dist/core/c4/seed/template.js +109 -0
  420. package/dist/core/c4/seed/template.js.map +1 -0
  421. package/dist/core/c4/source-mask.js +82 -0
  422. package/dist/core/c4/source-mask.js.map +1 -0
  423. package/dist/core/c4/source-scan.js +227 -0
  424. package/dist/core/c4/source-scan.js.map +1 -0
  425. package/dist/core/c4/splice/authored-source.js +101 -0
  426. package/dist/core/c4/splice/authored-source.js.map +1 -0
  427. package/dist/core/c4/splice/contract.js +10 -0
  428. package/dist/core/c4/splice/contract.js.map +1 -0
  429. package/dist/core/c4/splice/delta-blocks.js +126 -0
  430. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  431. package/dist/core/c4/splice/identity/edges.js +36 -0
  432. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  433. package/dist/core/c4/splice/landscape-merge.js +269 -0
  434. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  435. package/dist/core/c4/splice/placement.js +194 -0
  436. package/dist/core/c4/splice/placement.js.map +1 -0
  437. package/dist/core/c4/workspace.js +172 -0
  438. package/dist/core/c4/workspace.js.map +1 -0
  439. package/dist/core/capabilities/authoring/notes.js +141 -0
  440. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  441. package/dist/core/capabilities/capabilities.js +124 -0
  442. package/dist/core/capabilities/capabilities.js.map +1 -0
  443. package/dist/core/capabilities/delta/doc.js +50 -0
  444. package/dist/core/capabilities/delta/doc.js.map +1 -0
  445. package/dist/core/capabilities/delta/overlay.js +129 -0
  446. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  447. package/dist/core/capabilities/delta/summary.js +57 -0
  448. package/dist/core/capabilities/delta/summary.js.map +1 -0
  449. package/dist/core/capabilities/delta/tree.js +43 -0
  450. package/dist/core/capabilities/delta/tree.js.map +1 -0
  451. package/dist/core/capabilities/delta/uncovered.js +222 -0
  452. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  453. package/dist/core/capabilities/findings.js +342 -0
  454. package/dist/core/capabilities/findings.js.map +1 -0
  455. package/dist/core/capabilities/realizes/findings.js +181 -0
  456. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  457. package/dist/core/capabilities/realizes/join.js +143 -0
  458. package/dist/core/capabilities/realizes/join.js.map +1 -0
  459. package/dist/core/capabilities/rollup.js +199 -0
  460. package/dist/core/capabilities/rollup.js.map +1 -0
  461. package/dist/core/capabilities/tree.js +126 -0
  462. package/dist/core/capabilities/tree.js.map +1 -0
  463. package/dist/core/capabilities/usecase-join.js +277 -0
  464. package/dist/core/capabilities/usecase-join.js.map +1 -0
  465. package/dist/core/coherence/authoring/scaffold.js +177 -0
  466. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  467. package/dist/core/coherence/authoring/sentinels.js +74 -0
  468. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  469. package/dist/core/coherence/coherence.js +251 -0
  470. package/dist/core/coherence/coherence.js.map +1 -0
  471. package/dist/core/coherence/declared.js +269 -0
  472. package/dist/core/coherence/declared.js.map +1 -0
  473. package/dist/core/coherence/events/declared.js +206 -0
  474. package/dist/core/coherence/events/declared.js.map +1 -0
  475. package/dist/core/coherence/events/events.js +204 -0
  476. package/dist/core/coherence/events/events.js.map +1 -0
  477. package/dist/core/coherence/events/grades.js +166 -0
  478. package/dist/core/coherence/events/grades.js.map +1 -0
  479. package/dist/core/coherence/events/lookups.js +122 -0
  480. package/dist/core/coherence/events/lookups.js.map +1 -0
  481. package/dist/core/coherence/events/merged.js +40 -0
  482. package/dist/core/coherence/events/merged.js.map +1 -0
  483. package/dist/core/coherence/living.js +198 -0
  484. package/dist/core/coherence/living.js.map +1 -0
  485. package/dist/core/coherence/lookups.js +155 -0
  486. package/dist/core/coherence/lookups.js.map +1 -0
  487. package/dist/core/coherence/pending.js +39 -0
  488. package/dist/core/coherence/pending.js.map +1 -0
  489. package/dist/core/conflict-markers.js +60 -0
  490. package/dist/core/conflict-markers.js.map +1 -0
  491. package/dist/core/delta/claims.js +73 -0
  492. package/dist/core/delta/claims.js.map +1 -0
  493. package/dist/core/delta/delta.js +296 -0
  494. package/dist/core/delta/delta.js.map +1 -0
  495. package/dist/core/delta/document.js +177 -0
  496. package/dist/core/delta/document.js.map +1 -0
  497. package/dist/core/delta/scope.js +48 -0
  498. package/dist/core/delta/scope.js.map +1 -0
  499. package/dist/core/delta/select.js +237 -0
  500. package/dist/core/delta/select.js.map +1 -0
  501. package/dist/core/dependencies/dependencies.js +141 -0
  502. package/dist/core/dependencies/dependencies.js.map +1 -0
  503. package/dist/core/dependencies/facts.js +165 -0
  504. package/dist/core/dependencies/facts.js.map +1 -0
  505. package/dist/core/dependencies/fanin.js +88 -0
  506. package/dist/core/dependencies/fanin.js.map +1 -0
  507. package/dist/core/dependencies/graph.js +106 -0
  508. package/dist/core/dependencies/graph.js.map +1 -0
  509. package/dist/core/diff/base-git.js +148 -0
  510. package/dist/core/diff/base-git.js.map +1 -0
  511. package/dist/core/diff/base-state.js +209 -0
  512. package/dist/core/diff/base-state.js.map +1 -0
  513. package/dist/core/diff/current-state.js +96 -0
  514. package/dist/core/diff/current-state.js.map +1 -0
  515. package/dist/core/diff/scope/changed-paths.js +188 -0
  516. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  517. package/dist/core/diff/semantic.js +243 -0
  518. package/dist/core/diff/semantic.js.map +1 -0
  519. package/dist/core/diff/victims.js +247 -0
  520. package/dist/core/diff/victims.js.map +1 -0
  521. package/dist/core/docs.js +59 -55
  522. package/dist/core/docs.js.map +1 -1
  523. package/dist/core/doctor/agents.js +222 -0
  524. package/dist/core/doctor/agents.js.map +1 -0
  525. package/dist/core/doctor/config.js +135 -0
  526. package/dist/core/doctor/config.js.map +1 -0
  527. package/dist/core/doctor/doctor.js +275 -0
  528. package/dist/core/doctor/doctor.js.map +1 -0
  529. package/dist/core/doctor/report.js +13 -0
  530. package/dist/core/doctor/report.js.map +1 -0
  531. package/dist/core/doctor/residue.js +110 -0
  532. package/dist/core/doctor/residue.js.map +1 -0
  533. package/dist/core/document/apply.js +77 -0
  534. package/dist/core/document/apply.js.map +1 -0
  535. package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
  536. package/dist/core/document/frontmatter.js.map +1 -0
  537. package/dist/core/document/grammar/directives.js +143 -0
  538. package/dist/core/document/grammar/directives.js.map +1 -0
  539. package/dist/core/document/parse.js +263 -0
  540. package/dist/core/document/parse.js.map +1 -0
  541. package/dist/core/document/scenarios.js +221 -0
  542. package/dist/core/document/scenarios.js.map +1 -0
  543. package/dist/core/document/spec.js +241 -0
  544. package/dist/core/document/spec.js.map +1 -0
  545. package/dist/core/{config.js → envelope/config.js} +79 -18
  546. package/dist/core/envelope/config.js.map +1 -0
  547. package/dist/core/envelope/json.js +175 -0
  548. package/dist/core/envelope/json.js.map +1 -0
  549. package/dist/core/{version.js → envelope/version.js} +3 -3
  550. package/dist/core/envelope/version.js.map +1 -0
  551. package/dist/core/explain/families.js +175 -0
  552. package/dist/core/explain/families.js.map +1 -0
  553. package/dist/core/explain/fix-tables.js +178 -0
  554. package/dist/core/explain/fix-tables.js.map +1 -0
  555. package/dist/core/explain/lookup.js +181 -0
  556. package/dist/core/explain/lookup.js.map +1 -0
  557. package/dist/core/explain/refusals.js +49 -0
  558. package/dist/core/explain/refusals.js.map +1 -0
  559. package/dist/core/explain/terms.js +144 -0
  560. package/dist/core/explain/terms.js.map +1 -0
  561. package/dist/core/explore/describe.js +105 -0
  562. package/dist/core/explore/describe.js.map +1 -0
  563. package/dist/core/{explore.js → explore/explore.js} +50 -101
  564. package/dist/core/explore/explore.js.map +1 -0
  565. package/dist/core/fleet-context.js +132 -77
  566. package/dist/core/fleet-context.js.map +1 -1
  567. package/dist/core/gate/checks.js +201 -0
  568. package/dist/core/gate/checks.js.map +1 -0
  569. package/dist/core/gate/partners.js +205 -0
  570. package/dist/core/gate/partners.js.map +1 -0
  571. package/dist/core/gate/report.js +47 -0
  572. package/dist/core/gate/report.js.map +1 -0
  573. package/dist/core/gate/verification.js +113 -0
  574. package/dist/core/gate/verification.js.map +1 -0
  575. package/dist/core/gherkin/digest.js +60 -0
  576. package/dist/core/gherkin/digest.js.map +1 -0
  577. package/dist/core/gherkin/emit.js +177 -0
  578. package/dist/core/gherkin/emit.js.map +1 -0
  579. package/dist/core/gherkin/read.js +76 -0
  580. package/dist/core/gherkin/read.js.map +1 -0
  581. package/dist/core/gherkin/stale.js +234 -0
  582. package/dist/core/gherkin/stale.js.map +1 -0
  583. package/dist/core/gherkin/stamp.js +77 -0
  584. package/dist/core/gherkin/stamp.js.map +1 -0
  585. package/dist/core/gherkin/steps/catalogue.js +154 -0
  586. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  587. package/dist/core/gherkin/steps/inventory.js +98 -0
  588. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  589. package/dist/core/gherkin/steps/phrase.js +72 -0
  590. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  591. package/dist/core/glossary/delta.js +106 -0
  592. package/dist/core/glossary/delta.js.map +1 -0
  593. package/dist/core/glossary/tree.js +86 -0
  594. package/dist/core/glossary/tree.js.map +1 -0
  595. package/dist/core/kernel/concurrency.js.map +1 -0
  596. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  597. package/dist/core/kernel/document-bytes.js.map +1 -0
  598. package/dist/core/kernel/fences.js +42 -0
  599. package/dist/core/kernel/fences.js.map +1 -0
  600. package/dist/core/kernel/ids/capability.js +72 -0
  601. package/dist/core/kernel/ids/capability.js.map +1 -0
  602. package/dist/core/kernel/ids/dirs.js +33 -0
  603. package/dist/core/kernel/ids/dirs.js.map +1 -0
  604. package/dist/core/kernel/ids/feature.js +75 -0
  605. package/dist/core/kernel/ids/feature.js.map +1 -0
  606. package/dist/core/kernel/ids/service.js +156 -0
  607. package/dist/core/kernel/ids/service.js.map +1 -0
  608. package/dist/core/kernel/ids/subsystem.js +63 -0
  609. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  610. package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
  611. package/dist/core/kernel/path-safety.js.map +1 -0
  612. package/dist/core/kernel/records.js.map +1 -0
  613. package/dist/core/links/backlinks.js +68 -0
  614. package/dist/core/links/backlinks.js.map +1 -0
  615. package/dist/core/links/case.js +74 -0
  616. package/dist/core/links/case.js.map +1 -0
  617. package/dist/core/links/corpus.js +104 -0
  618. package/dist/core/links/corpus.js.map +1 -0
  619. package/dist/core/links/findings.js +110 -0
  620. package/dist/core/links/findings.js.map +1 -0
  621. package/dist/core/links/parse.js +236 -0
  622. package/dist/core/links/parse.js.map +1 -0
  623. package/dist/core/mcp/argv.js +111 -0
  624. package/dist/core/mcp/argv.js.map +1 -0
  625. package/dist/core/mcp/author-tools.js +72 -0
  626. package/dist/core/mcp/author-tools.js.map +1 -0
  627. package/dist/core/mcp/framing.js +46 -0
  628. package/dist/core/mcp/framing.js.map +1 -0
  629. package/dist/core/mcp/protocol.js +280 -0
  630. package/dist/core/mcp/protocol.js.map +1 -0
  631. package/dist/core/mcp/tools.js +314 -0
  632. package/dist/core/mcp/tools.js.map +1 -0
  633. package/dist/core/obligations/obligations.js +106 -0
  634. package/dist/core/obligations/obligations.js.map +1 -0
  635. package/dist/core/openapi/baseline/gate.js +166 -0
  636. package/dist/core/openapi/baseline/gate.js.map +1 -0
  637. package/dist/core/openapi/baseline/plan.js +112 -0
  638. package/dist/core/openapi/baseline/plan.js.map +1 -0
  639. package/dist/core/openapi/baseline/record.js +175 -0
  640. package/dist/core/openapi/baseline/record.js.map +1 -0
  641. package/dist/core/openapi/depth.js +122 -0
  642. package/dist/core/openapi/depth.js.map +1 -0
  643. package/dist/core/openapi/digest.js +189 -0
  644. package/dist/core/openapi/digest.js.map +1 -0
  645. package/dist/core/{openapi.js → openapi/doc.js} +44 -106
  646. package/dist/core/openapi/doc.js.map +1 -0
  647. package/dist/core/openapi/merge/components.js +234 -0
  648. package/dist/core/openapi/merge/components.js.map +1 -0
  649. package/dist/core/openapi/merge/error.js +26 -0
  650. package/dist/core/openapi/merge/error.js.map +1 -0
  651. package/dist/core/openapi/merge/markers.js +208 -0
  652. package/dist/core/openapi/merge/markers.js.map +1 -0
  653. package/dist/core/openapi/merge/merge.js +256 -0
  654. package/dist/core/openapi/merge/merge.js.map +1 -0
  655. package/dist/core/openapi/merge/pin.js +128 -0
  656. package/dist/core/openapi/merge/pin.js.map +1 -0
  657. package/dist/core/openspec/decide/capabilities.js +244 -0
  658. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  659. package/dist/core/openspec/decide/dispositions.js +63 -0
  660. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  661. package/dist/core/openspec/decide/renames.js +179 -0
  662. package/dist/core/openspec/decide/renames.js.map +1 -0
  663. package/dist/core/openspec/decide/verdict.js +84 -0
  664. package/dist/core/openspec/decide/verdict.js.map +1 -0
  665. package/dist/core/openspec/inventory.js +221 -0
  666. package/dist/core/openspec/inventory.js.map +1 -0
  667. package/dist/core/openspec/model/mapping.js +76 -0
  668. package/dist/core/openspec/model/mapping.js.map +1 -0
  669. package/dist/core/openspec/model/model.js +65 -0
  670. package/dist/core/openspec/model/model.js.map +1 -0
  671. package/dist/core/openspec/scan/changes.js +235 -0
  672. package/dist/core/openspec/scan/changes.js.map +1 -0
  673. package/dist/core/openspec/scan/config.js +200 -0
  674. package/dist/core/openspec/scan/config.js.map +1 -0
  675. package/dist/core/openspec/scan/shape.js +260 -0
  676. package/dist/core/openspec/scan/shape.js.map +1 -0
  677. package/dist/core/openspec/scan/walk.js +133 -0
  678. package/dist/core/openspec/scan/walk.js.map +1 -0
  679. package/dist/core/openspec/scan/workspace.js +71 -0
  680. package/dist/core/openspec/scan/workspace.js.map +1 -0
  681. package/dist/core/owners/codeowners.js +141 -0
  682. package/dist/core/owners/codeowners.js.map +1 -0
  683. package/dist/core/pack/features.js +120 -0
  684. package/dist/core/pack/features.js.map +1 -0
  685. package/dist/core/pack/joins.js +112 -0
  686. package/dist/core/pack/joins.js.map +1 -0
  687. package/dist/core/pack/living.js +118 -0
  688. package/dist/core/pack/living.js.map +1 -0
  689. package/dist/core/pack/pack.js +76 -0
  690. package/dist/core/pack/pack.js.map +1 -0
  691. package/dist/core/permissions/permissions.js +87 -0
  692. package/dist/core/permissions/permissions.js.map +1 -0
  693. package/dist/core/projection/api.js +84 -0
  694. package/dist/core/projection/api.js.map +1 -0
  695. package/dist/core/projection/arch-slice.js +63 -0
  696. package/dist/core/projection/arch-slice.js.map +1 -0
  697. package/dist/core/projection/events.js +34 -0
  698. package/dist/core/projection/events.js.map +1 -0
  699. package/dist/core/provenance/findings.js +208 -0
  700. package/dist/core/provenance/findings.js.map +1 -0
  701. package/dist/core/provenance/git.js +225 -0
  702. package/dist/core/provenance/git.js.map +1 -0
  703. package/dist/core/provenance/gitq/moves.js +182 -0
  704. package/dist/core/provenance/gitq/moves.js.map +1 -0
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  707. package/dist/core/provenance/sample/scope.js +238 -0
  708. package/dist/core/provenance/sample/scope.js.map +1 -0
  709. package/dist/core/provenance/sample/sections.js +61 -0
  710. package/dist/core/provenance/sample/sections.js.map +1 -0
  711. package/dist/core/provenance/sources.js +263 -0
  712. package/dist/core/provenance/sources.js.map +1 -0
  713. package/dist/core/provenance/stamp.js +232 -0
  714. package/dist/core/provenance/stamp.js.map +1 -0
  715. package/dist/core/provenance/walk.js +157 -0
  716. package/dist/core/provenance/walk.js.map +1 -0
  717. package/dist/core/repo/authored/paths.js +192 -0
  718. package/dist/core/repo/authored/paths.js.map +1 -0
  719. package/dist/core/repo/entries.js +126 -0
  720. package/dist/core/repo/entries.js.map +1 -0
  721. package/dist/core/repo/paths.js +236 -0
  722. package/dist/core/repo/paths.js.map +1 -0
  723. package/dist/core/repo/repo.js +248 -0
  724. package/dist/core/repo/repo.js.map +1 -0
  725. package/dist/core/repo/service-target.js +153 -0
  726. package/dist/core/repo/service-target.js.map +1 -0
  727. package/dist/core/repo/state.js +58 -0
  728. package/dist/core/repo/state.js.map +1 -0
  729. package/dist/core/repo/tree/find.js +52 -0
  730. package/dist/core/repo/tree/find.js.map +1 -0
  731. package/dist/core/repo/tree/fs.js +64 -0
  732. package/dist/core/repo/tree/fs.js.map +1 -0
  733. package/dist/core/repo/tree/marker.js +61 -0
  734. package/dist/core/repo/tree/marker.js.map +1 -0
  735. package/dist/core/repo/tree/views.js +172 -0
  736. package/dist/core/repo/tree/views.js.map +1 -0
  737. package/dist/core/repo/tree/walk.js +234 -0
  738. package/dist/core/repo/tree/walk.js.map +1 -0
  739. package/dist/core/results.js +99 -2
  740. package/dist/core/results.js.map +1 -1
  741. package/dist/core/scaffold/landscape.js +131 -0
  742. package/dist/core/scaffold/landscape.js.map +1 -0
  743. package/dist/core/scaffold/readme.js +84 -0
  744. package/dist/core/scaffold/readme.js.map +1 -0
  745. package/dist/core/staging/commit.js +241 -0
  746. package/dist/core/staging/commit.js.map +1 -0
  747. package/dist/core/staging/interrupted.js +96 -0
  748. package/dist/core/staging/interrupted.js.map +1 -0
  749. package/dist/core/staging/lock.js +206 -0
  750. package/dist/core/staging/lock.js.map +1 -0
  751. package/dist/core/staging/recovery/finding.js +35 -0
  752. package/dist/core/staging/recovery/finding.js.map +1 -0
  753. package/dist/core/staging/recovery/intent.js +98 -0
  754. package/dist/core/staging/recovery/intent.js.map +1 -0
  755. package/dist/core/staging/recovery/recover.js +126 -0
  756. package/dist/core/staging/recovery/recover.js.map +1 -0
  757. package/dist/core/staging/recovery/residue.js +62 -0
  758. package/dist/core/staging/recovery/residue.js.map +1 -0
  759. package/dist/core/staging/snapshot.js +202 -0
  760. package/dist/core/staging/snapshot.js.map +1 -0
  761. package/dist/core/staging/txn/forward.js +171 -0
  762. package/dist/core/staging/txn/forward.js.map +1 -0
  763. package/dist/core/staging/txn/journal.js +139 -0
  764. package/dist/core/staging/txn/journal.js.map +1 -0
  765. package/dist/core/staging/txn/transaction.js +75 -0
  766. package/dist/core/staging/txn/transaction.js.map +1 -0
  767. package/dist/core/staging/writes.js +113 -0
  768. package/dist/core/staging/writes.js.map +1 -0
  769. package/dist/core/status/actions/execution.js +49 -0
  770. package/dist/core/status/actions/execution.js.map +1 -0
  771. package/dist/core/status/contracts.js +102 -0
  772. package/dist/core/status/contracts.js.map +1 -0
  773. package/dist/core/status/feature/artifacts.js +171 -0
  774. package/dist/core/status/feature/artifacts.js.map +1 -0
  775. package/dist/core/status/feature/feature.js +207 -0
  776. package/dist/core/status/feature/feature.js.map +1 -0
  777. package/dist/core/status/feature/next.js +150 -0
  778. package/dist/core/status/feature/next.js.map +1 -0
  779. package/dist/core/status/feature/state.js +21 -0
  780. package/dist/core/status/feature/state.js.map +1 -0
  781. package/dist/core/status/fleet/fleet.js +187 -0
  782. package/dist/core/status/fleet/fleet.js.map +1 -0
  783. package/dist/core/status/fleet/next.js +207 -0
  784. package/dist/core/status/fleet/next.js.map +1 -0
  785. package/dist/core/status/interrupted.js +97 -0
  786. package/dist/core/status/interrupted.js.map +1 -0
  787. package/dist/core/status/report.js +31 -0
  788. package/dist/core/status/report.js.map +1 -0
  789. package/dist/core/status/scan.js +41 -0
  790. package/dist/core/status/scan.js.map +1 -0
  791. package/dist/core/status/verification.js +201 -0
  792. package/dist/core/status/verification.js.map +1 -0
  793. package/dist/core/usecases/capability.js +169 -0
  794. package/dist/core/usecases/capability.js.map +1 -0
  795. package/dist/core/usecases/delta/claims.js +116 -0
  796. package/dist/core/usecases/delta/claims.js.map +1 -0
  797. package/dist/core/usecases/delta/flows.js +103 -0
  798. package/dist/core/usecases/delta/flows.js.map +1 -0
  799. package/dist/core/usecases/delta/overlay.js +235 -0
  800. package/dist/core/usecases/delta/overlay.js.map +1 -0
  801. package/dist/core/usecases/fleet.js +137 -0
  802. package/dist/core/usecases/fleet.js.map +1 -0
  803. package/dist/core/usecases/operations.js +111 -0
  804. package/dist/core/usecases/operations.js.map +1 -0
  805. package/dist/core/usecases/place.js +44 -0
  806. package/dist/core/usecases/place.js.map +1 -0
  807. package/dist/core/usecases/touch.js +101 -0
  808. package/dist/core/usecases/touch.js.map +1 -0
  809. package/dist/core/verify/answers.js +173 -0
  810. package/dist/core/verify/answers.js.map +1 -0
  811. package/dist/core/verify/build.js +150 -0
  812. package/dist/core/verify/build.js.map +1 -0
  813. package/dist/core/verify/checklist.js +201 -0
  814. package/dist/core/verify/checklist.js.map +1 -0
  815. package/dist/core/verify/claims/identity.js +61 -0
  816. package/dist/core/verify/claims/identity.js.map +1 -0
  817. package/dist/core/verify/cross/diff.js +97 -0
  818. package/dist/core/verify/cross/diff.js.map +1 -0
  819. package/dist/core/verify/evidence/contract.js +169 -0
  820. package/dist/core/verify/evidence/contract.js.map +1 -0
  821. package/dist/core/verify/file.js +257 -0
  822. package/dist/core/verify/file.js.map +1 -0
  823. package/dist/core/verify/pins/lint.js +157 -0
  824. package/dist/core/verify/pins/lint.js.map +1 -0
  825. package/dist/core/verify/pins/pin.js +95 -0
  826. package/dist/core/verify/pins/pin.js.map +1 -0
  827. package/dist/core/verify/record.js +142 -0
  828. package/dist/core/verify/record.js.map +1 -0
  829. package/dist/core/verify/store/commit.js +89 -0
  830. package/dist/core/verify/store/commit.js.map +1 -0
  831. package/dist/core/verify/store/render.js +57 -0
  832. package/dist/core/verify/store/render.js.map +1 -0
  833. package/dist/core/vocabulary/health.js +91 -0
  834. package/dist/core/vocabulary/health.js.map +1 -0
  835. package/dist/core/vocabulary/issue.js +55 -0
  836. package/dist/core/vocabulary/issue.js.map +1 -0
  837. package/dist/core/vocabulary/maturity.js +145 -0
  838. package/dist/core/vocabulary/maturity.js.map +1 -0
  839. package/dist/core/{report.js → vocabulary/report.js} +30 -2
  840. package/dist/core/vocabulary/report.js.map +1 -0
  841. package/dist/core/vocabulary/steps.js +266 -0
  842. package/dist/core/vocabulary/steps.js.map +1 -0
  843. package/dist/core/workspace/discover.js +239 -0
  844. package/dist/core/workspace/discover.js.map +1 -0
  845. package/dist/core/workspace/render.js +52 -0
  846. package/dist/core/workspace/render.js.map +1 -0
  847. package/examples/README.md +189 -0
  848. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  849. package/examples/docs/architecture/capabilities.yaml +31 -0
  850. package/examples/docs/architecture/landscape.likec4 +280 -0
  851. package/examples/docs/architecture/obligations.yaml +23 -0
  852. package/examples/docs/architecture/permissions.yaml +50 -0
  853. package/examples/docs/architecture/subsystems.likec4 +11 -0
  854. package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
  855. package/examples/docs/capabilities/checkout/spec.md +55 -0
  856. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  857. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  858. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  859. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  860. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
  863. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  864. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  865. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  866. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  867. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  868. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
  869. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  870. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  871. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  872. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  873. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  874. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  875. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  876. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  877. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  878. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  879. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
  880. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  881. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  882. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  883. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  884. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  885. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  886. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  887. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  888. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  889. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  890. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  891. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  892. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  893. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  894. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  895. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  896. package/examples/docs/glossary/order.md +15 -0
  897. package/examples/docs/glossary/payments/authorization.md +14 -0
  898. package/examples/docs/likec4.config.json +9 -0
  899. package/examples/docs/loam.json +3 -0
  900. package/examples/docs/services/checkout-web/model.likec4 +109 -0
  901. package/examples/docs/services/checkout-web/spec.md +91 -0
  902. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  903. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  904. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  905. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  906. package/examples/docs/services/order-service/arch.spec.md +127 -0
  907. package/examples/docs/services/order-service/asyncapi.yaml +108 -0
  908. package/examples/docs/services/order-service/health.yaml +57 -0
  909. package/examples/docs/services/order-service/model.likec4 +138 -0
  910. package/examples/docs/services/order-service/openapi.yaml +257 -0
  911. package/examples/docs/services/order-service/runbook.md +62 -0
  912. package/examples/docs/services/order-service/spec.md +134 -0
  913. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  914. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  915. package/examples/docs/services/payment-service/arch.spec.md +73 -0
  916. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  917. package/examples/docs/services/payment-service/health.yaml +39 -0
  918. package/examples/docs/services/payment-service/model.likec4 +67 -0
  919. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  920. package/examples/docs/services/payment-service/runbook.md +37 -0
  921. package/examples/docs/services/payment-service/spec.md +88 -0
  922. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  923. package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
  924. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  925. package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
  926. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  927. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  928. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  929. package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
  930. package/examples/docs/services/platform/notification-service/health.yaml +35 -0
  931. package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
  932. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  933. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  934. package/examples/docs/services/platform/subsystem.yaml +2 -0
  935. package/examples/fleet.yaml +57 -0
  936. package/package.json +19 -6
  937. package/dist/commands/adopt.js +0 -240
  938. package/dist/commands/adopt.js.map +0 -1
  939. package/dist/commands/archive.js +0 -1313
  940. package/dist/commands/archive.js.map +0 -1
  941. package/dist/commands/delta.js +0 -388
  942. package/dist/commands/delta.js.map +0 -1
  943. package/dist/commands/docs-repo-gate.js.map +0 -1
  944. package/dist/commands/format.js +0 -17
  945. package/dist/commands/format.js.map +0 -1
  946. package/dist/commands/gherkin.js +0 -309
  947. package/dist/commands/gherkin.js.map +0 -1
  948. package/dist/commands/init.js.map +0 -1
  949. package/dist/commands/list.js +0 -291
  950. package/dist/commands/list.js.map +0 -1
  951. package/dist/commands/migrate-openspec.js +0 -950
  952. package/dist/commands/migrate-openspec.js.map +0 -1
  953. package/dist/commands/new.js +0 -413
  954. package/dist/commands/new.js.map +0 -1
  955. package/dist/commands/rebase.js +0 -356
  956. package/dist/commands/rebase.js.map +0 -1
  957. package/dist/commands/show.js.map +0 -1
  958. package/dist/commands/status.js +0 -254
  959. package/dist/commands/status.js.map +0 -1
  960. package/dist/commands/unarchive.js.map +0 -1
  961. package/dist/commands/validate.js +0 -1591
  962. package/dist/commands/validate.js.map +0 -1
  963. package/dist/commands/verify.js +0 -775
  964. package/dist/commands/verify.js.map +0 -1
  965. package/dist/commands/vouch.js +0 -343
  966. package/dist/commands/vouch.js.map +0 -1
  967. package/dist/core/agent.js +0 -2065
  968. package/dist/core/agent.js.map +0 -1
  969. package/dist/core/agents-stamp.js +0 -68
  970. package/dist/core/agents-stamp.js.map +0 -1
  971. package/dist/core/arch.js +0 -130
  972. package/dist/core/arch.js.map +0 -1
  973. package/dist/core/brief.js +0 -733
  974. package/dist/core/brief.js.map +0 -1
  975. package/dist/core/coherence.js +0 -577
  976. package/dist/core/coherence.js.map +0 -1
  977. package/dist/core/concurrency.js.map +0 -1
  978. package/dist/core/config.js.map +0 -1
  979. package/dist/core/delta.js +0 -476
  980. package/dist/core/delta.js.map +0 -1
  981. package/dist/core/dependencies.js +0 -356
  982. package/dist/core/dependencies.js.map +0 -1
  983. package/dist/core/doctor.js +0 -559
  984. package/dist/core/doctor.js.map +0 -1
  985. package/dist/core/document-bytes.js.map +0 -1
  986. package/dist/core/explore.js.map +0 -1
  987. package/dist/core/frontmatter.js.map +0 -1
  988. package/dist/core/gherkin.js +0 -463
  989. package/dist/core/gherkin.js.map +0 -1
  990. package/dist/core/health.js +0 -67
  991. package/dist/core/health.js.map +0 -1
  992. package/dist/core/ids.js +0 -122
  993. package/dist/core/ids.js.map +0 -1
  994. package/dist/core/issue.js +0 -9
  995. package/dist/core/issue.js.map +0 -1
  996. package/dist/core/json.js +0 -74
  997. package/dist/core/json.js.map +0 -1
  998. package/dist/core/likec4.js +0 -479
  999. package/dist/core/likec4.js.map +0 -1
  1000. package/dist/core/maturity.js +0 -66
  1001. package/dist/core/maturity.js.map +0 -1
  1002. package/dist/core/openapi-merge.js +0 -552
  1003. package/dist/core/openapi-merge.js.map +0 -1
  1004. package/dist/core/openapi.js.map +0 -1
  1005. package/dist/core/openspec-inventory.js +0 -1440
  1006. package/dist/core/openspec-inventory.js.map +0 -1
  1007. package/dist/core/path-safety.js.map +0 -1
  1008. package/dist/core/provenance.js +0 -720
  1009. package/dist/core/provenance.js.map +0 -1
  1010. package/dist/core/records.js.map +0 -1
  1011. package/dist/core/repo.js +0 -436
  1012. package/dist/core/repo.js.map +0 -1
  1013. package/dist/core/report.js.map +0 -1
  1014. package/dist/core/spec.js +0 -481
  1015. package/dist/core/spec.js.map +0 -1
  1016. package/dist/core/staging.js +0 -890
  1017. package/dist/core/staging.js.map +0 -1
  1018. package/dist/core/status.js +0 -1104
  1019. package/dist/core/status.js.map +0 -1
  1020. package/dist/core/steps.js +0 -72
  1021. package/dist/core/steps.js.map +0 -1
  1022. package/dist/core/verify.js +0 -807
  1023. package/dist/core/verify.js.map +0 -1
  1024. package/dist/core/version.js.map +0 -1
  1025. /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
  1026. /package/dist/core/{records.js → kernel/records.js} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklist.js","sourceRoot":"","sources":["../../../src/core/verify/checklist.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The questions: what a feature's own artifacts promised, derived mechanically.\n *\n * The original plan was to extract C4 from the built code and diff it against\n * the delta. There is no such extractor and there will not be one — nothing\n * deterministic reads a service and says what its architecture MEANS, and two\n * generated models of the same code disagree in wording every run, so the diff\n * would flap and be switched off inside a week.\n *\n * What survives of the idea is the part that was always deterministic, and it\n * is this module: a feature says this service will exist, it will expose this\n * operation, that service will call it, this scenario will have a test. The\n * list comes from the same files `validate` already reads.\n *\n * The claim ids are a function of the claim and of nothing else — so two runs\n * are diffable, reordering the delta renames nothing, and rewording a scenario\n * DOES rename its claim, because an answer about text nobody wrote must not\n * carry over.\n *\n * `scenarioBodyHash` lives in `core/gherkin/digest.ts` — one recipe shared\n * with `core/gherkin/stamp.ts`, which stamps the same digest as a tag on every\n * generated scenario so `--results` can match a cucumber report back to a\n * claim. A second spelling of the hash would silently stop every scenario\n * claim from being answerable by a run.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { readAsyncapi } from \"../asyncapi/read.js\";\nimport { type Elem } from \"../c4/likec4.js\";\nimport { elementService, serviceResolver } from \"../c4/resolve/service.js\";\nimport { ACTOR_KINDS } from \"../vocabulary/maturity.js\";\nimport { operationIds, operations } from \"../openapi/doc.js\";\nimport { featurePaths, featureSpecPaths } from \"../repo/paths.js\";\nimport { locateServicePaths } from \"../repo/service-target.js\";\nimport { featureSpecServices } from \"../repo/repo.js\";\nimport { enumeratedServiceIds } from \"../repo/service-target.js\";\nimport { FleetContext } from \"../fleet-context.js\";\nimport { parseRequirements } from \"../document/parse.js\";\nimport { scenarioBodyHash } from \"../gherkin/digest.js\";\nimport type { DocsDir, FeatureDir } from \"../kernel/ids/dirs.js\";\n// The kind vocabulary and both hash recipes live in ./claims/identity.ts —\n// one module for everything that decides whether two runs ask the same\n// question, and this one for how the questions are derived.\nimport {\n checklistDigest,\n claimId,\n DIGEST_LENGTH,\n ID_LENGTH,\n type ClaimKind,\n} from \"./claims/identity.js\";\n\nexport interface Claim {\n /** `<kind>-<8 hex>` — stable for the life of the claim. See `claimId`. */\n id: string;\n kind: ClaimKind;\n /** The service whose code answers this. A caller's claim is filed under the caller. */\n subject: string;\n /** The claim in one line, answerable without reading the feature's files. */\n claim: string;\n /**\n * `scenario.tested` only: the first {@link DIGEST_LENGTH} hex of the\n * scenario's body hash — the exact digest `loam gherkin` stamps as\n * `@loam-digest-…`, which is what a cucumber report scenario carries and\n * what `--results` matches on. Absent on every other kind.\n */\n digest?: string;\n /**\n * `api.exposes` only: the operationId the claim asserts, structurally — the\n * join key `--contract-results` matches a contract report's entries on,\n * exactly as `digest` is `--results`'s. Never parsed back out of the claim\n * text, which is prose and may be reworded. Absent on every other kind.\n */\n operation?: string;\n /**\n * The literal string the claim asserts of the cited artifact — the\n * operationId for `api.exposes`, the message name for `event.declares`, the\n * edge's op for `c4.calls` — carried structurally so evidence pins\n * (`./pins/pin.ts`) can stamp it at record time and the read side never\n * parses it back out of claim prose. A separate field from `operation` on\n * purpose: `contestedOperations` filters on `operation !== undefined` and\n * must not start seeing `c4.calls` claims. Absent where a claim asserts no\n * literal (`service.exists`, `scenario.tested`).\n */\n token?: string;\n}\n\nexport interface Checklist {\n feature: string;\n claims: Claim[];\n /** A digest of the claim id SET — what says a record still answers this feature. */\n digest: string;\n}\n\n/**\n * Derive the checklist from a feature's own artifacts. No code is read here and\n * none should be: the whole design rests on the questions being computed from\n * documents that do not change between runs.\n */\nexport async function featureChecklist(\n docsDir: DocsDir,\n featureDir: FeatureDir,\n featureId: string,\n fleet?: FleetContext,\n): Promise<Checklist> {\n // The per-service loop below resolves living contracts through the\n // enumeration twice per service; without a shared context each of those is\n // a full fleet walk, so deriving one checklist cost O(services²) reads. A\n // caller-supplied context is used when given; otherwise one is created for\n // this derivation alone — the loop still pays a single walk either way.\n const ctx = fleet ?? new FleetContext();\n const seen = new Map<string, number>();\n const claim = (kind: ClaimKind, subject: string, parts: string[], text: string): Claim => ({\n id: claimId(featureId, kind, parts, seen),\n kind,\n subject,\n claim: text,\n });\n\n const exists: Claim[] = [];\n const exposes: Claim[] = [];\n const declares: Claim[] = [];\n const calls: Claim[] = [];\n const scenarios: Claim[] = [];\n\n const specServices = await featureSpecServices(featureDir, ctx);\n\n // Architecture — what the delta promised the fleet would look like. Loaded\n // through the context rather than a bare parse, so a caller that derives\n // several checklists in one invocation (`loam gate`'s verification check,\n // the fleet forms) shares one parse per delta — and a batch prefetch\n // (`FleetContext.prefetchLikeC4`) genuinely seeds this load.\n const deltaPath = featurePaths(featureDir).delta;\n if (existsSync(deltaPath)) {\n const res = await ctx.loadLikeC4(deltaPath);\n // A delta nobody can parse promises nothing checkable. `validate` already\n // reports it; inventing claims out of a broken document would only add noise.\n if (res.errors.length === 0) {\n const elements: Elem[] = res.elements;\n for (const e of elements) {\n if (!e.tags.includes(featureId)) continue;\n // A dotted id is a container INSIDE a service, and an actor is nobody's\n // repository. Neither is a service that has to exist.\n if (e.id.includes(\".\") || ACTOR_KINDS.has(e.kind.toLowerCase())) continue;\n const svc = elementService(e);\n exists.push(claim(\"service.exists\", svc, [svc], `service '${svc}' exists`));\n }\n // The enumerated fleet — `services/` plus this feature's own `specs/`\n // directories, the only place a service the feature INTRODUCES has a\n // directory at all — rides into the resolver so a claim about an edge\n // drawn into a modelled container names the service that owns it. A\n // claim against a service called \"api\" that has never existed is one no\n // evidence in any repository could ever answer, and the fleet half alone\n // still derived exactly that claim for an introduced service's own\n // container. Unenumerable services/ degrades to the feature's names.\n const svcOf = serviceResolver(\n elements,\n new Set<string>([...(await enumeratedServiceIds(docsDir, ctx)), ...specServices]),\n );\n for (const r of res.relationships) {\n // Untagged edges are context for the diagram; an edge with no operation\n // names nothing specific enough to look for in the code.\n if (!r.tags.includes(featureId) || r.op === undefined) continue;\n const from = svcOf(r.source);\n const to = svcOf(r.target);\n calls.push({\n ...claim(\"c4.calls\", from, [from, to, r.op], `${from} calls '${r.op}' on ${to}`),\n // The same string as the provider's api.exposes token, scanned in the\n // CALLER's cited file — a call site plausibly spells the operationId.\n token: r.op,\n });\n }\n }\n }\n\n for (const svc of specServices) {\n const paths = featureSpecPaths(featureDir, svc);\n\n // Contract — only what is NEW. A delta's openapi.yaml is a whole document,\n // not a patch, so authors restate the living API inside it; asking whether a\n // service still exposes what it already exposed is noise.\n const featOps = (await operations(paths.openapi))\n .filter((operation) => !operation.remove)\n .map((operation) => operation.id);\n if (featOps.length > 0) {\n const living = new Set(await operationIds((await locateServicePaths(docsDir, svc, ctx)).openapi));\n for (const op of featOps) {\n if (living.has(op)) continue;\n exposes.push({\n ...claim(\"api.exposes\", svc, [svc, op], `${svc} exposes operationId '${op}'`),\n operation: op,\n token: op,\n });\n }\n }\n\n // Events — the same NEW-only discipline on the async axis: a delta's\n // asyncapi.yaml is a complete document too, so what the living contract\n // already sends or receives is restatement, not a promise. Removals are\n // not questions either — the reader already keeps marked declarations out\n // of the sent/received sets — and an unreadable delta promises nothing\n // checkable, exactly like the broken C4 delta above.\n const events = await readAsyncapi(paths.asyncapi);\n if (events.sent.length > 0 || events.received.length > 0) {\n const living = await readAsyncapi((await locateServicePaths(docsDir, svc, ctx)).asyncapi);\n const directions = [\n { direction: \"sends\", feat: events.sent, known: new Set(living.sent) },\n { direction: \"receives\", feat: events.received, known: new Set(living.received) },\n ] as const;\n for (const d of directions) {\n for (const name of d.feat) {\n if (d.known.has(name)) continue;\n declares.push({\n ...claim(\n \"event.declares\",\n svc,\n [svc, d.direction, name],\n `${svc} declares it ${d.direction} message '${name}'`,\n ),\n token: name,\n });\n }\n }\n }\n\n // Behaviour — the scenarios of the requirements this feature CHANGES. A BASE\n // requirement is the living state quoted inside the delta, and a REMOVED one\n // is being retired: neither is work anybody has to have done.\n if (existsSync(paths.spec)) {\n for (const r of parseRequirements(await readFile(paths.spec, \"utf8\"))) {\n if (r.kind === \"BASE\" || r.kind === \"REMOVED\") continue;\n for (const s of r.scenarios) {\n const body = scenarioBodyHash(svc, s.lines);\n scenarios.push({\n ...claim(\n \"scenario.tested\",\n svc,\n [svc, r.id ?? r.name, s.name, body.slice(0, ID_LENGTH)],\n `scenario '${s.name}' of requirement '${r.name}' (${svc}) is covered by a test`,\n ),\n digest: body.slice(0, DIGEST_LENGTH),\n });\n }\n }\n }\n\n // The architecture spec axis, same walk: an arch scenario is a promise like\n // any other — the outbox test nobody was going to write IS the point of the\n // axis. The source file rides in the id tuple AND in the body hash itself\n // (two axes are two namespaces: identically-worded scenarios must stay two\n // questions, and the axis-salted digest is what keeps a business-only test\n // run from answering the arch claim) and in the claim text, so the\n // answering agent knows it is being asked for an integration/ops test, not\n // an acceptance test.\n if (existsSync(paths.archSpec)) {\n for (const r of parseRequirements(await readFile(paths.archSpec, \"utf8\"))) {\n if (r.kind === \"BASE\" || r.kind === \"REMOVED\") continue;\n for (const s of r.scenarios) {\n const body = scenarioBodyHash(svc, s.lines, \"arch\");\n scenarios.push({\n ...claim(\n \"scenario.tested\",\n svc,\n [svc, \"arch.spec.md\", r.id ?? r.name, s.name, body.slice(0, ID_LENGTH)],\n `scenario '${s.name}' of arch requirement '${r.name}' (${svc}, arch.spec.md) is covered by a test`,\n ),\n digest: body.slice(0, DIGEST_LENGTH),\n });\n }\n }\n }\n }\n\n const claims = [...exists, ...exposes, ...declares, ...calls, ...scenarios];\n return { feature: featureId, claims, digest: checklistDigest(claims.map((c) => c.id)) };\n}\n"]}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * What a claim is about, and what makes it the same claim next run: the kind
3
+ * vocabulary and the two hash recipes. Moved out of `../checklist.ts` when the
4
+ * `operation` join key pushed the derivation module over the line limit — the
5
+ * seam was already in that file's own header, which discusses what a claim's
6
+ * id is a function of apart from how the questions are derived. The kinds live
7
+ * beside the id recipe rather than beside the derivation because the id STARTS
8
+ * with the kind: the two are one identity, and a diff to this module is a diff
9
+ * to every record in the fleet, which is exactly why it holds nothing else.
10
+ */
11
+ import { createHash } from "node:crypto";
12
+ /**
13
+ * What a claim is about. The order is the order the checklist comes back in,
14
+ * and it reads as the story of the feature: the service exists, it exposes its
15
+ * operations, it declares its messages, the calls into it are wired, the
16
+ * behaviour is tested.
17
+ */
18
+ export const CLAIM_KINDS = ["service.exists", "api.exposes", "event.declares", "c4.calls", "scenario.tested"];
19
+ /**
20
+ * How much of the sha256 goes into an id, and into a digest — the checklist's,
21
+ * and a scenario claim's runner-matching one, which is deliberately the same
22
+ * 16 hex `loam gherkin` stamps (its GHERKIN_DIGEST_LENGTH): the tag in a
23
+ * cucumber report and the digest on a claim must be the same string.
24
+ */
25
+ export const ID_LENGTH = 8;
26
+ export const DIGEST_LENGTH = 16;
27
+ /**
28
+ * A claim's identity: a hash of what it says, and nothing about how it was
29
+ * produced.
30
+ *
31
+ * The feature id is part of it so an answers file for one feature can never
32
+ * validate against another. Two claims that really are identical (the same
33
+ * scenario name twice under one requirement) are distinguished by occurrence, in
34
+ * document order — they are still two questions, and answering one must not
35
+ * answer the other.
36
+ *
37
+ * The hash is short because the claim text sits next to it everywhere it is
38
+ * shown; it identifies a question, it does not authenticate one.
39
+ */
40
+ export function claimId(featureId, kind, parts, seen) {
41
+ // NUL-joined so no claim's own text can spell another claim's tuple by
42
+ // containing the separator: ['a b','c'] and ['a','b c'] stay two questions.
43
+ const tuple = [featureId, kind, ...parts].join("\u0000");
44
+ const n = (seen.get(tuple) ?? 0) + 1;
45
+ seen.set(tuple, n);
46
+ const canonical = n === 1 ? tuple : `${tuple}\u0000#${n}`;
47
+ return `${kind}-${createHash("sha256").update(canonical).digest("hex").slice(0, ID_LENGTH)}`;
48
+ }
49
+ /**
50
+ * A digest of the claim id SET — sorted, so reordering the artifacts does not
51
+ * make a record look stale. It changes when a claim is added, removed or
52
+ * reworded, which is exactly when an answer set stops describing the feature.
53
+ * Takes the ids rather than the claims so this module never has to import the
54
+ * `Claim` shape the derivation declares — the recipe is over ids and nothing
55
+ * else, and the signature now says so.
56
+ */
57
+ export function checklistDigest(ids) {
58
+ const sorted = [...ids].sort();
59
+ return createHash("sha256").update(sorted.join("\n")).digest("hex").slice(0, DIGEST_LENGTH);
60
+ }
61
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../../../src/core/verify/claims/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,EAAE,UAAU,EAAE,iBAAiB,CAAU,CAAC;AAGvH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC;AAC3B,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAEhC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,OAAO,CACrB,SAAiB,EACjB,IAAe,EACf,KAAe,EACf,IAAyB;IAEzB,uEAAuE;IACvE,4EAA4E;IAC5E,MAAM,KAAK,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACnB,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,UAAU,CAAC,EAAE,CAAC;IAC1D,OAAO,GAAG,IAAI,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;AAC/F,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,GAAsB;IACpD,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;AAC9F,CAAC","sourcesContent":["/**\n * What a claim is about, and what makes it the same claim next run: the kind\n * vocabulary and the two hash recipes. Moved out of `../checklist.ts` when the\n * `operation` join key pushed the derivation module over the line limit — the\n * seam was already in that file's own header, which discusses what a claim's\n * id is a function of apart from how the questions are derived. The kinds live\n * beside the id recipe rather than beside the derivation because the id STARTS\n * with the kind: the two are one identity, and a diff to this module is a diff\n * to every record in the fleet, which is exactly why it holds nothing else.\n */\nimport { createHash } from \"node:crypto\";\n\n/**\n * What a claim is about. The order is the order the checklist comes back in,\n * and it reads as the story of the feature: the service exists, it exposes its\n * operations, it declares its messages, the calls into it are wired, the\n * behaviour is tested.\n */\nexport const CLAIM_KINDS = [\"service.exists\", \"api.exposes\", \"event.declares\", \"c4.calls\", \"scenario.tested\"] as const;\nexport type ClaimKind = (typeof CLAIM_KINDS)[number];\n\n/**\n * How much of the sha256 goes into an id, and into a digest — the checklist's,\n * and a scenario claim's runner-matching one, which is deliberately the same\n * 16 hex `loam gherkin` stamps (its GHERKIN_DIGEST_LENGTH): the tag in a\n * cucumber report and the digest on a claim must be the same string.\n */\nexport const ID_LENGTH = 8;\nexport const DIGEST_LENGTH = 16;\n\n/**\n * A claim's identity: a hash of what it says, and nothing about how it was\n * produced.\n *\n * The feature id is part of it so an answers file for one feature can never\n * validate against another. Two claims that really are identical (the same\n * scenario name twice under one requirement) are distinguished by occurrence, in\n * document order — they are still two questions, and answering one must not\n * answer the other.\n *\n * The hash is short because the claim text sits next to it everywhere it is\n * shown; it identifies a question, it does not authenticate one.\n */\nexport function claimId(\n featureId: string,\n kind: ClaimKind,\n parts: string[],\n seen: Map<string, number>,\n): string {\n // NUL-joined so no claim's own text can spell another claim's tuple by\n // containing the separator: ['a b','c'] and ['a','b c'] stay two questions.\n const tuple = [featureId, kind, ...parts].join(\"\\u0000\");\n const n = (seen.get(tuple) ?? 0) + 1;\n seen.set(tuple, n);\n const canonical = n === 1 ? tuple : `${tuple}\\u0000#${n}`;\n return `${kind}-${createHash(\"sha256\").update(canonical).digest(\"hex\").slice(0, ID_LENGTH)}`;\n}\n\n/**\n * A digest of the claim id SET — sorted, so reordering the artifacts does not\n * make a record look stale. It changes when a claim is added, removed or\n * reworded, which is exactly when an answer set stops describing the feature.\n * Takes the ids rather than the claims so this module never has to import the\n * `Claim` shape the derivation declares — the recipe is over ids and nothing\n * else, and the signature now says so.\n */\nexport function checklistDigest(ids: readonly string[]): string {\n const sorted = [...ids].sort();\n return createHash(\"sha256\").update(sorted.join(\"\\n\")).digest(\"hex\").slice(0, DIGEST_LENGTH);\n}\n"]}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * The FILE a piece of evidence cites: one trailing `:<line>` or
3
+ * `:<line>-<line>` suffix stripped, nothing else judged. Mechanical string
4
+ * surgery on purpose — evidence is prose the answerer wrote, and any deeper
5
+ * reading (resolving against a tree, normalizing separators) would turn the
6
+ * disjointness signal into an opinion about paths instead of a fact about
7
+ * citations.
8
+ */
9
+ function citedFile(evidence) {
10
+ return evidence.replace(/:\d+(-\d+)?$/, "");
11
+ }
12
+ function side(answer) {
13
+ return {
14
+ verdict: answer.verdict,
15
+ evidence: answer.evidence,
16
+ ...(answer.note === undefined ? {} : { note: answer.note }),
17
+ };
18
+ }
19
+ function crossRow(claim, a, b) {
20
+ const base = {
21
+ id: claim.id,
22
+ kind: claim.kind,
23
+ subject: claim.subject,
24
+ claim: claim.claim,
25
+ a: side(a),
26
+ b: side(b),
27
+ };
28
+ if (a.verdict !== b.verdict)
29
+ return { ...base, code: "cross.disagree" };
30
+ if (a.verdict === "confirmed") {
31
+ // Both confirmed, so both cite at least one entry (`checkAnswers` refuses
32
+ // an evidenced-nothing confirmation) — disjoint therefore means "looked in
33
+ // different places and agreed anyway", never "nobody cited anything".
34
+ const files = new Set(a.evidence.map(citedFile));
35
+ const disjoint = !b.evidence.some((entry) => files.has(citedFile(entry)));
36
+ return { ...base, code: "cross.agree-confirmed", ...(disjoint ? { evidenceDisjoint: true } : {}) };
37
+ }
38
+ return { ...base, code: "cross.agree-unconfirmed" };
39
+ }
40
+ /**
41
+ * Join two validated answer sets over the claims they both answered.
42
+ *
43
+ * Both sets must have come out of `checkAnswers` over THIS `claims` array,
44
+ * which refuses any set that does not answer every claim exactly once — so
45
+ * there is deliberately no missing-answer branch in the result shape. The
46
+ * guard below still fails closed on a caller that skipped validation: a
47
+ * silent skip would report "no disagreement" about a claim nobody compared,
48
+ * which is the one lie this module exists to prevent.
49
+ */
50
+ export function crossExamine(claims, a, b) {
51
+ const byIdA = new Map(a.map((answer) => [answer.id, answer]));
52
+ const byIdB = new Map(b.map((answer) => [answer.id, answer]));
53
+ const rows = claims.map((claim) => {
54
+ const answerA = byIdA.get(claim.id);
55
+ const answerB = byIdB.get(claim.id);
56
+ if (answerA === undefined || answerB === undefined) {
57
+ throw new Error(`crossExamine: claim ${claim.id} has no answer in the ${answerA === undefined ? "first" : "second"} set — ` +
58
+ "validate both sets with checkAnswers over the same claims before joining them");
59
+ }
60
+ return crossRow(claim, answerA, answerB);
61
+ });
62
+ const of = (code) => rows.filter((row) => row.code === code).length;
63
+ const disagreements = rows.filter((row) => row.code === "cross.disagree");
64
+ return {
65
+ rows,
66
+ summary: {
67
+ claims: rows.length,
68
+ agreeConfirmed: of("cross.agree-confirmed"),
69
+ agreeUnconfirmed: of("cross.agree-unconfirmed"),
70
+ disagree: disagreements.length,
71
+ evidenceDisjoint: rows.filter((row) => row.code === "cross.agree-confirmed" && row.evidenceDisjoint === true)
72
+ .length,
73
+ },
74
+ disagreements,
75
+ };
76
+ }
77
+ /**
78
+ * The one notice this lens raises: agreements whose cited file sets share no
79
+ * path. Second in the reading order after the disagreements, because it is
80
+ * the shape correlated agreement takes when both agents guessed — each found
81
+ * something plausible somewhere, and nothing says they found the same thing.
82
+ */
83
+ export function disjointNotice(rows) {
84
+ const ids = rows
85
+ .filter((row) => row.code === "cross.agree-confirmed" && row.evidenceDisjoint === true)
86
+ .map((row) => row.id);
87
+ if (ids.length === 0)
88
+ return null;
89
+ return {
90
+ code: "cross.evidence-disjoint",
91
+ severity: "warn",
92
+ message: `${ids.length} agreed-confirmed claim(s) cite non-overlapping files: ${ids.join(", ")}. ` +
93
+ "Two agents agreeing from different evidence is the second thing to read, after the disagreements.",
94
+ claims: ids,
95
+ };
96
+ }
97
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../../src/core/verify/cross/diff.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Mechanical cross-examination of two blind answer sets over one checklist.\n *\n * The doctrine lives here because every surface reads it from this module:\n * agreement is a review-ranking signal, never a verdict. The two sets almost\n * always come from two contexts of the same model, so their agreeing is\n * correlated evidence — which is why this module deliberately imports nothing\n * from `../record.ts`'s verdict machinery (`verificationVerdict`,\n * `tallyRecord`): a cross-examination has no `verified`, no `attested`, and\n * can never upgrade either. What it ranks is where a human reads first — the\n * disagreements, then the agreements whose cited files do not overlap.\n *\n * The join is by claim id ONLY. The ids are deterministic functions of the\n * claims (`../claims/identity.ts`), which is the whole mechanism: two agents\n * who never saw each other's work still answered the same question under the\n * same key, so their answers are mechanically joinable — where fuzzy-matching\n * claim TEXT would make \"the same question\" an opinion about wording.\n */\nimport type { Answer, Verdict } from \"../answers.js\";\nimport type { Claim } from \"../checklist.js\";\nimport type { ClaimKind } from \"../claims/identity.js\";\nimport type { VerifyNotice } from \"../record.js\";\n\n/**\n * One side's answer, as the cross-examination reports it. Deliberately\n * narrower than {@link Answer}: `answered_by` is always `agent` under a diff\n * (both sets validate through `checkAnswers`' agent path, no report in\n * sight), and `evidence_pins` never rides through — a pin is loam's own\n * stamp, absent from `checkAnswers`' output by construction, and a diff of\n * caller-written files must not launder one into a payload.\n */\nexport interface CrossAnswer {\n verdict: Verdict;\n evidence: string[];\n note?: string;\n}\n\ninterface CrossBase {\n id: string;\n kind: ClaimKind;\n subject: string;\n claim: string;\n a: CrossAnswer;\n b: CrossAnswer;\n}\n\n/**\n * One claim, both answers, and what their comparison is. A union rather than\n * an optional-field record so `evidenceDisjoint` is not constructible on the\n * arms it means nothing for: two agents disagreeing cite different things by\n * definition, and two unconfirmed answers cite nothing.\n */\nexport type CrossClaim =\n | (CrossBase & { code: \"cross.agree-confirmed\"; evidenceDisjoint?: true })\n | (CrossBase & { code: \"cross.agree-unconfirmed\" })\n | (CrossBase & { code: \"cross.disagree\" });\n\nexport type CrossCode = CrossClaim[\"code\"];\n\nexport interface CrossExamination {\n /** Checklist order — the order the questions were asked, whatever either agent did. */\n rows: CrossClaim[];\n summary: {\n claims: number;\n agreeConfirmed: number;\n agreeUnconfirmed: number;\n disagree: number;\n evidenceDisjoint: number;\n };\n /** The `cross.disagree` rows again, first-class: they are what a reader is for. */\n disagreements: CrossClaim[];\n}\n\n/**\n * The FILE a piece of evidence cites: one trailing `:<line>` or\n * `:<line>-<line>` suffix stripped, nothing else judged. Mechanical string\n * surgery on purpose — evidence is prose the answerer wrote, and any deeper\n * reading (resolving against a tree, normalizing separators) would turn the\n * disjointness signal into an opinion about paths instead of a fact about\n * citations.\n */\nfunction citedFile(evidence: string): string {\n return evidence.replace(/:\\d+(-\\d+)?$/, \"\");\n}\n\nfunction side(answer: Answer): CrossAnswer {\n return {\n verdict: answer.verdict,\n evidence: answer.evidence,\n ...(answer.note === undefined ? {} : { note: answer.note }),\n };\n}\n\nfunction crossRow(claim: Claim, a: Answer, b: Answer): CrossClaim {\n const base: CrossBase = {\n id: claim.id,\n kind: claim.kind,\n subject: claim.subject,\n claim: claim.claim,\n a: side(a),\n b: side(b),\n };\n if (a.verdict !== b.verdict) return { ...base, code: \"cross.disagree\" };\n if (a.verdict === \"confirmed\") {\n // Both confirmed, so both cite at least one entry (`checkAnswers` refuses\n // an evidenced-nothing confirmation) — disjoint therefore means \"looked in\n // different places and agreed anyway\", never \"nobody cited anything\".\n const files = new Set(a.evidence.map(citedFile));\n const disjoint = !b.evidence.some((entry) => files.has(citedFile(entry)));\n return { ...base, code: \"cross.agree-confirmed\", ...(disjoint ? { evidenceDisjoint: true as const } : {}) };\n }\n return { ...base, code: \"cross.agree-unconfirmed\" };\n}\n\n/**\n * Join two validated answer sets over the claims they both answered.\n *\n * Both sets must have come out of `checkAnswers` over THIS `claims` array,\n * which refuses any set that does not answer every claim exactly once — so\n * there is deliberately no missing-answer branch in the result shape. The\n * guard below still fails closed on a caller that skipped validation: a\n * silent skip would report \"no disagreement\" about a claim nobody compared,\n * which is the one lie this module exists to prevent.\n */\nexport function crossExamine(claims: Claim[], a: Answer[], b: Answer[]): CrossExamination {\n const byIdA = new Map(a.map((answer) => [answer.id, answer]));\n const byIdB = new Map(b.map((answer) => [answer.id, answer]));\n const rows = claims.map((claim) => {\n const answerA = byIdA.get(claim.id);\n const answerB = byIdB.get(claim.id);\n if (answerA === undefined || answerB === undefined) {\n throw new Error(\n `crossExamine: claim ${claim.id} has no answer in the ${answerA === undefined ? \"first\" : \"second\"} set — ` +\n \"validate both sets with checkAnswers over the same claims before joining them\",\n );\n }\n return crossRow(claim, answerA, answerB);\n });\n const of = (code: CrossCode): number => rows.filter((row) => row.code === code).length;\n const disagreements = rows.filter((row) => row.code === \"cross.disagree\");\n return {\n rows,\n summary: {\n claims: rows.length,\n agreeConfirmed: of(\"cross.agree-confirmed\"),\n agreeUnconfirmed: of(\"cross.agree-unconfirmed\"),\n disagree: disagreements.length,\n evidenceDisjoint: rows.filter((row) => row.code === \"cross.agree-confirmed\" && row.evidenceDisjoint === true)\n .length,\n },\n disagreements,\n };\n}\n\n/**\n * The one notice this lens raises: agreements whose cited file sets share no\n * path. Second in the reading order after the disagreements, because it is\n * the shape correlated agreement takes when both agents guessed — each found\n * something plausible somewhere, and nothing says they found the same thing.\n */\nexport function disjointNotice(rows: readonly CrossClaim[]): VerifyNotice | null {\n const ids = rows\n .filter((row) => row.code === \"cross.agree-confirmed\" && row.evidenceDisjoint === true)\n .map((row) => row.id);\n if (ids.length === 0) return null;\n return {\n code: \"cross.evidence-disjoint\",\n severity: \"warn\",\n message:\n `${ids.length} agreed-confirmed claim(s) cite non-overlapping files: ${ids.join(\", \")}. ` +\n \"Two agents agreeing from different evidence is the second thing to read, after the disagreements.\",\n claims: ids,\n };\n}\n"]}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * `loam verify --contract-results` — an API contract-test report as the answer
3
+ * sheet for `api.exposes` claims.
4
+ *
5
+ * The accepted shape is loam's own documented one (SCHEMA.md, "Contract-test
6
+ * reports"): `{"loamContractReport": 1, "results": [{"operationId": "…",
7
+ * "status": "passed"}]}`. It is deliberately a shape tools EMIT INTO rather
8
+ * than a vendor format loam parses, because no surveyed vendor format carries
9
+ * both halves of what confirming needs — an unambiguous executed-AND-passed
10
+ * status and a deterministic operation join key. Specmatic's JSON coverage
11
+ * report was the v1 candidate and is declined by name: its `coverageStatus:
12
+ * "covered"` means exercised, not passed (a red run still writes "covered"),
13
+ * so an adapter over it would confirm exactly what a failing suite refuted.
14
+ *
15
+ * The operationId is the ONLY identity, matched against the structured
16
+ * `operation` a claim carries (`../checklist.ts`). It is half an identity, and
17
+ * the design leans on the missing half being supplied by scope: an operationId
18
+ * is unique within ONE contract document, not across a fleet, and a report
19
+ * entry names no service — so when more than one service on the handed-in
20
+ * checklist exposes the same operationId, the claims are refused rather than
21
+ * answered ({@link contestedOperations}), and `--service` is what gives a
22
+ * contract report an owner, exactly as it is for a contested scenario digest.
23
+ * Within one service's claims the match is exact, and renaming an operation
24
+ * renames its claim, so rewording cannot carry an answer over. Names and free
25
+ * text match nothing.
26
+ *
27
+ * Parsing is strict where the cucumber reader is tolerant, and the asymmetry
28
+ * is deliberate: a cucumber report is another tool's file full of legitimate
29
+ * entries loam has no business judging, while this shape exists for exactly
30
+ * one purpose, so an entry that cannot be matched is a malformed report, not
31
+ * scenery. A file that is recognizably not this shape refuses rather than
32
+ * quietly answering every claim "not exercised" — an unparseable report never
33
+ * silently answers zero claims as if none matched.
34
+ */
35
+ import { isRecord } from "../../kernel/records.js";
36
+ import {} from "../answers.js";
37
+ import {} from "../checklist.js";
38
+ /** The marker key that makes a JSON document this shape, and the version this loam reads. */
39
+ export const CONTRACT_REPORT_MARKER = "loamContractReport";
40
+ export const CONTRACT_REPORT_VERSION = 1;
41
+ /**
42
+ * Read a parsed JSON document down to its runs. `reportName` is how the caller
43
+ * spelled the file, for the refusal message; core never prints, so a refusal
44
+ * is data for the command to fail with (`answers-unreadable`).
45
+ */
46
+ export function readContractReport(doc, reportName) {
47
+ const shape = `{"${CONTRACT_REPORT_MARKER}": ${CONTRACT_REPORT_VERSION}, "results": [{"operationId": "…", "status": "passed"}]}`;
48
+ if (!isRecord(doc) || !(CONTRACT_REPORT_MARKER in doc)) {
49
+ return {
50
+ ok: false,
51
+ message: `${reportName} is not a contract-results report — expected loam's generic shape ${shape} ` +
52
+ "(see SCHEMA.md's contract-test reports section; Specmatic, Pact, Dredd and property harnesses emit it with a one-line transform).",
53
+ };
54
+ }
55
+ if (doc[CONTRACT_REPORT_MARKER] !== CONTRACT_REPORT_VERSION) {
56
+ // A later version may redefine what an entry means; reading it with this
57
+ // parser could confirm something the report never said. Fail closed.
58
+ return {
59
+ ok: false,
60
+ message: `${reportName} declares ${CONTRACT_REPORT_MARKER}: ${JSON.stringify(doc[CONTRACT_REPORT_MARKER])} — ` +
61
+ `this loam reads version ${CONTRACT_REPORT_VERSION} only.`,
62
+ };
63
+ }
64
+ const results = doc["results"];
65
+ if (!Array.isArray(results)) {
66
+ return { ok: false, message: `${reportName} has no \`results\` array — expected ${shape}.` };
67
+ }
68
+ const runs = [];
69
+ for (const [i, entry] of results.entries()) {
70
+ const where = `${reportName} entry ${i + 1}`;
71
+ if (!isRecord(entry))
72
+ return { ok: false, message: `${where} is not an object — expected ${shape}.` };
73
+ const operationId = entry["operationId"];
74
+ if (typeof operationId !== "string" || operationId.length === 0) {
75
+ return { ok: false, message: `${where} has no operationId — every entry must name the operation it exercised.` };
76
+ }
77
+ const status = entry["status"];
78
+ if (typeof status !== "string" || status.length === 0) {
79
+ return {
80
+ ok: false,
81
+ message: `${where} ('${operationId}') has no status — expected "passed", "failed", or the tool's own word for anything else.`,
82
+ };
83
+ }
84
+ const test = entry["test"];
85
+ runs.push({
86
+ operationId,
87
+ status,
88
+ ...(typeof test === "string" && test.trim().length > 0 ? { test: test.trim() } : {}),
89
+ });
90
+ }
91
+ return { ok: true, runs };
92
+ }
93
+ /**
94
+ * The operationIds that more than one service on this checklist exposes, with
95
+ * the services that expose them — `contestedDigests`' (core/results.ts) exact
96
+ * shape, for this axis's join key.
97
+ *
98
+ * An operationId is unique within one contract document, not across a fleet:
99
+ * two services may each expose a 'createSplit', and a report entry carries no
100
+ * service half, so a single contract report matches both services' claims and
101
+ * cannot say whose suite it describes. The all-at-once form once confirmed a
102
+ * service from a suite that never touched it exactly this way. loam does not
103
+ * choose: those claims are refused rather than answered, and `--service` is
104
+ * what gives a report an owner — it narrows the checklist to one subject
105
+ * before the matching starts, so nothing handed in here is contested.
106
+ */
107
+ export function contestedOperations(claims) {
108
+ const owners = new Map();
109
+ for (const c of claims) {
110
+ if (c.operation === undefined)
111
+ continue;
112
+ const seen = owners.get(c.operation) ?? new Set();
113
+ seen.add(c.subject);
114
+ owners.set(c.operation, seen);
115
+ }
116
+ const contested = new Map();
117
+ for (const [operation, services] of owners) {
118
+ if (services.size > 1)
119
+ contested.set(operation, [...services].sort());
120
+ }
121
+ return contested;
122
+ }
123
+ /**
124
+ * Answer every claim from the report — the contract runner's half of the
125
+ * record. Total over the claims handed in, like `runnerAnswers`: a claim the
126
+ * report does not exercise is answered `unconfirmed`, never skipped, because
127
+ * silence must never read as checked. Report entries matching no claim are
128
+ * skipped silently — a real contract suite exercises the whole living API,
129
+ * and the claims only ever cover what the feature ADDS.
130
+ *
131
+ * Confirmation is strict on purpose: every matching entry (an operationId the
132
+ * report holds twice is two test cases, and all of them count) has status
133
+ * exactly `"passed"`. One non-passed entry wins as failure, and an unknown
134
+ * status is named in the note rather than rounded to either verdict. An
135
+ * operationId two services expose is refused before any of that: see
136
+ * {@link contestedOperations}.
137
+ */
138
+ export function contractAnswers(claims, runs, reportName) {
139
+ const contested = contestedOperations(claims);
140
+ return claims.map((c) => {
141
+ const rivals = c.operation === undefined ? undefined : contested.get(c.operation);
142
+ if (rivals !== undefined) {
143
+ return answer(c.id, "unconfirmed", [], `operationId '${c.operation}' is exposed by more than one service on this checklist (${rivals.join(", ")}), ` +
144
+ `so ${reportName} cannot say whose suite exercised it. Record each service's claims from its own repo with --service.`);
145
+ }
146
+ if (c.operation === undefined) {
147
+ // Unreachable for the api.exposes claims this loam derives, which always
148
+ // carry one — but the function is total, and a claim without a join key
149
+ // must fail closed rather than throw or silently confirm.
150
+ return answer(c.id, "unconfirmed", [], "claim carries no operationId for a contract report to match on");
151
+ }
152
+ const matching = runs.filter((r) => r.operationId === c.operation);
153
+ if (matching.length === 0) {
154
+ return answer(c.id, "unconfirmed", [], `not exercised — no entry in ${reportName} names operationId '${c.operation}'`);
155
+ }
156
+ const failing = matching.filter((r) => r.status !== "passed");
157
+ if (failing.length === 0) {
158
+ return answer(c.id, "confirmed", matching.map((r) => `${reportName}: ${r.test ?? `operationId '${c.operation}' passed`}`));
159
+ }
160
+ const first = failing[0];
161
+ const why = first.status === "failed" ? "failed" : `status '${first.status}' is not 'passed'`;
162
+ const rerun = matching.length > 1 ? ` — ${failing.length} of ${matching.length} matching entries did not pass` : "";
163
+ return answer(c.id, "unconfirmed", [], `${why} (${reportName}${first.test === undefined ? "" : `: ${first.test}`})${rerun}`);
164
+ });
165
+ }
166
+ function answer(id, verdict, evidence, note) {
167
+ return { id, verdict, evidence, ...(note === undefined ? {} : { note }), answered_by: "external-runner" };
168
+ }
169
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../../src/core/verify/evidence/contract.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `loam verify --contract-results` — an API contract-test report as the answer\n * sheet for `api.exposes` claims.\n *\n * The accepted shape is loam's own documented one (SCHEMA.md, \"Contract-test\n * reports\"): `{\"loamContractReport\": 1, \"results\": [{\"operationId\": \"…\",\n * \"status\": \"passed\"}]}`. It is deliberately a shape tools EMIT INTO rather\n * than a vendor format loam parses, because no surveyed vendor format carries\n * both halves of what confirming needs — an unambiguous executed-AND-passed\n * status and a deterministic operation join key. Specmatic's JSON coverage\n * report was the v1 candidate and is declined by name: its `coverageStatus:\n * \"covered\"` means exercised, not passed (a red run still writes \"covered\"),\n * so an adapter over it would confirm exactly what a failing suite refuted.\n *\n * The operationId is the ONLY identity, matched against the structured\n * `operation` a claim carries (`../checklist.ts`). It is half an identity, and\n * the design leans on the missing half being supplied by scope: an operationId\n * is unique within ONE contract document, not across a fleet, and a report\n * entry names no service — so when more than one service on the handed-in\n * checklist exposes the same operationId, the claims are refused rather than\n * answered ({@link contestedOperations}), and `--service` is what gives a\n * contract report an owner, exactly as it is for a contested scenario digest.\n * Within one service's claims the match is exact, and renaming an operation\n * renames its claim, so rewording cannot carry an answer over. Names and free\n * text match nothing.\n *\n * Parsing is strict where the cucumber reader is tolerant, and the asymmetry\n * is deliberate: a cucumber report is another tool's file full of legitimate\n * entries loam has no business judging, while this shape exists for exactly\n * one purpose, so an entry that cannot be matched is a malformed report, not\n * scenery. A file that is recognizably not this shape refuses rather than\n * quietly answering every claim \"not exercised\" — an unparseable report never\n * silently answers zero claims as if none matched.\n */\nimport { isRecord } from \"../../kernel/records.js\";\nimport { type Answer } from \"../answers.js\";\nimport { type Claim } from \"../checklist.js\";\n\n/** The marker key that makes a JSON document this shape, and the version this loam reads. */\nexport const CONTRACT_REPORT_MARKER = \"loamContractReport\";\nexport const CONTRACT_REPORT_VERSION = 1;\n\n/** One report entry, reduced to what matching needs. Extra keys pass untouched. */\nexport interface ContractRun {\n operationId: string;\n /** Exactly `\"passed\"` confirms; `\"failed\"` and every other string do not. */\n status: string;\n /** Optional free text naming the test — it rides into the evidence line. */\n test?: string;\n}\n\nexport type ContractReportRead =\n | { ok: true; runs: ContractRun[] }\n | { ok: false; message: string };\n\n/**\n * Read a parsed JSON document down to its runs. `reportName` is how the caller\n * spelled the file, for the refusal message; core never prints, so a refusal\n * is data for the command to fail with (`answers-unreadable`).\n */\nexport function readContractReport(doc: unknown, reportName: string): ContractReportRead {\n const shape =\n `{\"${CONTRACT_REPORT_MARKER}\": ${CONTRACT_REPORT_VERSION}, \"results\": [{\"operationId\": \"…\", \"status\": \"passed\"}]}`;\n if (!isRecord(doc) || !(CONTRACT_REPORT_MARKER in doc)) {\n return {\n ok: false,\n message:\n `${reportName} is not a contract-results report — expected loam's generic shape ${shape} ` +\n \"(see SCHEMA.md's contract-test reports section; Specmatic, Pact, Dredd and property harnesses emit it with a one-line transform).\",\n };\n }\n if (doc[CONTRACT_REPORT_MARKER] !== CONTRACT_REPORT_VERSION) {\n // A later version may redefine what an entry means; reading it with this\n // parser could confirm something the report never said. Fail closed.\n return {\n ok: false,\n message:\n `${reportName} declares ${CONTRACT_REPORT_MARKER}: ${JSON.stringify(doc[CONTRACT_REPORT_MARKER])} — ` +\n `this loam reads version ${CONTRACT_REPORT_VERSION} only.`,\n };\n }\n const results = doc[\"results\"];\n if (!Array.isArray(results)) {\n return { ok: false, message: `${reportName} has no \\`results\\` array — expected ${shape}.` };\n }\n const runs: ContractRun[] = [];\n for (const [i, entry] of results.entries()) {\n const where = `${reportName} entry ${i + 1}`;\n if (!isRecord(entry)) return { ok: false, message: `${where} is not an object — expected ${shape}.` };\n const operationId = entry[\"operationId\"];\n if (typeof operationId !== \"string\" || operationId.length === 0) {\n return { ok: false, message: `${where} has no operationId — every entry must name the operation it exercised.` };\n }\n const status = entry[\"status\"];\n if (typeof status !== \"string\" || status.length === 0) {\n return {\n ok: false,\n message: `${where} ('${operationId}') has no status — expected \"passed\", \"failed\", or the tool's own word for anything else.`,\n };\n }\n const test = entry[\"test\"];\n runs.push({\n operationId,\n status,\n ...(typeof test === \"string\" && test.trim().length > 0 ? { test: test.trim() } : {}),\n });\n }\n return { ok: true, runs };\n}\n\n/**\n * The operationIds that more than one service on this checklist exposes, with\n * the services that expose them — `contestedDigests`' (core/results.ts) exact\n * shape, for this axis's join key.\n *\n * An operationId is unique within one contract document, not across a fleet:\n * two services may each expose a 'createSplit', and a report entry carries no\n * service half, so a single contract report matches both services' claims and\n * cannot say whose suite it describes. The all-at-once form once confirmed a\n * service from a suite that never touched it exactly this way. loam does not\n * choose: those claims are refused rather than answered, and `--service` is\n * what gives a report an owner — it narrows the checklist to one subject\n * before the matching starts, so nothing handed in here is contested.\n */\nexport function contestedOperations(claims: readonly Claim[]): Map<string, string[]> {\n const owners = new Map<string, Set<string>>();\n for (const c of claims) {\n if (c.operation === undefined) continue;\n const seen = owners.get(c.operation) ?? new Set<string>();\n seen.add(c.subject);\n owners.set(c.operation, seen);\n }\n const contested = new Map<string, string[]>();\n for (const [operation, services] of owners) {\n if (services.size > 1) contested.set(operation, [...services].sort());\n }\n return contested;\n}\n\n/**\n * Answer every claim from the report — the contract runner's half of the\n * record. Total over the claims handed in, like `runnerAnswers`: a claim the\n * report does not exercise is answered `unconfirmed`, never skipped, because\n * silence must never read as checked. Report entries matching no claim are\n * skipped silently — a real contract suite exercises the whole living API,\n * and the claims only ever cover what the feature ADDS.\n *\n * Confirmation is strict on purpose: every matching entry (an operationId the\n * report holds twice is two test cases, and all of them count) has status\n * exactly `\"passed\"`. One non-passed entry wins as failure, and an unknown\n * status is named in the note rather than rounded to either verdict. An\n * operationId two services expose is refused before any of that: see\n * {@link contestedOperations}.\n */\nexport function contractAnswers(claims: Claim[], runs: ContractRun[], reportName: string): Answer[] {\n const contested = contestedOperations(claims);\n return claims.map((c) => {\n const rivals = c.operation === undefined ? undefined : contested.get(c.operation);\n if (rivals !== undefined) {\n return answer(\n c.id,\n \"unconfirmed\",\n [],\n `operationId '${c.operation}' is exposed by more than one service on this checklist (${rivals.join(\", \")}), ` +\n `so ${reportName} cannot say whose suite exercised it. Record each service's claims from its own repo with --service.`,\n );\n }\n if (c.operation === undefined) {\n // Unreachable for the api.exposes claims this loam derives, which always\n // carry one — but the function is total, and a claim without a join key\n // must fail closed rather than throw or silently confirm.\n return answer(c.id, \"unconfirmed\", [], \"claim carries no operationId for a contract report to match on\");\n }\n const matching = runs.filter((r) => r.operationId === c.operation);\n if (matching.length === 0) {\n return answer(\n c.id,\n \"unconfirmed\",\n [],\n `not exercised — no entry in ${reportName} names operationId '${c.operation}'`,\n );\n }\n const failing = matching.filter((r) => r.status !== \"passed\");\n if (failing.length === 0) {\n return answer(\n c.id,\n \"confirmed\",\n matching.map((r) => `${reportName}: ${r.test ?? `operationId '${c.operation}' passed`}`),\n );\n }\n const first = failing[0]!;\n const why = first.status === \"failed\" ? \"failed\" : `status '${first.status}' is not 'passed'`;\n const rerun =\n matching.length > 1 ? ` — ${failing.length} of ${matching.length} matching entries did not pass` : \"\";\n return answer(\n c.id,\n \"unconfirmed\",\n [],\n `${why} (${reportName}${first.test === undefined ? \"\" : `: ${first.test}`})${rerun}`,\n );\n });\n}\n\nfunction answer(id: string, verdict: Answer[\"verdict\"], evidence: string[], note?: string): Answer {\n return { id, verdict, evidence, ...(note === undefined ? {} : { note }), answered_by: \"external-runner\" };\n}\n"]}