@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,207 @@
1
+ /**
2
+ * The baseline axis of the feature gate: which of the surfaces this delta
3
+ * SPELLS does it actually edit? A feature's openapi.yaml needs only what it
4
+ * changes, but it may quote more — and until the pins existed the merge
5
+ * upserted quotations too, which reverted whatever had landed on them since.
6
+ *
7
+ * Extracted from `coherence/declared.ts` when the operation pin grew its two
8
+ * sibling surfaces (path-item non-method keys, components): the grading is one
9
+ * subject with three families, and coherence/ is at its file limit. Everything
10
+ * here is graded by the ONE classifier in `../digest.ts` over the ONE surface
11
+ * enumeration in `./record.ts`, so the gate, the rebase plan and the merge
12
+ * cannot drift into different ideas of what a delta restates.
13
+ */
14
+ import { parse } from "yaml";
15
+ import { classifyBaselineDigests, OPENAPI_BASELINE_KEY, OPENAPI_BASELINES_KEY, OPERATION_DIGEST_LENGTH, OPERATION_DIGEST_RE, valueDigest, } from "../digest.js";
16
+ import { entryFor, readBaselineRecord, restatedSurfaces, surfaceIn } from "./record.js";
17
+ /**
18
+ * Grade every baseline this feature contract carries — operation pins,
19
+ * path-item keys, components — against the living contract. Slot-keyed for
20
+ * operations, (path, key)-keyed and (kind/name)-keyed for the record, exactly
21
+ * as the merge writes. With no living side there are no surface checks at all:
22
+ * everything the delta spells is new, and a baseline only means something for
23
+ * a value that already exists.
24
+ */
25
+ export function openapiBaselineIssues(input) {
26
+ const { featDoc, livingDoc, service, featureId } = input;
27
+ const issues = [];
28
+ // Slot-keyed on BOTH sides, an operation with no operationId included: the
29
+ // merge replaces whatever stands at a method and path, and `loam rebase`
30
+ // pins against whatever stands there, named or not. Reading named
31
+ // operations alone, this gate refused as pinned over "no operation at that
32
+ // slot" the very pin rebase had just written over an unnamed one — the two
33
+ // could never agree — and an unpinned quote over it drew no
34
+ // `openapi.baseline-missing` at all.
35
+ const livingBySlot = new Map([...livingDoc.ops, ...livingDoc.anonymousOps].map((op) => [`${op.method} ${op.path}`, op]));
36
+ const restated = [
37
+ // A removal marker is not a restatement of anything; its own exactness
38
+ // check (`openapi.remove-target-mismatch`) already guards the slot.
39
+ ...featDoc.ops.filter((op) => !op.remove),
40
+ ...featDoc.anonymousOps,
41
+ ];
42
+ let unpinned = 0;
43
+ for (const op of restated) {
44
+ const where = `${op.method.toUpperCase()} ${op.path}`;
45
+ // How the messages name it: the slot, and the operationId where it has one.
46
+ const named = op.id === undefined ? where : `${where} ('${op.id}')`;
47
+ const livingOp = livingBySlot.get(`${op.method} ${op.path}`);
48
+ if (op.basedOn !== undefined && !OPERATION_DIGEST_RE.test(op.basedOn)) {
49
+ issues.push({
50
+ severity: "error",
51
+ code: "openapi.baseline-invalid",
52
+ subject: service,
53
+ message: `${service}: ${where} has invalid ${OPENAPI_BASELINE_KEY} '${op.basedOn}' — expected ${OPERATION_DIGEST_LENGTH} lowercase hex characters, as \`loam rebase\` writes them`,
54
+ });
55
+ continue;
56
+ }
57
+ const verdict = classifyBaselineDigests(op.basedOn, op.digest, livingOp?.digest);
58
+ if (verdict === "unfounded") {
59
+ // Three ways here, and the message must not pick the wrong one for the
60
+ // author. A pin is only ever written over a living operation, so a pin
61
+ // with nothing living behind it usually means the operation was there
62
+ // and LEFT — a parallel feature retired it, or MOVED it to another slot
63
+ // (moving an endpoint is the most common contract edit there is). This
64
+ // used to say "drop the marker", and dropping it is exactly how the
65
+ // quote then archived as an addition and put the operation back — and
66
+ // for a move the retirement advice is wrong too: the id still lives, so
67
+ // archiving past `openapi.op-revived` would answer it at both slots.
68
+ // The living contract says which: a move leaves the id at another slot
69
+ // (and so does a retirement here followed by a re-add there, which
70
+ // reads the same from this side). The third way — a pin hand-written
71
+ // onto a genuinely new operation — is the rare one. The two addresses
72
+ // are a condition ("while it still lives there"), not a forecast: a
73
+ // delta swapping the id back defines another operation at the address
74
+ // it lives at, with or without an operationId, and the merge replaces
75
+ // it there. The revival check (coherence/retired/revival/) reads the
76
+ // contract that merge would write and stands down whenever it answers
77
+ // an id the living contract still holds — as here — at one address, so
78
+ // this must not tell the author otherwise —
79
+ // and for that delta a removal marker at the address cannot be written
80
+ // beside the other operation, hence the second remedy.
81
+ const movedTo = op.id === undefined ? [] : livingDoc.ops.filter((l) => !l.remove && l.id === op.id).map((l) => `${l.method.toUpperCase()} ${l.path}`);
82
+ issues.push({
83
+ severity: "error",
84
+ code: "openapi.baseline-invalid",
85
+ subject: service,
86
+ message: movedTo.length > 0
87
+ ? `${service}: ${where} ('${op.id}') carries ${OPENAPI_BASELINE_KEY}, but the living contract has no operation at that slot — '${op.id}' lives at ${movedTo.join(" and ")} now: a parallel feature moved it there (or retired it here, and another re-added it there). Re-read it there and delete this operation from the delta, making any change at its new address; archived while it still lives there, it would put '${op.id}' back at ${where} as well, one operationId at two addresses. To move it back on purpose, drop the pin and add a removal marker for '${op.id}' at ${movedTo.join(" and ")} to this delta, or define another operation there.`
88
+ : `${service}: ${named} carries ${OPENAPI_BASELINE_KEY}, but the living contract has no operation at that slot — the version it was pinned to is gone. If a parallel feature retired it, re-read the living contract and delete this operation from the delta, unless this feature deliberately brings it back (then drop the pin and archive with --approve past \`openapi.op-revived\`). A genuinely new operation has no living version to be based on and carries no pin.`,
89
+ });
90
+ }
91
+ else if (verdict === "stale") {
92
+ issues.push({
93
+ severity: "error",
94
+ code: "openapi.baseline-stale",
95
+ subject: service,
96
+ message: `${service}: ${named} was written against living version ${op.basedOn}, but the living contract now holds ${livingOp.digest} — somebody landed a change to it in between, and merging this would replace theirs outright. Re-read the living operation, fold in what you still mean, then run \`loam rebase ${featureId}\`.`,
97
+ });
98
+ }
99
+ else if (verdict === "unpinned" && livingOp !== undefined) {
100
+ // Counted, not listed. A delta over a thirty-operation service quotes
101
+ // twenty-nine of them, and twenty-nine identical warnings naming a fix
102
+ // that is ONE command teaches people to filter the code out.
103
+ unpinned += 1;
104
+ }
105
+ }
106
+ // The two surfaces the operation pin cannot reach, graded from the
107
+ // `x-loam-baselines` record by the same classifier. Unreadable documents
108
+ // never get here on the feature side (`openapi.invalid` suspends the axis);
109
+ // an unreadable LIVING side is that contract's own `openapi.invalid`, and
110
+ // grading against its empty parse would call every restatement new.
111
+ const missing = { keys: 0, components: 0 };
112
+ if (input.livingText !== undefined && !featDoc.unreadable && !livingDoc.unreadable) {
113
+ const featPlain = parse(input.featureText);
114
+ const livingPlain = parse(input.livingText);
115
+ const { record, problems } = readBaselineRecord(featPlain);
116
+ for (const problem of problems) {
117
+ issues.push({
118
+ severity: "error",
119
+ code: "openapi.baseline-invalid",
120
+ subject: service,
121
+ message: `${service}: ${problem} — the record is \`loam rebase\`'s bookkeeping and cannot be graded as it stands; re-run \`loam rebase ${featureId}\` to rebuild it`,
122
+ });
123
+ }
124
+ const surfaces = restatedSurfaces(featPlain);
125
+ // An entry pinning a surface the delta does not restate is a claim about
126
+ // nothing — usually a surface the author deleted after rebasing. Distinct
127
+ // from `unfounded` below, where the surface IS restated and the LIVING
128
+ // side is what vanished.
129
+ const restated = new Set(surfaces.map((s) => (s.kind === "path-item" ? `${s.path}\0${s.key}` : s.id)));
130
+ for (const [path, keys] of Object.entries(record.pathItems)) {
131
+ for (const key of Object.keys(keys)) {
132
+ if (restated.has(`${path}\0${key}`))
133
+ continue;
134
+ issues.push({
135
+ severity: "error",
136
+ code: "openapi.baseline-invalid",
137
+ subject: service,
138
+ message: `${service}: ${OPENAPI_BASELINES_KEY} pins '${key}' (${path}), but this feature's openapi.yaml does not restate that key — re-run \`loam rebase ${featureId}\` to rebuild the record`,
139
+ });
140
+ }
141
+ }
142
+ for (const id of Object.keys(record.components)) {
143
+ if (restated.has(id))
144
+ continue;
145
+ issues.push({
146
+ severity: "error",
147
+ code: "openapi.baseline-invalid",
148
+ subject: service,
149
+ message: `${service}: ${OPENAPI_BASELINES_KEY} pins component '${id}', but this feature's openapi.yaml does not declare it — re-run \`loam rebase ${featureId}\` to rebuild the record`,
150
+ });
151
+ }
152
+ for (const s of surfaces) {
153
+ const label = s.kind === "path-item" ? `path-level key '${s.key}' (${s.path})` : `component '${s.id}'`;
154
+ const entry = entryFor(record, s);
155
+ const living = surfaceIn(livingPlain, s);
156
+ const livingDigest = living.found ? valueDigest(living.value) : undefined;
157
+ const verdict = classifyBaselineDigests(entry, valueDigest(s.value), livingDigest);
158
+ if (verdict === "unpinned") {
159
+ if (living.found) {
160
+ if (s.kind === "path-item")
161
+ missing.keys += 1;
162
+ else
163
+ missing.components += 1;
164
+ }
165
+ }
166
+ else if (verdict === "stale") {
167
+ issues.push({
168
+ severity: "error",
169
+ code: "openapi.baseline-stale",
170
+ subject: service,
171
+ message: `${service}: ${label} was pinned to living version ${entry}, but the living contract now holds ${livingDigest} — somebody landed a change to it in between, and merging this would replace theirs outright. Re-read the living value, fold in what you still mean, then run \`loam rebase ${featureId}\`.`,
172
+ });
173
+ }
174
+ else if (verdict === "unfounded") {
175
+ issues.push({
176
+ severity: "error",
177
+ code: "openapi.baseline-invalid",
178
+ subject: service,
179
+ message: `${service}: ${label} is pinned to ${entry}, but the living contract no longer has that surface — the pin is structurally unresolvable; re-read the living contract, then run \`loam rebase ${featureId}\``,
180
+ });
181
+ }
182
+ }
183
+ }
184
+ if (unpinned > 0 || missing.keys > 0 || missing.components > 0) {
185
+ // A warning that GATES archive, same doctrine as `delta.baseline-missing`
186
+ // (delta/select.ts): the document is legal, but an unpinned quote is
187
+ // exactly the shape that reverts another feature's landed change at exit
188
+ // 0, and every count covers only values the living contract already has —
189
+ // a genuinely new operation, key or component never trips it. That is
190
+ // also why it cannot see a quote of an operation a parallel feature
191
+ // RETIRED: absent from living, it reads exactly like a new one — nor of
192
+ // one a parallel feature MOVED, quoted at the slot it left, since nothing
193
+ // living stands at that slot. Telling either apart from an addition takes
194
+ // the archived features' removal markers, which this gate never reads —
195
+ // `openapi.op-revived` (core/coherence/retired/) asks that question. `loam rebase` pins a whole service in one command;
196
+ // `--approve` says the unpinned merge is meant.
197
+ issues.push({
198
+ severity: "warn",
199
+ gates: true,
200
+ code: "openapi.baseline-missing",
201
+ subject: service,
202
+ message: `${service}: ${unpinned} operation(s), ${missing.keys} path-level key(s) and ${missing.components} component(s) in this feature's openapi.yaml carry no baseline pin (${OPENAPI_BASELINE_KEY} / ${OPENAPI_BASELINES_KEY}), so the merge cannot tell which ones this delta EDITS from the ones it merely restates — it will upsert all of them, reverting anything that landed on the restated ones. Run \`loam rebase ${featureId} --service ${service}\`, or archive with --approve to merge unpinned deliberately.`,
203
+ });
204
+ }
205
+ return issues;
206
+ }
207
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../../../../src/core/openapi/baseline/gate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The baseline axis of the feature gate: which of the surfaces this delta\n * SPELLS does it actually edit? A feature's openapi.yaml needs only what it\n * changes, but it may quote more — and until the pins existed the merge\n * upserted quotations too, which reverted whatever had landed on them since.\n *\n * Extracted from `coherence/declared.ts` when the operation pin grew its two\n * sibling surfaces (path-item non-method keys, components): the grading is one\n * subject with three families, and coherence/ is at its file limit. Everything\n * here is graded by the ONE classifier in `../digest.ts` over the ONE surface\n * enumeration in `./record.ts`, so the gate, the rebase plan and the merge\n * cannot drift into different ideas of what a delta restates.\n */\nimport { parse } from \"yaml\";\nimport type { Issue } from \"../../vocabulary/issue.js\";\nimport type { OpenapiDoc } from \"../doc.js\";\nimport {\n classifyBaselineDigests,\n OPENAPI_BASELINE_KEY,\n OPENAPI_BASELINES_KEY,\n OPERATION_DIGEST_LENGTH,\n OPERATION_DIGEST_RE,\n valueDigest,\n} from \"../digest.js\";\nimport { entryFor, readBaselineRecord, restatedSurfaces, surfaceIn } from \"./record.js\";\n\n/** Everything the gate needs about one service's pair of contracts. */\nexport interface BaselineGateInput {\n /** The FEATURE contract as `readOpenapi` parsed it — ops carry digests and pins. */\n featDoc: OpenapiDoc;\n /** The LIVING contract's parse; empty when the file is absent. */\n livingDoc: OpenapiDoc;\n /** The feature contract's text — the surface record and values are read from it. */\n featureText: string;\n /** The living contract's text, or undefined when no living contract exists. */\n livingText: string | undefined;\n service: string;\n featureId: string;\n}\n\n/**\n * Grade every baseline this feature contract carries — operation pins,\n * path-item keys, components — against the living contract. Slot-keyed for\n * operations, (path, key)-keyed and (kind/name)-keyed for the record, exactly\n * as the merge writes. With no living side there are no surface checks at all:\n * everything the delta spells is new, and a baseline only means something for\n * a value that already exists.\n */\nexport function openapiBaselineIssues(input: BaselineGateInput): Issue[] {\n const { featDoc, livingDoc, service, featureId } = input;\n const issues: Issue[] = [];\n // Slot-keyed on BOTH sides, an operation with no operationId included: the\n // merge replaces whatever stands at a method and path, and `loam rebase`\n // pins against whatever stands there, named or not. Reading named\n // operations alone, this gate refused as pinned over \"no operation at that\n // slot\" the very pin rebase had just written over an unnamed one — the two\n // could never agree — and an unpinned quote over it drew no\n // `openapi.baseline-missing` at all.\n const livingBySlot = new Map<string, { digest: string }>(\n [...livingDoc.ops, ...livingDoc.anonymousOps].map((op) => [`${op.method} ${op.path}`, op]),\n );\n const restated: Array<{ id?: string; path: string; method: string; digest: string; basedOn?: string }> = [\n // A removal marker is not a restatement of anything; its own exactness\n // check (`openapi.remove-target-mismatch`) already guards the slot.\n ...featDoc.ops.filter((op) => !op.remove),\n ...featDoc.anonymousOps,\n ];\n let unpinned = 0;\n for (const op of restated) {\n const where = `${op.method.toUpperCase()} ${op.path}`;\n // How the messages name it: the slot, and the operationId where it has one.\n const named = op.id === undefined ? where : `${where} ('${op.id}')`;\n const livingOp = livingBySlot.get(`${op.method} ${op.path}`);\n if (op.basedOn !== undefined && !OPERATION_DIGEST_RE.test(op.basedOn)) {\n issues.push({\n severity: \"error\",\n code: \"openapi.baseline-invalid\",\n subject: service,\n message: `${service}: ${where} has invalid ${OPENAPI_BASELINE_KEY} '${op.basedOn}' — expected ${OPERATION_DIGEST_LENGTH} lowercase hex characters, as \\`loam rebase\\` writes them`,\n });\n continue;\n }\n const verdict = classifyBaselineDigests(op.basedOn, op.digest, livingOp?.digest);\n if (verdict === \"unfounded\") {\n // Three ways here, and the message must not pick the wrong one for the\n // author. A pin is only ever written over a living operation, so a pin\n // with nothing living behind it usually means the operation was there\n // and LEFT — a parallel feature retired it, or MOVED it to another slot\n // (moving an endpoint is the most common contract edit there is). This\n // used to say \"drop the marker\", and dropping it is exactly how the\n // quote then archived as an addition and put the operation back — and\n // for a move the retirement advice is wrong too: the id still lives, so\n // archiving past `openapi.op-revived` would answer it at both slots.\n // The living contract says which: a move leaves the id at another slot\n // (and so does a retirement here followed by a re-add there, which\n // reads the same from this side). The third way — a pin hand-written\n // onto a genuinely new operation — is the rare one. The two addresses\n // are a condition (\"while it still lives there\"), not a forecast: a\n // delta swapping the id back defines another operation at the address\n // it lives at, with or without an operationId, and the merge replaces\n // it there. The revival check (coherence/retired/revival/) reads the\n // contract that merge would write and stands down whenever it answers\n // an id the living contract still holds — as here — at one address, so\n // this must not tell the author otherwise —\n // and for that delta a removal marker at the address cannot be written\n // beside the other operation, hence the second remedy.\n const movedTo = op.id === undefined ? [] : livingDoc.ops.filter((l) => !l.remove && l.id === op.id).map((l) => `${l.method.toUpperCase()} ${l.path}`);\n issues.push({\n severity: \"error\",\n code: \"openapi.baseline-invalid\",\n subject: service,\n message: movedTo.length > 0\n ? `${service}: ${where} ('${op.id}') carries ${OPENAPI_BASELINE_KEY}, but the living contract has no operation at that slot — '${op.id}' lives at ${movedTo.join(\" and \")} now: a parallel feature moved it there (or retired it here, and another re-added it there). Re-read it there and delete this operation from the delta, making any change at its new address; archived while it still lives there, it would put '${op.id}' back at ${where} as well, one operationId at two addresses. To move it back on purpose, drop the pin and add a removal marker for '${op.id}' at ${movedTo.join(\" and \")} to this delta, or define another operation there.`\n : `${service}: ${named} carries ${OPENAPI_BASELINE_KEY}, but the living contract has no operation at that slot — the version it was pinned to is gone. If a parallel feature retired it, re-read the living contract and delete this operation from the delta, unless this feature deliberately brings it back (then drop the pin and archive with --approve past \\`openapi.op-revived\\`). A genuinely new operation has no living version to be based on and carries no pin.`,\n });\n } else if (verdict === \"stale\") {\n issues.push({\n severity: \"error\",\n code: \"openapi.baseline-stale\",\n subject: service,\n message: `${service}: ${named} was written against living version ${op.basedOn}, but the living contract now holds ${livingOp!.digest} — somebody landed a change to it in between, and merging this would replace theirs outright. Re-read the living operation, fold in what you still mean, then run \\`loam rebase ${featureId}\\`.`,\n });\n } else if (verdict === \"unpinned\" && livingOp !== undefined) {\n // Counted, not listed. A delta over a thirty-operation service quotes\n // twenty-nine of them, and twenty-nine identical warnings naming a fix\n // that is ONE command teaches people to filter the code out.\n unpinned += 1;\n }\n }\n\n // The two surfaces the operation pin cannot reach, graded from the\n // `x-loam-baselines` record by the same classifier. Unreadable documents\n // never get here on the feature side (`openapi.invalid` suspends the axis);\n // an unreadable LIVING side is that contract's own `openapi.invalid`, and\n // grading against its empty parse would call every restatement new.\n const missing = { keys: 0, components: 0 };\n if (input.livingText !== undefined && !featDoc.unreadable && !livingDoc.unreadable) {\n const featPlain: unknown = parse(input.featureText);\n const livingPlain: unknown = parse(input.livingText);\n const { record, problems } = readBaselineRecord(featPlain);\n for (const problem of problems) {\n issues.push({\n severity: \"error\",\n code: \"openapi.baseline-invalid\",\n subject: service,\n message: `${service}: ${problem} — the record is \\`loam rebase\\`'s bookkeeping and cannot be graded as it stands; re-run \\`loam rebase ${featureId}\\` to rebuild it`,\n });\n }\n const surfaces = restatedSurfaces(featPlain);\n // An entry pinning a surface the delta does not restate is a claim about\n // nothing — usually a surface the author deleted after rebasing. Distinct\n // from `unfounded` below, where the surface IS restated and the LIVING\n // side is what vanished.\n const restated = new Set(surfaces.map((s) => (s.kind === \"path-item\" ? `${s.path}\\0${s.key}` : s.id)));\n for (const [path, keys] of Object.entries(record.pathItems)) {\n for (const key of Object.keys(keys)) {\n if (restated.has(`${path}\\0${key}`)) continue;\n issues.push({\n severity: \"error\",\n code: \"openapi.baseline-invalid\",\n subject: service,\n message: `${service}: ${OPENAPI_BASELINES_KEY} pins '${key}' (${path}), but this feature's openapi.yaml does not restate that key — re-run \\`loam rebase ${featureId}\\` to rebuild the record`,\n });\n }\n }\n for (const id of Object.keys(record.components)) {\n if (restated.has(id)) continue;\n issues.push({\n severity: \"error\",\n code: \"openapi.baseline-invalid\",\n subject: service,\n message: `${service}: ${OPENAPI_BASELINES_KEY} pins component '${id}', but this feature's openapi.yaml does not declare it — re-run \\`loam rebase ${featureId}\\` to rebuild the record`,\n });\n }\n for (const s of surfaces) {\n const label = s.kind === \"path-item\" ? `path-level key '${s.key}' (${s.path})` : `component '${s.id}'`;\n const entry = entryFor(record, s);\n const living = surfaceIn(livingPlain, s);\n const livingDigest = living.found ? valueDigest(living.value) : undefined;\n const verdict = classifyBaselineDigests(entry, valueDigest(s.value), livingDigest);\n if (verdict === \"unpinned\") {\n if (living.found) {\n if (s.kind === \"path-item\") missing.keys += 1;\n else missing.components += 1;\n }\n } else if (verdict === \"stale\") {\n issues.push({\n severity: \"error\",\n code: \"openapi.baseline-stale\",\n subject: service,\n message: `${service}: ${label} was pinned to living version ${entry}, but the living contract now holds ${livingDigest} — somebody landed a change to it in between, and merging this would replace theirs outright. Re-read the living value, fold in what you still mean, then run \\`loam rebase ${featureId}\\`.`,\n });\n } else if (verdict === \"unfounded\") {\n issues.push({\n severity: \"error\",\n code: \"openapi.baseline-invalid\",\n subject: service,\n message: `${service}: ${label} is pinned to ${entry}, but the living contract no longer has that surface — the pin is structurally unresolvable; re-read the living contract, then run \\`loam rebase ${featureId}\\``,\n });\n }\n }\n }\n\n if (unpinned > 0 || missing.keys > 0 || missing.components > 0) {\n // A warning that GATES archive, same doctrine as `delta.baseline-missing`\n // (delta/select.ts): the document is legal, but an unpinned quote is\n // exactly the shape that reverts another feature's landed change at exit\n // 0, and every count covers only values the living contract already has —\n // a genuinely new operation, key or component never trips it. That is\n // also why it cannot see a quote of an operation a parallel feature\n // RETIRED: absent from living, it reads exactly like a new one — nor of\n // one a parallel feature MOVED, quoted at the slot it left, since nothing\n // living stands at that slot. Telling either apart from an addition takes\n // the archived features' removal markers, which this gate never reads —\n // `openapi.op-revived` (core/coherence/retired/) asks that question. `loam rebase` pins a whole service in one command;\n // `--approve` says the unpinned merge is meant.\n issues.push({\n severity: \"warn\",\n gates: true,\n code: \"openapi.baseline-missing\",\n subject: service,\n message: `${service}: ${unpinned} operation(s), ${missing.keys} path-level key(s) and ${missing.components} component(s) in this feature's openapi.yaml carry no baseline pin (${OPENAPI_BASELINE_KEY} / ${OPENAPI_BASELINES_KEY}), so the merge cannot tell which ones this delta EDITS from the ones it merely restates — it will upsert all of them, reverting anything that landed on the restated ones. Run \\`loam rebase ${featureId} --service ${service}\\`, or archive with --approve to merge unpinned deliberately.`,\n });\n }\n return issues;\n}\n"]}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * What `loam rebase` writes on the surface axis: the `x-loam-baselines` record,
3
+ * rebuilt wholesale from what is on disk right now.
4
+ *
5
+ * The record is rebuilt rather than patched for the same reason the operation
6
+ * pin is always the LIVING digest: a pin is a claim about what its author read,
7
+ * and an entry left behind for a surface the delta no longer restates — or one
8
+ * whose living counterpart is gone — is a claim nobody is making any more.
9
+ * Wholesale rebuild prunes both without a second code path, and the sorted
10
+ * serialization (`buildRecord`) is what makes a second run byte-identical.
11
+ *
12
+ * The record is written OVER the author's text (`writeTreeOver`), so a run
13
+ * that rewrites it changes the record's own lines and no others. The
14
+ * whole-document print it used to take re-folded every long line of the
15
+ * feature contract, re-padded its flow sequences and turned its CRLF into LF
16
+ * — a diff the author had to read through to find the one key loam wrote.
17
+ *
18
+ * This module must not import from `../merge/` — the merge reads
19
+ * `./record.ts`, so a value edge back into `merge/` would be a package cycle.
20
+ * That is also why an unreadable document is answered with "nothing to pin"
21
+ * instead of `OpenapiMergeError`: every caller chains this AFTER
22
+ * `pinOpenapiOperations` (on the event axis, after `pinAsyncapiSlots` and its
23
+ * `AsyncapiMergeError`), which has already thrown that error for any document
24
+ * either side cannot parse, so the silent answer here is unreachable in
25
+ * practice and merely keeps the failure ownership where it already lives.
26
+ */
27
+ import { isDeepStrictEqual } from "node:util";
28
+ import { parseDocument } from "yaml";
29
+ import { isRecord } from "../../kernel/records.js";
30
+ import { OPENAPI_BASELINES_KEY, valueDigest } from "../digest.js";
31
+ import { writeTreeOver } from "../contract-tree.js";
32
+ import { buildRecord, entryFor, readBaselineRecord, restatedSurfaces, surfaceIn } from "./record.js";
33
+ /**
34
+ * The refusal for a document the printer cannot write. Not a merge error, for
35
+ * the header's reason. Unreachable in practice: the printer refuses only a
36
+ * document with parse errors or an alias `toJS` cannot resolve, and
37
+ * `planOpenapiBaselines` has already returned for both before it writes.
38
+ * Should it throw anyway, its message passes through, as it did when this
39
+ * module called `doc.toString()` bare.
40
+ */
41
+ const unprintable = (detail) => new Error(detail);
42
+ /**
43
+ * Pin every restated path-item key and component of a feature contract against
44
+ * the living one. The entry is always `valueDigest` of the LIVING value, never
45
+ * of the delta's own — the one rule that yields both merge verdicts: a surface
46
+ * the author only QUOTED equals its own entry, one they EDITED differs from it.
47
+ *
48
+ * A surface with no living counterpart is `unresolved` and deliberately absent
49
+ * from the record. Stamping a pin against nothing is not a harmless extra key:
50
+ * `classifyBaselineDigests` calls a pin with no living side `unfounded`, and
51
+ * the gate then refuses the delta as `openapi.baseline-invalid` (or
52
+ * `asyncapi.baseline-invalid`) — rebase would be writing the file the gate
53
+ * sends its author back to rebase.
54
+ *
55
+ * `surfacesOf` is the one thing the two contract axes do differently: the
56
+ * OpenAPI default walks `paths` and `components`, and the event axis passes
57
+ * `asyncapiSurfaces` (core/asyncapi/baseline/surfaces.ts says why it is a
58
+ * separate enumeration). Everything after the walk — the record, its sorted
59
+ * writer, the idempotence check — is axis-neutral, which is why the event
60
+ * planner is this function rather than a copy of it.
61
+ */
62
+ export function planOpenapiBaselines(featureText, livingText, surfacesOf = restatedSurfaces) {
63
+ const doc = parseDocument(featureText);
64
+ if (doc.errors.length > 0)
65
+ return { text: null, pins: [] };
66
+ let featPlain;
67
+ let livingPlain;
68
+ try {
69
+ featPlain = doc.toJS() ?? {};
70
+ const living = parseDocument(livingText);
71
+ if (living.errors.length > 0)
72
+ return { text: null, pins: [] };
73
+ livingPlain = living.toJS() ?? {};
74
+ }
75
+ catch {
76
+ return { text: null, pins: [] };
77
+ }
78
+ const current = readBaselineRecord(featPlain).record;
79
+ const pathItems = new Map();
80
+ const components = new Map();
81
+ const pins = [];
82
+ for (const surface of surfacesOf(featPlain)) {
83
+ // A malformed current entry reads back as absent (readBaselineRecord drops
84
+ // it into `problems`), so this run reports `pinned` and overwrites it —
85
+ // rebase is the command the gate's `openapi.baseline-invalid` (and
86
+ // `asyncapi.baseline-invalid`) sends people to, and it must repair what it
87
+ // names.
88
+ const from = entryFor(current, surface);
89
+ const base = {
90
+ kind: surface.kind,
91
+ target: surface.kind === "path-item" ? `${surface.path} '${surface.key}'` : surface.id,
92
+ };
93
+ const livingValue = surfaceIn(livingPlain, surface);
94
+ if (!livingValue.found) {
95
+ pins.push({ ...base, status: "unresolved", from: from ?? null, to: null });
96
+ continue;
97
+ }
98
+ const digest = valueDigest(livingValue.value);
99
+ if (surface.kind === "path-item") {
100
+ let keys = pathItems.get(surface.path);
101
+ if (keys === undefined)
102
+ pathItems.set(surface.path, (keys = new Map()));
103
+ keys.set(surface.key, digest);
104
+ }
105
+ else {
106
+ components.set(surface.id, digest);
107
+ }
108
+ pins.push({
109
+ ...base,
110
+ status: from === digest ? "unchanged" : from === undefined ? "pinned" : "repinned",
111
+ from: from ?? null,
112
+ to: digest,
113
+ });
114
+ }
115
+ // The written form drops empty sections, and the whole key when both are —
116
+ // a bare `x-loam-baselines: {}` would be bookkeeping about nothing, in every
117
+ // delta whose surfaces are all new. An AsyncAPI document has no path items,
118
+ // so on that axis `pathItems` is always the empty section dropped here.
119
+ const rebuilt = buildRecord({ pathItems, components });
120
+ const written = {};
121
+ if (Object.keys(rebuilt.pathItems).length > 0)
122
+ written["pathItems"] = rebuilt.pathItems;
123
+ if (Object.keys(rebuilt.components).length > 0)
124
+ written["components"] = rebuilt.components;
125
+ const raw = isRecord(featPlain) ? featPlain[OPENAPI_BASELINES_KEY] : undefined;
126
+ if (Object.keys(written).length === 0) {
127
+ if (raw === undefined)
128
+ return { text: null, pins };
129
+ doc.deleteIn([OPENAPI_BASELINES_KEY]);
130
+ return { text: writeTreeOver(doc, featureText, unprintable), pins };
131
+ }
132
+ // Deep-equal, not byte-equal: the comparison must ignore key order exactly as
133
+ // the digests do, so a record an author reordered by hand is left in their
134
+ // order — and a second run over this function's own sorted output finds the
135
+ // parse equal and writes nothing, which is the byte-for-byte idempotence
136
+ // `loam rebase` promises.
137
+ if (isDeepStrictEqual(raw, written))
138
+ return { text: null, pins };
139
+ doc.setIn([OPENAPI_BASELINES_KEY], written);
140
+ return { text: writeTreeOver(doc, featureText, unprintable), pins };
141
+ }
142
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../../src/core/openapi/baseline/plan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What `loam rebase` writes on the surface axis: the `x-loam-baselines` record,\n * rebuilt wholesale from what is on disk right now.\n *\n * The record is rebuilt rather than patched for the same reason the operation\n * pin is always the LIVING digest: a pin is a claim about what its author read,\n * and an entry left behind for a surface the delta no longer restates — or one\n * whose living counterpart is gone — is a claim nobody is making any more.\n * Wholesale rebuild prunes both without a second code path, and the sorted\n * serialization (`buildRecord`) is what makes a second run byte-identical.\n *\n * The record is written OVER the author's text (`writeTreeOver`), so a run\n * that rewrites it changes the record's own lines and no others. The\n * whole-document print it used to take re-folded every long line of the\n * feature contract, re-padded its flow sequences and turned its CRLF into LF\n * — a diff the author had to read through to find the one key loam wrote.\n *\n * This module must not import from `../merge/` — the merge reads\n * `./record.ts`, so a value edge back into `merge/` would be a package cycle.\n * That is also why an unreadable document is answered with \"nothing to pin\"\n * instead of `OpenapiMergeError`: every caller chains this AFTER\n * `pinOpenapiOperations` (on the event axis, after `pinAsyncapiSlots` and its\n * `AsyncapiMergeError`), which has already thrown that error for any document\n * either side cannot parse, so the silent answer here is unreachable in\n * practice and merely keeps the failure ownership where it already lives.\n */\nimport { isDeepStrictEqual } from \"node:util\";\nimport { parseDocument } from \"yaml\";\nimport { isRecord } from \"../../kernel/records.js\";\nimport { OPENAPI_BASELINES_KEY, valueDigest } from \"../digest.js\";\nimport { writeTreeOver } from \"../contract-tree.js\";\nimport { buildRecord, entryFor, readBaselineRecord, restatedSurfaces, surfaceIn, type RestatedSurface } from \"./record.js\";\n\n/** What happened to one restated surface's baseline entry. */\nexport interface SurfacePin {\n /** Which surface family the entry pins. */\n kind: \"path-item\" | \"component\";\n /** `/orders '<key>'` for a path-item key; `<kind>/<name>` for a component. */\n target: string;\n status:\n /** It had no entry and now has one. */\n | \"pinned\"\n /** It named an older living version; it now names the current one. */\n | \"repinned\"\n /** It already named the current living version — no write. */\n | \"unchanged\"\n /** The living contract has no such surface: this feature is adding it, and it gets NO entry. */\n | \"unresolved\";\n from: string | null;\n to: string | null;\n}\n\n/**\n * The refusal for a document the printer cannot write. Not a merge error, for\n * the header's reason. Unreachable in practice: the printer refuses only a\n * document with parse errors or an alias `toJS` cannot resolve, and\n * `planOpenapiBaselines` has already returned for both before it writes.\n * Should it throw anyway, its message passes through, as it did when this\n * module called `doc.toString()` bare.\n */\nconst unprintable = (detail: string): Error => new Error(detail);\n\nexport interface OpenapiBaselinePlan {\n /** The rewritten contract, or null when the record already says what this run would write. */\n text: string | null;\n pins: SurfacePin[];\n}\n\n/**\n * Pin every restated path-item key and component of a feature contract against\n * the living one. The entry is always `valueDigest` of the LIVING value, never\n * of the delta's own — the one rule that yields both merge verdicts: a surface\n * the author only QUOTED equals its own entry, one they EDITED differs from it.\n *\n * A surface with no living counterpart is `unresolved` and deliberately absent\n * from the record. Stamping a pin against nothing is not a harmless extra key:\n * `classifyBaselineDigests` calls a pin with no living side `unfounded`, and\n * the gate then refuses the delta as `openapi.baseline-invalid` (or\n * `asyncapi.baseline-invalid`) — rebase would be writing the file the gate\n * sends its author back to rebase.\n *\n * `surfacesOf` is the one thing the two contract axes do differently: the\n * OpenAPI default walks `paths` and `components`, and the event axis passes\n * `asyncapiSurfaces` (core/asyncapi/baseline/surfaces.ts says why it is a\n * separate enumeration). Everything after the walk — the record, its sorted\n * writer, the idempotence check — is axis-neutral, which is why the event\n * planner is this function rather than a copy of it.\n */\nexport function planOpenapiBaselines(\n featureText: string,\n livingText: string,\n surfacesOf: (plain: unknown) => readonly RestatedSurface[] = restatedSurfaces,\n): OpenapiBaselinePlan {\n const doc = parseDocument(featureText);\n if (doc.errors.length > 0) return { text: null, pins: [] };\n let featPlain: unknown;\n let livingPlain: unknown;\n try {\n featPlain = doc.toJS() ?? {};\n const living = parseDocument(livingText);\n if (living.errors.length > 0) return { text: null, pins: [] };\n livingPlain = living.toJS() ?? {};\n } catch {\n return { text: null, pins: [] };\n }\n\n const current = readBaselineRecord(featPlain).record;\n const pathItems = new Map<string, Map<string, string>>();\n const components = new Map<string, string>();\n const pins: SurfacePin[] = [];\n for (const surface of surfacesOf(featPlain)) {\n // A malformed current entry reads back as absent (readBaselineRecord drops\n // it into `problems`), so this run reports `pinned` and overwrites it —\n // rebase is the command the gate's `openapi.baseline-invalid` (and\n // `asyncapi.baseline-invalid`) sends people to, and it must repair what it\n // names.\n const from = entryFor(current, surface);\n const base = {\n kind: surface.kind,\n target: surface.kind === \"path-item\" ? `${surface.path} '${surface.key}'` : surface.id,\n } as const;\n const livingValue = surfaceIn(livingPlain, surface);\n if (!livingValue.found) {\n pins.push({ ...base, status: \"unresolved\", from: from ?? null, to: null });\n continue;\n }\n const digest = valueDigest(livingValue.value);\n if (surface.kind === \"path-item\") {\n let keys = pathItems.get(surface.path);\n if (keys === undefined) pathItems.set(surface.path, (keys = new Map()));\n keys.set(surface.key, digest);\n } else {\n components.set(surface.id, digest);\n }\n pins.push({\n ...base,\n status: from === digest ? \"unchanged\" : from === undefined ? \"pinned\" : \"repinned\",\n from: from ?? null,\n to: digest,\n });\n }\n\n // The written form drops empty sections, and the whole key when both are —\n // a bare `x-loam-baselines: {}` would be bookkeeping about nothing, in every\n // delta whose surfaces are all new. An AsyncAPI document has no path items,\n // so on that axis `pathItems` is always the empty section dropped here.\n const rebuilt = buildRecord({ pathItems, components });\n const written: Record<string, unknown> = {};\n if (Object.keys(rebuilt.pathItems).length > 0) written[\"pathItems\"] = rebuilt.pathItems;\n if (Object.keys(rebuilt.components).length > 0) written[\"components\"] = rebuilt.components;\n const raw = isRecord(featPlain) ? featPlain[OPENAPI_BASELINES_KEY] : undefined;\n if (Object.keys(written).length === 0) {\n if (raw === undefined) return { text: null, pins };\n doc.deleteIn([OPENAPI_BASELINES_KEY]);\n return { text: writeTreeOver(doc, featureText, unprintable), pins };\n }\n // Deep-equal, not byte-equal: the comparison must ignore key order exactly as\n // the digests do, so a record an author reordered by hand is left in their\n // order — and a second run over this function's own sorted output finds the\n // parse equal and writes nothing, which is the byte-for-byte idempotence\n // `loam rebase` promises.\n if (isDeepStrictEqual(raw, written)) return { text: null, pins };\n doc.setIn([OPENAPI_BASELINES_KEY], written);\n return { text: writeTreeOver(doc, featureText, unprintable), pins };\n}\n"]}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * The `x-loam-baselines` record: what it holds, how it reads back, and which
3
+ * of a feature document's surfaces it may speak for.
4
+ *
5
+ * One enumeration (`restatedSurfaces`) shared by the rebase plan, the gate and
6
+ * the merge, so the three cannot drift into different ideas of what a feature
7
+ * "restates" — the exact drift the operation axis's shared classifier exists
8
+ * to prevent. Reading is deliberately permissive-with-problems: a malformed
9
+ * record is DESCRIBED (`problems`), never diagnosed here — the gate refuses
10
+ * it, parsers never print, which is doc.ts's own doctrine.
11
+ */
12
+ import { isRecord } from "../../kernel/records.js";
13
+ import { HTTP_METHODS } from "../doc.js";
14
+ import { FEATURE_ONLY_KEYS, OPENAPI_BASELINES_KEY, OPERATION_DIGEST_RE } from "../digest.js";
15
+ /** The record a plain-parsed feature document carries, plus everything wrong with it. */
16
+ export function readBaselineRecord(plain) {
17
+ const problems = [];
18
+ const record = { pathItems: {}, components: {} };
19
+ if (!isRecord(plain))
20
+ return { record, problems };
21
+ const raw = plain[OPENAPI_BASELINES_KEY];
22
+ if (raw === undefined)
23
+ return { record, problems };
24
+ if (!isRecord(raw)) {
25
+ problems.push(`${OPENAPI_BASELINES_KEY} is not a mapping`);
26
+ return { record, problems };
27
+ }
28
+ const items = raw["pathItems"];
29
+ if (items !== undefined) {
30
+ if (!isRecord(items))
31
+ problems.push(`${OPENAPI_BASELINES_KEY}.pathItems is not a mapping`);
32
+ else {
33
+ for (const [path, keys] of Object.entries(items)) {
34
+ if (!isRecord(keys)) {
35
+ problems.push(`${OPENAPI_BASELINES_KEY}.pathItems['${path}'] is not a mapping`);
36
+ continue;
37
+ }
38
+ for (const [key, digest] of Object.entries(keys)) {
39
+ if (typeof digest !== "string" || !OPERATION_DIGEST_RE.test(digest)) {
40
+ problems.push(`${OPENAPI_BASELINES_KEY}.pathItems['${path}']['${key}'] is not a 16-hex digest`);
41
+ continue;
42
+ }
43
+ (record.pathItems[path] ??= {})[key] = digest;
44
+ }
45
+ }
46
+ }
47
+ }
48
+ const comps = raw["components"];
49
+ if (comps !== undefined) {
50
+ if (!isRecord(comps))
51
+ problems.push(`${OPENAPI_BASELINES_KEY}.components is not a mapping`);
52
+ else {
53
+ for (const [id, digest] of Object.entries(comps)) {
54
+ if (typeof digest !== "string" || !OPERATION_DIGEST_RE.test(digest)) {
55
+ problems.push(`${OPENAPI_BASELINES_KEY}.components['${id}'] is not a 16-hex digest`);
56
+ continue;
57
+ }
58
+ record.components[id] = digest;
59
+ }
60
+ }
61
+ }
62
+ for (const key of Object.keys(raw)) {
63
+ if (key !== "pathItems" && key !== "components")
64
+ problems.push(`${OPENAPI_BASELINES_KEY}.${key} is not a recognised section`);
65
+ }
66
+ return { record, problems };
67
+ }
68
+ /**
69
+ * Every surface this feature document RESTATES — the enumeration the plan
70
+ * pins, the gate grades and the merge classifies. Path-item surfaces are the
71
+ * non-HTTP-method keys (the feature-only markers are bookkeeping, not
72
+ * surfaces; a METHOD whose value is a removal marker is the operation pin's
73
+ * territory — but a non-method key is a surface whatever its value looks
74
+ * like, because skipping the removal SHAPE here once let it through unpinned
75
+ * and the merge wrote `{x-loam-remove: true}` over a living shared
76
+ * `parameters` at exit 0). Component surfaces are every
77
+ * `components/<kind>/<name>` the document declares.
78
+ */
79
+ export function restatedSurfaces(plain) {
80
+ const out = [];
81
+ if (!isRecord(plain))
82
+ return out;
83
+ const paths = plain["paths"];
84
+ if (isRecord(paths)) {
85
+ for (const [path, item] of Object.entries(paths)) {
86
+ if (!isRecord(item))
87
+ continue;
88
+ for (const [key, value] of Object.entries(item)) {
89
+ // Methods are the operation pin's territory and the feature-only
90
+ // markers are bookkeeping; everything else is a surface — INCLUDING a
91
+ // non-method key whose value happens to be removal-shaped. Skipping
92
+ // that shape here once let it through unpinned and ungraded, and the
93
+ // merge then wrote `{x-loam-remove: true}` over a living shared
94
+ // `parameters` array at exit 0. The merge's own publishable filter
95
+ // (markers.ts withoutFeatureMarkers) must keep agreeing with this
96
+ // pair of exclusions — the surfaces test pins the agreement.
97
+ if (HTTP_METHODS.has(key) || FEATURE_ONLY_KEYS.has(key))
98
+ continue;
99
+ out.push({ kind: "path-item", path, key, value });
100
+ }
101
+ }
102
+ }
103
+ const comps = plain["components"];
104
+ if (isRecord(comps)) {
105
+ for (const [kind, names] of Object.entries(comps)) {
106
+ if (!isRecord(names))
107
+ continue;
108
+ for (const [name, value] of Object.entries(names)) {
109
+ out.push({ kind: "component", id: `${kind}/${name}`, value });
110
+ }
111
+ }
112
+ }
113
+ return out;
114
+ }
115
+ /**
116
+ * The value one plain-parsed document holds for one surface, `found`
117
+ * distinguishing "absent" from a legal null. ONE spelling for the plan and the
118
+ * gate, because "does the living contract have this surface" is half of every
119
+ * verdict — two lookups could disagree about absence, and the disagreement
120
+ * would surface as a pin graded against the wrong baseline.
121
+ */
122
+ /**
123
+ * The record's entry for one surface, or undefined — the mirror of
124
+ * `surfaceIn`, and one spelling for the same reason: four open-coded lookups
125
+ * could disagree about absence, and a disagreement surfaces as a pin graded
126
+ * against the wrong baseline.
127
+ */
128
+ export function entryFor(record, surface) {
129
+ return surface.kind === "path-item" ? record.pathItems[surface.path]?.[surface.key] : record.components[surface.id];
130
+ }
131
+ export function surfaceIn(plain, surface) {
132
+ const absent = { found: false, value: undefined };
133
+ if (!isRecord(plain))
134
+ return absent;
135
+ if (surface.kind === "path-item") {
136
+ const paths = plain["paths"];
137
+ if (!isRecord(paths))
138
+ return absent;
139
+ const item = paths[surface.path];
140
+ if (!isRecord(item) || !(surface.key in item))
141
+ return absent;
142
+ return { found: true, value: item[surface.key] };
143
+ }
144
+ // The first `/` is the kind boundary, exactly as the merge's `#/components/`
145
+ // regex reads it — OpenAPI component names cannot legally contain one.
146
+ const cut = surface.id.indexOf("/");
147
+ const comps = plain["components"];
148
+ if (!isRecord(comps))
149
+ return absent;
150
+ const names = comps[surface.id.slice(0, cut)];
151
+ const name = surface.id.slice(cut + 1);
152
+ if (!isRecord(names) || !(name in names))
153
+ return absent;
154
+ return { found: true, value: names[name] };
155
+ }
156
+ /**
157
+ * The record as rebase writes it: lexicographically sorted at every level, so
158
+ * a second run is byte-identical and diffs stay readable.
159
+ */
160
+ export function buildRecord(pins) {
161
+ const sorted = (keys) => [...keys].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
162
+ const record = { pathItems: {}, components: {} };
163
+ for (const path of sorted(pins.pathItems.keys())) {
164
+ const keys = pins.pathItems.get(path);
165
+ const entry = {};
166
+ for (const key of sorted(keys.keys()))
167
+ entry[key] = keys.get(key);
168
+ record.pathItems[path] = entry;
169
+ }
170
+ for (const id of sorted(pins.components.keys()))
171
+ record.components[id] = pins.components.get(id);
172
+ return record;
173
+ }
174
+ //# sourceMappingURL=record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../../../src/core/openapi/baseline/record.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The `x-loam-baselines` record: what it holds, how it reads back, and which\n * of a feature document's surfaces it may speak for.\n *\n * One enumeration (`restatedSurfaces`) shared by the rebase plan, the gate and\n * the merge, so the three cannot drift into different ideas of what a feature\n * \"restates\" — the exact drift the operation axis's shared classifier exists\n * to prevent. Reading is deliberately permissive-with-problems: a malformed\n * record is DESCRIBED (`problems`), never diagnosed here — the gate refuses\n * it, parsers never print, which is doc.ts's own doctrine.\n */\nimport { isRecord } from \"../../kernel/records.js\";\nimport { HTTP_METHODS } from \"../doc.js\";\nimport { FEATURE_ONLY_KEYS, OPENAPI_BASELINES_KEY, OPERATION_DIGEST_RE } from \"../digest.js\";\n\n/** The record as read: per-(path, key) digests and per-(kind/name) digests. */\nexport interface BaselineRecord {\n pathItems: Record<string, Record<string, string>>;\n components: Record<string, string>;\n}\n\n/** One surface a feature restates: a path-item non-method key, or a component. */\nexport type RestatedSurface =\n | { kind: \"path-item\"; path: string; key: string; value: unknown }\n | { kind: \"component\"; id: string; value: unknown };\n\n/** The record a plain-parsed feature document carries, plus everything wrong with it. */\nexport function readBaselineRecord(plain: unknown): { record: BaselineRecord; problems: string[] } {\n const problems: string[] = [];\n const record: BaselineRecord = { pathItems: {}, components: {} };\n if (!isRecord(plain)) return { record, problems };\n const raw = plain[OPENAPI_BASELINES_KEY];\n if (raw === undefined) return { record, problems };\n if (!isRecord(raw)) {\n problems.push(`${OPENAPI_BASELINES_KEY} is not a mapping`);\n return { record, problems };\n }\n const items = raw[\"pathItems\"];\n if (items !== undefined) {\n if (!isRecord(items)) problems.push(`${OPENAPI_BASELINES_KEY}.pathItems is not a mapping`);\n else {\n for (const [path, keys] of Object.entries(items)) {\n if (!isRecord(keys)) {\n problems.push(`${OPENAPI_BASELINES_KEY}.pathItems['${path}'] is not a mapping`);\n continue;\n }\n for (const [key, digest] of Object.entries(keys)) {\n if (typeof digest !== \"string\" || !OPERATION_DIGEST_RE.test(digest)) {\n problems.push(`${OPENAPI_BASELINES_KEY}.pathItems['${path}']['${key}'] is not a 16-hex digest`);\n continue;\n }\n (record.pathItems[path] ??= {})[key] = digest;\n }\n }\n }\n }\n const comps = raw[\"components\"];\n if (comps !== undefined) {\n if (!isRecord(comps)) problems.push(`${OPENAPI_BASELINES_KEY}.components is not a mapping`);\n else {\n for (const [id, digest] of Object.entries(comps)) {\n if (typeof digest !== \"string\" || !OPERATION_DIGEST_RE.test(digest)) {\n problems.push(`${OPENAPI_BASELINES_KEY}.components['${id}'] is not a 16-hex digest`);\n continue;\n }\n record.components[id] = digest;\n }\n }\n }\n for (const key of Object.keys(raw)) {\n if (key !== \"pathItems\" && key !== \"components\") problems.push(`${OPENAPI_BASELINES_KEY}.${key} is not a recognised section`);\n }\n return { record, problems };\n}\n\n/**\n * Every surface this feature document RESTATES — the enumeration the plan\n * pins, the gate grades and the merge classifies. Path-item surfaces are the\n * non-HTTP-method keys (the feature-only markers are bookkeeping, not\n * surfaces; a METHOD whose value is a removal marker is the operation pin's\n * territory — but a non-method key is a surface whatever its value looks\n * like, because skipping the removal SHAPE here once let it through unpinned\n * and the merge wrote `{x-loam-remove: true}` over a living shared\n * `parameters` at exit 0). Component surfaces are every\n * `components/<kind>/<name>` the document declares.\n */\nexport function restatedSurfaces(plain: unknown): RestatedSurface[] {\n const out: RestatedSurface[] = [];\n if (!isRecord(plain)) return out;\n const paths = plain[\"paths\"];\n if (isRecord(paths)) {\n for (const [path, item] of Object.entries(paths)) {\n if (!isRecord(item)) continue;\n for (const [key, value] of Object.entries(item)) {\n // Methods are the operation pin's territory and the feature-only\n // markers are bookkeeping; everything else is a surface — INCLUDING a\n // non-method key whose value happens to be removal-shaped. Skipping\n // that shape here once let it through unpinned and ungraded, and the\n // merge then wrote `{x-loam-remove: true}` over a living shared\n // `parameters` array at exit 0. The merge's own publishable filter\n // (markers.ts withoutFeatureMarkers) must keep agreeing with this\n // pair of exclusions — the surfaces test pins the agreement.\n if (HTTP_METHODS.has(key) || FEATURE_ONLY_KEYS.has(key)) continue;\n out.push({ kind: \"path-item\", path, key, value });\n }\n }\n }\n const comps = plain[\"components\"];\n if (isRecord(comps)) {\n for (const [kind, names] of Object.entries(comps)) {\n if (!isRecord(names)) continue;\n for (const [name, value] of Object.entries(names)) {\n out.push({ kind: \"component\", id: `${kind}/${name}`, value });\n }\n }\n }\n return out;\n}\n\n/**\n * The value one plain-parsed document holds for one surface, `found`\n * distinguishing \"absent\" from a legal null. ONE spelling for the plan and the\n * gate, because \"does the living contract have this surface\" is half of every\n * verdict — two lookups could disagree about absence, and the disagreement\n * would surface as a pin graded against the wrong baseline.\n */\n/**\n * The record's entry for one surface, or undefined — the mirror of\n * `surfaceIn`, and one spelling for the same reason: four open-coded lookups\n * could disagree about absence, and a disagreement surfaces as a pin graded\n * against the wrong baseline.\n */\nexport function entryFor(record: BaselineRecord, surface: RestatedSurface): string | undefined {\n return surface.kind === \"path-item\" ? record.pathItems[surface.path]?.[surface.key] : record.components[surface.id];\n}\n\nexport function surfaceIn(plain: unknown, surface: RestatedSurface): { found: boolean; value: unknown } {\n const absent = { found: false, value: undefined };\n if (!isRecord(plain)) return absent;\n if (surface.kind === \"path-item\") {\n const paths = plain[\"paths\"];\n if (!isRecord(paths)) return absent;\n const item = paths[surface.path];\n if (!isRecord(item) || !(surface.key in item)) return absent;\n return { found: true, value: item[surface.key] };\n }\n // The first `/` is the kind boundary, exactly as the merge's `#/components/`\n // regex reads it — OpenAPI component names cannot legally contain one.\n const cut = surface.id.indexOf(\"/\");\n const comps = plain[\"components\"];\n if (!isRecord(comps)) return absent;\n const names = comps[surface.id.slice(0, cut)];\n const name = surface.id.slice(cut + 1);\n if (!isRecord(names) || !(name in names)) return absent;\n return { found: true, value: names[name] };\n}\n\n/**\n * The record as rebase writes it: lexicographically sorted at every level, so\n * a second run is byte-identical and diffs stay readable.\n */\nexport function buildRecord(pins: { pathItems: Map<string, Map<string, string>>; components: Map<string, string> }): BaselineRecord {\n const sorted = (keys: Iterable<string>): string[] => [...keys].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));\n const record: BaselineRecord = { pathItems: {}, components: {} };\n for (const path of sorted(pins.pathItems.keys())) {\n const keys = pins.pathItems.get(path)!;\n const entry: Record<string, string> = {};\n for (const key of sorted(keys.keys())) entry[key] = keys.get(key)!;\n record.pathItems[path] = entry;\n }\n for (const id of sorted(pins.components.keys())) record.components[id] = pins.components.get(id)!;\n return record;\n}\n"]}