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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1256) hide show
  1. package/CHANGELOG.md +5992 -82
  2. package/COMPARISON.md +168 -63
  3. package/CONTRIBUTING.md +121 -0
  4. package/MIGRATING-from-OpenSpec.md +238 -55
  5. package/QUICKSTART.md +302 -0
  6. package/README.md +653 -144
  7. package/ROADMAP.md +1035 -0
  8. package/SCHEMA.md +3916 -263
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +927 -0
  11. package/dist/cli.js +133 -21
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +204 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +309 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +74 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/closing.js +42 -0
  20. package/dist/commands/archive/closing.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
  22. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  24. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  25. package/dist/commands/archive/plan/contracts/openapi.js +193 -0
  26. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  28. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  29. package/dist/commands/archive/plan/document/head.js +151 -0
  30. package/dist/commands/archive/plan/document/head.js.map +1 -0
  31. package/dist/commands/archive/plan/document/links.js +284 -0
  32. package/dist/commands/archive/plan/document/links.js.map +1 -0
  33. package/dist/commands/archive/plan/document/run.js +136 -0
  34. package/dist/commands/archive/plan/document/run.js.map +1 -0
  35. package/dist/commands/archive/plan/gate.js +319 -0
  36. package/dist/commands/archive/plan/gate.js.map +1 -0
  37. package/dist/commands/archive/plan/landscape.js +298 -0
  38. package/dist/commands/archive/plan/landscape.js.map +1 -0
  39. package/dist/commands/archive/plan/model/extending.js +85 -0
  40. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  41. package/dist/commands/archive/plan/refusal.js +106 -0
  42. package/dist/commands/archive/plan/refusal.js.map +1 -0
  43. package/dist/commands/archive/plan/specs.js +318 -0
  44. package/dist/commands/archive/plan/specs.js.map +1 -0
  45. package/dist/commands/archive/plan/state.js +30 -0
  46. package/dist/commands/archive/plan/state.js.map +1 -0
  47. package/dist/commands/archive/run.js +355 -0
  48. package/dist/commands/archive/run.js.map +1 -0
  49. package/dist/commands/archive/shipped.js +49 -0
  50. package/dist/commands/archive/shipped.js.map +1 -0
  51. package/dist/commands/context/context.js +166 -0
  52. package/dist/commands/context/context.js.map +1 -0
  53. package/dist/commands/context/print.js +305 -0
  54. package/dist/commands/context/print.js.map +1 -0
  55. package/dist/commands/delta/delta.js +367 -0
  56. package/dist/commands/delta/delta.js.map +1 -0
  57. package/dist/commands/delta/print.js +221 -0
  58. package/dist/commands/delta/print.js.map +1 -0
  59. package/dist/commands/dependencies.js +6 -8
  60. package/dist/commands/dependencies.js.map +1 -1
  61. package/dist/commands/diff/diff.js +86 -0
  62. package/dist/commands/diff/diff.js.map +1 -0
  63. package/dist/commands/diff/print.js +38 -0
  64. package/dist/commands/diff/print.js.map +1 -0
  65. package/dist/commands/doctor.js +65 -5
  66. package/dist/commands/doctor.js.map +1 -1
  67. package/dist/commands/explain/explain.js +227 -0
  68. package/dist/commands/explain/explain.js.map +1 -0
  69. package/dist/commands/explore.js +39 -28
  70. package/dist/commands/explore.js.map +1 -1
  71. package/dist/commands/gate/gate.js +152 -0
  72. package/dist/commands/gate/gate.js.map +1 -0
  73. package/dist/commands/gate/print.js +66 -0
  74. package/dist/commands/gate/print.js.map +1 -0
  75. package/dist/commands/gherkin/commit.js +105 -0
  76. package/dist/commands/gherkin/commit.js.map +1 -0
  77. package/dist/commands/gherkin/gherkin.js +262 -0
  78. package/dist/commands/gherkin/gherkin.js.map +1 -0
  79. package/dist/commands/gherkin/reconcile.js +146 -0
  80. package/dist/commands/gherkin/reconcile.js.map +1 -0
  81. package/dist/commands/gherkin/render.js +77 -0
  82. package/dist/commands/gherkin/render.js.map +1 -0
  83. package/dist/commands/init/example.js +204 -0
  84. package/dist/commands/init/example.js.map +1 -0
  85. package/dist/commands/init/first-hour.js +72 -0
  86. package/dist/commands/init/first-hour.js.map +1 -0
  87. package/dist/commands/{init.js → init/init.js} +142 -71
  88. package/dist/commands/init/init.js.map +1 -0
  89. package/dist/commands/init/mcp.js +131 -0
  90. package/dist/commands/init/mcp.js.map +1 -0
  91. package/dist/commands/init/options.js +78 -0
  92. package/dist/commands/init/options.js.map +1 -0
  93. package/dist/commands/instructions.js +72 -14
  94. package/dist/commands/instructions.js.map +1 -1
  95. package/dist/commands/list/campaign/campaign.js +63 -0
  96. package/dist/commands/list/campaign/campaign.js.map +1 -0
  97. package/dist/commands/list/campaign/owners.js +65 -0
  98. package/dist/commands/list/campaign/owners.js.map +1 -0
  99. package/dist/commands/list/json.js +155 -0
  100. package/dist/commands/list/json.js.map +1 -0
  101. package/dist/commands/list/list.js +358 -0
  102. package/dist/commands/list/list.js.map +1 -0
  103. package/dist/commands/list/print.js +344 -0
  104. package/dist/commands/list/print.js.map +1 -0
  105. package/dist/commands/list/review.js +120 -0
  106. package/dist/commands/list/review.js.map +1 -0
  107. package/dist/commands/list/suites/suites.js +140 -0
  108. package/dist/commands/list/suites/suites.js.map +1 -0
  109. package/dist/commands/list/views.js +108 -0
  110. package/dist/commands/list/views.js.map +1 -0
  111. package/dist/commands/mcp/dispatch.js +238 -0
  112. package/dist/commands/mcp/dispatch.js.map +1 -0
  113. package/dist/commands/mcp/mcp.js +75 -0
  114. package/dist/commands/mcp/mcp.js.map +1 -0
  115. package/dist/commands/mcp/serve.js +55 -0
  116. package/dist/commands/mcp/serve.js.map +1 -0
  117. package/dist/commands/migrate-openspec/materialize/active.js +175 -0
  118. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  119. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  120. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  121. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  122. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  123. package/dist/commands/migrate-openspec/materialize/stage.js +143 -0
  124. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  125. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  126. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  127. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  128. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  129. package/dist/commands/migrate-openspec/openspec/decisions.js +86 -0
  130. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  131. package/dist/commands/migrate-openspec/openspec/error.js +18 -0
  132. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  133. package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
  134. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  135. package/dist/commands/migrate-openspec/openspec/paths.js +40 -0
  136. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  137. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  138. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  139. package/dist/commands/migrate-openspec/print.js +89 -0
  140. package/dist/commands/migrate-openspec/print.js.map +1 -0
  141. package/dist/commands/new/capability-template.js +118 -0
  142. package/dist/commands/new/capability-template.js.map +1 -0
  143. package/dist/commands/new/commit.js +62 -0
  144. package/dist/commands/new/commit.js.map +1 -0
  145. package/dist/commands/new/modifies.js +206 -0
  146. package/dist/commands/new/modifies.js.map +1 -0
  147. package/dist/commands/new/new.js +328 -0
  148. package/dist/commands/new/new.js.map +1 -0
  149. package/dist/commands/new/templates.js +279 -0
  150. package/dist/commands/new/templates.js.map +1 -0
  151. package/dist/commands/open.js +199 -0
  152. package/dist/commands/open.js.map +1 -0
  153. package/dist/commands/policy/format.js +152 -0
  154. package/dist/commands/policy/format.js.map +1 -0
  155. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +38 -11
  156. package/dist/commands/policy/gate.js.map +1 -0
  157. package/dist/commands/rebase/edit.js +106 -0
  158. package/dist/commands/rebase/edit.js.map +1 -0
  159. package/dist/commands/rebase/living.js +185 -0
  160. package/dist/commands/rebase/living.js.map +1 -0
  161. package/dist/commands/rebase/plan.js +245 -0
  162. package/dist/commands/rebase/plan.js.map +1 -0
  163. package/dist/commands/rebase/rebase.js +300 -0
  164. package/dist/commands/rebase/rebase.js.map +1 -0
  165. package/dist/commands/seed/commit.js +221 -0
  166. package/dist/commands/seed/commit.js.map +1 -0
  167. package/dist/commands/seed/plan.js +278 -0
  168. package/dist/commands/seed/plan.js.map +1 -0
  169. package/dist/commands/seed/seed.js +174 -0
  170. package/dist/commands/seed/seed.js.map +1 -0
  171. package/dist/commands/show/feature.js +182 -0
  172. package/dist/commands/show/feature.js.map +1 -0
  173. package/dist/commands/show/introduced.js +157 -0
  174. package/dist/commands/show/introduced.js.map +1 -0
  175. package/dist/commands/show/marks.js +53 -0
  176. package/dist/commands/show/marks.js.map +1 -0
  177. package/dist/commands/show/service.js +239 -0
  178. package/dist/commands/show/service.js.map +1 -0
  179. package/dist/commands/show/show.js +87 -0
  180. package/dist/commands/show/show.js.map +1 -0
  181. package/dist/commands/status/fleet-next.js +90 -0
  182. package/dist/commands/status/fleet-next.js.map +1 -0
  183. package/dist/commands/status/json.js +47 -0
  184. package/dist/commands/status/json.js.map +1 -0
  185. package/dist/commands/status/print.js +209 -0
  186. package/dist/commands/status/print.js.map +1 -0
  187. package/dist/commands/status/status.js +115 -0
  188. package/dist/commands/status/status.js.map +1 -0
  189. package/dist/commands/steps/steps.js +269 -0
  190. package/dist/commands/steps/steps.js.map +1 -0
  191. package/dist/commands/subsystem/edit.js +192 -0
  192. package/dist/commands/subsystem/edit.js.map +1 -0
  193. package/dist/commands/subsystem/move.js +325 -0
  194. package/dist/commands/subsystem/move.js.map +1 -0
  195. package/dist/commands/subsystem/query.js +113 -0
  196. package/dist/commands/subsystem/query.js.map +1 -0
  197. package/dist/commands/subsystem/subsystem.js +98 -0
  198. package/dist/commands/subsystem/subsystem.js.map +1 -0
  199. package/dist/commands/subsystem/sync.js +318 -0
  200. package/dist/commands/subsystem/sync.js.map +1 -0
  201. package/dist/commands/subsystem/txn/exclude.js +132 -0
  202. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  203. package/dist/commands/subsystem/txn/links.js +128 -0
  204. package/dist/commands/subsystem/txn/links.js.map +1 -0
  205. package/dist/commands/subsystem/txn/report.js +174 -0
  206. package/dist/commands/subsystem/txn/report.js.map +1 -0
  207. package/dist/commands/subsystem/txn/txn.js +196 -0
  208. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  209. package/dist/commands/subsystem/txn/views.js +249 -0
  210. package/dist/commands/subsystem/txn/views.js.map +1 -0
  211. package/dist/commands/tasks/actions.js +107 -0
  212. package/dist/commands/tasks/actions.js.map +1 -0
  213. package/dist/commands/tasks/render.js +253 -0
  214. package/dist/commands/tasks/render.js.map +1 -0
  215. package/dist/commands/tasks/tasks.js +119 -0
  216. package/dist/commands/tasks/tasks.js.map +1 -0
  217. package/dist/commands/unarchive/manifest.js +176 -0
  218. package/dist/commands/unarchive/manifest.js.map +1 -0
  219. package/dist/commands/unarchive/restore.js +254 -0
  220. package/dist/commands/unarchive/restore.js.map +1 -0
  221. package/dist/commands/unarchive/unarchive.js +59 -0
  222. package/dist/commands/unarchive/unarchive.js.map +1 -0
  223. package/dist/commands/validate/arch-coverage.js +245 -0
  224. package/dist/commands/validate/arch-coverage.js.map +1 -0
  225. package/dist/commands/validate/checks/fleet-shape.js +204 -0
  226. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  227. package/dist/commands/validate/checks/health-deps.js +58 -0
  228. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  229. package/dist/commands/validate/checks/introduced.js +102 -0
  230. package/dist/commands/validate/checks/introduced.js.map +1 -0
  231. package/dist/commands/validate/checks/requirements.js +264 -0
  232. package/dist/commands/validate/checks/requirements.js.map +1 -0
  233. package/dist/commands/validate/checks/sources.js +85 -0
  234. package/dist/commands/validate/checks/sources.js.map +1 -0
  235. package/dist/commands/validate/coverage/covers-after.js +105 -0
  236. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  237. package/dist/commands/validate/feature.js +222 -0
  238. package/dist/commands/validate/feature.js.map +1 -0
  239. package/dist/commands/validate/fleet/census.js +93 -0
  240. package/dist/commands/validate/fleet/census.js.map +1 -0
  241. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  242. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  243. package/dist/commands/validate/fleet/landscape.js +371 -0
  244. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  245. package/dist/commands/validate/fleet/load.js +118 -0
  246. package/dist/commands/validate/fleet/load.js.map +1 -0
  247. package/dist/commands/validate/fleet/map/attest.js +98 -0
  248. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  249. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  250. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  251. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  252. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  253. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  254. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  255. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  256. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  257. package/dist/commands/validate/fleet/obligations.js +266 -0
  258. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  259. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  260. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  261. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  262. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  263. package/dist/commands/validate/fleet/scorecard/print.js +71 -0
  264. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  265. package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
  266. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  267. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  268. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  269. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  270. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  271. package/dist/commands/validate/fleet/views/ids.js +75 -0
  272. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  273. package/dist/commands/validate/fleet/views/projects.js +278 -0
  274. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  275. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  276. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  277. package/dist/commands/validate/fleet/views/stale.js +52 -0
  278. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  279. package/dist/commands/validate/links/corpus.js +89 -0
  280. package/dist/commands/validate/links/corpus.js.map +1 -0
  281. package/dist/commands/validate/links/glossary.js +75 -0
  282. package/dist/commands/validate/links/glossary.js.map +1 -0
  283. package/dist/commands/validate/render/repeats.js +63 -0
  284. package/dist/commands/validate/render/repeats.js.map +1 -0
  285. package/dist/commands/validate/render/rollups.js +115 -0
  286. package/dist/commands/validate/render/rollups.js.map +1 -0
  287. package/dist/commands/validate/render/text.js +199 -0
  288. package/dist/commands/validate/render/text.js.map +1 -0
  289. package/dist/commands/validate/report.js +145 -0
  290. package/dist/commands/validate/report.js.map +1 -0
  291. package/dist/commands/validate/scope.js +113 -0
  292. package/dist/commands/validate/scope.js.map +1 -0
  293. package/dist/commands/validate/service/api.js +252 -0
  294. package/dist/commands/validate/service/api.js.map +1 -0
  295. package/dist/commands/validate/service/contracts/generated.js +134 -0
  296. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  297. package/dist/commands/validate/service/events/events.js +241 -0
  298. package/dist/commands/validate/service/events/events.js.map +1 -0
  299. package/dist/commands/validate/service/events/message-producers.js +77 -0
  300. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  301. package/dist/commands/validate/service/evidence-pins.js +177 -0
  302. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  303. package/dist/commands/validate/service/model/diverged.js +226 -0
  304. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  305. package/dist/commands/validate/service/model/grade.js +163 -0
  306. package/dist/commands/validate/service/model/grade.js.map +1 -0
  307. package/dist/commands/validate/service/service.js +310 -0
  308. package/dist/commands/validate/service/service.js.map +1 -0
  309. package/dist/commands/validate/service/specs.js +279 -0
  310. package/dist/commands/validate/service/specs.js.map +1 -0
  311. package/dist/commands/validate/service/spine.js +148 -0
  312. package/dist/commands/validate/service/spine.js.map +1 -0
  313. package/dist/commands/validate/service/usecases/tags.js +113 -0
  314. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  315. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  316. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  317. package/dist/commands/validate/validate.js +363 -0
  318. package/dist/commands/validate/validate.js.map +1 -0
  319. package/dist/commands/verify/cross/diff.js +178 -0
  320. package/dist/commands/verify/cross/diff.js.map +1 -0
  321. package/dist/commands/verify/evidence/contract.js +32 -0
  322. package/dist/commands/verify/evidence/contract.js.map +1 -0
  323. package/dist/commands/verify/evidence/pins.js +52 -0
  324. package/dist/commands/verify/evidence/pins.js.map +1 -0
  325. package/dist/commands/verify/evidence/read.js +81 -0
  326. package/dist/commands/verify/evidence/read.js.map +1 -0
  327. package/dist/commands/verify/frozen.js +263 -0
  328. package/dist/commands/verify/frozen.js.map +1 -0
  329. package/dist/commands/verify/record.js +278 -0
  330. package/dist/commands/verify/record.js.map +1 -0
  331. package/dist/commands/verify/report.js +206 -0
  332. package/dist/commands/verify/report.js.map +1 -0
  333. package/dist/commands/verify/results.js +328 -0
  334. package/dist/commands/verify/results.js.map +1 -0
  335. package/dist/commands/verify/verify.js +220 -0
  336. package/dist/commands/verify/verify.js.map +1 -0
  337. package/dist/commands/vouch/contract.js +11 -0
  338. package/dist/commands/vouch/contract.js.map +1 -0
  339. package/dist/commands/vouch/pack/contract.js +2 -0
  340. package/dist/commands/vouch/pack/contract.js.map +1 -0
  341. package/dist/commands/vouch/pack/pack.js +266 -0
  342. package/dist/commands/vouch/pack/pack.js.map +1 -0
  343. package/dist/commands/vouch/pack/print.js +266 -0
  344. package/dist/commands/vouch/pack/print.js.map +1 -0
  345. package/dist/commands/vouch/pack/sections.js +141 -0
  346. package/dist/commands/vouch/pack/sections.js.map +1 -0
  347. package/dist/commands/vouch/prompt/confirm.js +46 -0
  348. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  349. package/dist/commands/vouch/report.js +101 -0
  350. package/dist/commands/vouch/report.js.map +1 -0
  351. package/dist/commands/vouch/run.js +230 -0
  352. package/dist/commands/vouch/run.js.map +1 -0
  353. package/dist/commands/vouch/sample/plan.js +111 -0
  354. package/dist/commands/vouch/sample/plan.js.map +1 -0
  355. package/dist/commands/vouch/sample/print.js +109 -0
  356. package/dist/commands/vouch/sample/print.js.map +1 -0
  357. package/dist/commands/vouch/vet/verify.js +155 -0
  358. package/dist/commands/vouch/vet/verify.js.map +1 -0
  359. package/dist/commands/vouch/vouch.js +169 -0
  360. package/dist/commands/vouch/vouch.js.map +1 -0
  361. package/dist/core/agent/agents-md/command-map.js +299 -0
  362. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  363. package/dist/core/agent/agents-md/map/explain.js +46 -0
  364. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  365. package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
  366. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  367. package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
  368. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  369. package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
  370. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  371. package/dist/core/agent/agents-md/map/mcp.js +44 -0
  372. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  373. package/dist/core/agent/agents-md/map/status.js +78 -0
  374. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  375. package/dist/core/agent/agents-md/map/subsystem.js +104 -0
  376. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  377. package/dist/core/agent/agents-md/map/usecases.js +138 -0
  378. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  379. package/dist/core/agent/agents-md/refusals.js +273 -0
  380. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  381. package/dist/core/agent/agents-md.js +203 -0
  382. package/dist/core/agent/agents-md.js.map +1 -0
  383. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -0
  384. package/dist/core/agent/agents-stamp.js.map +1 -0
  385. package/dist/core/agent/contract.js +2 -0
  386. package/dist/core/agent/contract.js.map +1 -0
  387. package/dist/core/agent/protocol.js +193 -0
  388. package/dist/core/agent/protocol.js.map +1 -0
  389. package/dist/core/agent/scaffold.js +254 -0
  390. package/dist/core/agent/scaffold.js.map +1 -0
  391. package/dist/core/agent/support/report.js +144 -0
  392. package/dist/core/agent/support/report.js.map +1 -0
  393. package/dist/core/agent/tools/dialects.js +151 -0
  394. package/dist/core/agent/tools/dialects.js.map +1 -0
  395. package/dist/core/agent/tools/registry.js +193 -0
  396. package/dist/core/agent/tools/registry.js.map +1 -0
  397. package/dist/core/agent/workflows/adopt.js +280 -0
  398. package/dist/core/agent/workflows/adopt.js.map +1 -0
  399. package/dist/core/agent/workflows/check.js +373 -0
  400. package/dist/core/agent/workflows/check.js.map +1 -0
  401. package/dist/core/agent/workflows/closing.js +323 -0
  402. package/dist/core/agent/workflows/closing.js.map +1 -0
  403. package/dist/core/agent/workflows/feature.js +220 -0
  404. package/dist/core/agent/workflows/feature.js.map +1 -0
  405. package/dist/core/agent/workflows/implement.js +188 -0
  406. package/dist/core/agent/workflows/implement.js.map +1 -0
  407. package/dist/core/agent/workflows/reference/authoring.js +311 -0
  408. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  409. package/dist/core/agent/workflows/reference/codes.js +67 -0
  410. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  411. package/dist/core/agent/workflows/reference/done-check.js +210 -0
  412. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  413. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  414. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  415. package/dist/core/agent/workflows/reference/reference.js +19 -0
  416. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  417. package/dist/core/agent/workflows/reference/spine.js +338 -0
  418. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  419. package/dist/core/asyncapi/baseline/plan.js +43 -0
  420. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  421. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  422. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  423. package/dist/core/asyncapi/depth.js +164 -0
  424. package/dist/core/asyncapi/depth.js.map +1 -0
  425. package/dist/core/asyncapi/digest.js +146 -0
  426. package/dist/core/asyncapi/digest.js.map +1 -0
  427. package/dist/core/asyncapi/merge/components.js +92 -0
  428. package/dist/core/asyncapi/merge/components.js.map +1 -0
  429. package/dist/core/asyncapi/merge/error.js +38 -0
  430. package/dist/core/asyncapi/merge/error.js.map +1 -0
  431. package/dist/core/asyncapi/merge/markers.js +290 -0
  432. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  433. package/dist/core/asyncapi/merge/merge.js +195 -0
  434. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  435. package/dist/core/asyncapi/merge/pin.js +83 -0
  436. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  437. package/dist/core/asyncapi/model.js +11 -0
  438. package/dist/core/asyncapi/model.js.map +1 -0
  439. package/dist/core/asyncapi/producers.js +50 -0
  440. package/dist/core/asyncapi/producers.js.map +1 -0
  441. package/dist/core/asyncapi/read.js +263 -0
  442. package/dist/core/asyncapi/read.js.map +1 -0
  443. package/dist/core/brief/brief.js +285 -0
  444. package/dist/core/brief/brief.js.map +1 -0
  445. package/dist/core/brief/checks.js +385 -0
  446. package/dist/core/brief/checks.js.map +1 -0
  447. package/dist/core/brief/landscape.js +273 -0
  448. package/dist/core/brief/landscape.js.map +1 -0
  449. package/dist/core/brief/map/extend.js +84 -0
  450. package/dist/core/brief/map/extend.js.map +1 -0
  451. package/dist/core/brief/map/owed.js +266 -0
  452. package/dist/core/brief/map/owed.js.map +1 -0
  453. package/dist/core/brief/targets.js +304 -0
  454. package/dist/core/brief/targets.js.map +1 -0
  455. package/dist/core/brief/unchecked.js +58 -0
  456. package/dist/core/brief/unchecked.js.map +1 -0
  457. package/dist/core/c4/arch.js +190 -0
  458. package/dist/core/c4/arch.js.map +1 -0
  459. package/dist/core/c4/direction/direction.js +114 -0
  460. package/dist/core/c4/direction/direction.js.map +1 -0
  461. package/dist/core/c4/likec4.js +243 -0
  462. package/dist/core/c4/likec4.js.map +1 -0
  463. package/dist/core/c4/locate/unlocated.js +150 -0
  464. package/dist/core/c4/locate/unlocated.js.map +1 -0
  465. package/dist/core/c4/parsed/deployment.js +160 -0
  466. package/dist/core/c4/parsed/deployment.js.map +1 -0
  467. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  468. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  469. package/dist/core/c4/parsed/specification.js +78 -0
  470. package/dist/core/c4/parsed/specification.js.map +1 -0
  471. package/dist/core/c4/parsed/values.js +110 -0
  472. package/dist/core/c4/parsed/values.js.map +1 -0
  473. package/dist/core/c4/parsed/view-ids.js +113 -0
  474. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  475. package/dist/core/c4/prefetch/fleet.js +134 -0
  476. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  477. package/dist/core/c4/project/architecture.js +161 -0
  478. package/dist/core/c4/project/architecture.js.map +1 -0
  479. package/dist/core/c4/project/batch.js +140 -0
  480. package/dist/core/c4/project/batch.js.map +1 -0
  481. package/dist/core/c4/project/documents.js +89 -0
  482. package/dist/core/c4/project/documents.js.map +1 -0
  483. package/dist/core/c4/project/load.js +219 -0
  484. package/dist/core/c4/project/load.js.map +1 -0
  485. package/dist/core/c4/project/staged.js +277 -0
  486. package/dist/core/c4/project/staged.js.map +1 -0
  487. package/dist/core/c4/resolve/attested.js +0 -0
  488. package/dist/core/c4/resolve/attested.js.map +1 -0
  489. package/dist/core/c4/resolve/external.js +51 -0
  490. package/dist/core/c4/resolve/external.js.map +1 -0
  491. package/dist/core/c4/resolve/service.js +174 -0
  492. package/dist/core/c4/resolve/service.js.map +1 -0
  493. package/dist/core/c4/resolve/steps.js +290 -0
  494. package/dist/core/c4/resolve/steps.js.map +1 -0
  495. package/dist/core/c4/resolve/systems.js +154 -0
  496. package/dist/core/c4/resolve/systems.js.map +1 -0
  497. package/dist/core/c4/root-project/exclude.js +352 -0
  498. package/dist/core/c4/root-project/exclude.js.map +1 -0
  499. package/dist/core/c4/seed/fleet-file.js +201 -0
  500. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  501. package/dist/core/c4/seed/items.js +91 -0
  502. package/dist/core/c4/seed/items.js.map +1 -0
  503. package/dist/core/c4/seed/stamp.js +48 -0
  504. package/dist/core/c4/seed/stamp.js.map +1 -0
  505. package/dist/core/c4/seed/template.js +173 -0
  506. package/dist/core/c4/seed/template.js.map +1 -0
  507. package/dist/core/c4/service-model/created/models.js +96 -0
  508. package/dist/core/c4/service-model/created/models.js.map +1 -0
  509. package/dist/core/c4/service-model/documents.js +47 -0
  510. package/dist/core/c4/service-model/documents.js.map +1 -0
  511. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  512. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  513. package/dist/core/c4/service-model/load.js +165 -0
  514. package/dist/core/c4/service-model/load.js.map +1 -0
  515. package/dist/core/c4/service-model/renderer.js +128 -0
  516. package/dist/core/c4/service-model/renderer.js.map +1 -0
  517. package/dist/core/c4/service-model/shape.js +106 -0
  518. package/dist/core/c4/service-model/shape.js.map +1 -0
  519. package/dist/core/c4/service-model/slice.js +188 -0
  520. package/dist/core/c4/service-model/slice.js.map +1 -0
  521. package/dist/core/c4/source-mask.js +369 -0
  522. package/dist/core/c4/source-mask.js.map +1 -0
  523. package/dist/core/c4/source-scan.js +308 -0
  524. package/dist/core/c4/source-scan.js.map +1 -0
  525. package/dist/core/c4/splice/authored-source.js +167 -0
  526. package/dist/core/c4/splice/authored-source.js.map +1 -0
  527. package/dist/core/c4/splice/contract.js +30 -0
  528. package/dist/core/c4/splice/contract.js.map +1 -0
  529. package/dist/core/c4/splice/delta-blocks.js +126 -0
  530. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  531. package/dist/core/c4/splice/identity/declared.js +87 -0
  532. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  533. package/dist/core/c4/splice/identity/edges.js +73 -0
  534. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  535. package/dist/core/c4/splice/identity/existing.js +80 -0
  536. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  537. package/dist/core/c4/splice/identity/interior.js +80 -0
  538. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  539. package/dist/core/c4/splice/identity/owner.js +50 -0
  540. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  541. package/dist/core/c4/splice/landscape-merge.js +337 -0
  542. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  543. package/dist/core/c4/splice/model/merge.js +151 -0
  544. package/dist/core/c4/splice/model/merge.js.map +1 -0
  545. package/dist/core/c4/splice/placement.js +298 -0
  546. package/dist/core/c4/splice/placement.js.map +1 -0
  547. package/dist/core/c4/splice/text/spot.js +131 -0
  548. package/dist/core/c4/splice/text/spot.js.map +1 -0
  549. package/dist/core/c4/workspace.js +166 -0
  550. package/dist/core/c4/workspace.js.map +1 -0
  551. package/dist/core/capabilities/authoring/notes.js +141 -0
  552. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  553. package/dist/core/capabilities/capabilities.js +124 -0
  554. package/dist/core/capabilities/capabilities.js.map +1 -0
  555. package/dist/core/capabilities/delta/doc.js +47 -0
  556. package/dist/core/capabilities/delta/doc.js.map +1 -0
  557. package/dist/core/capabilities/delta/overlay.js +129 -0
  558. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  559. package/dist/core/capabilities/delta/summary.js +57 -0
  560. package/dist/core/capabilities/delta/summary.js.map +1 -0
  561. package/dist/core/capabilities/delta/tree.js +43 -0
  562. package/dist/core/capabilities/delta/tree.js.map +1 -0
  563. package/dist/core/capabilities/delta/uncovered.js +222 -0
  564. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  565. package/dist/core/capabilities/findings.js +338 -0
  566. package/dist/core/capabilities/findings.js.map +1 -0
  567. package/dist/core/capabilities/realizes/findings.js +174 -0
  568. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  569. package/dist/core/capabilities/realizes/join.js +123 -0
  570. package/dist/core/capabilities/realizes/join.js.map +1 -0
  571. package/dist/core/capabilities/rollup.js +205 -0
  572. package/dist/core/capabilities/rollup.js.map +1 -0
  573. package/dist/core/capabilities/tree.js +104 -0
  574. package/dist/core/capabilities/tree.js.map +1 -0
  575. package/dist/core/capabilities/usecase-join.js +267 -0
  576. package/dist/core/capabilities/usecase-join.js.map +1 -0
  577. package/dist/core/coherence/authoring/scaffold.js +185 -0
  578. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  579. package/dist/core/coherence/authoring/sentinels.js +75 -0
  580. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  581. package/dist/core/coherence/calls/called.js +52 -0
  582. package/dist/core/coherence/calls/called.js.map +1 -0
  583. package/dist/core/coherence/coherence.js +332 -0
  584. package/dist/core/coherence/coherence.js.map +1 -0
  585. package/dist/core/coherence/consumed/operations.js +70 -0
  586. package/dist/core/coherence/consumed/operations.js.map +1 -0
  587. package/dist/core/coherence/consumed/refusal.js +38 -0
  588. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  589. package/dist/core/coherence/covers/health.js +85 -0
  590. package/dist/core/coherence/covers/health.js.map +1 -0
  591. package/dist/core/coherence/declared.js +295 -0
  592. package/dist/core/coherence/declared.js.map +1 -0
  593. package/dist/core/coherence/events/declared.js +191 -0
  594. package/dist/core/coherence/events/declared.js.map +1 -0
  595. package/dist/core/coherence/events/events.js +335 -0
  596. package/dist/core/coherence/events/events.js.map +1 -0
  597. package/dist/core/coherence/events/grades.js +189 -0
  598. package/dist/core/coherence/events/grades.js.map +1 -0
  599. package/dist/core/coherence/events/lookups.js +63 -0
  600. package/dist/core/coherence/events/lookups.js.map +1 -0
  601. package/dist/core/coherence/events/produced.js +100 -0
  602. package/dist/core/coherence/events/produced.js.map +1 -0
  603. package/dist/core/coherence/living.js +198 -0
  604. package/dist/core/coherence/living.js.map +1 -0
  605. package/dist/core/coherence/lookups.js +95 -0
  606. package/dist/core/coherence/lookups.js.map +1 -0
  607. package/dist/core/coherence/pending.js +39 -0
  608. package/dist/core/coherence/pending.js.map +1 -0
  609. package/dist/core/coherence/retired/archived.js +285 -0
  610. package/dist/core/coherence/retired/archived.js.map +1 -0
  611. package/dist/core/coherence/retired/event-pair.js +62 -0
  612. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  613. package/dist/core/coherence/retired/merged.js +79 -0
  614. package/dist/core/coherence/retired/merged.js.map +1 -0
  615. package/dist/core/coherence/retired/retirement.js +49 -0
  616. package/dist/core/coherence/retired/retirement.js.map +1 -0
  617. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  618. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  619. package/dist/core/coherence/retired/revival/revived.js +297 -0
  620. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  621. package/dist/core/conflict-markers.js +60 -0
  622. package/dist/core/conflict-markers.js.map +1 -0
  623. package/dist/core/consumers/after.js +113 -0
  624. package/dist/core/consumers/after.js.map +1 -0
  625. package/dist/core/consumers/consumers.js +296 -0
  626. package/dist/core/consumers/consumers.js.map +1 -0
  627. package/dist/core/consumers/current.js +211 -0
  628. package/dist/core/consumers/current.js.map +1 -0
  629. package/dist/core/consumers/scan.js +46 -0
  630. package/dist/core/consumers/scan.js.map +1 -0
  631. package/dist/core/consumers/state.js +27 -0
  632. package/dist/core/consumers/state.js.map +1 -0
  633. package/dist/core/delta/claims.js +73 -0
  634. package/dist/core/delta/claims.js.map +1 -0
  635. package/dist/core/delta/delta.js +341 -0
  636. package/dist/core/delta/delta.js.map +1 -0
  637. package/dist/core/delta/document.js +177 -0
  638. package/dist/core/delta/document.js.map +1 -0
  639. package/dist/core/delta/scope.js +48 -0
  640. package/dist/core/delta/scope.js.map +1 -0
  641. package/dist/core/delta/select.js +237 -0
  642. package/dist/core/delta/select.js.map +1 -0
  643. package/dist/core/dependencies/dependencies.js +141 -0
  644. package/dist/core/dependencies/dependencies.js.map +1 -0
  645. package/dist/core/dependencies/facts.js +165 -0
  646. package/dist/core/dependencies/facts.js.map +1 -0
  647. package/dist/core/dependencies/fanin.js +88 -0
  648. package/dist/core/dependencies/fanin.js.map +1 -0
  649. package/dist/core/dependencies/graph.js +106 -0
  650. package/dist/core/dependencies/graph.js.map +1 -0
  651. package/dist/core/deployment/delta.js +191 -0
  652. package/dist/core/deployment/delta.js.map +1 -0
  653. package/dist/core/deployment/objects.js +145 -0
  654. package/dist/core/deployment/objects.js.map +1 -0
  655. package/dist/core/diff/base-git.js +230 -0
  656. package/dist/core/diff/base-git.js.map +1 -0
  657. package/dist/core/diff/base-state.js +237 -0
  658. package/dist/core/diff/base-state.js.map +1 -0
  659. package/dist/core/diff/joins.js +136 -0
  660. package/dist/core/diff/joins.js.map +1 -0
  661. package/dist/core/diff/scope/changed-paths.js +204 -0
  662. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  663. package/dist/core/diff/scope/edges.js +82 -0
  664. package/dist/core/diff/scope/edges.js.map +1 -0
  665. package/dist/core/diff/semantic.js +312 -0
  666. package/dist/core/diff/semantic.js.map +1 -0
  667. package/dist/core/docs.js +37 -85
  668. package/dist/core/docs.js.map +1 -1
  669. package/dist/core/doctor/agents.js +238 -0
  670. package/dist/core/doctor/agents.js.map +1 -0
  671. package/dist/core/doctor/config.js +139 -0
  672. package/dist/core/doctor/config.js.map +1 -0
  673. package/dist/core/doctor/doctor.js +355 -0
  674. package/dist/core/doctor/doctor.js.map +1 -0
  675. package/dist/core/doctor/report.js +13 -0
  676. package/dist/core/doctor/report.js.map +1 -0
  677. package/dist/core/doctor/reports/scan.js +242 -0
  678. package/dist/core/doctor/reports/scan.js.map +1 -0
  679. package/dist/core/doctor/residue.js +110 -0
  680. package/dist/core/doctor/residue.js.map +1 -0
  681. package/dist/core/document/apply.js +224 -0
  682. package/dist/core/document/apply.js.map +1 -0
  683. package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -2
  684. package/dist/core/document/frontmatter.js.map +1 -0
  685. package/dist/core/document/grammar/directives.js +143 -0
  686. package/dist/core/document/grammar/directives.js.map +1 -0
  687. package/dist/core/document/parse.js +286 -0
  688. package/dist/core/document/parse.js.map +1 -0
  689. package/dist/core/document/scenarios.js +238 -0
  690. package/dist/core/document/scenarios.js.map +1 -0
  691. package/dist/core/document/spec.js +234 -0
  692. package/dist/core/document/spec.js.map +1 -0
  693. package/dist/core/{config.js → envelope/config.js} +89 -18
  694. package/dist/core/envelope/config.js.map +1 -0
  695. package/dist/core/envelope/json.js +209 -0
  696. package/dist/core/envelope/json.js.map +1 -0
  697. package/dist/core/{version.js → envelope/version.js} +3 -3
  698. package/dist/core/envelope/version.js.map +1 -0
  699. package/dist/core/explain/families.js +180 -0
  700. package/dist/core/explain/families.js.map +1 -0
  701. package/dist/core/explain/fix-tables.js +178 -0
  702. package/dist/core/explain/fix-tables.js.map +1 -0
  703. package/dist/core/explain/lookup.js +194 -0
  704. package/dist/core/explain/lookup.js.map +1 -0
  705. package/dist/core/explain/refusals.js +49 -0
  706. package/dist/core/explain/refusals.js.map +1 -0
  707. package/dist/core/explain/terms/documents.js +227 -0
  708. package/dist/core/explain/terms/documents.js.map +1 -0
  709. package/dist/core/explain/terms/done-check.js +144 -0
  710. package/dist/core/explain/terms/done-check.js.map +1 -0
  711. package/dist/core/explain/terms/entry.js +14 -0
  712. package/dist/core/explain/terms/entry.js.map +1 -0
  713. package/dist/core/explain/terms/stages.js +71 -0
  714. package/dist/core/explain/terms/stages.js.map +1 -0
  715. package/dist/core/explain/terms/tasks.js +97 -0
  716. package/dist/core/explain/terms/tasks.js.map +1 -0
  717. package/dist/core/explain/terms.js +103 -0
  718. package/dist/core/explain/terms.js.map +1 -0
  719. package/dist/core/explore/describe.js +105 -0
  720. package/dist/core/explore/describe.js.map +1 -0
  721. package/dist/core/explore/explore.js +204 -0
  722. package/dist/core/explore/explore.js.map +1 -0
  723. package/dist/core/fleet-context.js +174 -146
  724. package/dist/core/fleet-context.js.map +1 -1
  725. package/dist/core/gate/checks.js +208 -0
  726. package/dist/core/gate/checks.js.map +1 -0
  727. package/dist/core/gate/partners.js +246 -0
  728. package/dist/core/gate/partners.js.map +1 -0
  729. package/dist/core/gate/report.js +47 -0
  730. package/dist/core/gate/report.js.map +1 -0
  731. package/dist/core/gate/verification.js +176 -0
  732. package/dist/core/gate/verification.js.map +1 -0
  733. package/dist/core/gherkin/digest.js +60 -0
  734. package/dist/core/gherkin/digest.js.map +1 -0
  735. package/dist/core/gherkin/emit.js +177 -0
  736. package/dist/core/gherkin/emit.js.map +1 -0
  737. package/dist/core/gherkin/read.js +76 -0
  738. package/dist/core/gherkin/read.js.map +1 -0
  739. package/dist/core/gherkin/stale.js +210 -0
  740. package/dist/core/gherkin/stale.js.map +1 -0
  741. package/dist/core/gherkin/stamp.js +77 -0
  742. package/dist/core/gherkin/stamp.js.map +1 -0
  743. package/dist/core/gherkin/steps/catalogue.js +154 -0
  744. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  745. package/dist/core/gherkin/steps/inventory.js +98 -0
  746. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  747. package/dist/core/gherkin/steps/phrase.js +72 -0
  748. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  749. package/dist/core/glossary/delta.js +109 -0
  750. package/dist/core/glossary/delta.js.map +1 -0
  751. package/dist/core/glossary/tree.js +73 -0
  752. package/dist/core/glossary/tree.js.map +1 -0
  753. package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -0
  754. package/dist/core/kernel/concurrency.js.map +1 -0
  755. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  756. package/dist/core/kernel/document-bytes.js.map +1 -0
  757. package/dist/core/kernel/fences.js +42 -0
  758. package/dist/core/kernel/fences.js.map +1 -0
  759. package/dist/core/kernel/ids/capability.js +72 -0
  760. package/dist/core/kernel/ids/capability.js.map +1 -0
  761. package/dist/core/kernel/ids/dirs.js +33 -0
  762. package/dist/core/kernel/ids/dirs.js.map +1 -0
  763. package/dist/core/kernel/ids/feature.js +75 -0
  764. package/dist/core/kernel/ids/feature.js.map +1 -0
  765. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  766. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  767. package/dist/core/kernel/ids/service.js +156 -0
  768. package/dist/core/kernel/ids/service.js.map +1 -0
  769. package/dist/core/kernel/ids/subsystem.js +63 -0
  770. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  771. package/dist/core/{path-safety.js → kernel/path-safety.js} +56 -4
  772. package/dist/core/kernel/path-safety.js.map +1 -0
  773. package/dist/core/{records.js → kernel/records.js} +11 -0
  774. package/dist/core/kernel/records.js.map +1 -0
  775. package/dist/core/links/backlinks.js +66 -0
  776. package/dist/core/links/backlinks.js.map +1 -0
  777. package/dist/core/links/case.js +74 -0
  778. package/dist/core/links/case.js.map +1 -0
  779. package/dist/core/links/corpus.js +118 -0
  780. package/dist/core/links/corpus.js.map +1 -0
  781. package/dist/core/links/findings.js +110 -0
  782. package/dist/core/links/findings.js.map +1 -0
  783. package/dist/core/links/parse.js +265 -0
  784. package/dist/core/links/parse.js.map +1 -0
  785. package/dist/core/mcp/argv.js +212 -0
  786. package/dist/core/mcp/argv.js.map +1 -0
  787. package/dist/core/mcp/author-tools.js +73 -0
  788. package/dist/core/mcp/author-tools.js.map +1 -0
  789. package/dist/core/mcp/framing.js +46 -0
  790. package/dist/core/mcp/framing.js.map +1 -0
  791. package/dist/core/mcp/protocol.js +280 -0
  792. package/dist/core/mcp/protocol.js.map +1 -0
  793. package/dist/core/mcp/tools.js +324 -0
  794. package/dist/core/mcp/tools.js.map +1 -0
  795. package/dist/core/obligations/obligations.js +106 -0
  796. package/dist/core/obligations/obligations.js.map +1 -0
  797. package/dist/core/openapi/baseline/gate.js +207 -0
  798. package/dist/core/openapi/baseline/gate.js.map +1 -0
  799. package/dist/core/openapi/baseline/plan.js +142 -0
  800. package/dist/core/openapi/baseline/plan.js.map +1 -0
  801. package/dist/core/openapi/baseline/record.js +174 -0
  802. package/dist/core/openapi/baseline/record.js.map +1 -0
  803. package/dist/core/openapi/contract-text.js +33 -0
  804. package/dist/core/openapi/contract-text.js.map +1 -0
  805. package/dist/core/openapi/contract-tree.js +301 -0
  806. package/dist/core/openapi/contract-tree.js.map +1 -0
  807. package/dist/core/openapi/depth.js +136 -0
  808. package/dist/core/openapi/depth.js.map +1 -0
  809. package/dist/core/openapi/digest.js +239 -0
  810. package/dist/core/openapi/digest.js.map +1 -0
  811. package/dist/core/{openapi.js → openapi/doc.js} +54 -108
  812. package/dist/core/openapi/doc.js.map +1 -0
  813. package/dist/core/openapi/merge/components.js +199 -0
  814. package/dist/core/openapi/merge/components.js.map +1 -0
  815. package/dist/core/openapi/merge/error.js +16 -0
  816. package/dist/core/openapi/merge/error.js.map +1 -0
  817. package/dist/core/openapi/merge/markers.js +204 -0
  818. package/dist/core/openapi/merge/markers.js.map +1 -0
  819. package/dist/core/openapi/merge/merge.js +232 -0
  820. package/dist/core/openapi/merge/merge.js.map +1 -0
  821. package/dist/core/openapi/merge/pin.js +110 -0
  822. package/dist/core/openapi/merge/pin.js.map +1 -0
  823. package/dist/core/openspec/decide/capabilities.js +244 -0
  824. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  825. package/dist/core/openspec/decide/dispositions.js +63 -0
  826. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  827. package/dist/core/openspec/decide/renames.js +179 -0
  828. package/dist/core/openspec/decide/renames.js.map +1 -0
  829. package/dist/core/openspec/decide/verdict.js +84 -0
  830. package/dist/core/openspec/decide/verdict.js.map +1 -0
  831. package/dist/core/openspec/inventory.js +220 -0
  832. package/dist/core/openspec/inventory.js.map +1 -0
  833. package/dist/core/openspec/model/mapping.js +78 -0
  834. package/dist/core/openspec/model/mapping.js.map +1 -0
  835. package/dist/core/openspec/model/model.js +70 -0
  836. package/dist/core/openspec/model/model.js.map +1 -0
  837. package/dist/core/openspec/scan/changes.js +241 -0
  838. package/dist/core/openspec/scan/changes.js.map +1 -0
  839. package/dist/core/openspec/scan/config.js +191 -0
  840. package/dist/core/openspec/scan/config.js.map +1 -0
  841. package/dist/core/openspec/scan/shape.js +304 -0
  842. package/dist/core/openspec/scan/shape.js.map +1 -0
  843. package/dist/core/openspec/scan/walk.js +116 -0
  844. package/dist/core/openspec/scan/walk.js.map +1 -0
  845. package/dist/core/openspec/scan/workspace.js +71 -0
  846. package/dist/core/openspec/scan/workspace.js.map +1 -0
  847. package/dist/core/owners/codeowners.js +141 -0
  848. package/dist/core/owners/codeowners.js.map +1 -0
  849. package/dist/core/pack/features.js +120 -0
  850. package/dist/core/pack/features.js.map +1 -0
  851. package/dist/core/pack/joins.js +112 -0
  852. package/dist/core/pack/joins.js.map +1 -0
  853. package/dist/core/pack/living.js +157 -0
  854. package/dist/core/pack/living.js.map +1 -0
  855. package/dist/core/pack/pack.js +120 -0
  856. package/dist/core/pack/pack.js.map +1 -0
  857. package/dist/core/permissions/permissions.js +87 -0
  858. package/dist/core/permissions/permissions.js.map +1 -0
  859. package/dist/core/projection/api.js +84 -0
  860. package/dist/core/projection/api.js.map +1 -0
  861. package/dist/core/projection/arch-slice.js +63 -0
  862. package/dist/core/projection/arch-slice.js.map +1 -0
  863. package/dist/core/projection/events.js +34 -0
  864. package/dist/core/projection/events.js.map +1 -0
  865. package/dist/core/projection/introduced.js +14 -0
  866. package/dist/core/projection/introduced.js.map +1 -0
  867. package/dist/core/provenance/findings.js +244 -0
  868. package/dist/core/provenance/findings.js.map +1 -0
  869. package/dist/core/provenance/git.js +201 -0
  870. package/dist/core/provenance/git.js.map +1 -0
  871. package/dist/core/provenance/gitq/moves.js +139 -0
  872. package/dist/core/provenance/gitq/moves.js.map +1 -0
  873. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  874. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  875. package/dist/core/provenance/sample/scope.js +238 -0
  876. package/dist/core/provenance/sample/scope.js.map +1 -0
  877. package/dist/core/provenance/sample/sections.js +61 -0
  878. package/dist/core/provenance/sample/sections.js.map +1 -0
  879. package/dist/core/provenance/sources.js +280 -0
  880. package/dist/core/provenance/sources.js.map +1 -0
  881. package/dist/core/provenance/stamp.js +220 -0
  882. package/dist/core/provenance/stamp.js.map +1 -0
  883. package/dist/core/provenance/walk.js +157 -0
  884. package/dist/core/provenance/walk.js.map +1 -0
  885. package/dist/core/repo/authored/paths.js +210 -0
  886. package/dist/core/repo/authored/paths.js.map +1 -0
  887. package/dist/core/repo/entries.js +126 -0
  888. package/dist/core/repo/entries.js.map +1 -0
  889. package/dist/core/repo/paths.js +322 -0
  890. package/dist/core/repo/paths.js.map +1 -0
  891. package/dist/core/repo/repo.js +308 -0
  892. package/dist/core/repo/repo.js.map +1 -0
  893. package/dist/core/repo/service-target.js +153 -0
  894. package/dist/core/repo/service-target.js.map +1 -0
  895. package/dist/core/repo/state.js +58 -0
  896. package/dist/core/repo/state.js.map +1 -0
  897. package/dist/core/repo/tree/find.js +61 -0
  898. package/dist/core/repo/tree/find.js.map +1 -0
  899. package/dist/core/repo/tree/fs.js +90 -0
  900. package/dist/core/repo/tree/fs.js.map +1 -0
  901. package/dist/core/repo/tree/marker.js +61 -0
  902. package/dist/core/repo/tree/marker.js.map +1 -0
  903. package/dist/core/repo/tree/render/body.js +258 -0
  904. package/dist/core/repo/tree/render/body.js.map +1 -0
  905. package/dist/core/repo/tree/render/projects.js +182 -0
  906. package/dist/core/repo/tree/render/projects.js.map +1 -0
  907. package/dist/core/repo/tree/render/service/header.js +125 -0
  908. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  909. package/dist/core/repo/tree/render/service/peers.js +28 -0
  910. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  911. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  912. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  913. package/dist/core/repo/tree/render/service/views.js +78 -0
  914. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  915. package/dist/core/repo/tree/render/stale.js +42 -0
  916. package/dist/core/repo/tree/render/stale.js.map +1 -0
  917. package/dist/core/repo/tree/render/text.js +84 -0
  918. package/dist/core/repo/tree/render/text.js.map +1 -0
  919. package/dist/core/repo/tree/render/views.js +293 -0
  920. package/dist/core/repo/tree/render/views.js.map +1 -0
  921. package/dist/core/repo/tree/walk.js +255 -0
  922. package/dist/core/repo/tree/walk.js.map +1 -0
  923. package/dist/core/results.js +146 -14
  924. package/dist/core/results.js.map +1 -1
  925. package/dist/core/scaffold/landscape.js +239 -0
  926. package/dist/core/scaffold/landscape.js.map +1 -0
  927. package/dist/core/scaffold/legacy.js +271 -0
  928. package/dist/core/scaffold/legacy.js.map +1 -0
  929. package/dist/core/scaffold/readme.js +84 -0
  930. package/dist/core/scaffold/readme.js.map +1 -0
  931. package/dist/core/staging/commit.js +252 -0
  932. package/dist/core/staging/commit.js.map +1 -0
  933. package/dist/core/staging/interrupted.js +96 -0
  934. package/dist/core/staging/interrupted.js.map +1 -0
  935. package/dist/core/staging/lock.js +268 -0
  936. package/dist/core/staging/lock.js.map +1 -0
  937. package/dist/core/staging/recovery/finding.js +35 -0
  938. package/dist/core/staging/recovery/finding.js.map +1 -0
  939. package/dist/core/staging/recovery/intent.js +95 -0
  940. package/dist/core/staging/recovery/intent.js.map +1 -0
  941. package/dist/core/staging/recovery/recover.js +204 -0
  942. package/dist/core/staging/recovery/recover.js.map +1 -0
  943. package/dist/core/staging/recovery/residue.js +62 -0
  944. package/dist/core/staging/recovery/residue.js.map +1 -0
  945. package/dist/core/staging/snapshot/manifest.js +188 -0
  946. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  947. package/dist/core/staging/snapshot/snapshot.js +196 -0
  948. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  949. package/dist/core/staging/txn/forward.js +181 -0
  950. package/dist/core/staging/txn/forward.js.map +1 -0
  951. package/dist/core/staging/txn/journal.js +139 -0
  952. package/dist/core/staging/txn/journal.js.map +1 -0
  953. package/dist/core/staging/txn/transaction.js +75 -0
  954. package/dist/core/staging/txn/transaction.js.map +1 -0
  955. package/dist/core/staging/writes.js +113 -0
  956. package/dist/core/staging/writes.js.map +1 -0
  957. package/dist/core/status/actions/execution.js +60 -0
  958. package/dist/core/status/actions/execution.js.map +1 -0
  959. package/dist/core/status/contracts.js +126 -0
  960. package/dist/core/status/contracts.js.map +1 -0
  961. package/dist/core/status/feature/artifacts.js +196 -0
  962. package/dist/core/status/feature/artifacts.js.map +1 -0
  963. package/dist/core/status/feature/feature.js +214 -0
  964. package/dist/core/status/feature/feature.js.map +1 -0
  965. package/dist/core/status/feature/next.js +163 -0
  966. package/dist/core/status/feature/next.js.map +1 -0
  967. package/dist/core/status/feature/state.js +21 -0
  968. package/dist/core/status/feature/state.js.map +1 -0
  969. package/dist/core/status/feature/words.js +96 -0
  970. package/dist/core/status/feature/words.js.map +1 -0
  971. package/dist/core/status/fleet/fleet.js +216 -0
  972. package/dist/core/status/fleet/fleet.js.map +1 -0
  973. package/dist/core/status/fleet/next.js +302 -0
  974. package/dist/core/status/fleet/next.js.map +1 -0
  975. package/dist/core/status/interrupted.js +97 -0
  976. package/dist/core/status/interrupted.js.map +1 -0
  977. package/dist/core/status/report.js +31 -0
  978. package/dist/core/status/report.js.map +1 -0
  979. package/dist/core/status/scan.js +41 -0
  980. package/dist/core/status/scan.js.map +1 -0
  981. package/dist/core/status/verification.js +216 -0
  982. package/dist/core/status/verification.js.map +1 -0
  983. package/dist/core/tasks/packet.js +199 -0
  984. package/dist/core/tasks/packet.js.map +1 -0
  985. package/dist/core/tasks/record.js +43 -0
  986. package/dist/core/tasks/record.js.map +1 -0
  987. package/dist/core/tasks/sources.js +181 -0
  988. package/dist/core/tasks/sources.js.map +1 -0
  989. package/dist/core/tasks/stamps.js +76 -0
  990. package/dist/core/tasks/stamps.js.map +1 -0
  991. package/dist/core/tasks/unit.js +0 -0
  992. package/dist/core/tasks/unit.js.map +1 -0
  993. package/dist/core/usecases/capability.js +166 -0
  994. package/dist/core/usecases/capability.js.map +1 -0
  995. package/dist/core/usecases/delta/claims.js +140 -0
  996. package/dist/core/usecases/delta/claims.js.map +1 -0
  997. package/dist/core/usecases/delta/flows.js +101 -0
  998. package/dist/core/usecases/delta/flows.js.map +1 -0
  999. package/dist/core/usecases/delta/modified.js +315 -0
  1000. package/dist/core/usecases/delta/modified.js.map +1 -0
  1001. package/dist/core/usecases/delta/overlay.js +76 -0
  1002. package/dist/core/usecases/delta/overlay.js.map +1 -0
  1003. package/dist/core/usecases/fleet.js +296 -0
  1004. package/dist/core/usecases/fleet.js.map +1 -0
  1005. package/dist/core/usecases/grade/capability-tag.js +93 -0
  1006. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  1007. package/dist/core/usecases/grade/feature.js +88 -0
  1008. package/dist/core/usecases/grade/feature.js.map +1 -0
  1009. package/dist/core/usecases/grade/requirement-tag.js +94 -0
  1010. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  1011. package/dist/core/usecases/grade/steps.js +266 -0
  1012. package/dist/core/usecases/grade/steps.js.map +1 -0
  1013. package/dist/core/usecases/grade/usecases.js +112 -0
  1014. package/dist/core/usecases/grade/usecases.js.map +1 -0
  1015. package/dist/core/usecases/operations.js +123 -0
  1016. package/dist/core/usecases/operations.js.map +1 -0
  1017. package/dist/core/usecases/place.js +44 -0
  1018. package/dist/core/usecases/place.js.map +1 -0
  1019. package/dist/core/usecases/service/exclude.js +119 -0
  1020. package/dist/core/usecases/service/exclude.js.map +1 -0
  1021. package/dist/core/usecases/service/flows.js +164 -0
  1022. package/dist/core/usecases/service/flows.js.map +1 -0
  1023. package/dist/core/usecases/suites/participants.js +83 -0
  1024. package/dist/core/usecases/suites/participants.js.map +1 -0
  1025. package/dist/core/usecases/suites/suites.js +45 -0
  1026. package/dist/core/usecases/suites/suites.js.map +1 -0
  1027. package/dist/core/usecases/touch.js +101 -0
  1028. package/dist/core/usecases/touch.js.map +1 -0
  1029. package/dist/core/verify/answers.js +180 -0
  1030. package/dist/core/verify/answers.js.map +1 -0
  1031. package/dist/core/verify/build.js +170 -0
  1032. package/dist/core/verify/build.js.map +1 -0
  1033. package/dist/core/verify/checklist.js +259 -0
  1034. package/dist/core/verify/checklist.js.map +1 -0
  1035. package/dist/core/verify/claims/identity.js +61 -0
  1036. package/dist/core/verify/claims/identity.js.map +1 -0
  1037. package/dist/core/verify/cross/diff.js +97 -0
  1038. package/dist/core/verify/cross/diff.js.map +1 -0
  1039. package/dist/core/verify/evidence/contract.js +169 -0
  1040. package/dist/core/verify/evidence/contract.js.map +1 -0
  1041. package/dist/core/verify/location.js +67 -0
  1042. package/dist/core/verify/location.js.map +1 -0
  1043. package/dist/core/verify/pins/lint.js +158 -0
  1044. package/dist/core/verify/pins/lint.js.map +1 -0
  1045. package/dist/core/verify/pins/pin.js +95 -0
  1046. package/dist/core/verify/pins/pin.js.map +1 -0
  1047. package/dist/core/verify/read/file.js +224 -0
  1048. package/dist/core/verify/read/file.js.map +1 -0
  1049. package/dist/core/verify/read/shape.js +169 -0
  1050. package/dist/core/verify/read/shape.js.map +1 -0
  1051. package/dist/core/verify/read/union.js +105 -0
  1052. package/dist/core/verify/read/union.js.map +1 -0
  1053. package/dist/core/verify/record.js +165 -0
  1054. package/dist/core/verify/record.js.map +1 -0
  1055. package/dist/core/verify/store/commit.js +99 -0
  1056. package/dist/core/verify/store/commit.js.map +1 -0
  1057. package/dist/core/verify/store/render.js +61 -0
  1058. package/dist/core/verify/store/render.js.map +1 -0
  1059. package/dist/core/vocabulary/health.js +91 -0
  1060. package/dist/core/vocabulary/health.js.map +1 -0
  1061. package/dist/core/vocabulary/issue.js +59 -0
  1062. package/dist/core/vocabulary/issue.js.map +1 -0
  1063. package/dist/core/vocabulary/maturity.js +216 -0
  1064. package/dist/core/vocabulary/maturity.js.map +1 -0
  1065. package/dist/core/vocabulary/report.js +90 -0
  1066. package/dist/core/vocabulary/report.js.map +1 -0
  1067. package/dist/core/vocabulary/steps.js +266 -0
  1068. package/dist/core/vocabulary/steps.js.map +1 -0
  1069. package/dist/core/workspace/discover.js +239 -0
  1070. package/dist/core/workspace/discover.js.map +1 -0
  1071. package/dist/core/workspace/render.js +52 -0
  1072. package/dist/core/workspace/render.js.map +1 -0
  1073. package/examples/README.md +232 -0
  1074. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  1075. package/examples/docs/architecture/capabilities.yaml +31 -0
  1076. package/examples/docs/architecture/landscape.likec4 +336 -0
  1077. package/examples/docs/architecture/obligations.yaml +23 -0
  1078. package/examples/docs/architecture/permissions.yaml +50 -0
  1079. package/examples/docs/architecture/services.likec4 +70 -0
  1080. package/examples/docs/architecture/subsystems.likec4 +18 -0
  1081. package/examples/docs/architecture/usecases/order-notification.likec4 +74 -0
  1082. package/examples/docs/capabilities/checkout/spec.md +55 -0
  1083. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  1084. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  1085. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  1086. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  1087. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  1088. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  1089. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +132 -0
  1090. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  1091. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  1092. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  1093. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  1094. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  1095. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +31 -0
  1096. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  1097. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  1098. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  1099. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  1100. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  1101. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  1102. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  1103. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  1104. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  1105. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  1106. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +73 -0
  1107. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  1108. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  1109. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  1110. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  1111. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  1112. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  1113. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  1114. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  1115. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  1116. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  1117. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  1118. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  1119. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  1120. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  1121. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  1122. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  1123. package/examples/docs/glossary/order.md +15 -0
  1124. package/examples/docs/glossary/payments/authorization.md +14 -0
  1125. package/examples/docs/likec4.config.json +8 -0
  1126. package/examples/docs/loam.json +3 -0
  1127. package/examples/docs/services/checkout-web/model.likec4 +92 -0
  1128. package/examples/docs/services/checkout-web/spec.md +91 -0
  1129. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  1130. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  1131. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  1132. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  1133. package/examples/docs/services/order-service/arch.spec.md +134 -0
  1134. package/examples/docs/services/order-service/asyncapi.yaml +109 -0
  1135. package/examples/docs/services/order-service/health.yaml +57 -0
  1136. package/examples/docs/services/order-service/model.likec4 +126 -0
  1137. package/examples/docs/services/order-service/openapi.yaml +257 -0
  1138. package/examples/docs/services/order-service/runbook.md +62 -0
  1139. package/examples/docs/services/order-service/spec.md +134 -0
  1140. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  1141. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  1142. package/examples/docs/services/payment-service/arch.spec.md +76 -0
  1143. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  1144. package/examples/docs/services/payment-service/health.yaml +39 -0
  1145. package/examples/docs/services/payment-service/model.likec4 +68 -0
  1146. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  1147. package/examples/docs/services/payment-service/runbook.md +37 -0
  1148. package/examples/docs/services/payment-service/spec.md +88 -0
  1149. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  1150. package/examples/docs/services/platform/identity-service/arch.spec.md +120 -0
  1151. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  1152. package/examples/docs/services/platform/identity-service/model.likec4 +81 -0
  1153. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  1154. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  1155. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  1156. package/examples/docs/services/platform/notification-service/asyncapi.yaml +200 -0
  1157. package/examples/docs/services/platform/notification-service/health.yaml +40 -0
  1158. package/examples/docs/services/platform/notification-service/model.likec4 +97 -0
  1159. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  1160. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  1161. package/examples/docs/services/platform/subsystem.yaml +2 -0
  1162. package/examples/fleet.yaml +57 -0
  1163. package/package.json +19 -6
  1164. package/dist/commands/adopt.js +0 -240
  1165. package/dist/commands/adopt.js.map +0 -1
  1166. package/dist/commands/archive.js +0 -1313
  1167. package/dist/commands/archive.js.map +0 -1
  1168. package/dist/commands/delta.js +0 -388
  1169. package/dist/commands/delta.js.map +0 -1
  1170. package/dist/commands/docs-repo-gate.js.map +0 -1
  1171. package/dist/commands/format.js +0 -17
  1172. package/dist/commands/format.js.map +0 -1
  1173. package/dist/commands/gherkin.js +0 -309
  1174. package/dist/commands/gherkin.js.map +0 -1
  1175. package/dist/commands/init.js.map +0 -1
  1176. package/dist/commands/list.js +0 -295
  1177. package/dist/commands/list.js.map +0 -1
  1178. package/dist/commands/migrate-openspec.js +0 -950
  1179. package/dist/commands/migrate-openspec.js.map +0 -1
  1180. package/dist/commands/new.js +0 -413
  1181. package/dist/commands/new.js.map +0 -1
  1182. package/dist/commands/rebase.js +0 -356
  1183. package/dist/commands/rebase.js.map +0 -1
  1184. package/dist/commands/show.js +0 -320
  1185. package/dist/commands/show.js.map +0 -1
  1186. package/dist/commands/status.js +0 -262
  1187. package/dist/commands/status.js.map +0 -1
  1188. package/dist/commands/unarchive.js +0 -317
  1189. package/dist/commands/unarchive.js.map +0 -1
  1190. package/dist/commands/validate.js +0 -1773
  1191. package/dist/commands/validate.js.map +0 -1
  1192. package/dist/commands/verify.js +0 -775
  1193. package/dist/commands/verify.js.map +0 -1
  1194. package/dist/commands/vouch.js +0 -421
  1195. package/dist/commands/vouch.js.map +0 -1
  1196. package/dist/core/agent.js +0 -2173
  1197. package/dist/core/agent.js.map +0 -1
  1198. package/dist/core/agents-stamp.js.map +0 -1
  1199. package/dist/core/arch.js +0 -130
  1200. package/dist/core/arch.js.map +0 -1
  1201. package/dist/core/asyncapi.js +0 -253
  1202. package/dist/core/asyncapi.js.map +0 -1
  1203. package/dist/core/brief.js +0 -755
  1204. package/dist/core/brief.js.map +0 -1
  1205. package/dist/core/coherence.js +0 -577
  1206. package/dist/core/coherence.js.map +0 -1
  1207. package/dist/core/concurrency.js.map +0 -1
  1208. package/dist/core/config.js.map +0 -1
  1209. package/dist/core/delta.js +0 -476
  1210. package/dist/core/delta.js.map +0 -1
  1211. package/dist/core/dependencies.js +0 -356
  1212. package/dist/core/dependencies.js.map +0 -1
  1213. package/dist/core/doctor.js +0 -596
  1214. package/dist/core/doctor.js.map +0 -1
  1215. package/dist/core/document-bytes.js.map +0 -1
  1216. package/dist/core/explore.js +0 -225
  1217. package/dist/core/explore.js.map +0 -1
  1218. package/dist/core/frontmatter.js.map +0 -1
  1219. package/dist/core/gherkin.js +0 -463
  1220. package/dist/core/gherkin.js.map +0 -1
  1221. package/dist/core/health.js +0 -67
  1222. package/dist/core/health.js.map +0 -1
  1223. package/dist/core/ids.js +0 -122
  1224. package/dist/core/ids.js.map +0 -1
  1225. package/dist/core/issue.js +0 -9
  1226. package/dist/core/issue.js.map +0 -1
  1227. package/dist/core/json.js +0 -74
  1228. package/dist/core/json.js.map +0 -1
  1229. package/dist/core/likec4.js +0 -489
  1230. package/dist/core/likec4.js.map +0 -1
  1231. package/dist/core/maturity.js +0 -66
  1232. package/dist/core/maturity.js.map +0 -1
  1233. package/dist/core/openapi-merge.js +0 -552
  1234. package/dist/core/openapi-merge.js.map +0 -1
  1235. package/dist/core/openapi.js.map +0 -1
  1236. package/dist/core/openspec-inventory.js +0 -1440
  1237. package/dist/core/openspec-inventory.js.map +0 -1
  1238. package/dist/core/path-safety.js.map +0 -1
  1239. package/dist/core/provenance.js +0 -787
  1240. package/dist/core/provenance.js.map +0 -1
  1241. package/dist/core/records.js.map +0 -1
  1242. package/dist/core/repo.js +0 -438
  1243. package/dist/core/repo.js.map +0 -1
  1244. package/dist/core/report.js +0 -47
  1245. package/dist/core/report.js.map +0 -1
  1246. package/dist/core/spec.js +0 -505
  1247. package/dist/core/spec.js.map +0 -1
  1248. package/dist/core/staging.js +0 -890
  1249. package/dist/core/staging.js.map +0 -1
  1250. package/dist/core/status.js +0 -1132
  1251. package/dist/core/status.js.map +0 -1
  1252. package/dist/core/steps.js +0 -72
  1253. package/dist/core/steps.js.map +0 -1
  1254. package/dist/core/verify.js +0 -807
  1255. package/dist/core/verify.js.map +0 -1
  1256. package/dist/core/version.js.map +0 -1
