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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1026) hide show
  1. package/CHANGELOG.md +2570 -61
  2. package/COMPARISON.md +80 -63
  3. package/CONTRIBUTING.md +84 -0
  4. package/MIGRATING-from-OpenSpec.md +213 -54
  5. package/QUICKSTART.md +125 -0
  6. package/README.md +450 -150
  7. package/ROADMAP.md +494 -0
  8. package/SCHEMA.md +2362 -245
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +701 -0
  11. package/dist/cli.js +113 -19
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +209 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +268 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +77 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/openapi.js +159 -0
  22. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  23. package/dist/commands/archive/plan/gate.js +317 -0
  24. package/dist/commands/archive/plan/gate.js.map +1 -0
  25. package/dist/commands/archive/plan/landscape.js +161 -0
  26. package/dist/commands/archive/plan/landscape.js.map +1 -0
  27. package/dist/commands/archive/plan/refusal.js +111 -0
  28. package/dist/commands/archive/plan/refusal.js.map +1 -0
  29. package/dist/commands/archive/plan/specs.js +237 -0
  30. package/dist/commands/archive/plan/specs.js.map +1 -0
  31. package/dist/commands/archive/plan/state.js +27 -0
  32. package/dist/commands/archive/plan/state.js.map +1 -0
  33. package/dist/commands/archive/run.js +251 -0
  34. package/dist/commands/archive/run.js.map +1 -0
  35. package/dist/commands/context/context.js +99 -0
  36. package/dist/commands/context/context.js.map +1 -0
  37. package/dist/commands/context/print.js +283 -0
  38. package/dist/commands/context/print.js.map +1 -0
  39. package/dist/commands/delta/delta.js +279 -0
  40. package/dist/commands/delta/delta.js.map +1 -0
  41. package/dist/commands/delta/print.js +205 -0
  42. package/dist/commands/delta/print.js.map +1 -0
  43. package/dist/commands/dependencies.js +9 -7
  44. package/dist/commands/dependencies.js.map +1 -1
  45. package/dist/commands/diff/diff.js +93 -0
  46. package/dist/commands/diff/diff.js.map +1 -0
  47. package/dist/commands/diff/print.js +38 -0
  48. package/dist/commands/diff/print.js.map +1 -0
  49. package/dist/commands/doctor.js +5 -4
  50. package/dist/commands/doctor.js.map +1 -1
  51. package/dist/commands/explain/explain.js +151 -0
  52. package/dist/commands/explain/explain.js.map +1 -0
  53. package/dist/commands/explore.js +29 -24
  54. package/dist/commands/explore.js.map +1 -1
  55. package/dist/commands/gate/gate.js +115 -0
  56. package/dist/commands/gate/gate.js.map +1 -0
  57. package/dist/commands/gate/print.js +54 -0
  58. package/dist/commands/gate/print.js.map +1 -0
  59. package/dist/commands/gherkin/commit.js +146 -0
  60. package/dist/commands/gherkin/commit.js.map +1 -0
  61. package/dist/commands/gherkin/gherkin.js +246 -0
  62. package/dist/commands/gherkin/gherkin.js.map +1 -0
  63. package/dist/commands/gherkin/reconcile.js +149 -0
  64. package/dist/commands/gherkin/reconcile.js.map +1 -0
  65. package/dist/commands/gherkin/render.js +77 -0
  66. package/dist/commands/gherkin/render.js.map +1 -0
  67. package/dist/commands/init/example.js +204 -0
  68. package/dist/commands/init/example.js.map +1 -0
  69. package/dist/commands/init/first-hour.js +28 -0
  70. package/dist/commands/init/first-hour.js.map +1 -0
  71. package/dist/commands/{init.js → init/init.js} +146 -71
  72. package/dist/commands/init/init.js.map +1 -0
  73. package/dist/commands/init/mcp.js +131 -0
  74. package/dist/commands/init/mcp.js.map +1 -0
  75. package/dist/commands/init/options.js +78 -0
  76. package/dist/commands/init/options.js.map +1 -0
  77. package/dist/commands/instructions.js +82 -14
  78. package/dist/commands/instructions.js.map +1 -1
  79. package/dist/commands/list/campaign/campaign.js +65 -0
  80. package/dist/commands/list/campaign/campaign.js.map +1 -0
  81. package/dist/commands/list/campaign/owners.js +65 -0
  82. package/dist/commands/list/campaign/owners.js.map +1 -0
  83. package/dist/commands/list/json.js +157 -0
  84. package/dist/commands/list/json.js.map +1 -0
  85. package/dist/commands/list/list.js +343 -0
  86. package/dist/commands/list/list.js.map +1 -0
  87. package/dist/commands/list/print.js +301 -0
  88. package/dist/commands/list/print.js.map +1 -0
  89. package/dist/commands/list/review.js +120 -0
  90. package/dist/commands/list/review.js.map +1 -0
  91. package/dist/commands/list/views.js +105 -0
  92. package/dist/commands/list/views.js.map +1 -0
  93. package/dist/commands/mcp/dispatch.js +183 -0
  94. package/dist/commands/mcp/dispatch.js.map +1 -0
  95. package/dist/commands/mcp/mcp.js +34 -0
  96. package/dist/commands/mcp/mcp.js.map +1 -0
  97. package/dist/commands/mcp/serve.js +55 -0
  98. package/dist/commands/mcp/serve.js.map +1 -0
  99. package/dist/commands/migrate-openspec/materialize/active.js +170 -0
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  101. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  102. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  103. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  104. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  105. package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
  106. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  107. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  108. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  109. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  110. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  111. package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
  112. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  113. package/dist/commands/migrate-openspec/openspec/error.js +19 -0
  114. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  115. package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
  116. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  117. package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
  118. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  119. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  120. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  121. package/dist/commands/migrate-openspec/print.js +89 -0
  122. package/dist/commands/migrate-openspec/print.js.map +1 -0
  123. package/dist/commands/new/commit.js +76 -0
  124. package/dist/commands/new/commit.js.map +1 -0
  125. package/dist/commands/new/new.js +283 -0
  126. package/dist/commands/new/new.js.map +1 -0
  127. package/dist/commands/new/templates.js +355 -0
  128. package/dist/commands/new/templates.js.map +1 -0
  129. package/dist/commands/open.js +203 -0
  130. package/dist/commands/open.js.map +1 -0
  131. package/dist/commands/policy/format.js +152 -0
  132. package/dist/commands/policy/format.js.map +1 -0
  133. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
  134. package/dist/commands/policy/gate.js.map +1 -0
  135. package/dist/commands/rebase/edit.js +106 -0
  136. package/dist/commands/rebase/edit.js.map +1 -0
  137. package/dist/commands/rebase/living.js +185 -0
  138. package/dist/commands/rebase/living.js.map +1 -0
  139. package/dist/commands/rebase/plan.js +245 -0
  140. package/dist/commands/rebase/plan.js.map +1 -0
  141. package/dist/commands/rebase/rebase.js +275 -0
  142. package/dist/commands/rebase/rebase.js.map +1 -0
  143. package/dist/commands/seed/commit.js +192 -0
  144. package/dist/commands/seed/commit.js.map +1 -0
  145. package/dist/commands/seed/plan.js +133 -0
  146. package/dist/commands/seed/plan.js.map +1 -0
  147. package/dist/commands/seed/seed.js +172 -0
  148. package/dist/commands/seed/seed.js.map +1 -0
  149. package/dist/commands/show/feature.js +178 -0
  150. package/dist/commands/show/feature.js.map +1 -0
  151. package/dist/commands/show/marks.js +24 -0
  152. package/dist/commands/show/marks.js.map +1 -0
  153. package/dist/commands/{show.js → show/service.js} +63 -152
  154. package/dist/commands/show/service.js.map +1 -0
  155. package/dist/commands/show/show.js +77 -0
  156. package/dist/commands/show/show.js.map +1 -0
  157. package/dist/commands/status/json.js +45 -0
  158. package/dist/commands/status/json.js.map +1 -0
  159. package/dist/commands/status/print.js +157 -0
  160. package/dist/commands/status/print.js.map +1 -0
  161. package/dist/commands/status/status.js +119 -0
  162. package/dist/commands/status/status.js.map +1 -0
  163. package/dist/commands/steps/steps.js +189 -0
  164. package/dist/commands/steps/steps.js.map +1 -0
  165. package/dist/commands/subsystem/edit.js +192 -0
  166. package/dist/commands/subsystem/edit.js.map +1 -0
  167. package/dist/commands/subsystem/move.js +265 -0
  168. package/dist/commands/subsystem/move.js.map +1 -0
  169. package/dist/commands/subsystem/query.js +115 -0
  170. package/dist/commands/subsystem/query.js.map +1 -0
  171. package/dist/commands/subsystem/subsystem.js +101 -0
  172. package/dist/commands/subsystem/subsystem.js.map +1 -0
  173. package/dist/commands/subsystem/sync.js +103 -0
  174. package/dist/commands/subsystem/sync.js.map +1 -0
  175. package/dist/commands/subsystem/txn/txn.js +94 -0
  176. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  177. package/dist/commands/subsystem/txn/views.js +70 -0
  178. package/dist/commands/subsystem/txn/views.js.map +1 -0
  179. package/dist/commands/unarchive/manifest.js +160 -0
  180. package/dist/commands/unarchive/manifest.js.map +1 -0
  181. package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
  182. package/dist/commands/unarchive/restore.js.map +1 -0
  183. package/dist/commands/unarchive/unarchive.js +67 -0
  184. package/dist/commands/unarchive/unarchive.js.map +1 -0
  185. package/dist/commands/validate/arch-coverage.js +194 -0
  186. package/dist/commands/validate/arch-coverage.js.map +1 -0
  187. package/dist/commands/validate/checks/fleet-shape.js +296 -0
  188. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  189. package/dist/commands/validate/checks/health-deps.js +55 -0
  190. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  191. package/dist/commands/validate/checks/requirements.js +254 -0
  192. package/dist/commands/validate/checks/requirements.js.map +1 -0
  193. package/dist/commands/validate/checks/sources.js +76 -0
  194. package/dist/commands/validate/checks/sources.js.map +1 -0
  195. package/dist/commands/validate/checks/vocabulary.js +31 -0
  196. package/dist/commands/validate/checks/vocabulary.js.map +1 -0
  197. package/dist/commands/validate/feature.js +216 -0
  198. package/dist/commands/validate/feature.js.map +1 -0
  199. package/dist/commands/validate/fleet/census.js +69 -0
  200. package/dist/commands/validate/fleet/census.js.map +1 -0
  201. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  202. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  203. package/dist/commands/validate/fleet/landscape.js +353 -0
  204. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  205. package/dist/commands/validate/fleet/load.js +52 -0
  206. package/dist/commands/validate/fleet/load.js.map +1 -0
  207. package/dist/commands/validate/fleet/obligations.js +236 -0
  208. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  209. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  210. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  211. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  212. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  213. package/dist/commands/validate/fleet/scorecard/print.js +63 -0
  214. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  215. package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
  216. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  217. package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
  218. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
  219. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  220. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  221. package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
  222. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
  223. package/dist/commands/validate/fleet/usecases/steps.js +197 -0
  224. package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
  225. package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
  226. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
  227. package/dist/commands/validate/fleet/views/ids.js +40 -0
  228. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  229. package/dist/commands/validate/fleet/views/stale.js +59 -0
  230. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  231. package/dist/commands/validate/links/corpus.js +92 -0
  232. package/dist/commands/validate/links/corpus.js.map +1 -0
  233. package/dist/commands/validate/links/glossary.js +75 -0
  234. package/dist/commands/validate/links/glossary.js.map +1 -0
  235. package/dist/commands/validate/report.js +269 -0
  236. package/dist/commands/validate/report.js.map +1 -0
  237. package/dist/commands/validate/service/api.js +338 -0
  238. package/dist/commands/validate/service/api.js.map +1 -0
  239. package/dist/commands/validate/service/events/events.js +219 -0
  240. package/dist/commands/validate/service/events/events.js.map +1 -0
  241. package/dist/commands/validate/service/events/message-producers.js +77 -0
  242. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  243. package/dist/commands/validate/service/evidence-pins.js +131 -0
  244. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  245. package/dist/commands/validate/service/service.js +250 -0
  246. package/dist/commands/validate/service/service.js.map +1 -0
  247. package/dist/commands/validate/service/specs.js +219 -0
  248. package/dist/commands/validate/service/specs.js.map +1 -0
  249. package/dist/commands/validate/service/spine.js +113 -0
  250. package/dist/commands/validate/service/spine.js.map +1 -0
  251. package/dist/commands/validate/validate.js +338 -0
  252. package/dist/commands/validate/validate.js.map +1 -0
  253. package/dist/commands/verify/cross/diff.js +182 -0
  254. package/dist/commands/verify/cross/diff.js.map +1 -0
  255. package/dist/commands/verify/evidence/contract.js +32 -0
  256. package/dist/commands/verify/evidence/contract.js.map +1 -0
  257. package/dist/commands/verify/evidence/pins.js +52 -0
  258. package/dist/commands/verify/evidence/pins.js.map +1 -0
  259. package/dist/commands/verify/evidence/read.js +72 -0
  260. package/dist/commands/verify/evidence/read.js.map +1 -0
  261. package/dist/commands/verify/frozen.js +241 -0
  262. package/dist/commands/verify/frozen.js.map +1 -0
  263. package/dist/commands/verify/record.js +226 -0
  264. package/dist/commands/verify/record.js.map +1 -0
  265. package/dist/commands/verify/report.js +223 -0
  266. package/dist/commands/verify/report.js.map +1 -0
  267. package/dist/commands/verify/results.js +246 -0
  268. package/dist/commands/verify/results.js.map +1 -0
  269. package/dist/commands/verify/verify.js +217 -0
  270. package/dist/commands/verify/verify.js.map +1 -0
  271. package/dist/commands/vouch/contract.js +11 -0
  272. package/dist/commands/vouch/contract.js.map +1 -0
  273. package/dist/commands/vouch/pack/contract.js +2 -0
  274. package/dist/commands/vouch/pack/contract.js.map +1 -0
  275. package/dist/commands/vouch/pack/pack.js +266 -0
  276. package/dist/commands/vouch/pack/pack.js.map +1 -0
  277. package/dist/commands/vouch/pack/print.js +271 -0
  278. package/dist/commands/vouch/pack/print.js.map +1 -0
  279. package/dist/commands/vouch/pack/sections.js +142 -0
  280. package/dist/commands/vouch/pack/sections.js.map +1 -0
  281. package/dist/commands/vouch/prompt/confirm.js +46 -0
  282. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  283. package/dist/commands/vouch/report.js +101 -0
  284. package/dist/commands/vouch/report.js.map +1 -0
  285. package/dist/commands/vouch/run.js +285 -0
  286. package/dist/commands/vouch/run.js.map +1 -0
  287. package/dist/commands/vouch/sample/plan.js +125 -0
  288. package/dist/commands/vouch/sample/plan.js.map +1 -0
  289. package/dist/commands/vouch/sample/print.js +109 -0
  290. package/dist/commands/vouch/sample/print.js.map +1 -0
  291. package/dist/commands/vouch/vet/verify.js +123 -0
  292. package/dist/commands/vouch/vet/verify.js.map +1 -0
  293. package/dist/commands/vouch/vouch.js +176 -0
  294. package/dist/commands/vouch/vouch.js.map +1 -0
  295. package/dist/core/agent/agents-md/artifacts.js +220 -0
  296. package/dist/core/agent/agents-md/artifacts.js.map +1 -0
  297. package/dist/core/agent/agents-md/command-map.js +324 -0
  298. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  299. package/dist/core/agent/agents-md/cycle.js +165 -0
  300. package/dist/core/agent/agents-md/cycle.js.map +1 -0
  301. package/dist/core/agent/agents-md/map/explain.js +34 -0
  302. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  303. package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
  304. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  305. package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
  306. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  307. package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
  308. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  309. package/dist/core/agent/agents-md/map/mcp.js +41 -0
  310. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  311. package/dist/core/agent/agents-md/map/status.js +62 -0
  312. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  313. package/dist/core/agent/agents-md/map/subsystem.js +32 -0
  314. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  315. package/dist/core/agent/agents-md/map/usecases.js +60 -0
  316. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  317. package/dist/core/agent/agents-md/refusals.js +246 -0
  318. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  319. package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
  320. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
  321. package/dist/core/agent/agents-md/spine.js +40 -0
  322. package/dist/core/agent/agents-md/spine.js.map +1 -0
  323. package/dist/core/agent/agents-md.js +170 -0
  324. package/dist/core/agent/agents-md.js.map +1 -0
  325. package/dist/core/agent/agents-stamp.js +155 -0
  326. package/dist/core/agent/agents-stamp.js.map +1 -0
  327. package/dist/core/agent/contract.js +2 -0
  328. package/dist/core/agent/contract.js.map +1 -0
  329. package/dist/core/agent/protocol.js +193 -0
  330. package/dist/core/agent/protocol.js.map +1 -0
  331. package/dist/core/agent/scaffold.js +259 -0
  332. package/dist/core/agent/scaffold.js.map +1 -0
  333. package/dist/core/agent/support/report.js +103 -0
  334. package/dist/core/agent/support/report.js.map +1 -0
  335. package/dist/core/agent/tools/dialects.js +150 -0
  336. package/dist/core/agent/tools/dialects.js.map +1 -0
  337. package/dist/core/agent/tools/registry.js +228 -0
  338. package/dist/core/agent/tools/registry.js.map +1 -0
  339. package/dist/core/agent/workflows/adopt.js +133 -0
  340. package/dist/core/agent/workflows/adopt.js.map +1 -0
  341. package/dist/core/agent/workflows/check.js +334 -0
  342. package/dist/core/agent/workflows/check.js.map +1 -0
  343. package/dist/core/agent/workflows/closing.js +262 -0
  344. package/dist/core/agent/workflows/closing.js.map +1 -0
  345. package/dist/core/agent/workflows/feature.js +105 -0
  346. package/dist/core/agent/workflows/feature.js.map +1 -0
  347. package/dist/core/agent/workflows/implement.js +105 -0
  348. package/dist/core/agent/workflows/implement.js.map +1 -0
  349. package/dist/core/agent/workflows/reference/authoring.js +209 -0
  350. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  351. package/dist/core/agent/workflows/reference/codes.js +65 -0
  352. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  353. package/dist/core/agent/workflows/reference/done-check.js +188 -0
  354. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  355. package/dist/core/agent/workflows/reference/reference.js +16 -0
  356. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  357. package/dist/core/agent/workflows/reference/spine.js +297 -0
  358. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  359. package/dist/core/asyncapi/baseline/plan.js +110 -0
  360. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  361. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  362. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  363. package/dist/core/asyncapi/depth.js +164 -0
  364. package/dist/core/asyncapi/depth.js.map +1 -0
  365. package/dist/core/asyncapi/digest.js +141 -0
  366. package/dist/core/asyncapi/digest.js.map +1 -0
  367. package/dist/core/asyncapi/merge/components.js +91 -0
  368. package/dist/core/asyncapi/merge/components.js.map +1 -0
  369. package/dist/core/asyncapi/merge/error.js +33 -0
  370. package/dist/core/asyncapi/merge/error.js.map +1 -0
  371. package/dist/core/asyncapi/merge/markers.js +308 -0
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  373. package/dist/core/asyncapi/merge/merge.js +215 -0
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  375. package/dist/core/asyncapi/merge/pin.js +107 -0
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  377. package/dist/core/asyncapi/model.js +11 -0
  378. package/dist/core/asyncapi/model.js.map +1 -0
  379. package/dist/core/asyncapi/producers.js +50 -0
  380. package/dist/core/asyncapi/producers.js.map +1 -0
  381. package/dist/core/asyncapi/read.js +239 -0
  382. package/dist/core/asyncapi/read.js.map +1 -0
  383. package/dist/core/brief/brief.js +225 -0
  384. package/dist/core/brief/brief.js.map +1 -0
  385. package/dist/core/brief/checks.js +250 -0
  386. package/dist/core/brief/checks.js.map +1 -0
  387. package/dist/core/brief/landscape.js +194 -0
  388. package/dist/core/brief/landscape.js.map +1 -0
  389. package/dist/core/brief/targets.js +226 -0
  390. package/dist/core/brief/targets.js.map +1 -0
  391. package/dist/core/brief/unchecked.js +47 -0
  392. package/dist/core/brief/unchecked.js.map +1 -0
  393. package/dist/core/c4/arch.js +282 -0
  394. package/dist/core/c4/arch.js.map +1 -0
  395. package/dist/core/c4/likec4.js +88 -0
  396. package/dist/core/c4/likec4.js.map +1 -0
  397. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  398. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  399. package/dist/core/c4/parsed/specification.js +78 -0
  400. package/dist/core/c4/parsed/specification.js.map +1 -0
  401. package/dist/core/c4/parsed/values.js +57 -0
  402. package/dist/core/c4/parsed/values.js.map +1 -0
  403. package/dist/core/c4/parsed/view-ids.js +75 -0
  404. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  405. package/dist/core/c4/project/architecture.js +45 -0
  406. package/dist/core/c4/project/architecture.js.map +1 -0
  407. package/dist/core/c4/project/documents.js +58 -0
  408. package/dist/core/c4/project/documents.js.map +1 -0
  409. package/dist/core/c4/project/load.js +183 -0
  410. package/dist/core/c4/project/load.js.map +1 -0
  411. package/dist/core/c4/resolve/service.js +113 -0
  412. package/dist/core/c4/resolve/service.js.map +1 -0
  413. package/dist/core/c4/seed/fleet-file.js +201 -0
  414. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  415. package/dist/core/c4/seed/items.js +91 -0
  416. package/dist/core/c4/seed/items.js.map +1 -0
  417. package/dist/core/c4/seed/stamp.js +48 -0
  418. package/dist/core/c4/seed/stamp.js.map +1 -0
  419. package/dist/core/c4/seed/template.js +109 -0
  420. package/dist/core/c4/seed/template.js.map +1 -0
  421. package/dist/core/c4/source-mask.js +82 -0
  422. package/dist/core/c4/source-mask.js.map +1 -0
  423. package/dist/core/c4/source-scan.js +227 -0
  424. package/dist/core/c4/source-scan.js.map +1 -0
  425. package/dist/core/c4/splice/authored-source.js +101 -0
  426. package/dist/core/c4/splice/authored-source.js.map +1 -0
  427. package/dist/core/c4/splice/contract.js +10 -0
  428. package/dist/core/c4/splice/contract.js.map +1 -0
  429. package/dist/core/c4/splice/delta-blocks.js +126 -0
  430. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  431. package/dist/core/c4/splice/identity/edges.js +36 -0
  432. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  433. package/dist/core/c4/splice/landscape-merge.js +269 -0
  434. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  435. package/dist/core/c4/splice/placement.js +194 -0
  436. package/dist/core/c4/splice/placement.js.map +1 -0
  437. package/dist/core/c4/workspace.js +172 -0
  438. package/dist/core/c4/workspace.js.map +1 -0
  439. package/dist/core/capabilities/authoring/notes.js +141 -0
  440. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  441. package/dist/core/capabilities/capabilities.js +124 -0
  442. package/dist/core/capabilities/capabilities.js.map +1 -0
  443. package/dist/core/capabilities/delta/doc.js +50 -0
  444. package/dist/core/capabilities/delta/doc.js.map +1 -0
  445. package/dist/core/capabilities/delta/overlay.js +129 -0
  446. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  447. package/dist/core/capabilities/delta/summary.js +57 -0
  448. package/dist/core/capabilities/delta/summary.js.map +1 -0
  449. package/dist/core/capabilities/delta/tree.js +43 -0
  450. package/dist/core/capabilities/delta/tree.js.map +1 -0
  451. package/dist/core/capabilities/delta/uncovered.js +222 -0
  452. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  453. package/dist/core/capabilities/findings.js +342 -0
  454. package/dist/core/capabilities/findings.js.map +1 -0
  455. package/dist/core/capabilities/realizes/findings.js +181 -0
  456. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  457. package/dist/core/capabilities/realizes/join.js +143 -0
  458. package/dist/core/capabilities/realizes/join.js.map +1 -0
  459. package/dist/core/capabilities/rollup.js +199 -0
  460. package/dist/core/capabilities/rollup.js.map +1 -0
  461. package/dist/core/capabilities/tree.js +126 -0
  462. package/dist/core/capabilities/tree.js.map +1 -0
  463. package/dist/core/capabilities/usecase-join.js +277 -0
  464. package/dist/core/capabilities/usecase-join.js.map +1 -0
  465. package/dist/core/coherence/authoring/scaffold.js +177 -0
  466. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  467. package/dist/core/coherence/authoring/sentinels.js +74 -0
  468. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  469. package/dist/core/coherence/coherence.js +251 -0
  470. package/dist/core/coherence/coherence.js.map +1 -0
  471. package/dist/core/coherence/declared.js +269 -0
  472. package/dist/core/coherence/declared.js.map +1 -0
  473. package/dist/core/coherence/events/declared.js +206 -0
  474. package/dist/core/coherence/events/declared.js.map +1 -0
  475. package/dist/core/coherence/events/events.js +204 -0
  476. package/dist/core/coherence/events/events.js.map +1 -0
  477. package/dist/core/coherence/events/grades.js +166 -0
  478. package/dist/core/coherence/events/grades.js.map +1 -0
  479. package/dist/core/coherence/events/lookups.js +122 -0
  480. package/dist/core/coherence/events/lookups.js.map +1 -0
  481. package/dist/core/coherence/events/merged.js +40 -0
  482. package/dist/core/coherence/events/merged.js.map +1 -0
  483. package/dist/core/coherence/living.js +198 -0
  484. package/dist/core/coherence/living.js.map +1 -0
  485. package/dist/core/coherence/lookups.js +155 -0
  486. package/dist/core/coherence/lookups.js.map +1 -0
  487. package/dist/core/coherence/pending.js +39 -0
  488. package/dist/core/coherence/pending.js.map +1 -0
  489. package/dist/core/conflict-markers.js +60 -0
  490. package/dist/core/conflict-markers.js.map +1 -0
  491. package/dist/core/delta/claims.js +73 -0
  492. package/dist/core/delta/claims.js.map +1 -0
  493. package/dist/core/delta/delta.js +296 -0
  494. package/dist/core/delta/delta.js.map +1 -0
  495. package/dist/core/delta/document.js +177 -0
  496. package/dist/core/delta/document.js.map +1 -0
  497. package/dist/core/delta/scope.js +48 -0
  498. package/dist/core/delta/scope.js.map +1 -0
  499. package/dist/core/delta/select.js +237 -0
  500. package/dist/core/delta/select.js.map +1 -0
  501. package/dist/core/dependencies/dependencies.js +141 -0
  502. package/dist/core/dependencies/dependencies.js.map +1 -0
  503. package/dist/core/dependencies/facts.js +165 -0
  504. package/dist/core/dependencies/facts.js.map +1 -0
  505. package/dist/core/dependencies/fanin.js +88 -0
  506. package/dist/core/dependencies/fanin.js.map +1 -0
  507. package/dist/core/dependencies/graph.js +106 -0
  508. package/dist/core/dependencies/graph.js.map +1 -0
  509. package/dist/core/diff/base-git.js +148 -0
  510. package/dist/core/diff/base-git.js.map +1 -0
  511. package/dist/core/diff/base-state.js +209 -0
  512. package/dist/core/diff/base-state.js.map +1 -0
  513. package/dist/core/diff/current-state.js +96 -0
  514. package/dist/core/diff/current-state.js.map +1 -0
  515. package/dist/core/diff/scope/changed-paths.js +188 -0
  516. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  517. package/dist/core/diff/semantic.js +243 -0
  518. package/dist/core/diff/semantic.js.map +1 -0
  519. package/dist/core/diff/victims.js +247 -0
  520. package/dist/core/diff/victims.js.map +1 -0
  521. package/dist/core/docs.js +59 -55
  522. package/dist/core/docs.js.map +1 -1
  523. package/dist/core/doctor/agents.js +222 -0
  524. package/dist/core/doctor/agents.js.map +1 -0
  525. package/dist/core/doctor/config.js +135 -0
  526. package/dist/core/doctor/config.js.map +1 -0
  527. package/dist/core/doctor/doctor.js +275 -0
  528. package/dist/core/doctor/doctor.js.map +1 -0
  529. package/dist/core/doctor/report.js +13 -0
  530. package/dist/core/doctor/report.js.map +1 -0
  531. package/dist/core/doctor/residue.js +110 -0
  532. package/dist/core/doctor/residue.js.map +1 -0
  533. package/dist/core/document/apply.js +77 -0
  534. package/dist/core/document/apply.js.map +1 -0
  535. package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
  536. package/dist/core/document/frontmatter.js.map +1 -0
  537. package/dist/core/document/grammar/directives.js +143 -0
  538. package/dist/core/document/grammar/directives.js.map +1 -0
  539. package/dist/core/document/parse.js +263 -0
  540. package/dist/core/document/parse.js.map +1 -0
  541. package/dist/core/document/scenarios.js +221 -0
  542. package/dist/core/document/scenarios.js.map +1 -0
  543. package/dist/core/document/spec.js +241 -0
  544. package/dist/core/document/spec.js.map +1 -0
  545. package/dist/core/{config.js → envelope/config.js} +79 -18
  546. package/dist/core/envelope/config.js.map +1 -0
  547. package/dist/core/envelope/json.js +175 -0
  548. package/dist/core/envelope/json.js.map +1 -0
  549. package/dist/core/{version.js → envelope/version.js} +3 -3
  550. package/dist/core/envelope/version.js.map +1 -0
  551. package/dist/core/explain/families.js +175 -0
  552. package/dist/core/explain/families.js.map +1 -0
  553. package/dist/core/explain/fix-tables.js +178 -0
  554. package/dist/core/explain/fix-tables.js.map +1 -0
  555. package/dist/core/explain/lookup.js +181 -0
  556. package/dist/core/explain/lookup.js.map +1 -0
  557. package/dist/core/explain/refusals.js +49 -0
  558. package/dist/core/explain/refusals.js.map +1 -0
  559. package/dist/core/explain/terms.js +144 -0
  560. package/dist/core/explain/terms.js.map +1 -0
  561. package/dist/core/explore/describe.js +105 -0
  562. package/dist/core/explore/describe.js.map +1 -0
  563. package/dist/core/{explore.js → explore/explore.js} +50 -101
  564. package/dist/core/explore/explore.js.map +1 -0
  565. package/dist/core/fleet-context.js +132 -77
  566. package/dist/core/fleet-context.js.map +1 -1
  567. package/dist/core/gate/checks.js +201 -0
  568. package/dist/core/gate/checks.js.map +1 -0
  569. package/dist/core/gate/partners.js +205 -0
  570. package/dist/core/gate/partners.js.map +1 -0
  571. package/dist/core/gate/report.js +47 -0
  572. package/dist/core/gate/report.js.map +1 -0
  573. package/dist/core/gate/verification.js +113 -0
  574. package/dist/core/gate/verification.js.map +1 -0
  575. package/dist/core/gherkin/digest.js +60 -0
  576. package/dist/core/gherkin/digest.js.map +1 -0
  577. package/dist/core/gherkin/emit.js +177 -0
  578. package/dist/core/gherkin/emit.js.map +1 -0
  579. package/dist/core/gherkin/read.js +76 -0
  580. package/dist/core/gherkin/read.js.map +1 -0
  581. package/dist/core/gherkin/stale.js +234 -0
  582. package/dist/core/gherkin/stale.js.map +1 -0
  583. package/dist/core/gherkin/stamp.js +77 -0
  584. package/dist/core/gherkin/stamp.js.map +1 -0
  585. package/dist/core/gherkin/steps/catalogue.js +154 -0
  586. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  587. package/dist/core/gherkin/steps/inventory.js +98 -0
  588. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  589. package/dist/core/gherkin/steps/phrase.js +72 -0
  590. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  591. package/dist/core/glossary/delta.js +106 -0
  592. package/dist/core/glossary/delta.js.map +1 -0
  593. package/dist/core/glossary/tree.js +86 -0
  594. package/dist/core/glossary/tree.js.map +1 -0
  595. package/dist/core/kernel/concurrency.js.map +1 -0
  596. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  597. package/dist/core/kernel/document-bytes.js.map +1 -0
  598. package/dist/core/kernel/fences.js +42 -0
  599. package/dist/core/kernel/fences.js.map +1 -0
  600. package/dist/core/kernel/ids/capability.js +72 -0
  601. package/dist/core/kernel/ids/capability.js.map +1 -0
  602. package/dist/core/kernel/ids/dirs.js +33 -0
  603. package/dist/core/kernel/ids/dirs.js.map +1 -0
  604. package/dist/core/kernel/ids/feature.js +75 -0
  605. package/dist/core/kernel/ids/feature.js.map +1 -0
  606. package/dist/core/kernel/ids/service.js +156 -0
  607. package/dist/core/kernel/ids/service.js.map +1 -0
  608. package/dist/core/kernel/ids/subsystem.js +63 -0
  609. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  610. package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
  611. package/dist/core/kernel/path-safety.js.map +1 -0
  612. package/dist/core/kernel/records.js.map +1 -0
  613. package/dist/core/links/backlinks.js +68 -0
  614. package/dist/core/links/backlinks.js.map +1 -0
  615. package/dist/core/links/case.js +74 -0
  616. package/dist/core/links/case.js.map +1 -0
  617. package/dist/core/links/corpus.js +104 -0
  618. package/dist/core/links/corpus.js.map +1 -0
  619. package/dist/core/links/findings.js +110 -0
  620. package/dist/core/links/findings.js.map +1 -0
  621. package/dist/core/links/parse.js +236 -0
  622. package/dist/core/links/parse.js.map +1 -0
  623. package/dist/core/mcp/argv.js +111 -0
  624. package/dist/core/mcp/argv.js.map +1 -0
  625. package/dist/core/mcp/author-tools.js +72 -0
  626. package/dist/core/mcp/author-tools.js.map +1 -0
  627. package/dist/core/mcp/framing.js +46 -0
  628. package/dist/core/mcp/framing.js.map +1 -0
  629. package/dist/core/mcp/protocol.js +280 -0
  630. package/dist/core/mcp/protocol.js.map +1 -0
  631. package/dist/core/mcp/tools.js +314 -0
  632. package/dist/core/mcp/tools.js.map +1 -0
  633. package/dist/core/obligations/obligations.js +106 -0
  634. package/dist/core/obligations/obligations.js.map +1 -0
  635. package/dist/core/openapi/baseline/gate.js +166 -0
  636. package/dist/core/openapi/baseline/gate.js.map +1 -0
  637. package/dist/core/openapi/baseline/plan.js +112 -0
  638. package/dist/core/openapi/baseline/plan.js.map +1 -0
  639. package/dist/core/openapi/baseline/record.js +175 -0
  640. package/dist/core/openapi/baseline/record.js.map +1 -0
  641. package/dist/core/openapi/depth.js +122 -0
  642. package/dist/core/openapi/depth.js.map +1 -0
  643. package/dist/core/openapi/digest.js +189 -0
  644. package/dist/core/openapi/digest.js.map +1 -0
  645. package/dist/core/{openapi.js → openapi/doc.js} +44 -106
  646. package/dist/core/openapi/doc.js.map +1 -0
  647. package/dist/core/openapi/merge/components.js +234 -0
  648. package/dist/core/openapi/merge/components.js.map +1 -0
  649. package/dist/core/openapi/merge/error.js +26 -0
  650. package/dist/core/openapi/merge/error.js.map +1 -0
  651. package/dist/core/openapi/merge/markers.js +208 -0
  652. package/dist/core/openapi/merge/markers.js.map +1 -0
  653. package/dist/core/openapi/merge/merge.js +256 -0
  654. package/dist/core/openapi/merge/merge.js.map +1 -0
  655. package/dist/core/openapi/merge/pin.js +128 -0
  656. package/dist/core/openapi/merge/pin.js.map +1 -0
  657. package/dist/core/openspec/decide/capabilities.js +244 -0
  658. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  659. package/dist/core/openspec/decide/dispositions.js +63 -0
  660. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  661. package/dist/core/openspec/decide/renames.js +179 -0
  662. package/dist/core/openspec/decide/renames.js.map +1 -0
  663. package/dist/core/openspec/decide/verdict.js +84 -0
  664. package/dist/core/openspec/decide/verdict.js.map +1 -0
  665. package/dist/core/openspec/inventory.js +221 -0
  666. package/dist/core/openspec/inventory.js.map +1 -0
  667. package/dist/core/openspec/model/mapping.js +76 -0
  668. package/dist/core/openspec/model/mapping.js.map +1 -0
  669. package/dist/core/openspec/model/model.js +65 -0
  670. package/dist/core/openspec/model/model.js.map +1 -0
  671. package/dist/core/openspec/scan/changes.js +235 -0
  672. package/dist/core/openspec/scan/changes.js.map +1 -0
  673. package/dist/core/openspec/scan/config.js +200 -0
  674. package/dist/core/openspec/scan/config.js.map +1 -0
  675. package/dist/core/openspec/scan/shape.js +260 -0
  676. package/dist/core/openspec/scan/shape.js.map +1 -0
  677. package/dist/core/openspec/scan/walk.js +133 -0
  678. package/dist/core/openspec/scan/walk.js.map +1 -0
  679. package/dist/core/openspec/scan/workspace.js +71 -0
  680. package/dist/core/openspec/scan/workspace.js.map +1 -0
  681. package/dist/core/owners/codeowners.js +141 -0
  682. package/dist/core/owners/codeowners.js.map +1 -0
  683. package/dist/core/pack/features.js +120 -0
  684. package/dist/core/pack/features.js.map +1 -0
  685. package/dist/core/pack/joins.js +112 -0
  686. package/dist/core/pack/joins.js.map +1 -0
  687. package/dist/core/pack/living.js +118 -0
  688. package/dist/core/pack/living.js.map +1 -0
  689. package/dist/core/pack/pack.js +76 -0
  690. package/dist/core/pack/pack.js.map +1 -0
  691. package/dist/core/permissions/permissions.js +87 -0
  692. package/dist/core/permissions/permissions.js.map +1 -0
  693. package/dist/core/projection/api.js +84 -0
  694. package/dist/core/projection/api.js.map +1 -0
  695. package/dist/core/projection/arch-slice.js +63 -0
  696. package/dist/core/projection/arch-slice.js.map +1 -0
  697. package/dist/core/projection/events.js +34 -0
  698. package/dist/core/projection/events.js.map +1 -0
  699. package/dist/core/provenance/findings.js +208 -0
  700. package/dist/core/provenance/findings.js.map +1 -0
  701. package/dist/core/provenance/git.js +225 -0
  702. package/dist/core/provenance/git.js.map +1 -0
  703. package/dist/core/provenance/gitq/moves.js +182 -0
  704. package/dist/core/provenance/gitq/moves.js.map +1 -0
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  707. package/dist/core/provenance/sample/scope.js +238 -0
  708. package/dist/core/provenance/sample/scope.js.map +1 -0
  709. package/dist/core/provenance/sample/sections.js +61 -0
  710. package/dist/core/provenance/sample/sections.js.map +1 -0
  711. package/dist/core/provenance/sources.js +263 -0
  712. package/dist/core/provenance/sources.js.map +1 -0
  713. package/dist/core/provenance/stamp.js +232 -0
  714. package/dist/core/provenance/stamp.js.map +1 -0
  715. package/dist/core/provenance/walk.js +157 -0
  716. package/dist/core/provenance/walk.js.map +1 -0
  717. package/dist/core/repo/authored/paths.js +192 -0
  718. package/dist/core/repo/authored/paths.js.map +1 -0
  719. package/dist/core/repo/entries.js +126 -0
  720. package/dist/core/repo/entries.js.map +1 -0
  721. package/dist/core/repo/paths.js +236 -0
  722. package/dist/core/repo/paths.js.map +1 -0
  723. package/dist/core/repo/repo.js +248 -0
  724. package/dist/core/repo/repo.js.map +1 -0
  725. package/dist/core/repo/service-target.js +153 -0
  726. package/dist/core/repo/service-target.js.map +1 -0
  727. package/dist/core/repo/state.js +58 -0
  728. package/dist/core/repo/state.js.map +1 -0
  729. package/dist/core/repo/tree/find.js +52 -0
  730. package/dist/core/repo/tree/find.js.map +1 -0
  731. package/dist/core/repo/tree/fs.js +64 -0
  732. package/dist/core/repo/tree/fs.js.map +1 -0
  733. package/dist/core/repo/tree/marker.js +61 -0
  734. package/dist/core/repo/tree/marker.js.map +1 -0
  735. package/dist/core/repo/tree/views.js +172 -0
  736. package/dist/core/repo/tree/views.js.map +1 -0
  737. package/dist/core/repo/tree/walk.js +234 -0
  738. package/dist/core/repo/tree/walk.js.map +1 -0
  739. package/dist/core/results.js +99 -2
  740. package/dist/core/results.js.map +1 -1
  741. package/dist/core/scaffold/landscape.js +131 -0
  742. package/dist/core/scaffold/landscape.js.map +1 -0
  743. package/dist/core/scaffold/readme.js +84 -0
  744. package/dist/core/scaffold/readme.js.map +1 -0
  745. package/dist/core/staging/commit.js +241 -0
  746. package/dist/core/staging/commit.js.map +1 -0
  747. package/dist/core/staging/interrupted.js +96 -0
  748. package/dist/core/staging/interrupted.js.map +1 -0
  749. package/dist/core/staging/lock.js +206 -0
  750. package/dist/core/staging/lock.js.map +1 -0
  751. package/dist/core/staging/recovery/finding.js +35 -0
  752. package/dist/core/staging/recovery/finding.js.map +1 -0
  753. package/dist/core/staging/recovery/intent.js +98 -0
  754. package/dist/core/staging/recovery/intent.js.map +1 -0
  755. package/dist/core/staging/recovery/recover.js +126 -0
  756. package/dist/core/staging/recovery/recover.js.map +1 -0
  757. package/dist/core/staging/recovery/residue.js +62 -0
  758. package/dist/core/staging/recovery/residue.js.map +1 -0
  759. package/dist/core/staging/snapshot.js +202 -0
  760. package/dist/core/staging/snapshot.js.map +1 -0
  761. package/dist/core/staging/txn/forward.js +171 -0
  762. package/dist/core/staging/txn/forward.js.map +1 -0
  763. package/dist/core/staging/txn/journal.js +139 -0
  764. package/dist/core/staging/txn/journal.js.map +1 -0
  765. package/dist/core/staging/txn/transaction.js +75 -0
  766. package/dist/core/staging/txn/transaction.js.map +1 -0
  767. package/dist/core/staging/writes.js +113 -0
  768. package/dist/core/staging/writes.js.map +1 -0
  769. package/dist/core/status/actions/execution.js +49 -0
  770. package/dist/core/status/actions/execution.js.map +1 -0
  771. package/dist/core/status/contracts.js +102 -0
  772. package/dist/core/status/contracts.js.map +1 -0
  773. package/dist/core/status/feature/artifacts.js +171 -0
  774. package/dist/core/status/feature/artifacts.js.map +1 -0
  775. package/dist/core/status/feature/feature.js +207 -0
  776. package/dist/core/status/feature/feature.js.map +1 -0
  777. package/dist/core/status/feature/next.js +150 -0
  778. package/dist/core/status/feature/next.js.map +1 -0
  779. package/dist/core/status/feature/state.js +21 -0
  780. package/dist/core/status/feature/state.js.map +1 -0
  781. package/dist/core/status/fleet/fleet.js +187 -0
  782. package/dist/core/status/fleet/fleet.js.map +1 -0
  783. package/dist/core/status/fleet/next.js +207 -0
  784. package/dist/core/status/fleet/next.js.map +1 -0
  785. package/dist/core/status/interrupted.js +97 -0
  786. package/dist/core/status/interrupted.js.map +1 -0
  787. package/dist/core/status/report.js +31 -0
  788. package/dist/core/status/report.js.map +1 -0
  789. package/dist/core/status/scan.js +41 -0
  790. package/dist/core/status/scan.js.map +1 -0
  791. package/dist/core/status/verification.js +201 -0
  792. package/dist/core/status/verification.js.map +1 -0
  793. package/dist/core/usecases/capability.js +169 -0
  794. package/dist/core/usecases/capability.js.map +1 -0
  795. package/dist/core/usecases/delta/claims.js +116 -0
  796. package/dist/core/usecases/delta/claims.js.map +1 -0
  797. package/dist/core/usecases/delta/flows.js +103 -0
  798. package/dist/core/usecases/delta/flows.js.map +1 -0
  799. package/dist/core/usecases/delta/overlay.js +235 -0
  800. package/dist/core/usecases/delta/overlay.js.map +1 -0
  801. package/dist/core/usecases/fleet.js +137 -0
  802. package/dist/core/usecases/fleet.js.map +1 -0
  803. package/dist/core/usecases/operations.js +111 -0
  804. package/dist/core/usecases/operations.js.map +1 -0
  805. package/dist/core/usecases/place.js +44 -0
  806. package/dist/core/usecases/place.js.map +1 -0
  807. package/dist/core/usecases/touch.js +101 -0
  808. package/dist/core/usecases/touch.js.map +1 -0
  809. package/dist/core/verify/answers.js +173 -0
  810. package/dist/core/verify/answers.js.map +1 -0
  811. package/dist/core/verify/build.js +150 -0
  812. package/dist/core/verify/build.js.map +1 -0
  813. package/dist/core/verify/checklist.js +201 -0
  814. package/dist/core/verify/checklist.js.map +1 -0
  815. package/dist/core/verify/claims/identity.js +61 -0
  816. package/dist/core/verify/claims/identity.js.map +1 -0
  817. package/dist/core/verify/cross/diff.js +97 -0
  818. package/dist/core/verify/cross/diff.js.map +1 -0
  819. package/dist/core/verify/evidence/contract.js +169 -0
  820. package/dist/core/verify/evidence/contract.js.map +1 -0
  821. package/dist/core/verify/file.js +257 -0
  822. package/dist/core/verify/file.js.map +1 -0
  823. package/dist/core/verify/pins/lint.js +157 -0
  824. package/dist/core/verify/pins/lint.js.map +1 -0
  825. package/dist/core/verify/pins/pin.js +95 -0
  826. package/dist/core/verify/pins/pin.js.map +1 -0
  827. package/dist/core/verify/record.js +142 -0
  828. package/dist/core/verify/record.js.map +1 -0
  829. package/dist/core/verify/store/commit.js +89 -0
  830. package/dist/core/verify/store/commit.js.map +1 -0
  831. package/dist/core/verify/store/render.js +57 -0
  832. package/dist/core/verify/store/render.js.map +1 -0
  833. package/dist/core/vocabulary/health.js +91 -0
  834. package/dist/core/vocabulary/health.js.map +1 -0
  835. package/dist/core/vocabulary/issue.js +55 -0
  836. package/dist/core/vocabulary/issue.js.map +1 -0
  837. package/dist/core/vocabulary/maturity.js +145 -0
  838. package/dist/core/vocabulary/maturity.js.map +1 -0
  839. package/dist/core/{report.js → vocabulary/report.js} +30 -2
  840. package/dist/core/vocabulary/report.js.map +1 -0
  841. package/dist/core/vocabulary/steps.js +266 -0
  842. package/dist/core/vocabulary/steps.js.map +1 -0
  843. package/dist/core/workspace/discover.js +239 -0
  844. package/dist/core/workspace/discover.js.map +1 -0
  845. package/dist/core/workspace/render.js +52 -0
  846. package/dist/core/workspace/render.js.map +1 -0
  847. package/examples/README.md +189 -0
  848. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  849. package/examples/docs/architecture/capabilities.yaml +31 -0
  850. package/examples/docs/architecture/landscape.likec4 +280 -0
  851. package/examples/docs/architecture/obligations.yaml +23 -0
  852. package/examples/docs/architecture/permissions.yaml +50 -0
  853. package/examples/docs/architecture/subsystems.likec4 +11 -0
  854. package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
  855. package/examples/docs/capabilities/checkout/spec.md +55 -0
  856. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  857. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  858. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  859. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  860. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
  863. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  864. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  865. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  866. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  867. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  868. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
  869. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  870. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  871. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  872. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  873. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  874. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  875. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  876. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  877. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  878. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  879. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
  880. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  881. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  882. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  883. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  884. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  885. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  886. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  887. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  888. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  889. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  890. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  891. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  892. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  893. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  894. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  895. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  896. package/examples/docs/glossary/order.md +15 -0
  897. package/examples/docs/glossary/payments/authorization.md +14 -0
  898. package/examples/docs/likec4.config.json +9 -0
  899. package/examples/docs/loam.json +3 -0
  900. package/examples/docs/services/checkout-web/model.likec4 +109 -0
  901. package/examples/docs/services/checkout-web/spec.md +91 -0
  902. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  903. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  904. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  905. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  906. package/examples/docs/services/order-service/arch.spec.md +127 -0
  907. package/examples/docs/services/order-service/asyncapi.yaml +108 -0
  908. package/examples/docs/services/order-service/health.yaml +57 -0
  909. package/examples/docs/services/order-service/model.likec4 +138 -0
  910. package/examples/docs/services/order-service/openapi.yaml +257 -0
  911. package/examples/docs/services/order-service/runbook.md +62 -0
  912. package/examples/docs/services/order-service/spec.md +134 -0
  913. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  914. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  915. package/examples/docs/services/payment-service/arch.spec.md +73 -0
  916. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  917. package/examples/docs/services/payment-service/health.yaml +39 -0
  918. package/examples/docs/services/payment-service/model.likec4 +67 -0
  919. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  920. package/examples/docs/services/payment-service/runbook.md +37 -0
  921. package/examples/docs/services/payment-service/spec.md +88 -0
  922. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  923. package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
  924. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  925. package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
  926. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  927. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  928. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  929. package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
  930. package/examples/docs/services/platform/notification-service/health.yaml +35 -0
  931. package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
  932. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  933. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  934. package/examples/docs/services/platform/subsystem.yaml +2 -0
  935. package/examples/fleet.yaml +57 -0
  936. package/package.json +19 -6
  937. package/dist/commands/adopt.js +0 -240
  938. package/dist/commands/adopt.js.map +0 -1
  939. package/dist/commands/archive.js +0 -1313
  940. package/dist/commands/archive.js.map +0 -1
  941. package/dist/commands/delta.js +0 -388
  942. package/dist/commands/delta.js.map +0 -1
  943. package/dist/commands/docs-repo-gate.js.map +0 -1
  944. package/dist/commands/format.js +0 -17
  945. package/dist/commands/format.js.map +0 -1
  946. package/dist/commands/gherkin.js +0 -309
  947. package/dist/commands/gherkin.js.map +0 -1
  948. package/dist/commands/init.js.map +0 -1
  949. package/dist/commands/list.js +0 -291
  950. package/dist/commands/list.js.map +0 -1
  951. package/dist/commands/migrate-openspec.js +0 -950
  952. package/dist/commands/migrate-openspec.js.map +0 -1
  953. package/dist/commands/new.js +0 -413
  954. package/dist/commands/new.js.map +0 -1
  955. package/dist/commands/rebase.js +0 -356
  956. package/dist/commands/rebase.js.map +0 -1
  957. package/dist/commands/show.js.map +0 -1
  958. package/dist/commands/status.js +0 -254
  959. package/dist/commands/status.js.map +0 -1
  960. package/dist/commands/unarchive.js.map +0 -1
  961. package/dist/commands/validate.js +0 -1591
  962. package/dist/commands/validate.js.map +0 -1
  963. package/dist/commands/verify.js +0 -775
  964. package/dist/commands/verify.js.map +0 -1
  965. package/dist/commands/vouch.js +0 -343
  966. package/dist/commands/vouch.js.map +0 -1
  967. package/dist/core/agent.js +0 -2065
  968. package/dist/core/agent.js.map +0 -1
  969. package/dist/core/agents-stamp.js +0 -68
  970. package/dist/core/agents-stamp.js.map +0 -1
  971. package/dist/core/arch.js +0 -130
  972. package/dist/core/arch.js.map +0 -1
  973. package/dist/core/brief.js +0 -733
  974. package/dist/core/brief.js.map +0 -1
  975. package/dist/core/coherence.js +0 -577
  976. package/dist/core/coherence.js.map +0 -1
  977. package/dist/core/concurrency.js.map +0 -1
  978. package/dist/core/config.js.map +0 -1
  979. package/dist/core/delta.js +0 -476
  980. package/dist/core/delta.js.map +0 -1
  981. package/dist/core/dependencies.js +0 -356
  982. package/dist/core/dependencies.js.map +0 -1
  983. package/dist/core/doctor.js +0 -559
  984. package/dist/core/doctor.js.map +0 -1
  985. package/dist/core/document-bytes.js.map +0 -1
  986. package/dist/core/explore.js.map +0 -1
  987. package/dist/core/frontmatter.js.map +0 -1
  988. package/dist/core/gherkin.js +0 -463
  989. package/dist/core/gherkin.js.map +0 -1
  990. package/dist/core/health.js +0 -67
  991. package/dist/core/health.js.map +0 -1
  992. package/dist/core/ids.js +0 -122
  993. package/dist/core/ids.js.map +0 -1
  994. package/dist/core/issue.js +0 -9
  995. package/dist/core/issue.js.map +0 -1
  996. package/dist/core/json.js +0 -74
  997. package/dist/core/json.js.map +0 -1
  998. package/dist/core/likec4.js +0 -479
  999. package/dist/core/likec4.js.map +0 -1
  1000. package/dist/core/maturity.js +0 -66
  1001. package/dist/core/maturity.js.map +0 -1
  1002. package/dist/core/openapi-merge.js +0 -552
  1003. package/dist/core/openapi-merge.js.map +0 -1
  1004. package/dist/core/openapi.js.map +0 -1
  1005. package/dist/core/openspec-inventory.js +0 -1440
  1006. package/dist/core/openspec-inventory.js.map +0 -1
  1007. package/dist/core/path-safety.js.map +0 -1
  1008. package/dist/core/provenance.js +0 -720
  1009. package/dist/core/provenance.js.map +0 -1
  1010. package/dist/core/records.js.map +0 -1
  1011. package/dist/core/repo.js +0 -436
  1012. package/dist/core/repo.js.map +0 -1
  1013. package/dist/core/report.js.map +0 -1
  1014. package/dist/core/spec.js +0 -481
  1015. package/dist/core/spec.js.map +0 -1
  1016. package/dist/core/staging.js +0 -890
  1017. package/dist/core/staging.js.map +0 -1
  1018. package/dist/core/status.js +0 -1104
  1019. package/dist/core/status.js.map +0 -1
  1020. package/dist/core/steps.js +0 -72
  1021. package/dist/core/steps.js.map +0 -1
  1022. package/dist/core/verify.js +0 -807
  1023. package/dist/core/verify.js.map +0 -1
  1024. package/dist/core/version.js.map +0 -1
  1025. /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
  1026. /package/dist/core/{records.js → kernel/records.js} +0 -0
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Which service owns which capability, and which feature owns which change —
3
+ * the two decisions a human has to make, graded against what the scan found.
4
+ *
5
+ * The routing this produces is what everything downstream selects with, which
6
+ * is why `servicesForRequirement` is returned as a function rather than as a
7
+ * map: a split capability routes per REQUIREMENT and a single-service one
8
+ * routes wholesale, and a caller that reimplemented that choice would put a
9
+ * living requirement and its own delta in different services.
10
+ */
11
+ import { resolve } from "node:path";
12
+ import { dictionary, ownValue } from "../../kernel/records.js";
13
+ import { FEATURE_ID_RULE, isFeatureId } from "../../kernel/ids/feature.js";
14
+ import { compareIds } from "../../repo/entries.js";
15
+ import { parseRequirements } from "../../document/parse.js";
16
+ import {} from "../../document/spec.js";
17
+ import {} from "../model/mapping.js";
18
+ import {} from "../model/model.js";
19
+ import { titleFromChangeId } from "../scan/changes.js";
20
+ export function capabilityDecisions(scan) {
21
+ const { root, mapping, bound, inventoryDigest, livingRequirements, active, renamed } = scan;
22
+ // Capability ownership must cover the active horizon too: a brand-new
23
+ // capability may exist only under changes/<id>/specs until archive.
24
+ //
25
+ // `routedNames` is the subset a split capability must actually allocate. A
26
+ // renamed requirement is routed by its FROM — that is what keeps the delta in
27
+ // the same services as the living text it rewrites — so demanding an
28
+ // allocation for its TO as well asked a reviewer for a decision apply ignores.
29
+ const requirementNamesByCapability = new Map();
30
+ const routedNamesByCapability = new Map();
31
+ const activeChangesByCapability = new Map();
32
+ const activeRenamePairs = renamed.filter((rename) => rename.scope === "active"
33
+ && rename.from !== null && rename.from !== ""
34
+ && rename.to !== null && rename.to !== "");
35
+ for (const [capability, requirements] of livingRequirements) {
36
+ requirementNamesByCapability.set(capability, new Set(requirements.map((item) => item.name)));
37
+ routedNamesByCapability.set(capability, new Set(requirements.map((item) => item.name)));
38
+ }
39
+ for (const change of active) {
40
+ for (const spec of change.specs) {
41
+ const names = requirementNamesByCapability.get(spec.capability) ?? new Set();
42
+ const routed = routedNamesByCapability.get(spec.capability) ?? new Set();
43
+ for (const name of spec.requirementNames) {
44
+ names.add(name);
45
+ const pairs = activeRenamePairs.filter((rename) => rename.changeId === change.id
46
+ && rename.capability === spec.capability
47
+ && (name === rename.from || name === rename.to));
48
+ routed.add(pairs.length === 1 ? pairs[0].from : name);
49
+ }
50
+ requirementNamesByCapability.set(spec.capability, names);
51
+ routedNamesByCapability.set(spec.capability, routed);
52
+ const changes = activeChangesByCapability.get(spec.capability) ?? new Set();
53
+ changes.add(change.id);
54
+ activeChangesByCapability.set(spec.capability, changes);
55
+ }
56
+ }
57
+ const allCapabilityIds = [...requirementNamesByCapability.keys()].sort(compareIds);
58
+ const mappingIssues = [];
59
+ if (bound) {
60
+ if (mapping.source === null) {
61
+ mappingIssues.push({
62
+ code: "mapping.source-missing",
63
+ key: "source",
64
+ message: "Mapping is not bound to an audited source root and inventory digest.",
65
+ });
66
+ }
67
+ else {
68
+ if (resolve(mapping.source.root) !== root) {
69
+ mappingIssues.push({
70
+ code: "mapping.source-root-mismatch",
71
+ key: "source.root",
72
+ message: `Mapping was created for ${mapping.source.root}, not ${root}.`,
73
+ });
74
+ }
75
+ if (mapping.source.inventoryDigest !== inventoryDigest) {
76
+ mappingIssues.push({
77
+ code: "mapping.source-digest-mismatch",
78
+ key: "source.inventoryDigest",
79
+ message: `OpenSpec source changed after audit (${mapping.source.inventoryDigest} != ${inventoryDigest}).`,
80
+ });
81
+ }
82
+ }
83
+ }
84
+ const capabilityIds = new Set(allCapabilityIds);
85
+ for (const capability of Object.keys(mapping.capabilities)) {
86
+ if (!capabilityIds.has(capability)) {
87
+ mappingIssues.push({
88
+ code: "mapping.unknown-capability",
89
+ key: capability,
90
+ message: `Mapping names unknown capability '${capability}'.`,
91
+ });
92
+ }
93
+ }
94
+ const mappingDecisions = allCapabilityIds.map((capability) => {
95
+ const capabilityMapping = ownValue(mapping.capabilities, capability)
96
+ ?? { services: [], requirementServices: dictionary() };
97
+ const services = [...new Set(capabilityMapping.services)]
98
+ .filter((service) => service.trim() !== "")
99
+ .sort(compareIds);
100
+ const requirementNames = [...(requirementNamesByCapability.get(capability) ?? [])].sort(compareIds);
101
+ const requirementNameSet = new Set(requirementNames);
102
+ const routedNames = [...(routedNamesByCapability.get(capability) ?? [])].sort(compareIds);
103
+ const requirementServices = dictionary();
104
+ for (const [requirement, allocated] of Object.entries(capabilityMapping.requirementServices)) {
105
+ if (!requirementNameSet.has(requirement)) {
106
+ mappingIssues.push({
107
+ code: "mapping.unknown-requirement",
108
+ key: `${capability}:${requirement}`,
109
+ message: `Capability '${capability}' mapping names unknown requirement '${requirement}'.`,
110
+ });
111
+ continue;
112
+ }
113
+ const selected = [...new Set(allocated)].filter(Boolean).sort(compareIds);
114
+ requirementServices[requirement] = selected;
115
+ for (const service of selected) {
116
+ if (!services.includes(service)) {
117
+ mappingIssues.push({
118
+ code: "mapping.requirement-service-unknown",
119
+ key: `${capability}:${requirement}`,
120
+ message: `Requirement '${requirement}' is allocated to '${service}', which is not in capability '${capability}' services.`,
121
+ });
122
+ }
123
+ }
124
+ }
125
+ // Only routed names get an empty slot in the skeleton: an unroutable name
126
+ // offered for allocation is a decision that changes nothing.
127
+ for (const requirement of routedNames) {
128
+ if (ownValue(requirementServices, requirement) === undefined)
129
+ requirementServices[requirement] = [];
130
+ }
131
+ if (services.length > 1) {
132
+ for (const requirement of routedNames) {
133
+ if ((ownValue(requirementServices, requirement) ?? []).length === 0) {
134
+ mappingIssues.push({
135
+ code: "mapping.requirement-allocation-missing",
136
+ key: `${capability}:${requirement}`,
137
+ message: `Split capability '${capability}' must allocate requirement '${requirement}' to at least one selected service.`,
138
+ });
139
+ }
140
+ }
141
+ for (const service of services) {
142
+ if (!Object.values(requirementServices).some((selected) => selected.includes(service))) {
143
+ mappingIssues.push({
144
+ code: "mapping.service-allocation-empty",
145
+ key: `${capability}:${service}`,
146
+ message: `Split capability '${capability}' selects service '${service}' but allocates no requirement to it.`,
147
+ });
148
+ }
149
+ }
150
+ }
151
+ return {
152
+ capability,
153
+ service: services.length === 1 ? services[0] : null,
154
+ services,
155
+ requirementServices,
156
+ suggestedService: capability.split("/").at(-1) ?? capability,
157
+ hasLivingSpec: livingRequirements.has(capability),
158
+ activeChanges: [...(activeChangesByCapability.get(capability) ?? [])].sort(compareIds),
159
+ status: services.length === 0 ? "needsMapping" : "mapped",
160
+ };
161
+ });
162
+ const decisionsByCapability = new Map(mappingDecisions.map((decision) => [decision.capability, decision]));
163
+ const servicesForRequirement = (capability, requirement) => {
164
+ const decision = decisionsByCapability.get(capability);
165
+ if (decision === undefined)
166
+ return [];
167
+ return decision.services.length === 1
168
+ ? decision.services
169
+ : ownValue(decision.requirementServices, requirement) ?? [];
170
+ };
171
+ const livingByService = new Map();
172
+ for (const [capability, requirements] of livingRequirements) {
173
+ for (const requirement of requirements) {
174
+ for (const service of servicesForRequirement(capability, requirement.name)) {
175
+ const routed = livingByService.get(service) ?? [];
176
+ routed.push({ capability, requirement });
177
+ livingByService.set(service, routed);
178
+ }
179
+ }
180
+ }
181
+ const activeChangeIds = new Set(active.map((change) => change.id));
182
+ for (const change of Object.keys(mapping.changes)) {
183
+ if (!activeChangeIds.has(change)) {
184
+ mappingIssues.push({
185
+ code: "mapping.unknown-change",
186
+ key: change,
187
+ message: `Mapping names unknown active change '${change}'.`,
188
+ });
189
+ }
190
+ }
191
+ const changeDecisions = active.map((change, index) => {
192
+ const suggestedTitle = titleFromChangeId(change.id);
193
+ const selected = ownValue(mapping.changes, change.id);
194
+ const feature = selected?.feature ?? null;
195
+ const title = selected?.title?.trim() ?? suggestedTitle;
196
+ if (selected !== undefined && title === "") {
197
+ mappingIssues.push({
198
+ code: "mapping.change-title-missing",
199
+ key: change.id,
200
+ message: `Active change '${change.id}' needs a non-empty title.`,
201
+ });
202
+ }
203
+ if (feature !== null && !isFeatureId(feature)) {
204
+ mappingIssues.push({
205
+ code: "mapping.feature-id-invalid",
206
+ key: change.id,
207
+ message: `Active change '${change.id}' maps to invalid loam feature id '${feature}'. ${FEATURE_ID_RULE}`,
208
+ });
209
+ }
210
+ return {
211
+ change: change.id,
212
+ feature,
213
+ title,
214
+ suggestedFeature: `FEAT-${index + 1}`,
215
+ suggestedTitle,
216
+ status: feature === null || title === "" ? "needsFeature" : "mapped",
217
+ };
218
+ });
219
+ const featureOwners = new Map();
220
+ for (const decision of changeDecisions) {
221
+ if (decision.feature === null || !isFeatureId(decision.feature))
222
+ continue;
223
+ const key = decision.feature.toLowerCase();
224
+ const owners = featureOwners.get(key) ?? [];
225
+ owners.push(decision.change);
226
+ featureOwners.set(key, owners);
227
+ }
228
+ for (const [feature, owners] of featureOwners) {
229
+ if (owners.length > 1) {
230
+ mappingIssues.push({
231
+ code: "mapping.feature-id-duplicate",
232
+ key: feature,
233
+ message: `Loam feature id '${feature}' is assigned to multiple OpenSpec changes: ${owners.join(", ")}.`,
234
+ });
235
+ }
236
+ }
237
+ return {
238
+ mappingIssues,
239
+ mappingDecisions,
240
+ changeDecisions,
241
+ routing: { servicesForRequirement, livingByService },
242
+ };
243
+ }
244
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../../../src/core/openspec/decide/capabilities.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Which service owns which capability, and which feature owns which change —\n * the two decisions a human has to make, graded against what the scan found.\n *\n * The routing this produces is what everything downstream selects with, which\n * is why `servicesForRequirement` is returned as a function rather than as a\n * map: a split capability routes per REQUIREMENT and a single-service one\n * routes wholesale, and a caller that reimplemented that choice would put a\n * living requirement and its own delta in different services.\n */\nimport { resolve } from \"node:path\";\nimport { dictionary, ownValue } from \"../../kernel/records.js\";\nimport { FEATURE_ID_RULE, isFeatureId } from \"../../kernel/ids/feature.js\";\nimport { compareIds } from \"../../repo/entries.js\";\nimport { parseRequirements } from \"../../document/parse.js\";\nimport { type Requirement } from \"../../document/spec.js\";\nimport {\n type OpenSpecMapping,\n type CapabilityMappingDecision,\n type OpenSpecChangeDecision,\n type OpenSpecMappingIssue,\n} from \"../model/mapping.js\";\nimport { type OpenSpecChange, type OpenSpecRenamedUsage } from \"../model/model.js\";\nimport { titleFromChangeId } from \"../scan/changes.js\";\n\n/** Everything the workspace scan found, before any decision is graded. */\nexport interface Scan {\n root: string;\n mapping: OpenSpecMapping;\n /** Whether a mapping was SUPPLIED — an audit grades no source binding. */\n bound: boolean;\n inventoryDigest: string;\n livingRequirements: Map<string, Requirement[]>;\n active: OpenSpecChange[];\n renamed: OpenSpecRenamedUsage[];\n}\n\n/** How a requirement reaches a service, once the capability decisions are in. */\nexport interface Routing {\n servicesForRequirement(capability: string, requirement: string): string[];\n livingByService: Map<string, Array<{ capability: string; requirement: Requirement }>>;\n}\n\nexport interface Decisions {\n mappingIssues: OpenSpecMappingIssue[];\n mappingDecisions: CapabilityMappingDecision[];\n changeDecisions: OpenSpecChangeDecision[];\n routing: Routing;\n}\n\nexport function capabilityDecisions(scan: Scan): Decisions {\n const { root, mapping, bound, inventoryDigest, livingRequirements, active, renamed } = scan;\n // Capability ownership must cover the active horizon too: a brand-new\n // capability may exist only under changes/<id>/specs until archive.\n //\n // `routedNames` is the subset a split capability must actually allocate. A\n // renamed requirement is routed by its FROM — that is what keeps the delta in\n // the same services as the living text it rewrites — so demanding an\n // allocation for its TO as well asked a reviewer for a decision apply ignores.\n const requirementNamesByCapability = new Map<string, Set<string>>();\n const routedNamesByCapability = new Map<string, Set<string>>();\n const activeChangesByCapability = new Map<string, Set<string>>();\n const activeRenamePairs = renamed.filter((rename) =>\n rename.scope === \"active\"\n && rename.from !== null && rename.from !== \"\"\n && rename.to !== null && rename.to !== \"\");\n for (const [capability, requirements] of livingRequirements) {\n requirementNamesByCapability.set(capability, new Set(requirements.map((item) => item.name)));\n routedNamesByCapability.set(capability, new Set(requirements.map((item) => item.name)));\n }\n for (const change of active) {\n for (const spec of change.specs) {\n const names = requirementNamesByCapability.get(spec.capability) ?? new Set<string>();\n const routed = routedNamesByCapability.get(spec.capability) ?? new Set<string>();\n for (const name of spec.requirementNames) {\n names.add(name);\n const pairs = activeRenamePairs.filter((rename) =>\n rename.changeId === change.id\n && rename.capability === spec.capability\n && (name === rename.from || name === rename.to));\n routed.add(pairs.length === 1 ? pairs[0]!.from! : name);\n }\n requirementNamesByCapability.set(spec.capability, names);\n routedNamesByCapability.set(spec.capability, routed);\n const changes = activeChangesByCapability.get(spec.capability) ?? new Set<string>();\n changes.add(change.id);\n activeChangesByCapability.set(spec.capability, changes);\n }\n }\n const allCapabilityIds = [...requirementNamesByCapability.keys()].sort(compareIds);\n\n const mappingIssues: OpenSpecMappingIssue[] = [];\n if (bound) {\n if (mapping.source === null) {\n mappingIssues.push({\n code: \"mapping.source-missing\",\n key: \"source\",\n message: \"Mapping is not bound to an audited source root and inventory digest.\",\n });\n } else {\n if (resolve(mapping.source.root) !== root) {\n mappingIssues.push({\n code: \"mapping.source-root-mismatch\",\n key: \"source.root\",\n message: `Mapping was created for ${mapping.source.root}, not ${root}.`,\n });\n }\n if (mapping.source.inventoryDigest !== inventoryDigest) {\n mappingIssues.push({\n code: \"mapping.source-digest-mismatch\",\n key: \"source.inventoryDigest\",\n message: `OpenSpec source changed after audit (${mapping.source.inventoryDigest} != ${inventoryDigest}).`,\n });\n }\n }\n }\n const capabilityIds = new Set(allCapabilityIds);\n for (const capability of Object.keys(mapping.capabilities)) {\n if (!capabilityIds.has(capability)) {\n mappingIssues.push({\n code: \"mapping.unknown-capability\",\n key: capability,\n message: `Mapping names unknown capability '${capability}'.`,\n });\n }\n }\n const mappingDecisions: CapabilityMappingDecision[] = allCapabilityIds.map((capability) => {\n const capabilityMapping = ownValue(mapping.capabilities, capability)\n ?? { services: [], requirementServices: dictionary<string[]>() };\n const services = [...new Set(capabilityMapping.services)]\n .filter((service) => service.trim() !== \"\")\n .sort(compareIds);\n const requirementNames = [...(requirementNamesByCapability.get(capability) ?? [])].sort(compareIds);\n const requirementNameSet = new Set(requirementNames);\n const routedNames = [...(routedNamesByCapability.get(capability) ?? [])].sort(compareIds);\n const requirementServices = dictionary<string[]>();\n for (const [requirement, allocated] of Object.entries(capabilityMapping.requirementServices)) {\n if (!requirementNameSet.has(requirement)) {\n mappingIssues.push({\n code: \"mapping.unknown-requirement\",\n key: `${capability}:${requirement}`,\n message: `Capability '${capability}' mapping names unknown requirement '${requirement}'.`,\n });\n continue;\n }\n const selected = [...new Set(allocated)].filter(Boolean).sort(compareIds);\n requirementServices[requirement] = selected;\n for (const service of selected) {\n if (!services.includes(service)) {\n mappingIssues.push({\n code: \"mapping.requirement-service-unknown\",\n key: `${capability}:${requirement}`,\n message: `Requirement '${requirement}' is allocated to '${service}', which is not in capability '${capability}' services.`,\n });\n }\n }\n }\n // Only routed names get an empty slot in the skeleton: an unroutable name\n // offered for allocation is a decision that changes nothing.\n for (const requirement of routedNames) {\n if (ownValue(requirementServices, requirement) === undefined) requirementServices[requirement] = [];\n }\n if (services.length > 1) {\n for (const requirement of routedNames) {\n if ((ownValue(requirementServices, requirement) ?? []).length === 0) {\n mappingIssues.push({\n code: \"mapping.requirement-allocation-missing\",\n key: `${capability}:${requirement}`,\n message: `Split capability '${capability}' must allocate requirement '${requirement}' to at least one selected service.`,\n });\n }\n }\n for (const service of services) {\n if (!Object.values(requirementServices).some((selected) => selected.includes(service))) {\n mappingIssues.push({\n code: \"mapping.service-allocation-empty\",\n key: `${capability}:${service}`,\n message: `Split capability '${capability}' selects service '${service}' but allocates no requirement to it.`,\n });\n }\n }\n }\n return {\n capability,\n service: services.length === 1 ? services[0]! : null,\n services,\n requirementServices,\n suggestedService: capability.split(\"/\").at(-1) ?? capability,\n hasLivingSpec: livingRequirements.has(capability),\n activeChanges: [...(activeChangesByCapability.get(capability) ?? [])].sort(compareIds),\n status: services.length === 0 ? \"needsMapping\" : \"mapped\",\n };\n });\n const decisionsByCapability = new Map(mappingDecisions.map((decision) => [decision.capability, decision]));\n const servicesForRequirement = (capability: string, requirement: string): string[] => {\n const decision = decisionsByCapability.get(capability);\n if (decision === undefined) return [];\n return decision.services.length === 1\n ? decision.services\n : ownValue(decision.requirementServices, requirement) ?? [];\n };\n const livingByService = new Map<string, Array<{ capability: string; requirement: ReturnType<typeof parseRequirements>[number] }>>();\n for (const [capability, requirements] of livingRequirements) {\n for (const requirement of requirements) {\n for (const service of servicesForRequirement(capability, requirement.name)) {\n const routed = livingByService.get(service) ?? [];\n routed.push({ capability, requirement });\n livingByService.set(service, routed);\n }\n }\n }\n\n const activeChangeIds = new Set(active.map((change) => change.id));\n for (const change of Object.keys(mapping.changes)) {\n if (!activeChangeIds.has(change)) {\n mappingIssues.push({\n code: \"mapping.unknown-change\",\n key: change,\n message: `Mapping names unknown active change '${change}'.`,\n });\n }\n }\n const changeDecisions: OpenSpecChangeDecision[] = active.map((change, index) => {\n const suggestedTitle = titleFromChangeId(change.id);\n const selected = ownValue(mapping.changes, change.id);\n const feature = selected?.feature ?? null;\n const title = selected?.title?.trim() ?? suggestedTitle;\n if (selected !== undefined && title === \"\") {\n mappingIssues.push({\n code: \"mapping.change-title-missing\",\n key: change.id,\n message: `Active change '${change.id}' needs a non-empty title.`,\n });\n }\n if (feature !== null && !isFeatureId(feature)) {\n mappingIssues.push({\n code: \"mapping.feature-id-invalid\",\n key: change.id,\n message: `Active change '${change.id}' maps to invalid loam feature id '${feature}'. ${FEATURE_ID_RULE}`,\n });\n }\n return {\n change: change.id,\n feature,\n title,\n suggestedFeature: `FEAT-${index + 1}`,\n suggestedTitle,\n status: feature === null || title === \"\" ? \"needsFeature\" : \"mapped\",\n };\n });\n const featureOwners = new Map<string, string[]>();\n for (const decision of changeDecisions) {\n if (decision.feature === null || !isFeatureId(decision.feature)) continue;\n const key = decision.feature.toLowerCase();\n const owners = featureOwners.get(key) ?? [];\n owners.push(decision.change);\n featureOwners.set(key, owners);\n }\n for (const [feature, owners] of featureOwners) {\n if (owners.length > 1) {\n mappingIssues.push({\n code: \"mapping.feature-id-duplicate\",\n key: feature,\n message: `Loam feature id '${feature}' is assigned to multiple OpenSpec changes: ${owners.join(\", \")}.`,\n });\n }\n }\n return {\n mappingIssues,\n mappingDecisions,\n changeDecisions,\n routing: { servicesForRequirement, livingByService },\n };\n}\n"]}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * What happens to each authored artifact loam has no equivalent for: a
3
+ * proposal, a task list, a design note.
4
+ *
5
+ * Every one of them is a decision rather than a default, because the honest
6
+ * answers differ per corpus — one team's `design.md` is an ADR, another's is a
7
+ * scratchpad. A disposition nobody chose is the one way this migration could
8
+ * quietly drop authored work, so an unset one blocks readiness.
9
+ */
10
+ import { ownValue } from "../../kernel/records.js";
11
+ import {} from "../model/mapping.js";
12
+ import {} from "../model/model.js";
13
+ export function artifactDispositions(artifacts, mapping, activeChangeIds, mappingIssues) {
14
+ const decisionKinds = new Set(["proposal", "tasks", "change-design"]);
15
+ const artifactDecisions = artifacts
16
+ // Never offer a disposition for an artifact no enumerated change owns —
17
+ // dot-prefixed change directories are refused, not migrated, and a
18
+ // `selectedDisposition` recorded for one is a decision about nothing.
19
+ .filter((artifact) => artifact.scope === "active"
20
+ && decisionKinds.has(artifact.kind)
21
+ && artifact.changeId !== undefined
22
+ && activeChangeIds.has(artifact.changeId))
23
+ .map((artifact) => {
24
+ const selected = ownValue(mapping.artifacts, artifact.path) ?? null;
25
+ return {
26
+ path: artifact.path,
27
+ kind: artifact.kind,
28
+ suggestedDisposition: artifact.disposition,
29
+ disposition: selected,
30
+ status: selected === null ? "needsDisposition" : "mapped",
31
+ };
32
+ });
33
+ const artifactPaths = new Set(artifactDecisions.map((decision) => decision.path));
34
+ // Sets of plain strings: the question being asked is "is this authored value
35
+ // one of the ones this kind accepts", and a set of the union could not be
36
+ // asked it without an assertion putting the answer back where it started.
37
+ const dispositionsByKind = {
38
+ proposal: new Set(["convert-to-intent", "retain-read-only", "manual-review"]),
39
+ tasks: new Set(["preserve-as-legacy-checklist", "retain-read-only", "manual-review"]),
40
+ "change-design": new Set(["review-as-feature-adr", "retain-read-only", "manual-review"]),
41
+ };
42
+ for (const [path, disposition] of Object.entries(mapping.artifacts)) {
43
+ if (!artifactPaths.has(path)) {
44
+ mappingIssues.push({
45
+ code: "mapping.unknown-artifact",
46
+ key: path,
47
+ message: `Mapping names unknown active authored artifact '${path}'.`,
48
+ });
49
+ }
50
+ else {
51
+ const decision = artifactDecisions.find((item) => item.path === path);
52
+ if (dispositionsByKind[decision.kind].has(disposition))
53
+ continue;
54
+ mappingIssues.push({
55
+ code: "mapping.invalid-artifact-disposition",
56
+ key: path,
57
+ message: `${decision.kind} artifact '${path}' has unsupported disposition '${disposition}'.`,
58
+ });
59
+ }
60
+ }
61
+ return artifactDecisions;
62
+ }
63
+ //# sourceMappingURL=dispositions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispositions.js","sourceRoot":"","sources":["../../../../src/core/openspec/decide/dispositions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAmD,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAmF,MAAM,mBAAmB,CAAC;AAEpH,MAAM,UAAU,oBAAoB,CAClC,SAA6B,EAC7B,OAAwB,EACxB,eAAoC,EACpC,aAAqC;IAEnC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAuB,CAAC,UAAU,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC;IAC5F,MAAM,iBAAiB,GAA+B,SAAS;QAC7D,wEAAwE;QACxE,mEAAmE;QACnE,sEAAsE;SACrE,MAAM,CAAC,CAAC,QAAQ,EAAmF,EAAE,CACpG,QAAQ,CAAC,KAAK,KAAK,QAAQ;WACxB,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;WAChC,QAAQ,CAAC,QAAQ,KAAK,SAAS;WAC/B,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;SAC3C,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE;QAChB,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;QACpE,OAAO;YACL,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,oBAAoB,EAAE,QAAQ,CAAC,WAAW;YAC1C,WAAW,EAAE,QAAQ;YACrB,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,kBAA2B,CAAC,CAAC,CAAC,QAAiB;SAC5E,CAAC;IACJ,CAAC,CAAC,CAAC;IACL,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAClF,6EAA6E;IAC7E,0EAA0E;IAC1E,0EAA0E;IAC1E,MAAM,kBAAkB,GAAkE;QACxF,QAAQ,EAAE,IAAI,GAAG,CAAC,CAAC,mBAAmB,EAAE,kBAAkB,EAAE,eAAe,CAAC,CAAC;QAC7E,KAAK,EAAE,IAAI,GAAG,CAAC,CAAC,8BAA8B,EAAE,kBAAkB,EAAE,eAAe,CAAC,CAAC;QACrF,eAAe,EAAE,IAAI,GAAG,CAAC,CAAC,uBAAuB,EAAE,kBAAkB,EAAE,eAAe,CAAC,CAAC;KACzF,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACpE,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,aAAa,CAAC,IAAI,CAAC;gBACjB,IAAI,EAAE,0BAA0B;gBAChC,GAAG,EAAE,IAAI;gBACT,OAAO,EAAE,mDAAmD,IAAI,IAAI;aACrE,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAE,CAAC;YACvE,IAAI,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC;gBAAE,SAAS;YACjE,aAAa,CAAC,IAAI,CAAC;gBACjB,IAAI,EAAE,sCAAsC;gBAC5C,GAAG,EAAE,IAAI;gBACT,OAAO,EAAE,GAAG,QAAQ,CAAC,IAAI,cAAc,IAAI,kCAAkC,WAAW,IAAI;aAC7F,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACH,OAAO,iBAAiB,CAAC;AAC3B,CAAC","sourcesContent":["/**\n * What happens to each authored artifact loam has no equivalent for: a\n * proposal, a task list, a design note.\n *\n * Every one of them is a decision rather than a default, because the honest\n * answers differ per corpus — one team's `design.md` is an ADR, another's is a\n * scratchpad. A disposition nobody chose is the one way this migration could\n * quietly drop authored work, so an unset one blocks readiness.\n */\nimport { ownValue } from \"../../kernel/records.js\";\nimport { type OpenSpecMapping, type OpenSpecMappingIssue } from \"../model/mapping.js\";\nimport { type OpenSpecArtifact, type OpenSpecArtifactDecision, type OpenSpecArtifactKind } from \"../model/model.js\";\n\nexport function artifactDispositions(\n artifacts: OpenSpecArtifact[],\n mapping: OpenSpecMapping,\n activeChangeIds: ReadonlySet<string>,\n mappingIssues: OpenSpecMappingIssue[],\n): OpenSpecArtifactDecision[] {\n const decisionKinds = new Set<OpenSpecArtifactKind>([\"proposal\", \"tasks\", \"change-design\"]);\n const artifactDecisions: OpenSpecArtifactDecision[] = artifacts\n // Never offer a disposition for an artifact no enumerated change owns —\n // dot-prefixed change directories are refused, not migrated, and a\n // `selectedDisposition` recorded for one is a decision about nothing.\n .filter((artifact): artifact is OpenSpecArtifact & { kind: \"proposal\" | \"tasks\" | \"change-design\" } =>\n artifact.scope === \"active\"\n && decisionKinds.has(artifact.kind)\n && artifact.changeId !== undefined\n && activeChangeIds.has(artifact.changeId))\n .map((artifact) => {\n const selected = ownValue(mapping.artifacts, artifact.path) ?? null;\n return {\n path: artifact.path,\n kind: artifact.kind,\n suggestedDisposition: artifact.disposition,\n disposition: selected,\n status: selected === null ? \"needsDisposition\" as const : \"mapped\" as const,\n };\n });\n const artifactPaths = new Set(artifactDecisions.map((decision) => decision.path));\n // Sets of plain strings: the question being asked is \"is this authored value\n // one of the ones this kind accepts\", and a set of the union could not be\n // asked it without an assertion putting the answer back where it started.\n const dispositionsByKind: Record<OpenSpecArtifactDecision[\"kind\"], ReadonlySet<string>> = {\n proposal: new Set([\"convert-to-intent\", \"retain-read-only\", \"manual-review\"]),\n tasks: new Set([\"preserve-as-legacy-checklist\", \"retain-read-only\", \"manual-review\"]),\n \"change-design\": new Set([\"review-as-feature-adr\", \"retain-read-only\", \"manual-review\"]),\n };\n for (const [path, disposition] of Object.entries(mapping.artifacts)) {\n if (!artifactPaths.has(path)) {\n mappingIssues.push({\n code: \"mapping.unknown-artifact\",\n key: path,\n message: `Mapping names unknown active authored artifact '${path}'.`,\n });\n } else {\n const decision = artifactDecisions.find((item) => item.path === path)!;\n if (dispositionsByKind[decision.kind].has(disposition)) continue;\n mappingIssues.push({\n code: \"mapping.invalid-artifact-disposition\",\n key: path,\n message: `${decision.kind} artifact '${path}' has unsupported disposition '${disposition}'.`,\n });\n }\n }\n return artifactDecisions;\n}\n"]}
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Every active RENAMED pair resolved against the living source of truth.
3
+ *
4
+ * This is the identity problem the whole package exists for: OpenSpec renames
5
+ * by writing FROM/TO bullets, loam renames by carrying one stable
6
+ * `Requirement-ID` through a MODIFIED requirement, and nothing mechanical
7
+ * bridges the two. So each pair is either resolved to an id the living text
8
+ * already carries, or it becomes a decision a human has to make — never a
9
+ * guess, because a wrong identity silently merges one requirement's text over
10
+ * another's.
11
+ *
12
+ * It MUTATES the usages it resolves rather than returning new ones: a rename is
13
+ * one fact seen in one file, and two copies of it — one resolved, one not — is
14
+ * exactly the bug this resolution exists to prevent.
15
+ */
16
+ import { ownValue } from "../../kernel/records.js";
17
+ import { REQUIREMENT_ID_RE, requirementIdDeclarations } from "../../document/spec.js";
18
+ import {} from "../model/mapping.js";
19
+ import {} from "../model/model.js";
20
+ import {} from "./capabilities.js";
21
+ export function resolveRenames(scan, routing, mappingIssues) {
22
+ const { mapping, livingRequirements, renamed } = scan;
23
+ const { livingByService, servicesForRequirement } = routing;
24
+ const activeRenames = renamed.filter((rename) => rename.scope === "active");
25
+ const renameKeys = new Set(activeRenames.map((rename) => rename.key));
26
+ for (const [key, requirementId] of Object.entries(mapping.renames)) {
27
+ if (!renameKeys.has(key)) {
28
+ mappingIssues.push({
29
+ code: "mapping.unknown-rename",
30
+ key,
31
+ message: `Mapping names unknown RENAMED pair '${key}'.`,
32
+ });
33
+ }
34
+ else if (!REQUIREMENT_ID_RE.test(requirementId)) {
35
+ mappingIssues.push({
36
+ code: "mapping.invalid-requirement-id",
37
+ key,
38
+ message: `RENAMED pair '${key}' has invalid Requirement-ID '${requirementId}'.`,
39
+ });
40
+ }
41
+ }
42
+ // Resolve every rename against the living source of truth. A mapped id is
43
+ // only needed when the source requirement does not already carry one.
44
+ for (const rename of activeRenames) {
45
+ if (rename.from === null || rename.from === "" || rename.to === null || rename.to === "")
46
+ continue;
47
+ const living = livingRequirements.get(rename.capability) ?? [];
48
+ const matches = living.filter((requirement) => requirement.name === rename.from);
49
+ if (matches.length === 0) {
50
+ mappingIssues.push({
51
+ code: "mapping.rename-source-missing",
52
+ key: rename.key,
53
+ message: `RENAMED source '${rename.from}' does not exist in living capability '${rename.capability}'.`,
54
+ });
55
+ rename.requirementId = null;
56
+ rename.status = "needsIdentity";
57
+ continue;
58
+ }
59
+ if (matches.length > 1) {
60
+ mappingIssues.push({
61
+ code: "mapping.rename-source-ambiguous",
62
+ key: rename.key,
63
+ message: `RENAMED source '${rename.from}' matches ${matches.length} living requirements in '${rename.capability}'.`,
64
+ });
65
+ rename.requirementId = null;
66
+ rename.status = "needsIdentity";
67
+ continue;
68
+ }
69
+ const source = matches[0];
70
+ const declarations = requirementIdDeclarations(source);
71
+ if (declarations.length > 0
72
+ && (declarations.length !== 1 || !REQUIREMENT_ID_RE.test(declarations[0]))) {
73
+ rename.existingRequirementId = source.id ?? null;
74
+ rename.requirementId = null;
75
+ rename.status = "needsIdentity";
76
+ mappingIssues.push({
77
+ code: "mapping.rename-source-id-invalid",
78
+ key: rename.key,
79
+ message: `RENAMED source '${rename.from}' has ${declarations.length === 1 ? "an invalid" : "repeated"} Requirement-ID declaration; repair the living source before migration.`,
80
+ });
81
+ continue;
82
+ }
83
+ rename.existingRequirementId = source.id ?? null;
84
+ const requestedId = ownValue(mapping.renames, rename.key) ?? null;
85
+ if (source.id !== undefined && requestedId !== null && requestedId !== source.id) {
86
+ mappingIssues.push({
87
+ code: "mapping.rename-existing-id-conflict",
88
+ key: rename.key,
89
+ message: `RENAMED source '${rename.from}' already has Requirement-ID '${source.id}'; mapping cannot replace it with '${requestedId}'.`,
90
+ });
91
+ }
92
+ rename.requirementId = source.id ?? requestedId;
93
+ rename.status = rename.requirementId === null ? "needsIdentity" : "mapped";
94
+ const routedServices = servicesForRequirement(rename.capability, rename.from);
95
+ if (rename.requirementId !== null) {
96
+ const collisionServices = routedServices.filter((service) => (livingByService.get(service) ?? []).some((entry) => entry.requirement !== source && entry.requirement.id === rename.requirementId));
97
+ if (collisionServices.length > 0) {
98
+ mappingIssues.push({
99
+ code: "mapping.rename-id-conflict",
100
+ key: rename.key,
101
+ message: `RENAMED identity '${rename.requirementId}' already belongs to another living requirement in mapped service(s): ${collisionServices.join(", ")}.`,
102
+ });
103
+ }
104
+ }
105
+ const targetCollisionServices = routedServices.filter((service) => (livingByService.get(service) ?? []).some((entry) => entry.requirement !== source && entry.requirement.name === rename.to));
106
+ if (rename.to === rename.from || targetCollisionServices.length > 0) {
107
+ mappingIssues.push({
108
+ code: "mapping.rename-target-conflict",
109
+ key: rename.key,
110
+ message: rename.to === rename.from
111
+ ? `RENAMED target '${rename.to}' is the same as its living source.`
112
+ : `RENAMED target '${rename.to}' conflicts in mapped service(s): ${targetCollisionServices.join(", ")}.`,
113
+ });
114
+ }
115
+ }
116
+ const renameSources = new Map();
117
+ const renameTargets = new Map();
118
+ for (const rename of activeRenames) {
119
+ if (rename.from === null || rename.to === null)
120
+ continue;
121
+ for (const service of servicesForRequirement(rename.capability, rename.from)) {
122
+ const sourceKey = `${service}\0${rename.from}`;
123
+ const targetKey = `${service}\0${rename.to}`;
124
+ const sources = renameSources.get(sourceKey) ?? [];
125
+ sources.push(rename);
126
+ renameSources.set(sourceKey, sources);
127
+ const targets = renameTargets.get(targetKey) ?? [];
128
+ targets.push(rename);
129
+ renameTargets.set(targetKey, targets);
130
+ }
131
+ }
132
+ for (const [key, uses] of renameSources) {
133
+ if (uses.length > 1) {
134
+ mappingIssues.push({
135
+ code: "mapping.rename-double-source",
136
+ key: key.replace("\0", ":"),
137
+ message: `Living requirement '${uses[0].from}' is renamed by multiple active changes: ${uses.map((item) => item.changeId).join(", ")}.`,
138
+ });
139
+ }
140
+ }
141
+ for (const [key, uses] of renameTargets) {
142
+ if (uses.length > 1) {
143
+ mappingIssues.push({
144
+ code: "mapping.rename-double-target",
145
+ key: key.replace("\0", ":"),
146
+ message: `Multiple active renames target '${uses[0].to}' in mapped service '${key.split("\0")[0]}'.`,
147
+ });
148
+ }
149
+ if (renameSources.has(key)) {
150
+ mappingIssues.push({
151
+ code: "mapping.rename-chain",
152
+ key: key.replace("\0", ":"),
153
+ message: `Active rename chain through '${uses[0].to}' must be collapsed into one reviewed rename.`,
154
+ });
155
+ }
156
+ }
157
+ const renameIdOwners = new Map();
158
+ for (const rename of activeRenames) {
159
+ if (rename.requirementId === null || rename.from === null)
160
+ continue;
161
+ for (const service of servicesForRequirement(rename.capability, rename.from)) {
162
+ const key = `${service}\0${rename.requirementId}`;
163
+ const owners = renameIdOwners.get(key) ?? new Set();
164
+ owners.add(`${rename.capability}:${rename.from}`);
165
+ renameIdOwners.set(key, owners);
166
+ }
167
+ }
168
+ for (const [key, owners] of renameIdOwners) {
169
+ if (owners.size > 1) {
170
+ const [service, requirementId] = key.split("\0");
171
+ mappingIssues.push({
172
+ code: "mapping.rename-id-conflict",
173
+ key,
174
+ message: `Requirement-ID '${requirementId}' is assigned to different RENAMED sources in mapped service '${service}': ${[...owners].join(", ")}.`,
175
+ });
176
+ }
177
+ }
178
+ }
179
+ //# sourceMappingURL=renames.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renames.js","sourceRoot":"","sources":["../../../../src/core/openspec/decide/renames.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Every active RENAMED pair resolved against the living source of truth.\n *\n * This is the identity problem the whole package exists for: OpenSpec renames\n * by writing FROM/TO bullets, loam renames by carrying one stable\n * `Requirement-ID` through a MODIFIED requirement, and nothing mechanical\n * bridges the two. So each pair is either resolved to an id the living text\n * already carries, or it becomes a decision a human has to make — never a\n * guess, because a wrong identity silently merges one requirement's text over\n * another's.\n *\n * It MUTATES the usages it resolves rather than returning new ones: a rename is\n * one fact seen in one file, and two copies of it — one resolved, one not — is\n * exactly the bug this resolution exists to prevent.\n */\nimport { ownValue } from \"../../kernel/records.js\";\nimport { REQUIREMENT_ID_RE, requirementIdDeclarations } from \"../../document/spec.js\";\nimport { type OpenSpecMappingIssue } from \"../model/mapping.js\";\nimport { type OpenSpecRenamedUsage } from \"../model/model.js\";\nimport { type Scan, type Routing } from \"./capabilities.js\";\n\nexport function resolveRenames(scan: Scan, routing: Routing, mappingIssues: OpenSpecMappingIssue[]): void {\n const { mapping, livingRequirements, renamed } = scan;\n const { livingByService, servicesForRequirement } = routing;\n const activeRenames = renamed.filter((rename) => rename.scope === \"active\");\n const renameKeys = new Set(activeRenames.map((rename) => rename.key));\n for (const [key, requirementId] of Object.entries(mapping.renames)) {\n if (!renameKeys.has(key)) {\n mappingIssues.push({\n code: \"mapping.unknown-rename\",\n key,\n message: `Mapping names unknown RENAMED pair '${key}'.`,\n });\n } else if (!REQUIREMENT_ID_RE.test(requirementId)) {\n mappingIssues.push({\n code: \"mapping.invalid-requirement-id\",\n key,\n message: `RENAMED pair '${key}' has invalid Requirement-ID '${requirementId}'.`,\n });\n }\n }\n\n // Resolve every rename against the living source of truth. A mapped id is\n // only needed when the source requirement does not already carry one.\n for (const rename of activeRenames) {\n if (rename.from === null || rename.from === \"\" || rename.to === null || rename.to === \"\") continue;\n const living = livingRequirements.get(rename.capability) ?? [];\n const matches = living.filter((requirement) => requirement.name === rename.from);\n if (matches.length === 0) {\n mappingIssues.push({\n code: \"mapping.rename-source-missing\",\n key: rename.key,\n message: `RENAMED source '${rename.from}' does not exist in living capability '${rename.capability}'.`,\n });\n rename.requirementId = null;\n rename.status = \"needsIdentity\";\n continue;\n }\n if (matches.length > 1) {\n mappingIssues.push({\n code: \"mapping.rename-source-ambiguous\",\n key: rename.key,\n message: `RENAMED source '${rename.from}' matches ${matches.length} living requirements in '${rename.capability}'.`,\n });\n rename.requirementId = null;\n rename.status = \"needsIdentity\";\n continue;\n }\n const source = matches[0]!;\n const declarations = requirementIdDeclarations(source);\n if (declarations.length > 0\n && (declarations.length !== 1 || !REQUIREMENT_ID_RE.test(declarations[0]!))) {\n rename.existingRequirementId = source.id ?? null;\n rename.requirementId = null;\n rename.status = \"needsIdentity\";\n mappingIssues.push({\n code: \"mapping.rename-source-id-invalid\",\n key: rename.key,\n message: `RENAMED source '${rename.from}' has ${declarations.length === 1 ? \"an invalid\" : \"repeated\"} Requirement-ID declaration; repair the living source before migration.`,\n });\n continue;\n }\n rename.existingRequirementId = source.id ?? null;\n const requestedId = ownValue(mapping.renames, rename.key) ?? null;\n if (source.id !== undefined && requestedId !== null && requestedId !== source.id) {\n mappingIssues.push({\n code: \"mapping.rename-existing-id-conflict\",\n key: rename.key,\n message: `RENAMED source '${rename.from}' already has Requirement-ID '${source.id}'; mapping cannot replace it with '${requestedId}'.`,\n });\n }\n rename.requirementId = source.id ?? requestedId;\n rename.status = rename.requirementId === null ? \"needsIdentity\" : \"mapped\";\n const routedServices = servicesForRequirement(rename.capability, rename.from);\n if (rename.requirementId !== null) {\n const collisionServices = routedServices.filter((service) =>\n (livingByService.get(service) ?? []).some(\n (entry) => entry.requirement !== source && entry.requirement.id === rename.requirementId,\n ));\n if (collisionServices.length > 0) {\n mappingIssues.push({\n code: \"mapping.rename-id-conflict\",\n key: rename.key,\n message: `RENAMED identity '${rename.requirementId}' already belongs to another living requirement in mapped service(s): ${collisionServices.join(\", \")}.`,\n });\n }\n }\n const targetCollisionServices = routedServices.filter((service) =>\n (livingByService.get(service) ?? []).some(\n (entry) => entry.requirement !== source && entry.requirement.name === rename.to,\n ));\n if (rename.to === rename.from || targetCollisionServices.length > 0) {\n mappingIssues.push({\n code: \"mapping.rename-target-conflict\",\n key: rename.key,\n message: rename.to === rename.from\n ? `RENAMED target '${rename.to}' is the same as its living source.`\n : `RENAMED target '${rename.to}' conflicts in mapped service(s): ${targetCollisionServices.join(\", \")}.`,\n });\n }\n }\n\n const renameSources = new Map<string, OpenSpecRenamedUsage[]>();\n const renameTargets = new Map<string, OpenSpecRenamedUsage[]>();\n for (const rename of activeRenames) {\n if (rename.from === null || rename.to === null) continue;\n for (const service of servicesForRequirement(rename.capability, rename.from)) {\n const sourceKey = `${service}\\0${rename.from}`;\n const targetKey = `${service}\\0${rename.to}`;\n const sources = renameSources.get(sourceKey) ?? [];\n sources.push(rename);\n renameSources.set(sourceKey, sources);\n const targets = renameTargets.get(targetKey) ?? [];\n targets.push(rename);\n renameTargets.set(targetKey, targets);\n }\n }\n for (const [key, uses] of renameSources) {\n if (uses.length > 1) {\n mappingIssues.push({\n code: \"mapping.rename-double-source\",\n key: key.replace(\"\\0\", \":\"),\n message: `Living requirement '${uses[0]!.from}' is renamed by multiple active changes: ${uses.map((item) => item.changeId).join(\", \")}.`,\n });\n }\n }\n for (const [key, uses] of renameTargets) {\n if (uses.length > 1) {\n mappingIssues.push({\n code: \"mapping.rename-double-target\",\n key: key.replace(\"\\0\", \":\"),\n message: `Multiple active renames target '${uses[0]!.to}' in mapped service '${key.split(\"\\0\")[0]}'.`,\n });\n }\n if (renameSources.has(key)) {\n mappingIssues.push({\n code: \"mapping.rename-chain\",\n key: key.replace(\"\\0\", \":\"),\n message: `Active rename chain through '${uses[0]!.to}' must be collapsed into one reviewed rename.`,\n });\n }\n }\n const renameIdOwners = new Map<string, Set<string>>();\n for (const rename of activeRenames) {\n if (rename.requirementId === null || rename.from === null) continue;\n for (const service of servicesForRequirement(rename.capability, rename.from)) {\n const key = `${service}\\0${rename.requirementId}`;\n const owners = renameIdOwners.get(key) ?? new Set<string>();\n owners.add(`${rename.capability}:${rename.from}`);\n renameIdOwners.set(key, owners);\n }\n }\n for (const [key, owners] of renameIdOwners) {\n if (owners.size > 1) {\n const [service, requirementId] = key.split(\"\\0\");\n mappingIssues.push({\n code: \"mapping.rename-id-conflict\",\n key,\n message: `Requirement-ID '${requirementId}' is assigned to different RENAMED sources in mapped service '${service}': ${[...owners].join(\", \")}.`,\n });\n }\n }\n}\n"]}