@@ -0,0 +1,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"]}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Where the verification record lives on disk — the one-file form, the
3
+ * per-service directory, and which of the two a reader is pointed at.
4
+ *
5
+ * Split out of `./record.ts`, which keeps what gets written down and how a set
6
+ * of answers counts up to a verdict: the addresses are a different subject from
7
+ * the shapes and the arithmetic, and the per-service directory pushed that
8
+ * module over the line limit. The readers (`./read/file.ts`), the writers
9
+ * (`loam verify`'s record step) and `status`'s artifact row all ask where the
10
+ * record is; none of them needs the record's shape to ask it.
11
+ */
12
+ import { existsSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ /**
15
+ * Where the record lives: inside the feature, so `archive` carries it into
16
+ * `features/archive/` with everything else and a reviewer finds it next to the
17
+ * delta it is about. YAML rather than frontmatter or JSON — it is data, it has
18
+ * to survive without loam, and one claim per block is a diff a person can read.
19
+ *
20
+ * This is the ONE-FILE form: what the all-at-once `--record` (no `--service`)
21
+ * writes, and what every federated record written before the per-service
22
+ * directory existed still is. It is read forever, active and archived alike.
23
+ * A federated attestation no longer goes here — see {@link serviceRecordPath}.
24
+ */
25
+ export function verificationPath(featureDir) {
26
+ return join(featureDir, "verification.yaml");
27
+ }
28
+ /**
29
+ * The federated record: one file per attesting service, and the DIRECTORY is
30
+ * the list — the `glossary/` and `capabilities/` rule.
31
+ *
32
+ * One shared file was the wrong shape for a fleet. Every service's attestation
33
+ * rewrote the same `summary`, `recorded` and checklist-ordered `claims`, so two
34
+ * docs-repo branches recording two DIFFERENT services always conflicted in git
35
+ * — add/add from an empty start, content conflicts on the summary once one
36
+ * attestation had merged — and sorting the attestations did not help, because
37
+ * two insertions at one anchor are a conflict whatever the order. The lock that
38
+ * serialises writers covers one checkout; a fleet records from many. With one
39
+ * file per service, two teams' records touch two different paths and merge
40
+ * cleanly, and the verdict is computed from the union at read time — which it
41
+ * always was: nothing ever trusted the stored `summary`.
42
+ */
43
+ export function verificationDir(featureDir) {
44
+ return join(featureDir, "verification");
45
+ }
46
+ /**
47
+ * One service's attestation file. The service id grammar admits no `/`, so this
48
+ * never leaves the directory — and the parameter type is what makes that a
49
+ * guarantee rather than a hope: a `PathableService` is a name whose provenance
50
+ * is the repository (a validated id, or a directory that exists), so a name a
51
+ * document merely asserts, or a raw flag nobody checked, does not compile here.
52
+ */
53
+ export function serviceRecordPath(featureDir, service) {
54
+ return join(verificationDir(featureDir), `${service}.yaml`);
55
+ }
56
+ /**
57
+ * Where a reader should look: the directory once it exists, the one file
58
+ * otherwise. A single path is lossy on purpose — a record mid-migration is
59
+ * both — and what a reader is pointed at is where the next attestation will
60
+ * land. A legacy file beside the directory is still read (see `./read/file.ts`);
61
+ * it is simply no longer where anything is written for a service.
62
+ */
63
+ export function recordLocation(featureDir) {
64
+ const dir = verificationDir(featureDir);
65
+ return existsSync(dir) ? dir : verificationPath(featureDir);
66
+ }
67
+ //# sourceMappingURL=location.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"location.js","sourceRoot":"","sources":["../../../src/core/verify/location.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB;IACjD,OAAO,IAAI,CAAC,UAAU,EAAE,mBAAmB,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,OAAO,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAkB,EAAE,OAAwB;IAC5E,OAAO,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,GAAG,OAAO,OAAO,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,UAAkB;IAC/C,MAAM,GAAG,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IACxC,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;AAC9D,CAAC","sourcesContent":["/**\n * Where the verification record lives on disk — the one-file form, the\n * per-service directory, and which of the two a reader is pointed at.\n *\n * Split out of `./record.ts`, which keeps what gets written down and how a set\n * of answers counts up to a verdict: the addresses are a different subject from\n * the shapes and the arithmetic, and the per-service directory pushed that\n * module over the line limit. The readers (`./read/file.ts`), the writers\n * (`loam verify`'s record step) and `status`'s artifact row all ask where the\n * record is; none of them needs the record's shape to ask it.\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { PathableService } from \"../kernel/ids/service.js\";\n\n/**\n * Where the record lives: inside the feature, so `archive` carries it into\n * `features/archive/` with everything else and a reviewer finds it next to the\n * delta it is about. YAML rather than frontmatter or JSON — it is data, it has\n * to survive without loam, and one claim per block is a diff a person can read.\n *\n * This is the ONE-FILE form: what the all-at-once `--record` (no `--service`)\n * writes, and what every federated record written before the per-service\n * directory existed still is. It is read forever, active and archived alike.\n * A federated attestation no longer goes here — see {@link serviceRecordPath}.\n */\nexport function verificationPath(featureDir: string): string {\n return join(featureDir, \"verification.yaml\");\n}\n\n/**\n * The federated record: one file per attesting service, and the DIRECTORY is\n * the list — the `glossary/` and `capabilities/` rule.\n *\n * One shared file was the wrong shape for a fleet. Every service's attestation\n * rewrote the same `summary`, `recorded` and checklist-ordered `claims`, so two\n * docs-repo branches recording two DIFFERENT services always conflicted in git\n * — add/add from an empty start, content conflicts on the summary once one\n * attestation had merged — and sorting the attestations did not help, because\n * two insertions at one anchor are a conflict whatever the order. The lock that\n * serialises writers covers one checkout; a fleet records from many. With one\n * file per service, two teams' records touch two different paths and merge\n * cleanly, and the verdict is computed from the union at read time — which it\n * always was: nothing ever trusted the stored `summary`.\n */\nexport function verificationDir(featureDir: string): string {\n return join(featureDir, \"verification\");\n}\n\n/**\n * One service's attestation file. The service id grammar admits no `/`, so this\n * never leaves the directory — and the parameter type is what makes that a\n * guarantee rather than a hope: a `PathableService` is a name whose provenance\n * is the repository (a validated id, or a directory that exists), so a name a\n * document merely asserts, or a raw flag nobody checked, does not compile here.\n */\nexport function serviceRecordPath(featureDir: string, service: PathableService): string {\n return join(verificationDir(featureDir), `${service}.yaml`);\n}\n\n/**\n * Where a reader should look: the directory once it exists, the one file\n * otherwise. A single path is lossy on purpose — a record mid-migration is\n * both — and what a reader is pointed at is where the next attestation will\n * land. A legacy file beside the directory is still read (see `./read/file.ts`);\n * it is simply no longer where anything is written for a service.\n */\nexport function recordLocation(featureDir: string): string {\n const dir = verificationDir(featureDir);\n return existsSync(dir) ? dir : verificationPath(featureDir);\n}\n"]}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Re-checking evidence pins against a working tree: pure data out, one grade
3
+ * per pin, and no verdict anywhere in the result on purpose — the lint demotes
4
+ * reviewer confidence, it never promotes or demotes a claim. Prints nothing;
5
+ * the validate command turns the grades into findings.
6
+ *
7
+ * The claim shape is structural rather than an import of `../record.js`'s
8
+ * `RecordedClaim`, and not only for the smallest-parameter rule: this package
9
+ * is imported BY `core/verify` and its `read/` sibling (`../read/shape.ts` asks
10
+ * `./pin.ts` for the read guard, `../answers.ts` for the shape), so importing
11
+ * the parent back would
12
+ * put a cycle in the package graph that `import/no-cycle` cannot see.
13
+ */
14
+ import { readFile, stat } from "node:fs/promises";
15
+ import { inOrder } from "../../kernel/concurrency.js";
16
+ import { resolvePortableFileInside, UnsafePathError } from "../../kernel/path-safety.js";
17
+ import { pinnedDigest, pinnedText, sourceLines } from "./pin.js";
18
+ /**
19
+ * Grade one record's pins for one service against that service's working tree.
20
+ *
21
+ * Only agent-confirmed claims of `service` are graded: a runner's or contract
22
+ * runner's evidence names a report entry, not a file, so there is nothing to
23
+ * re-check, and an unconfirmed claim pinned nothing. Absent `answered_by`
24
+ * counts as agent — the `attestedClaims` rule.
25
+ *
26
+ * Containment is per citation: one unreadable cited file degrades exactly the
27
+ * pins that cite it (graded `unresolved`), never the sibling pins and never
28
+ * the whole record. And "could not look" is never "looks fine": every failure
29
+ * to read is a drift entry, not a skip — fail closed at the validator.
30
+ */
31
+ export async function lintEvidencePins(claims, service, repoDir) {
32
+ // The closed side of the answerer test, on purpose: `answered_by` is an open
33
+ // string here (a record is hand-editable YAML, and a newer loam may add
34
+ // answerers), so excluding the known mechanical values would sweep every
35
+ // FUTURE mechanical answerer's report-entry citations into the `unpinned`
36
+ // tally with false "recorded before pins existed" advice. Only what is
37
+ // positively an agent's word is graded; absent counts as agent — the
38
+ // `attestedClaims` rule for records that predate `--results`.
39
+ const mine = claims.filter((c) => c.subject === service &&
40
+ c.verdict === "confirmed" &&
41
+ (c.answered_by === undefined || c.answered_by === "agent"));
42
+ // Join pins to evidence entries by the `path:line` key, never by position:
43
+ // a record is hand-editable YAML, and a positional join would let a deleted
44
+ // evidence line silently shift every later pin onto the wrong citation.
45
+ const joined = [];
46
+ let unpinned = 0;
47
+ for (const claim of mine) {
48
+ const pins = new Map((claim.evidence_pins ?? []).map((pin) => [`${pin.path}:${pin.line}`, pin]));
49
+ // A pin no evidence entry names pins nothing this claim cites (a hand
50
+ // edit); grading it would report drift about a citation the claim does not
51
+ // make, so only the joined pairs are graded. The reverse direction — a
52
+ // citation without a pin — is the `unpinned` tally.
53
+ for (const evidence of claim.evidence) {
54
+ const pin = pins.get(evidence);
55
+ if (pin === undefined)
56
+ unpinned += 1;
57
+ else
58
+ joined.push({ claim: claim.id, evidence, pin });
59
+ }
60
+ }
61
+ // Each distinct cited file is read and hashed once per call — a local map,
62
+ // per invocation, because module-level state leaks across tests and hosts.
63
+ // The reads are independent, so they go through the bounded pool; grading
64
+ // stays sequential below so `drifts` keeps record order.
65
+ const paths = [...new Set(joined.map((j) => j.pin.path))];
66
+ const states = new Map(await inOrder(paths, async (path) => [path, await readCited(repoDir, path)]));
67
+ let checked = 0;
68
+ const drifts = [];
69
+ for (const { claim, evidence, pin } of joined) {
70
+ const file = states.get(pin.path);
71
+ if (file === undefined || file.state === "unreadable") {
72
+ drifts.push({ claim, evidence, grade: "unresolved", what: file?.what ?? "the cited file was not read" });
73
+ continue;
74
+ }
75
+ const cited = file.lines[pin.line - 1];
76
+ if (cited === undefined) {
77
+ drifts.push({
78
+ claim,
79
+ evidence,
80
+ grade: "unresolved",
81
+ // `continue`, like the unreadable-file arm: an unresolvable CITATION
82
+ // is one finding, and a token scan on top would report the same
83
+ // damaged citation twice under two codes.
84
+ what: `the cited line is past the end — the file now has ${file.lines.length} line(s)`,
85
+ });
86
+ continue;
87
+ }
88
+ if (file.digest === pin.file_sha256) {
89
+ checked += 1;
90
+ }
91
+ else if (pinnedText(cited) === pin.text) {
92
+ // The mildest drift: the file changed around the cited line, which
93
+ // still reads as pinned — "reads as", not "is": both sides of the
94
+ // comparison are capped at PIN_TEXT_CAP, so a change past the cap on a
95
+ // pathological line is invisible to this grade (and visible to the
96
+ // digest, which is why this is a drift and not a clean pin).
97
+ drifts.push({
98
+ claim,
99
+ evidence,
100
+ grade: "moved",
101
+ what: "the file changed around the cited line, which still reads as pinned",
102
+ });
103
+ }
104
+ else {
105
+ drifts.push({
106
+ claim,
107
+ evidence,
108
+ grade: "line-changed",
109
+ what: `the cited line now reads '${pinnedText(cited)}' where the record pinned '${pin.text}'`,
110
+ });
111
+ }
112
+ // Independent of the grades above, clean pins included — a digest match
113
+ // must not read as "the token is still there", because content identical
114
+ // to record time says nothing once the file drifts back. "No longer" is
115
+ // the honest word here: the write side stamps `token` only when the
116
+ // attested blob contained it (EvidencePin.token), so this grade always
117
+ // convicts a disappearance, never re-litigates an absence the record-time
118
+ // notice already reported.
119
+ if (pin.token !== undefined && !file.text.includes(pin.token)) {
120
+ drifts.push({
121
+ claim,
122
+ evidence,
123
+ grade: "token-missing",
124
+ what: `the cited file no longer contains '${pin.token}' — the literal string the claim asserts`,
125
+ });
126
+ }
127
+ }
128
+ return { checked, drifts, unpinned };
129
+ }
130
+ /** One cited file against the working tree, every failure named rather than thrown. */
131
+ async function readCited(repoDir, path) {
132
+ let absolute;
133
+ try {
134
+ absolute = resolvePortableFileInside(repoDir, path, "pinned evidence");
135
+ }
136
+ catch (err) {
137
+ if (!(err instanceof UnsafePathError))
138
+ throw err;
139
+ return { state: "unreadable", what: `the pinned path is unsafe: ${err.message}` };
140
+ }
141
+ try {
142
+ const info = await stat(absolute);
143
+ if (!info.isFile())
144
+ return { state: "unreadable", what: "the cited path is not a regular file" };
145
+ const text = await readFile(absolute, "utf8");
146
+ return { state: "ok", digest: pinnedDigest(text), lines: sourceLines(text), text };
147
+ }
148
+ catch (err) {
149
+ // ENOENT is the common drift — the cited file is gone from the tree; any
150
+ // other errno (EACCES, EISDIR racing the stat) is named as itself, because
151
+ // "could not read" and "does not exist" call for different repairs.
152
+ if (err.code === "ENOENT") {
153
+ return { state: "unreadable", what: "the cited file does not exist in this working tree" };
154
+ }
155
+ return { state: "unreadable", what: err instanceof Error ? err.message : String(err) };
156
+ }
157
+ }
158
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../../../src/core/verify/pins/lint.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Re-checking evidence pins against a working tree: pure data out, one grade\n * per pin, and no verdict anywhere in the result on purpose — the lint demotes\n * reviewer confidence, it never promotes or demotes a claim. Prints nothing;\n * the validate command turns the grades into findings.\n *\n * The claim shape is structural rather than an import of `../record.js`'s\n * `RecordedClaim`, and not only for the smallest-parameter rule: this package\n * is imported BY `core/verify` and its `read/` sibling (`../read/shape.ts` asks\n * `./pin.ts` for the read guard, `../answers.ts` for the shape), so importing\n * the parent back would\n * put a cycle in the package graph that `import/no-cycle` cannot see.\n */\nimport { readFile, stat } from \"node:fs/promises\";\nimport { inOrder } from \"../../kernel/concurrency.js\";\nimport { resolvePortableFileInside, UnsafePathError } from \"../../kernel/path-safety.js\";\nimport { pinnedDigest, pinnedText, sourceLines, type EvidencePin } from \"./pin.js\";\n\n/** What the lint reads off a recorded claim — structurally, see the header. */\nexport interface PinnedClaim {\n id: string;\n /** Present in federated (schema 2) records — the service whose code answers it. */\n subject?: string;\n verdict: string;\n /** Absent counts as agent — the `attestedClaims` rule for records that predate `--results`. */\n answered_by?: string;\n evidence: string[];\n evidence_pins?: EvidencePin[];\n}\n\n/** One pin's disagreement with the working tree. `grade` is what a finding code is made from. */\nexport interface PinDrift {\n claim: string;\n /** The `path:line` citation the pin belongs to. */\n evidence: string;\n grade: \"unresolved\" | \"moved\" | \"line-changed\" | \"token-missing\";\n /** What changed, in one clause — rendered into a finding's detail line. */\n what: string;\n}\n\nexport interface PinLint {\n /** Pins that resolved clean: file digest unchanged against the working tree. */\n checked: number;\n /** In record order — claim by claim, citation by citation — so two runs diff. */\n drifts: PinDrift[];\n /** Agent-confirmed citations carrying no pin, plus claims with no pins at all. */\n unpinned: number;\n}\n\n/** What one cited file turned out to be, read and hashed once per lint call. */\ntype FileState =\n | { state: \"unreadable\"; what: string }\n | { state: \"ok\"; digest: string; lines: string[]; text: string };\n\n/**\n * Grade one record's pins for one service against that service's working tree.\n *\n * Only agent-confirmed claims of `service` are graded: a runner's or contract\n * runner's evidence names a report entry, not a file, so there is nothing to\n * re-check, and an unconfirmed claim pinned nothing. Absent `answered_by`\n * counts as agent — the `attestedClaims` rule.\n *\n * Containment is per citation: one unreadable cited file degrades exactly the\n * pins that cite it (graded `unresolved`), never the sibling pins and never\n * the whole record. And \"could not look\" is never \"looks fine\": every failure\n * to read is a drift entry, not a skip — fail closed at the validator.\n */\nexport async function lintEvidencePins(\n claims: readonly PinnedClaim[],\n service: string,\n repoDir: string,\n): Promise<PinLint> {\n // The closed side of the answerer test, on purpose: `answered_by` is an open\n // string here (a record is hand-editable YAML, and a newer loam may add\n // answerers), so excluding the known mechanical values would sweep every\n // FUTURE mechanical answerer's report-entry citations into the `unpinned`\n // tally with false \"recorded before pins existed\" advice. Only what is\n // positively an agent's word is graded; absent counts as agent — the\n // `attestedClaims` rule for records that predate `--results`.\n const mine = claims.filter(\n (c) =>\n c.subject === service &&\n c.verdict === \"confirmed\" &&\n (c.answered_by === undefined || c.answered_by === \"agent\"),\n );\n\n // Join pins to evidence entries by the `path:line` key, never by position:\n // a record is hand-editable YAML, and a positional join would let a deleted\n // evidence line silently shift every later pin onto the wrong citation.\n const joined: Array<{ claim: string; evidence: string; pin: EvidencePin }> = [];\n let unpinned = 0;\n for (const claim of mine) {\n const pins = new Map((claim.evidence_pins ?? []).map((pin) => [`${pin.path}:${pin.line}`, pin]));\n // A pin no evidence entry names pins nothing this claim cites (a hand\n // edit); grading it would report drift about a citation the claim does not\n // make, so only the joined pairs are graded. The reverse direction — a\n // citation without a pin — is the `unpinned` tally.\n for (const evidence of claim.evidence) {\n const pin = pins.get(evidence);\n if (pin === undefined) unpinned += 1;\n else joined.push({ claim: claim.id, evidence, pin });\n }\n }\n\n // Each distinct cited file is read and hashed once per call — a local map,\n // per invocation, because module-level state leaks across tests and hosts.\n // The reads are independent, so they go through the bounded pool; grading\n // stays sequential below so `drifts` keeps record order.\n const paths = [...new Set(joined.map((j) => j.pin.path))];\n const states = new Map(\n await inOrder(paths, async (path): Promise<[string, FileState]> => [path, await readCited(repoDir, path)]),\n );\n\n let checked = 0;\n const drifts: PinDrift[] = [];\n for (const { claim, evidence, pin } of joined) {\n const file = states.get(pin.path);\n if (file === undefined || file.state === \"unreadable\") {\n drifts.push({ claim, evidence, grade: \"unresolved\", what: file?.what ?? \"the cited file was not read\" });\n continue;\n }\n const cited = file.lines[pin.line - 1];\n if (cited === undefined) {\n drifts.push({\n claim,\n evidence,\n grade: \"unresolved\",\n // `continue`, like the unreadable-file arm: an unresolvable CITATION\n // is one finding, and a token scan on top would report the same\n // damaged citation twice under two codes.\n what: `the cited line is past the end — the file now has ${file.lines.length} line(s)`,\n });\n continue;\n }\n if (file.digest === pin.file_sha256) {\n checked += 1;\n } else if (pinnedText(cited) === pin.text) {\n // The mildest drift: the file changed around the cited line, which\n // still reads as pinned — \"reads as\", not \"is\": both sides of the\n // comparison are capped at PIN_TEXT_CAP, so a change past the cap on a\n // pathological line is invisible to this grade (and visible to the\n // digest, which is why this is a drift and not a clean pin).\n drifts.push({\n claim,\n evidence,\n grade: \"moved\",\n what: \"the file changed around the cited line, which still reads as pinned\",\n });\n } else {\n drifts.push({\n claim,\n evidence,\n grade: \"line-changed\",\n what: `the cited line now reads '${pinnedText(cited)}' where the record pinned '${pin.text}'`,\n });\n }\n // Independent of the grades above, clean pins included — a digest match\n // must not read as \"the token is still there\", because content identical\n // to record time says nothing once the file drifts back. \"No longer\" is\n // the honest word here: the write side stamps `token` only when the\n // attested blob contained it (EvidencePin.token), so this grade always\n // convicts a disappearance, never re-litigates an absence the record-time\n // notice already reported.\n if (pin.token !== undefined && !file.text.includes(pin.token)) {\n drifts.push({\n claim,\n evidence,\n grade: \"token-missing\",\n what: `the cited file no longer contains '${pin.token}' — the literal string the claim asserts`,\n });\n }\n }\n return { checked, drifts, unpinned };\n}\n\n/** One cited file against the working tree, every failure named rather than thrown. */\nasync function readCited(repoDir: string, path: string): Promise<FileState> {\n let absolute: string;\n try {\n absolute = resolvePortableFileInside(repoDir, path, \"pinned evidence\");\n } catch (err) {\n if (!(err instanceof UnsafePathError)) throw err;\n return { state: \"unreadable\", what: `the pinned path is unsafe: ${err.message}` };\n }\n try {\n const info = await stat(absolute);\n if (!info.isFile()) return { state: \"unreadable\", what: \"the cited path is not a regular file\" };\n const text = await readFile(absolute, \"utf8\");\n return { state: \"ok\", digest: pinnedDigest(text), lines: sourceLines(text), text };\n } catch (err) {\n // ENOENT is the common drift — the cited file is gone from the tree; any\n // other errno (EACCES, EISDIR racing the stat) is named as itself, because\n // \"could not read\" and \"does not exist\" call for different repairs.\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n return { state: \"unreadable\", what: \"the cited file does not exist in this working tree\" };\n }\n return { state: \"unreadable\", what: err instanceof Error ? err.message : String(err) };\n }\n}\n"]}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * The evidence pin's identity: what `verify --service --record` stamps beside a
3
+ * confirmed agent answer so a later `loam validate`, standing in the same
4
+ * service repository, can re-check the citation against the working tree.
5
+ *
6
+ * Be precise about what a pin proves, because the record travels without loam:
7
+ * a pin identifies WHAT was cited at the attested commit — the cited file's
8
+ * normalized sha256, the cited line's text, the literal token the claim
9
+ * asserts. It does not prove the claim true; an agent that cited the wrong
10
+ * line gets a faithful pin of the wrong line. That is why the read side
11
+ * (`./lint.ts`) only ever demotes reviewer confidence: no pin state moves a
12
+ * verdict in either direction.
13
+ */
14
+ import { createHash } from "node:crypto";
15
+ import { isRecord } from "../../kernel/records.js";
16
+ /**
17
+ * How much of the cited line a pin carries. Enough to recognize a line of
18
+ * source by eye and by equality; a cap because evidence may cite a line of a
19
+ * generated client or a minified bundle, and the record is a YAML file people
20
+ * read and diff — one pathological line must not turn it into one.
21
+ */
22
+ export const PIN_TEXT_CAP = 200;
23
+ /** The pin's line recipe: trimmed (indentation is formatting), capped at {@link PIN_TEXT_CAP}. */
24
+ export function pinnedText(line) {
25
+ const trimmed = line.trim();
26
+ return trimmed.length > PIN_TEXT_CAP ? trimmed.slice(0, PIN_TEXT_CAP) : trimmed;
27
+ }
28
+ /**
29
+ * The one spelling of where lines fall. Both sides of the pin — the write
30
+ * side's bounds checks and the read side's re-grade — must number lines
31
+ * identically, or a pin recorded at line 12 gets graded against a different
32
+ * line 12; four call sites each spelling the regex themselves is how that
33
+ * divergence would arrive, so the recipe has exactly one home.
34
+ */
35
+ export function sourceLines(source) {
36
+ return source.split(/\r\n|\n|\r/);
37
+ }
38
+ /**
39
+ * The cited line of a source text, through the pin recipe — or undefined when
40
+ * the line is past the end, which the caller grades (a refusal on the write
41
+ * side, `unresolved` on the read side).
42
+ */
43
+ export function citedLine(source, line) {
44
+ const raw = sourceLines(source)[line - 1];
45
+ return raw === undefined ? undefined : pinnedText(raw);
46
+ }
47
+ /**
48
+ * The pin's file digest: sha256 hex over the text with CRLF/CR normalized to
49
+ * LF.
50
+ *
51
+ * Normalized because git's eol config makes blob bytes and working-tree bytes
52
+ * legally differ: on a Windows checkout with `core.autocrlf=true`, the blob
53
+ * the attested commit holds is LF while every file on disk is CRLF, so an
54
+ * unnormalized digest would grade every pin `evidence.moved` forever on the
55
+ * checkout config alone. The pin must convict content change, never checkout
56
+ * config. The recipe is over TEXT by construction — the write side digests
57
+ * `git show` output already decoded as utf8 — and the symmetric cost is
58
+ * accepted and documented in SCHEMA.md: a pure line-ending change is invisible
59
+ * to the lint.
60
+ */
61
+ export function pinnedDigest(source) {
62
+ return createHash("sha256").update(source.replace(/\r\n|\r/g, "\n")).digest("hex");
63
+ }
64
+ /**
65
+ * The read-shape guard `asVerification` (../read/shape.ts) asks per claim, on the
66
+ * `isConsumedContractReport` model to the letter: absent is fine — every
67
+ * record written before pins existed, and every runner-answered claim, has
68
+ * none — but present must be whole for the four fields the lint dereferences.
69
+ * A broken pins block makes the WHOLE record unreadable and therefore never
70
+ * overwritten, exactly the contract-report rule: it is somebody's record, and
71
+ * a lint that silently skipped a malformed pin would read a hand-damaged
72
+ * record as drift-free. `token` stays optional-and-any-string for `format`'s
73
+ * reason — a field a newer loam learned to stamp must not brick the record
74
+ * here.
75
+ */
76
+ export function isEvidencePinList(v) {
77
+ if (v === undefined)
78
+ return true;
79
+ if (!Array.isArray(v))
80
+ return false;
81
+ for (const pin of v) {
82
+ if (!isRecord(pin))
83
+ return false;
84
+ if (typeof pin["path"] !== "string")
85
+ return false;
86
+ if (typeof pin["line"] !== "number" || !Number.isInteger(pin["line"]) || pin["line"] < 1)
87
+ return false;
88
+ if (typeof pin["file_sha256"] !== "string" || typeof pin["text"] !== "string")
89
+ return false;
90
+ if (pin["token"] !== undefined && typeof pin["token"] !== "string")
91
+ return false;
92
+ }
93
+ return true;
94
+ }
95
+ //# sourceMappingURL=pin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pin.js","sourceRoot":"","sources":["../../../../src/core/verify/pins/pin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AA4BnD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAC;AAEhC,kGAAkG;AAClG,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,OAAO,OAAO,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AAClF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,OAAO,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;AACpC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,IAAY;IACpD,MAAM,GAAG,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IAC1C,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACrF,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAAC,CAAU;IAC1C,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,KAAK,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;QACpB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACjC,IAAI,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAClD,IAAI,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACvG,IAAI,OAAO,GAAG,CAAC,aAAa,CAAC,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC5F,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;IACnF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["/**\n * The evidence pin's identity: what `verify --service --record` stamps beside a\n * confirmed agent answer so a later `loam validate`, standing in the same\n * service repository, can re-check the citation against the working tree.\n *\n * Be precise about what a pin proves, because the record travels without loam:\n * a pin identifies WHAT was cited at the attested commit — the cited file's\n * normalized sha256, the cited line's text, the literal token the claim\n * asserts. It does not prove the claim true; an agent that cited the wrong\n * line gets a faithful pin of the wrong line. That is why the read side\n * (`./lint.ts`) only ever demotes reviewer confidence: no pin state moves a\n * verdict in either direction.\n */\nimport { createHash } from \"node:crypto\";\nimport { isRecord } from \"../../kernel/records.js\";\n\nexport interface EvidencePin {\n /** The cited file, repo-relative in the portable spelling evidence entries use. */\n path: string;\n /** The cited line, 1-based — the `:N` of the evidence entry this pins. */\n line: number;\n /** sha256 hex of the whole file at the attested commit, normalized — see {@link pinnedDigest}. */\n file_sha256: string;\n /** The cited line at the attested commit, trimmed and capped — see {@link pinnedText}. */\n text: 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` (`Claim.token`, stamped at record time). Carried\n * on the pin so the read side scans the file for it and never has to\n * re-derive a checklist or parse claim prose. Absent for the kinds that\n * assert no token (`service.exists`, `scenario.tested`) — and absent when\n * the attested blob did not CONTAIN the token: that fact is warned once, at\n * record time, where the answerer can still act on it; a pin carrying it\n * would make `loam validate` repeat \"no longer contains\" forever about a\n * file that never did, with a re-record that re-derives the same state as\n * the only offered repair. `token-missing` therefore always means \"was\n * there at the attested commit and is gone\".\n */\n token?: string;\n}\n\n/**\n * How much of the cited line a pin carries. Enough to recognize a line of\n * source by eye and by equality; a cap because evidence may cite a line of a\n * generated client or a minified bundle, and the record is a YAML file people\n * read and diff — one pathological line must not turn it into one.\n */\nexport const PIN_TEXT_CAP = 200;\n\n/** The pin's line recipe: trimmed (indentation is formatting), capped at {@link PIN_TEXT_CAP}. */\nexport function pinnedText(line: string): string {\n const trimmed = line.trim();\n return trimmed.length > PIN_TEXT_CAP ? trimmed.slice(0, PIN_TEXT_CAP) : trimmed;\n}\n\n/**\n * The one spelling of where lines fall. Both sides of the pin — the write\n * side's bounds checks and the read side's re-grade — must number lines\n * identically, or a pin recorded at line 12 gets graded against a different\n * line 12; four call sites each spelling the regex themselves is how that\n * divergence would arrive, so the recipe has exactly one home.\n */\nexport function sourceLines(source: string): string[] {\n return source.split(/\\r\\n|\\n|\\r/);\n}\n\n/**\n * The cited line of a source text, through the pin recipe — or undefined when\n * the line is past the end, which the caller grades (a refusal on the write\n * side, `unresolved` on the read side).\n */\nexport function citedLine(source: string, line: number): string | undefined {\n const raw = sourceLines(source)[line - 1];\n return raw === undefined ? undefined : pinnedText(raw);\n}\n\n/**\n * The pin's file digest: sha256 hex over the text with CRLF/CR normalized to\n * LF.\n *\n * Normalized because git's eol config makes blob bytes and working-tree bytes\n * legally differ: on a Windows checkout with `core.autocrlf=true`, the blob\n * the attested commit holds is LF while every file on disk is CRLF, so an\n * unnormalized digest would grade every pin `evidence.moved` forever on the\n * checkout config alone. The pin must convict content change, never checkout\n * config. The recipe is over TEXT by construction — the write side digests\n * `git show` output already decoded as utf8 — and the symmetric cost is\n * accepted and documented in SCHEMA.md: a pure line-ending change is invisible\n * to the lint.\n */\nexport function pinnedDigest(source: string): string {\n return createHash(\"sha256\").update(source.replace(/\\r\\n|\\r/g, \"\\n\")).digest(\"hex\");\n}\n\n/**\n * The read-shape guard `asVerification` (../read/shape.ts) asks per claim, on the\n * `isConsumedContractReport` model to the letter: absent is fine — every\n * record written before pins existed, and every runner-answered claim, has\n * none — but present must be whole for the four fields the lint dereferences.\n * A broken pins block makes the WHOLE record unreadable and therefore never\n * overwritten, exactly the contract-report rule: it is somebody's record, and\n * a lint that silently skipped a malformed pin would read a hand-damaged\n * record as drift-free. `token` stays optional-and-any-string for `format`'s\n * reason — a field a newer loam learned to stamp must not brick the record\n * here.\n */\nexport function isEvidencePinList(v: unknown): boolean {\n if (v === undefined) return true;\n if (!Array.isArray(v)) return false;\n for (const pin of v) {\n if (!isRecord(pin)) return false;\n if (typeof pin[\"path\"] !== \"string\") return false;\n if (typeof pin[\"line\"] !== \"number\" || !Number.isInteger(pin[\"line\"]) || pin[\"line\"] < 1) return false;\n if (typeof pin[\"file_sha256\"] !== \"string\" || typeof pin[\"text\"] !== \"string\") return false;\n if (pin[\"token\"] !== undefined && typeof pin[\"token\"] !== \"string\") return false;\n }\n return true;\n}\n"]}