@ybotok/loam 0.2.0-alpha.6 → 0.2.0-alpha.9

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 (691) hide show
  1. package/CHANGELOG.md +1477 -1
  2. package/COMPARISON.md +91 -3
  3. package/CONTRIBUTING.md +37 -0
  4. package/MIGRATING-from-OpenSpec.md +40 -22
  5. package/QUICKSTART.md +181 -9
  6. package/README.md +256 -57
  7. package/ROADMAP.md +108 -11
  8. package/SCHEMA.md +721 -130
  9. package/WORKFLOW.md +272 -62
  10. package/dist/cli.js +26 -8
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/adopt/adopt.js +5 -10
  13. package/dist/commands/adopt/adopt.js.map +1 -1
  14. package/dist/commands/archive/archive.js +15 -18
  15. package/dist/commands/archive/archive.js.map +1 -1
  16. package/dist/commands/archive/plan/contracts/asyncapi.js +27 -41
  17. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
  18. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  19. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  20. package/dist/commands/archive/plan/contracts/openapi.js +25 -42
  21. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
  22. package/dist/commands/archive/plan/contracts/verdict-lines.js +41 -0
  23. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  24. package/dist/commands/archive/plan/gate.js +3 -7
  25. package/dist/commands/archive/plan/gate.js.map +1 -1
  26. package/dist/commands/archive/plan/landscape.js +4 -4
  27. package/dist/commands/archive/plan/landscape.js.map +1 -1
  28. package/dist/commands/archive/plan/refusal.js +8 -18
  29. package/dist/commands/archive/plan/refusal.js.map +1 -1
  30. package/dist/commands/archive/plan/specs.js +134 -25
  31. package/dist/commands/archive/plan/specs.js.map +1 -1
  32. package/dist/commands/archive/plan/state.js +1 -0
  33. package/dist/commands/archive/plan/state.js.map +1 -1
  34. package/dist/commands/archive/run.js +82 -33
  35. package/dist/commands/archive/run.js.map +1 -1
  36. package/dist/commands/archive/shipped.js +49 -0
  37. package/dist/commands/archive/shipped.js.map +1 -0
  38. package/dist/commands/context/context.js +4 -7
  39. package/dist/commands/context/context.js.map +1 -1
  40. package/dist/commands/context/print.js +2 -2
  41. package/dist/commands/context/print.js.map +1 -1
  42. package/dist/commands/delta/delta.js +44 -12
  43. package/dist/commands/delta/delta.js.map +1 -1
  44. package/dist/commands/delta/print.js +1 -1
  45. package/dist/commands/delta/print.js.map +1 -1
  46. package/dist/commands/dependencies.js +3 -7
  47. package/dist/commands/dependencies.js.map +1 -1
  48. package/dist/commands/diff/diff.js +20 -27
  49. package/dist/commands/diff/diff.js.map +1 -1
  50. package/dist/commands/explore.js +4 -8
  51. package/dist/commands/explore.js.map +1 -1
  52. package/dist/commands/gate/gate.js +45 -8
  53. package/dist/commands/gate/gate.js.map +1 -1
  54. package/dist/commands/gate/print.js +15 -3
  55. package/dist/commands/gate/print.js.map +1 -1
  56. package/dist/commands/gherkin/commit.js +13 -54
  57. package/dist/commands/gherkin/commit.js.map +1 -1
  58. package/dist/commands/gherkin/gherkin.js +36 -20
  59. package/dist/commands/gherkin/gherkin.js.map +1 -1
  60. package/dist/commands/gherkin/reconcile.js +10 -13
  61. package/dist/commands/gherkin/reconcile.js.map +1 -1
  62. package/dist/commands/init/first-hour.js +44 -0
  63. package/dist/commands/init/first-hour.js.map +1 -1
  64. package/dist/commands/init/init.js +18 -22
  65. package/dist/commands/init/init.js.map +1 -1
  66. package/dist/commands/list/campaign/campaign.js +4 -6
  67. package/dist/commands/list/campaign/campaign.js.map +1 -1
  68. package/dist/commands/list/json.js +0 -4
  69. package/dist/commands/list/json.js.map +1 -1
  70. package/dist/commands/list/list.js +38 -23
  71. package/dist/commands/list/list.js.map +1 -1
  72. package/dist/commands/list/print.js +38 -6
  73. package/dist/commands/list/print.js.map +1 -1
  74. package/dist/commands/list/suites/suites.js +140 -0
  75. package/dist/commands/list/suites/suites.js.map +1 -0
  76. package/dist/commands/list/views.js +28 -33
  77. package/dist/commands/list/views.js.map +1 -1
  78. package/dist/commands/mcp/dispatch.js +91 -36
  79. package/dist/commands/mcp/dispatch.js.map +1 -1
  80. package/dist/commands/mcp/mcp.js +56 -15
  81. package/dist/commands/mcp/mcp.js.map +1 -1
  82. package/dist/commands/mcp/serve.js.map +1 -1
  83. package/dist/commands/migrate-openspec/materialize/active.js +27 -22
  84. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
  85. package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
  86. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
  87. package/dist/commands/migrate-openspec/materialize/target.js +2 -2
  88. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
  89. package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
  90. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
  91. package/dist/commands/migrate-openspec/openspec/error.js +7 -8
  92. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
  93. package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
  94. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
  95. package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
  96. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
  97. package/dist/commands/new/capability-template.js +118 -0
  98. package/dist/commands/new/capability-template.js.map +1 -0
  99. package/dist/commands/new/commit.js +8 -22
  100. package/dist/commands/new/commit.js.map +1 -1
  101. package/dist/commands/new/modifies.js +206 -0
  102. package/dist/commands/new/modifies.js.map +1 -0
  103. package/dist/commands/new/new.js +59 -14
  104. package/dist/commands/new/new.js.map +1 -1
  105. package/dist/commands/new/templates.js +48 -124
  106. package/dist/commands/new/templates.js.map +1 -1
  107. package/dist/commands/open.js +3 -7
  108. package/dist/commands/open.js.map +1 -1
  109. package/dist/commands/policy/gate.js +27 -0
  110. package/dist/commands/policy/gate.js.map +1 -1
  111. package/dist/commands/rebase/plan.js +2 -2
  112. package/dist/commands/rebase/plan.js.map +1 -1
  113. package/dist/commands/rebase/rebase.js +60 -35
  114. package/dist/commands/rebase/rebase.js.map +1 -1
  115. package/dist/commands/seed/commit.js +55 -26
  116. package/dist/commands/seed/commit.js.map +1 -1
  117. package/dist/commands/seed/plan.js +64 -13
  118. package/dist/commands/seed/plan.js.map +1 -1
  119. package/dist/commands/seed/seed.js +6 -9
  120. package/dist/commands/seed/seed.js.map +1 -1
  121. package/dist/commands/show/show.js +3 -7
  122. package/dist/commands/show/show.js.map +1 -1
  123. package/dist/commands/status/print.js +13 -4
  124. package/dist/commands/status/print.js.map +1 -1
  125. package/dist/commands/status/status.js +3 -7
  126. package/dist/commands/status/status.js.map +1 -1
  127. package/dist/commands/steps/steps.js +3 -7
  128. package/dist/commands/steps/steps.js.map +1 -1
  129. package/dist/commands/subsystem/edit.js +7 -7
  130. package/dist/commands/subsystem/edit.js.map +1 -1
  131. package/dist/commands/subsystem/move.js +60 -25
  132. package/dist/commands/subsystem/move.js.map +1 -1
  133. package/dist/commands/subsystem/query.js +2 -4
  134. package/dist/commands/subsystem/query.js.map +1 -1
  135. package/dist/commands/subsystem/subsystem.js +4 -7
  136. package/dist/commands/subsystem/subsystem.js.map +1 -1
  137. package/dist/commands/subsystem/sync.js +141 -71
  138. package/dist/commands/subsystem/sync.js.map +1 -1
  139. package/dist/commands/subsystem/txn/report.js +55 -5
  140. package/dist/commands/subsystem/txn/report.js.map +1 -1
  141. package/dist/commands/subsystem/txn/txn.js +121 -45
  142. package/dist/commands/subsystem/txn/txn.js.map +1 -1
  143. package/dist/commands/subsystem/txn/views.js +82 -12
  144. package/dist/commands/subsystem/txn/views.js.map +1 -1
  145. package/dist/commands/tasks/render.js +116 -0
  146. package/dist/commands/tasks/render.js.map +1 -0
  147. package/dist/commands/tasks/tasks.js +113 -0
  148. package/dist/commands/tasks/tasks.js.map +1 -0
  149. package/dist/commands/unarchive/manifest.js +6 -9
  150. package/dist/commands/unarchive/manifest.js.map +1 -1
  151. package/dist/commands/unarchive/restore.js +17 -28
  152. package/dist/commands/unarchive/restore.js.map +1 -1
  153. package/dist/commands/unarchive/unarchive.js +22 -30
  154. package/dist/commands/unarchive/unarchive.js.map +1 -1
  155. package/dist/commands/validate/arch-coverage.js +6 -15
  156. package/dist/commands/validate/arch-coverage.js.map +1 -1
  157. package/dist/commands/validate/checks/fleet-shape.js +4 -49
  158. package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
  159. package/dist/commands/validate/checks/health-deps.js +9 -6
  160. package/dist/commands/validate/checks/health-deps.js.map +1 -1
  161. package/dist/commands/validate/checks/requirements.js +18 -8
  162. package/dist/commands/validate/checks/requirements.js.map +1 -1
  163. package/dist/commands/validate/checks/sources.js +6 -2
  164. package/dist/commands/validate/checks/sources.js.map +1 -1
  165. package/dist/commands/validate/feature.js +23 -19
  166. package/dist/commands/validate/feature.js.map +1 -1
  167. package/dist/commands/validate/fleet/census.js +26 -3
  168. package/dist/commands/validate/fleet/census.js.map +1 -1
  169. package/dist/commands/validate/fleet/landscape.js +35 -32
  170. package/dist/commands/validate/fleet/landscape.js.map +1 -1
  171. package/dist/commands/validate/fleet/map/attest.js +7 -12
  172. package/dist/commands/validate/fleet/map/attest.js.map +1 -1
  173. package/dist/commands/validate/fleet/map/bindings.js +16 -5
  174. package/dist/commands/validate/fleet/map/bindings.js.map +1 -1
  175. package/dist/commands/validate/fleet/map/consumers.js +43 -122
  176. package/dist/commands/validate/fleet/map/consumers.js.map +1 -1
  177. package/dist/commands/validate/fleet/map/usecases.js +5 -11
  178. package/dist/commands/validate/fleet/map/usecases.js.map +1 -1
  179. package/dist/commands/validate/fleet/obligations.js +1 -5
  180. package/dist/commands/validate/fleet/obligations.js.map +1 -1
  181. package/dist/commands/validate/fleet/scorecard/print.js +5 -1
  182. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
  183. package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
  184. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
  185. package/dist/commands/validate/fleet/usecases/usecases.js +6 -4
  186. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -1
  187. package/dist/commands/validate/fleet/views/fleet-project.js +1 -1
  188. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -1
  189. package/dist/commands/validate/fleet/views/ids.js +33 -7
  190. package/dist/commands/validate/fleet/views/ids.js.map +1 -1
  191. package/dist/commands/validate/fleet/views/root-documents.js +17 -35
  192. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -1
  193. package/dist/commands/validate/fleet/views/stale.js +31 -14
  194. package/dist/commands/validate/fleet/views/stale.js.map +1 -1
  195. package/dist/commands/validate/links/corpus.js +1 -4
  196. package/dist/commands/validate/links/corpus.js.map +1 -1
  197. package/dist/commands/validate/links/glossary.js.map +1 -1
  198. package/dist/commands/validate/report.js +5 -4
  199. package/dist/commands/validate/report.js.map +1 -1
  200. package/dist/commands/validate/scope.js +113 -0
  201. package/dist/commands/validate/scope.js.map +1 -0
  202. package/dist/commands/validate/service/api.js +16 -104
  203. package/dist/commands/validate/service/api.js.map +1 -1
  204. package/dist/commands/validate/service/contracts/generated.js +134 -0
  205. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  206. package/dist/commands/validate/service/events/events.js +1 -1
  207. package/dist/commands/validate/service/events/events.js.map +1 -1
  208. package/dist/commands/validate/service/events/message-producers.js +1 -1
  209. package/dist/commands/validate/service/events/message-producers.js.map +1 -1
  210. package/dist/commands/validate/service/evidence-pins.js +56 -10
  211. package/dist/commands/validate/service/evidence-pins.js.map +1 -1
  212. package/dist/commands/validate/service/service.js +16 -26
  213. package/dist/commands/validate/service/service.js.map +1 -1
  214. package/dist/commands/validate/service/specs.js +31 -38
  215. package/dist/commands/validate/service/specs.js.map +1 -1
  216. package/dist/commands/validate/service/spine.js +8 -11
  217. package/dist/commands/validate/service/spine.js.map +1 -1
  218. package/dist/commands/validate/service/usecases/usecases.js +3 -3
  219. package/dist/commands/validate/service/usecases/usecases.js.map +1 -1
  220. package/dist/commands/validate/validate.js +44 -26
  221. package/dist/commands/validate/validate.js.map +1 -1
  222. package/dist/commands/verify/cross/diff.js +2 -6
  223. package/dist/commands/verify/cross/diff.js.map +1 -1
  224. package/dist/commands/verify/evidence/contract.js +1 -1
  225. package/dist/commands/verify/evidence/contract.js.map +1 -1
  226. package/dist/commands/verify/evidence/read.js +12 -3
  227. package/dist/commands/verify/evidence/read.js.map +1 -1
  228. package/dist/commands/verify/frozen.js +45 -23
  229. package/dist/commands/verify/frozen.js.map +1 -1
  230. package/dist/commands/verify/record.js +69 -17
  231. package/dist/commands/verify/record.js.map +1 -1
  232. package/dist/commands/verify/report.js +27 -44
  233. package/dist/commands/verify/report.js.map +1 -1
  234. package/dist/commands/verify/results.js +112 -30
  235. package/dist/commands/verify/results.js.map +1 -1
  236. package/dist/commands/verify/verify.js +54 -51
  237. package/dist/commands/verify/verify.js.map +1 -1
  238. package/dist/commands/vouch/pack/pack.js +2 -2
  239. package/dist/commands/vouch/pack/pack.js.map +1 -1
  240. package/dist/commands/vouch/pack/print.js +1 -6
  241. package/dist/commands/vouch/pack/print.js.map +1 -1
  242. package/dist/commands/vouch/pack/sections.js +1 -2
  243. package/dist/commands/vouch/pack/sections.js.map +1 -1
  244. package/dist/commands/vouch/run.js +26 -81
  245. package/dist/commands/vouch/run.js.map +1 -1
  246. package/dist/commands/vouch/sample/plan.js +20 -34
  247. package/dist/commands/vouch/sample/plan.js.map +1 -1
  248. package/dist/commands/vouch/vet/verify.js +39 -7
  249. package/dist/commands/vouch/vet/verify.js.map +1 -1
  250. package/dist/commands/vouch/vouch.js +10 -17
  251. package/dist/commands/vouch/vouch.js.map +1 -1
  252. package/dist/core/agent/agents-md/command-map.js +57 -102
  253. package/dist/core/agent/agents-md/command-map.js.map +1 -1
  254. package/dist/core/agent/agents-md/map/explain.js +4 -3
  255. package/dist/core/agent/agents-md/map/explain.js.map +1 -1
  256. package/dist/core/agent/agents-md/map/lenses/context.js +4 -3
  257. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
  258. package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
  259. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
  260. package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
  261. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
  262. package/dist/core/agent/agents-md/map/mcp.js +10 -7
  263. package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
  264. package/dist/core/agent/agents-md/map/status.js +9 -3
  265. package/dist/core/agent/agents-md/map/status.js.map +1 -1
  266. package/dist/core/agent/agents-md/map/subsystem.js +31 -17
  267. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
  268. package/dist/core/agent/agents-md/map/usecases.js +24 -6
  269. package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
  270. package/dist/core/agent/agents-md/refusals.js +37 -21
  271. package/dist/core/agent/agents-md/refusals.js.map +1 -1
  272. package/dist/core/agent/agents-md.js +25 -10
  273. package/dist/core/agent/agents-md.js.map +1 -1
  274. package/dist/core/agent/agents-stamp.js +10 -0
  275. package/dist/core/agent/agents-stamp.js.map +1 -1
  276. package/dist/core/agent/scaffold.js +10 -15
  277. package/dist/core/agent/scaffold.js.map +1 -1
  278. package/dist/core/agent/tools/dialects.js +1 -0
  279. package/dist/core/agent/tools/dialects.js.map +1 -1
  280. package/dist/core/agent/tools/registry.js +41 -76
  281. package/dist/core/agent/tools/registry.js.map +1 -1
  282. package/dist/core/agent/workflows/adopt.js +5 -3
  283. package/dist/core/agent/workflows/adopt.js.map +1 -1
  284. package/dist/core/agent/workflows/check.js +25 -22
  285. package/dist/core/agent/workflows/check.js.map +1 -1
  286. package/dist/core/agent/workflows/closing.js +54 -21
  287. package/dist/core/agent/workflows/closing.js.map +1 -1
  288. package/dist/core/agent/workflows/feature.js +79 -11
  289. package/dist/core/agent/workflows/feature.js.map +1 -1
  290. package/dist/core/agent/workflows/implement.js +91 -13
  291. package/dist/core/agent/workflows/implement.js.map +1 -1
  292. package/dist/core/agent/workflows/reference/authoring.js +3 -1
  293. package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
  294. package/dist/core/agent/workflows/reference/codes.js +8 -6
  295. package/dist/core/agent/workflows/reference/codes.js.map +1 -1
  296. package/dist/core/agent/workflows/reference/done-check.js +37 -15
  297. package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
  298. package/dist/core/agent/workflows/reference/reference.js.map +1 -1
  299. package/dist/core/agent/workflows/reference/spine.js +62 -24
  300. package/dist/core/agent/workflows/reference/spine.js.map +1 -1
  301. package/dist/core/asyncapi/baseline/plan.js +14 -81
  302. package/dist/core/asyncapi/baseline/plan.js.map +1 -1
  303. package/dist/core/asyncapi/digest.js +30 -25
  304. package/dist/core/asyncapi/digest.js.map +1 -1
  305. package/dist/core/asyncapi/merge/components.js +5 -4
  306. package/dist/core/asyncapi/merge/components.js.map +1 -1
  307. package/dist/core/asyncapi/merge/error.js +7 -2
  308. package/dist/core/asyncapi/merge/error.js.map +1 -1
  309. package/dist/core/asyncapi/merge/markers.js +30 -50
  310. package/dist/core/asyncapi/merge/markers.js.map +1 -1
  311. package/dist/core/asyncapi/merge/merge.js +31 -53
  312. package/dist/core/asyncapi/merge/merge.js.map +1 -1
  313. package/dist/core/asyncapi/merge/pin.js +10 -36
  314. package/dist/core/asyncapi/merge/pin.js.map +1 -1
  315. package/dist/core/asyncapi/model.js.map +1 -1
  316. package/dist/core/asyncapi/read.js +36 -12
  317. package/dist/core/asyncapi/read.js.map +1 -1
  318. package/dist/core/brief/brief.js +30 -25
  319. package/dist/core/brief/brief.js.map +1 -1
  320. package/dist/core/brief/landscape.js +8 -12
  321. package/dist/core/brief/landscape.js.map +1 -1
  322. package/dist/core/brief/map/extend.js +8 -5
  323. package/dist/core/brief/map/extend.js.map +1 -1
  324. package/dist/core/brief/map/owed.js +8 -26
  325. package/dist/core/brief/map/owed.js.map +1 -1
  326. package/dist/core/brief/targets.js +79 -5
  327. package/dist/core/brief/targets.js.map +1 -1
  328. package/dist/core/brief/unchecked.js +1 -1
  329. package/dist/core/brief/unchecked.js.map +1 -1
  330. package/dist/core/c4/likec4.js +147 -16
  331. package/dist/core/c4/likec4.js.map +1 -1
  332. package/dist/core/c4/locate/unlocated.js +150 -0
  333. package/dist/core/c4/locate/unlocated.js.map +1 -0
  334. package/dist/core/c4/parsed/values.js +54 -1
  335. package/dist/core/c4/parsed/values.js.map +1 -1
  336. package/dist/core/c4/prefetch/fleet.js +1 -9
  337. package/dist/core/c4/prefetch/fleet.js.map +1 -1
  338. package/dist/core/c4/project/architecture.js +31 -9
  339. package/dist/core/c4/project/architecture.js.map +1 -1
  340. package/dist/core/c4/project/documents.js +36 -10
  341. package/dist/core/c4/project/documents.js.map +1 -1
  342. package/dist/core/c4/project/load.js +14 -21
  343. package/dist/core/c4/project/load.js.map +1 -1
  344. package/dist/core/c4/project/staged.js +7 -3
  345. package/dist/core/c4/project/staged.js.map +1 -1
  346. package/dist/core/c4/resolve/external.js +51 -0
  347. package/dist/core/c4/resolve/external.js.map +1 -0
  348. package/dist/core/c4/resolve/service.js +25 -1
  349. package/dist/core/c4/resolve/service.js.map +1 -1
  350. package/dist/core/c4/seed/template.js +15 -1
  351. package/dist/core/c4/seed/template.js.map +1 -1
  352. package/dist/core/c4/service-model/shape.js +2 -22
  353. package/dist/core/c4/service-model/shape.js.map +1 -1
  354. package/dist/core/c4/source-mask.js +288 -4
  355. package/dist/core/c4/source-mask.js.map +1 -1
  356. package/dist/core/c4/source-scan.js +203 -147
  357. package/dist/core/c4/source-scan.js.map +1 -1
  358. package/dist/core/c4/splice/authored-source.js +19 -0
  359. package/dist/core/c4/splice/authored-source.js.map +1 -1
  360. package/dist/core/c4/splice/delta-blocks.js +5 -18
  361. package/dist/core/c4/splice/delta-blocks.js.map +1 -1
  362. package/dist/core/c4/splice/landscape-merge.js +13 -8
  363. package/dist/core/c4/splice/landscape-merge.js.map +1 -1
  364. package/dist/core/c4/splice/model/merge.js +10 -6
  365. package/dist/core/c4/splice/model/merge.js.map +1 -1
  366. package/dist/core/c4/splice/placement.js +108 -18
  367. package/dist/core/c4/splice/placement.js.map +1 -1
  368. package/dist/core/c4/workspace.js +13 -22
  369. package/dist/core/c4/workspace.js.map +1 -1
  370. package/dist/core/capabilities/capabilities.js +6 -6
  371. package/dist/core/capabilities/capabilities.js.map +1 -1
  372. package/dist/core/capabilities/delta/doc.js +7 -10
  373. package/dist/core/capabilities/delta/doc.js.map +1 -1
  374. package/dist/core/capabilities/findings.js +15 -20
  375. package/dist/core/capabilities/findings.js.map +1 -1
  376. package/dist/core/capabilities/realizes/findings.js +12 -19
  377. package/dist/core/capabilities/realizes/findings.js.map +1 -1
  378. package/dist/core/capabilities/realizes/join.js +0 -20
  379. package/dist/core/capabilities/realizes/join.js.map +1 -1
  380. package/dist/core/capabilities/rollup.js +6 -0
  381. package/dist/core/capabilities/rollup.js.map +1 -1
  382. package/dist/core/capabilities/tree.js +6 -28
  383. package/dist/core/capabilities/tree.js.map +1 -1
  384. package/dist/core/capabilities/usecase-join.js +3 -13
  385. package/dist/core/capabilities/usecase-join.js.map +1 -1
  386. package/dist/core/coherence/authoring/scaffold.js +11 -3
  387. package/dist/core/coherence/authoring/scaffold.js.map +1 -1
  388. package/dist/core/coherence/authoring/sentinels.js +2 -1
  389. package/dist/core/coherence/authoring/sentinels.js.map +1 -1
  390. package/dist/core/coherence/coherence.js +30 -16
  391. package/dist/core/coherence/coherence.js.map +1 -1
  392. package/dist/core/coherence/consumed/operations.js +70 -0
  393. package/dist/core/coherence/consumed/operations.js.map +1 -0
  394. package/dist/core/coherence/consumed/refusal.js +38 -0
  395. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  396. package/dist/core/coherence/declared.js +60 -34
  397. package/dist/core/coherence/declared.js.map +1 -1
  398. package/dist/core/coherence/events/declared.js +44 -59
  399. package/dist/core/coherence/events/declared.js.map +1 -1
  400. package/dist/core/coherence/events/events.js +119 -8
  401. package/dist/core/coherence/events/events.js.map +1 -1
  402. package/dist/core/coherence/events/grades.js +31 -8
  403. package/dist/core/coherence/events/grades.js.map +1 -1
  404. package/dist/core/coherence/events/lookups.js +14 -82
  405. package/dist/core/coherence/events/lookups.js.map +1 -1
  406. package/dist/core/coherence/lookups.js +18 -78
  407. package/dist/core/coherence/lookups.js.map +1 -1
  408. package/dist/core/coherence/retired/archived.js +285 -0
  409. package/dist/core/coherence/retired/archived.js.map +1 -0
  410. package/dist/core/coherence/retired/event-pair.js +62 -0
  411. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  412. package/dist/core/coherence/retired/merged.js +79 -0
  413. package/dist/core/coherence/retired/merged.js.map +1 -0
  414. package/dist/core/coherence/retired/retirement.js +49 -0
  415. package/dist/core/coherence/retired/retirement.js.map +1 -0
  416. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  417. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  418. package/dist/core/coherence/retired/revival/revived.js +297 -0
  419. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  420. package/dist/core/consumers/after.js +113 -0
  421. package/dist/core/consumers/after.js.map +1 -0
  422. package/dist/core/consumers/consumers.js +296 -0
  423. package/dist/core/consumers/consumers.js.map +1 -0
  424. package/dist/core/consumers/current.js +211 -0
  425. package/dist/core/consumers/current.js.map +1 -0
  426. package/dist/core/consumers/scan.js +46 -0
  427. package/dist/core/consumers/scan.js.map +1 -0
  428. package/dist/core/consumers/state.js +27 -0
  429. package/dist/core/consumers/state.js.map +1 -0
  430. package/dist/core/delta/delta.js +1 -1
  431. package/dist/core/delta/delta.js.map +1 -1
  432. package/dist/core/deployment/delta.js +15 -16
  433. package/dist/core/deployment/delta.js.map +1 -1
  434. package/dist/core/diff/base-git.js +94 -12
  435. package/dist/core/diff/base-git.js.map +1 -1
  436. package/dist/core/diff/base-state.js +28 -16
  437. package/dist/core/diff/base-state.js.map +1 -1
  438. package/dist/core/diff/joins.js +136 -0
  439. package/dist/core/diff/joins.js.map +1 -0
  440. package/dist/core/diff/scope/changed-paths.js +22 -6
  441. package/dist/core/diff/scope/changed-paths.js.map +1 -1
  442. package/dist/core/diff/scope/edges.js +82 -0
  443. package/dist/core/diff/scope/edges.js.map +1 -0
  444. package/dist/core/diff/semantic.js +100 -31
  445. package/dist/core/diff/semantic.js.map +1 -1
  446. package/dist/core/doctor/agents.js +34 -18
  447. package/dist/core/doctor/agents.js.map +1 -1
  448. package/dist/core/doctor/report.js.map +1 -1
  449. package/dist/core/document/apply.js +10 -2
  450. package/dist/core/document/apply.js.map +1 -1
  451. package/dist/core/document/frontmatter.js +55 -0
  452. package/dist/core/document/frontmatter.js.map +1 -1
  453. package/dist/core/document/parse.js +29 -6
  454. package/dist/core/document/parse.js.map +1 -1
  455. package/dist/core/document/scenarios.js +17 -0
  456. package/dist/core/document/scenarios.js.map +1 -1
  457. package/dist/core/document/spec.js +4 -11
  458. package/dist/core/document/spec.js.map +1 -1
  459. package/dist/core/envelope/config.js +10 -0
  460. package/dist/core/envelope/config.js.map +1 -1
  461. package/dist/core/envelope/json.js +34 -0
  462. package/dist/core/envelope/json.js.map +1 -1
  463. package/dist/core/explain/families.js +17 -12
  464. package/dist/core/explain/families.js.map +1 -1
  465. package/dist/core/explain/refusals.js +3 -3
  466. package/dist/core/explain/refusals.js.map +1 -1
  467. package/dist/core/explain/terms.js +18 -9
  468. package/dist/core/explain/terms.js.map +1 -1
  469. package/dist/core/explore/explore.js +2 -7
  470. package/dist/core/explore/explore.js.map +1 -1
  471. package/dist/core/fleet-context.js +34 -95
  472. package/dist/core/fleet-context.js.map +1 -1
  473. package/dist/core/gate/checks.js +10 -3
  474. package/dist/core/gate/checks.js.map +1 -1
  475. package/dist/core/gate/partners.js +64 -19
  476. package/dist/core/gate/partners.js.map +1 -1
  477. package/dist/core/gate/report.js.map +1 -1
  478. package/dist/core/gate/verification.js +75 -12
  479. package/dist/core/gate/verification.js.map +1 -1
  480. package/dist/core/gherkin/stale.js +13 -37
  481. package/dist/core/gherkin/stale.js.map +1 -1
  482. package/dist/core/glossary/tree.js +6 -19
  483. package/dist/core/glossary/tree.js.map +1 -1
  484. package/dist/core/kernel/concurrency.js +19 -0
  485. package/dist/core/kernel/concurrency.js.map +1 -1
  486. package/dist/core/kernel/records.js +11 -0
  487. package/dist/core/kernel/records.js.map +1 -1
  488. package/dist/core/links/backlinks.js +1 -3
  489. package/dist/core/links/backlinks.js.map +1 -1
  490. package/dist/core/links/corpus.js +5 -36
  491. package/dist/core/links/corpus.js.map +1 -1
  492. package/dist/core/mcp/argv.js +101 -0
  493. package/dist/core/mcp/argv.js.map +1 -1
  494. package/dist/core/mcp/author-tools.js +2 -1
  495. package/dist/core/mcp/author-tools.js.map +1 -1
  496. package/dist/core/mcp/protocol.js +2 -2
  497. package/dist/core/mcp/protocol.js.map +1 -1
  498. package/dist/core/mcp/tools.js +43 -33
  499. package/dist/core/mcp/tools.js.map +1 -1
  500. package/dist/core/openapi/baseline/gate.js +53 -12
  501. package/dist/core/openapi/baseline/gate.js.map +1 -1
  502. package/dist/core/openapi/baseline/plan.js +22 -8
  503. package/dist/core/openapi/baseline/plan.js.map +1 -1
  504. package/dist/core/openapi/baseline/record.js +0 -1
  505. package/dist/core/openapi/baseline/record.js.map +1 -1
  506. package/dist/core/openapi/contract-text.js +33 -0
  507. package/dist/core/openapi/contract-text.js.map +1 -0
  508. package/dist/core/openapi/contract-tree.js +56 -0
  509. package/dist/core/openapi/contract-tree.js.map +1 -0
  510. package/dist/core/openapi/depth.js +38 -24
  511. package/dist/core/openapi/depth.js.map +1 -1
  512. package/dist/core/openapi/digest.js +52 -2
  513. package/dist/core/openapi/digest.js.map +1 -1
  514. package/dist/core/openapi/doc.js +12 -4
  515. package/dist/core/openapi/doc.js.map +1 -1
  516. package/dist/core/openapi/merge/components.js +25 -60
  517. package/dist/core/openapi/merge/components.js.map +1 -1
  518. package/dist/core/openapi/merge/error.js +3 -13
  519. package/dist/core/openapi/merge/error.js.map +1 -1
  520. package/dist/core/openapi/merge/markers.js +26 -30
  521. package/dist/core/openapi/merge/markers.js.map +1 -1
  522. package/dist/core/openapi/merge/merge.js +26 -52
  523. package/dist/core/openapi/merge/merge.js.map +1 -1
  524. package/dist/core/openapi/merge/pin.js +15 -35
  525. package/dist/core/openapi/merge/pin.js.map +1 -1
  526. package/dist/core/openspec/decide/verdict.js.map +1 -1
  527. package/dist/core/openspec/inventory.js +4 -5
  528. package/dist/core/openspec/inventory.js.map +1 -1
  529. package/dist/core/openspec/model/mapping.js +30 -28
  530. package/dist/core/openspec/model/mapping.js.map +1 -1
  531. package/dist/core/openspec/model/model.js +12 -7
  532. package/dist/core/openspec/model/model.js.map +1 -1
  533. package/dist/core/openspec/scan/changes.js +10 -4
  534. package/dist/core/openspec/scan/changes.js.map +1 -1
  535. package/dist/core/openspec/scan/config.js +7 -16
  536. package/dist/core/openspec/scan/config.js.map +1 -1
  537. package/dist/core/openspec/scan/shape.js +63 -19
  538. package/dist/core/openspec/scan/shape.js.map +1 -1
  539. package/dist/core/openspec/scan/walk.js +21 -38
  540. package/dist/core/openspec/scan/walk.js.map +1 -1
  541. package/dist/core/pack/living.js +2 -16
  542. package/dist/core/pack/living.js.map +1 -1
  543. package/dist/core/provenance/findings.js +48 -12
  544. package/dist/core/provenance/findings.js.map +1 -1
  545. package/dist/core/provenance/git.js +33 -57
  546. package/dist/core/provenance/git.js.map +1 -1
  547. package/dist/core/provenance/gitq/moves.js +71 -114
  548. package/dist/core/provenance/gitq/moves.js.map +1 -1
  549. package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
  550. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
  551. package/dist/core/provenance/sources.js +23 -6
  552. package/dist/core/provenance/sources.js.map +1 -1
  553. package/dist/core/provenance/stamp.js +5 -17
  554. package/dist/core/provenance/stamp.js.map +1 -1
  555. package/dist/core/repo/entries.js.map +1 -1
  556. package/dist/core/repo/paths.js +34 -29
  557. package/dist/core/repo/paths.js.map +1 -1
  558. package/dist/core/repo/repo.js +24 -14
  559. package/dist/core/repo/repo.js.map +1 -1
  560. package/dist/core/repo/tree/find.js +12 -3
  561. package/dist/core/repo/tree/find.js.map +1 -1
  562. package/dist/core/repo/tree/fs.js +27 -1
  563. package/dist/core/repo/tree/fs.js.map +1 -1
  564. package/dist/core/repo/tree/render/body.js +45 -6
  565. package/dist/core/repo/tree/render/body.js.map +1 -1
  566. package/dist/core/repo/tree/render/service/header.js +125 -0
  567. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  568. package/dist/core/repo/tree/render/service/peers.js +28 -0
  569. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  570. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  571. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  572. package/dist/core/repo/tree/render/service/views.js +78 -0
  573. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  574. package/dist/core/repo/tree/render/stale.js +19 -2
  575. package/dist/core/repo/tree/render/stale.js.map +1 -1
  576. package/dist/core/repo/tree/render/views.js +102 -33
  577. package/dist/core/repo/tree/render/views.js.map +1 -1
  578. package/dist/core/repo/tree/walk.js +8 -30
  579. package/dist/core/repo/tree/walk.js.map +1 -1
  580. package/dist/core/results.js +47 -12
  581. package/dist/core/results.js.map +1 -1
  582. package/dist/core/staging/commit.js +10 -12
  583. package/dist/core/staging/commit.js.map +1 -1
  584. package/dist/core/staging/lock.js +74 -12
  585. package/dist/core/staging/lock.js.map +1 -1
  586. package/dist/core/staging/recovery/intent.js +2 -5
  587. package/dist/core/staging/recovery/intent.js.map +1 -1
  588. package/dist/core/staging/recovery/recover.js +60 -1
  589. package/dist/core/staging/recovery/recover.js.map +1 -1
  590. package/dist/core/staging/snapshot/manifest.js +152 -0
  591. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  592. package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +10 -34
  593. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  594. package/dist/core/status/actions/execution.js +11 -0
  595. package/dist/core/status/actions/execution.js.map +1 -1
  596. package/dist/core/status/feature/artifacts.js +2 -2
  597. package/dist/core/status/feature/artifacts.js.map +1 -1
  598. package/dist/core/status/feature/feature.js +5 -11
  599. package/dist/core/status/feature/feature.js.map +1 -1
  600. package/dist/core/status/fleet/fleet.js +6 -2
  601. package/dist/core/status/fleet/fleet.js.map +1 -1
  602. package/dist/core/status/fleet/next.js +26 -3
  603. package/dist/core/status/fleet/next.js.map +1 -1
  604. package/dist/core/status/report.js.map +1 -1
  605. package/dist/core/status/verification.js +30 -15
  606. package/dist/core/status/verification.js.map +1 -1
  607. package/dist/core/tasks/packet.js +174 -0
  608. package/dist/core/tasks/packet.js.map +1 -0
  609. package/dist/core/tasks/record.js +43 -0
  610. package/dist/core/tasks/record.js.map +1 -0
  611. package/dist/core/tasks/sources.js +181 -0
  612. package/dist/core/tasks/sources.js.map +1 -0
  613. package/dist/core/tasks/stamps.js +76 -0
  614. package/dist/core/tasks/stamps.js.map +1 -0
  615. package/dist/core/tasks/unit.js +0 -0
  616. package/dist/core/tasks/unit.js.map +1 -0
  617. package/dist/core/usecases/capability.js +11 -14
  618. package/dist/core/usecases/capability.js.map +1 -1
  619. package/dist/core/usecases/delta/flows.js +5 -7
  620. package/dist/core/usecases/delta/flows.js.map +1 -1
  621. package/dist/core/usecases/fleet.js +178 -31
  622. package/dist/core/usecases/fleet.js.map +1 -1
  623. package/dist/core/usecases/operations.js +5 -4
  624. package/dist/core/usecases/operations.js.map +1 -1
  625. package/dist/core/usecases/service/flows.js +9 -6
  626. package/dist/core/usecases/service/flows.js.map +1 -1
  627. package/dist/core/usecases/suites/participants.js +83 -0
  628. package/dist/core/usecases/suites/participants.js.map +1 -0
  629. package/dist/core/usecases/suites/suites.js +45 -0
  630. package/dist/core/usecases/suites/suites.js.map +1 -0
  631. package/dist/core/verify/answers.js +12 -5
  632. package/dist/core/verify/answers.js.map +1 -1
  633. package/dist/core/verify/build.js +102 -82
  634. package/dist/core/verify/build.js.map +1 -1
  635. package/dist/core/verify/checklist.js +45 -10
  636. package/dist/core/verify/checklist.js.map +1 -1
  637. package/dist/core/verify/location.js +67 -0
  638. package/dist/core/verify/location.js.map +1 -0
  639. package/dist/core/verify/pins/lint.js +3 -2
  640. package/dist/core/verify/pins/lint.js.map +1 -1
  641. package/dist/core/verify/pins/pin.js +1 -1
  642. package/dist/core/verify/pins/pin.js.map +1 -1
  643. package/dist/core/verify/read/file.js +224 -0
  644. package/dist/core/verify/read/file.js.map +1 -0
  645. package/dist/core/verify/{file.js → read/shape.js} +16 -104
  646. package/dist/core/verify/read/shape.js.map +1 -0
  647. package/dist/core/verify/read/union.js +105 -0
  648. package/dist/core/verify/read/union.js.map +1 -0
  649. package/dist/core/verify/record.js +35 -12
  650. package/dist/core/verify/record.js.map +1 -1
  651. package/dist/core/verify/store/commit.js +40 -30
  652. package/dist/core/verify/store/commit.js.map +1 -1
  653. package/dist/core/verify/store/render.js +8 -4
  654. package/dist/core/verify/store/render.js.map +1 -1
  655. package/dist/core/vocabulary/issue.js +1 -0
  656. package/dist/core/vocabulary/issue.js.map +1 -1
  657. package/dist/core/vocabulary/maturity.js +53 -3
  658. package/dist/core/vocabulary/maturity.js.map +1 -1
  659. package/examples/README.md +28 -9
  660. package/examples/docs/architecture/landscape.likec4 +21 -7
  661. package/examples/docs/architecture/services.likec4 +70 -0
  662. package/examples/docs/architecture/subsystems.likec4 +3 -0
  663. package/examples/docs/architecture/usecases/order-notification.likec4 +6 -2
  664. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
  665. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
  666. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
  667. package/examples/docs/services/order-service/asyncapi.yaml +3 -2
  668. package/examples/docs/services/order-service/model.likec4 +10 -8
  669. package/examples/docs/services/payment-service/model.likec4 +6 -4
  670. package/examples/docs/services/platform/identity-service/model.likec4 +9 -7
  671. package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
  672. package/examples/docs/services/platform/notification-service/model.likec4 +4 -5
  673. package/package.json +1 -1
  674. package/dist/commands/validate/checks/vocabulary.js +0 -16
  675. package/dist/commands/validate/checks/vocabulary.js.map +0 -1
  676. package/dist/core/agent/agents-md/artifacts.js +0 -221
  677. package/dist/core/agent/agents-md/artifacts.js.map +0 -1
  678. package/dist/core/agent/agents-md/cycle.js +0 -180
  679. package/dist/core/agent/agents-md/cycle.js.map +0 -1
  680. package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
  681. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
  682. package/dist/core/agent/agents-md/spine.js +0 -40
  683. package/dist/core/agent/agents-md/spine.js.map +0 -1
  684. package/dist/core/coherence/events/merged.js +0 -40
  685. package/dist/core/coherence/events/merged.js.map +0 -1
  686. package/dist/core/diff/current-state.js +0 -96
  687. package/dist/core/diff/current-state.js.map +0 -1
  688. package/dist/core/diff/victims.js +0 -256
  689. package/dist/core/diff/victims.js.map +0 -1
  690. package/dist/core/staging/snapshot.js.map +0 -1
  691. package/dist/core/verify/file.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"authored-source.js","sourceRoot":"","sources":["../../../../src/core/c4/splice/authored-source.ts"],"names":[],"mappings":"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","sourcesContent":["import { maskSource, matchBrace } from \"../source-mask.js\";\n\n/** A half-open byte range of `deltaText`, as the source scan reports one. */\nexport interface SourceRange {\n start: number;\n end: number;\n}\n\n/**\n * A declaration's authored source, ready to land in the living landscape:\n * byte-verbatim except that the feature's own tag is stripped and the\n * indentation is rebased from where the block sat in the delta to where it\n * lands. A construct the strip leaves empty goes too — a line that held only\n * the tag disappears whole, and `x = kind 'y' { #FEAT-1 }` lands as\n * `x = kind 'y'`, not as a pair of empty braces.\n *\n * `omit` cuts named ranges of the delta out on the way over, and it exists for\n * one caller: a NEW service element whose interior belongs to that service's\n * extending model. The children come along in the parent's bytes — they carry no\n * feature tag of their own, because LikeC4 does not inherit tags, so nothing in\n * the addition set can see them — and the map must take the box without them or\n * the model can never declare them (verification 2026-09-04, refutation of E1).\n * The ranges join the tag's removals, so a body they empty collapses the same\n * way `#FEAT-1`-only braces do.\n */\n/** How a declaration is carried over: whose tag to drop, where it lands, and what to leave behind. */\nexport interface Carry {\n featureId: string;\n /** The indent of the position the block lands at. */\n indent: string;\n /** Delta ranges cut out on the way over — see the banner; `[]` when nothing rides separately. */\n omit?: readonly SourceRange[];\n}\n\nexport function spliceSource(\n deltaText: string,\n decl: { start: number; end: number; indent: string },\n carry: Carry,\n): string {\n const { featureId, indent: targetIndent, omit = [] } = carry;\n const block = deltaText.slice(decl.start, decl.end);\n const cuts = omit\n .filter((r) => r.start >= decl.start && r.end <= decl.end)\n .map((r) => wholeLines(block, r.start - decl.start, r.end - decl.start));\n return reindent(stripFeatureTag(block, featureId, cuts), decl.indent, targetIndent);\n}\n\n/**\n * Widen a cut to the whole lines it sits on, when it has them to itself.\n *\n * A scanned declaration's span starts at its first character and ends one past\n * its last brace, so cutting it verbatim would leave the leading indent and the\n * trailing newline behind as a blank line — and the emptied-line rule below only\n * fires on a removal a line contains. A cut sharing its line with other code is\n * left exactly as asked.\n */\nfunction wholeLines(block: string, start: number, end: number): [number, number] {\n const lineStart = block.lastIndexOf(\"\\n\", start - 1) + 1;\n if (!/^[ \\t]*$/.test(block.slice(lineStart, start))) return [start, end];\n const nl = block.indexOf(\"\\n\", end);\n const to = nl === -1 ? block.length : nl;\n if (!/^[ \\t\\r]*$/.test(block.slice(end, to))) return [start, end];\n return [lineStart, nl === -1 ? block.length : nl + 1];\n}\n\n/**\n * Rewrite the line endings a merge INSERTED to the ones the document already\n * uses.\n *\n * Splicing composes bytes from two files, and the delta's newlines are not\n * necessarily the living document's: on a repository without `core.autocrlf`\n * normalisation a CRLF landscape or model came back with a handful of bare-LF\n * lines in the spliced region — two conventions in one file, noisy in an editor\n * and in every diff (verification 2026-09-04, W-CRLF). One helper for both\n * merges, because both had it.\n *\n * Only a document with ONE convention is corrected, and then in whichever\n * direction it uses: a file that is already mixed has no convention to match, and\n * guessing one would rewrite lines nobody touched.\n */\nexport function matchLineEndings(document: string, merged: string): string {\n const crlf = (document.match(/\\r\\n/g) ?? []).length;\n const bare = (document.match(/(?<!\\r)\\n/g) ?? []).length;\n if (crlf > 0 && bare === 0) return merged.replace(/(?<!\\r)\\n/g, \"\\r\\n\");\n if (bare > 0 && crlf === 0) return merged.replace(/\\r\\n/g, \"\\n\");\n return merged;\n}\n\nfunction stripFeatureTag(block: string, featureId: string, cuts: ReadonlyArray<[number, number]>): string {\n const { code } = maskSource(block);\n const esc = featureId.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const removals: Array<[number, number]> = cuts.map(([s, e]) => [s, e]);\n for (const m of block.matchAll(new RegExp(`#${esc}(?![\\\\w-])`, \"g\"))) {\n // Only tags in CODE count — a description quoting \"#FEAT-1\" is content.\n if (code.slice(m.index, m.index + m[0].length) !== m[0]) continue;\n let s = m.index;\n let e = s + m[0].length;\n // Take the whitespace on ONE side with the token — trailing first, so\n // `#FEAT-1 #critical` leaves `#critical` at its own indent, and a token at\n // the end of a line does not leave a trailing space behind.\n if (block[e] === \" \" || block[e] === \"\\t\") {\n while (block[e] === \" \" || block[e] === \"\\t\") e += 1;\n } else {\n while (s > 0 && (block[s - 1] === \" \" || block[s - 1] === \"\\t\")) s -= 1;\n }\n removals.push([s, e]);\n }\n if (removals.length === 0) return block;\n\n // A line the strip emptied disappears whole, newline included.\n for (let lineStart = 0; lineStart < block.length; ) {\n const nl = block.indexOf(\"\\n\", lineStart);\n const lineEnd = nl === -1 ? block.length : nl + 1;\n if (\n removals.some(([s, e]) => s >= lineStart && e <= lineEnd) &&\n /^\\s*$/.test(residual(block, lineStart, nl === -1 ? block.length : nl, removals))\n ) {\n removals.push([lineStart, lineEnd]);\n }\n lineStart = lineEnd;\n }\n\n // A body the strip emptied goes too, braces and all — but only one the strip\n // emptied: braces that were authored empty are authored bytes and survive.\n for (let at = code.indexOf(\"{\"); at !== -1; at = code.indexOf(\"{\", at + 1)) {\n const closeAt = matchBrace(code, at);\n if (closeAt === -1) continue;\n if (!removals.some(([s, e]) => s > at && e <= closeAt)) continue;\n if (!/^\\s*$/.test(residual(block, at + 1, closeAt, removals))) continue;\n let s = at;\n while (s > 0 && /\\s/.test(block[s - 1]!)) s -= 1;\n removals.push([s, closeAt + 1]);\n }\n return applyRemovals(block, removals);\n}\n\n/** The text of [from, to) with the removal ranges cut out. */\nfunction residual(text: string, from: number, to: number, removals: Array<[number, number]>): string {\n let out = \"\";\n for (let i = from; i < to; i += 1) {\n if (!removals.some(([s, e]) => i >= s && i < e)) out += text[i];\n }\n return out;\n}\n\nfunction applyRemovals(text: string, removals: Array<[number, number]>): string {\n const sorted = [...removals].sort((a, b) => a[0] - b[0] || b[1] - a[1]);\n let out = \"\";\n let i = 0;\n for (const [s, e] of sorted) {\n if (s > i) out += text.slice(i, s);\n if (e > i) i = e;\n }\n return out + text.slice(i);\n}\n\n/**\n * Rebase a block's indentation: the `base` its lines carried in the delta\n * becomes `target`. The first line arrives with no leading whitespace (the\n * scanner's span starts at the declaration itself), so it only gains `target`.\n *\n * A CRLF delta's blank line is `\"\\r\"`, not `\"\"`, so splitting on `\\n` alone used\n * to hand a non-empty body to the rule below and every blank line inside a\n * spliced block came out carrying the target indent as trailing whitespace. The\n * carriage return is set aside and put back, which leaves the line's own ending\n * exactly as authored for `matchLineEndings` to reconcile.\n */\nfunction reindent(block: string, base: string, target: string): string {\n return block\n .split(\"\\n\")\n .map((line, k) => {\n const cr = line.endsWith(\"\\r\");\n const raw = cr ? line.slice(0, -1) : line;\n const body = k === 0 ? raw : raw.startsWith(base) ? raw.slice(base.length) : raw;\n return (body.length === 0 ? \"\" : target + body) + (cr ? \"\\r\" : \"\");\n })\n .join(\"\\n\");\n}\n"]}
1
+ {"version":3,"file":"authored-source.js","sourceRoot":"","sources":["../../../../src/core/c4/splice/authored-source.ts"],"names":[],"mappings":"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","sourcesContent":["import { maskSource, matchBrace } from \"../source-mask.js\";\n\n/** A half-open byte range of `deltaText`, as the source scan reports one. */\nexport interface SourceRange {\n start: number;\n end: number;\n}\n\n/**\n * A declaration's authored source, ready to land in the living landscape:\n * byte-verbatim except that the feature's own tag is stripped (with the `,` or\n * `;` that set it apart in a tag list, which would otherwise be left stray) and\n * the indentation is rebased from where the block sat in the delta to where it\n * lands. A construct the strip leaves empty goes too — a line that held only\n * the tag disappears whole, and `x = kind 'y' { #FEAT-1 }` lands as\n * `x = kind 'y'`, not as a pair of empty braces.\n *\n * `omit` cuts named ranges of the delta out on the way over, and it exists for\n * one caller: a NEW service element whose interior belongs to that service's\n * extending model. The children come along in the parent's bytes — they carry no\n * feature tag of their own, because LikeC4 does not inherit tags, so nothing in\n * the addition set can see them — and the map must take the box without them or\n * the model can never declare them (verification 2026-09-04, refutation of E1).\n * The ranges join the tag's removals, so a body they empty collapses the same\n * way `#FEAT-1`-only braces do.\n */\n/** How a declaration is carried over: whose tag to drop, where it lands, and what to leave behind. */\nexport interface Carry {\n featureId: string;\n /** The indent of the position the block lands at. */\n indent: string;\n /** Delta ranges cut out on the way over — see the banner; `[]` when nothing rides separately. */\n omit?: readonly SourceRange[];\n}\n\nexport function spliceSource(\n deltaText: string,\n decl: { start: number; end: number; indent: string },\n carry: Carry,\n): string {\n const { featureId, indent: targetIndent, omit = [] } = carry;\n const block = deltaText.slice(decl.start, decl.end);\n const cuts = omit\n .filter((r) => r.start >= decl.start && r.end <= decl.end)\n .map((r) => wholeLines(block, r.start - decl.start, r.end - decl.start));\n return reindent(stripFeatureTag(block, featureId, cuts), decl.indent, targetIndent);\n}\n\n/**\n * Widen a cut to the whole lines it sits on, when it has them to itself.\n *\n * A scanned declaration's span starts at its first character and ends one past\n * its last brace, so cutting it verbatim would leave the leading indent and the\n * trailing newline behind as a blank line — and the emptied-line rule below only\n * fires on a removal a line contains. A cut sharing its line with other code is\n * left exactly as asked.\n */\nfunction wholeLines(block: string, start: number, end: number): [number, number] {\n const lineStart = block.lastIndexOf(\"\\n\", start - 1) + 1;\n if (!/^[ \\t]*$/.test(block.slice(lineStart, start))) return [start, end];\n const nl = block.indexOf(\"\\n\", end);\n const to = nl === -1 ? block.length : nl;\n if (!/^[ \\t\\r]*$/.test(block.slice(end, to))) return [start, end];\n return [lineStart, nl === -1 ? block.length : nl + 1];\n}\n\n/**\n * Rewrite the line endings a merge INSERTED to the ones the document already\n * uses.\n *\n * Splicing composes bytes from two files, and the delta's newlines are not\n * necessarily the living document's: on a repository without `core.autocrlf`\n * normalisation a CRLF landscape or model came back with a handful of bare-LF\n * lines in the spliced region — two conventions in one file, noisy in an editor\n * and in every diff (verification 2026-09-04, W-CRLF). One helper for both\n * merges, because both had it.\n *\n * Only a document with ONE convention is corrected, and then in whichever\n * direction it uses: a file that is already mixed has no convention to match, and\n * guessing one would rewrite lines nobody touched.\n */\nexport function matchLineEndings(document: string, merged: string): string {\n const crlf = (document.match(/\\r\\n/g) ?? []).length;\n const bare = (document.match(/(?<!\\r)\\n/g) ?? []).length;\n if (crlf > 0 && bare === 0) return merged.replace(/(?<!\\r)\\n/g, \"\\r\\n\");\n if (bare > 0 && crlf === 0) return merged.replace(/\\r\\n/g, \"\\n\");\n return merged;\n}\n\nfunction stripFeatureTag(block: string, featureId: string, cuts: ReadonlyArray<[number, number]>): string {\n const { code } = maskSource(block);\n const esc = featureId.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const removals: Array<[number, number]> = cuts.map(([s, e]) => [s, e]);\n for (const m of block.matchAll(new RegExp(`#${esc}(?![\\\\w-])`, \"g\"))) {\n // Only tags in CODE count — a description quoting \"#FEAT-1\" is content.\n if (code.slice(m.index, m.index + m[0].length) !== m[0]) continue;\n let s = m.index;\n let e = s + m[0].length;\n // A tag list's separators go with the tag they separate. LikeC4 reads a\n // list as `#a #b, #c;` — one or more tags first, then `,` groups, then an\n // optional `;` — so `#FEAT-1, #x` stripped to `, #x` and `#FEAT-1;` to a\n // bare `;`, and the parse net refused a delta LikeC4 accepts. The comma\n // after the tag goes with it, else the comma before it; the `;` only when\n // no tag is left in front of it.\n const commaAfter = /^[ \\t]*,[ \\t]*/.exec(code.slice(e));\n const commaBefore = /,[ \\t]*$/.exec(code.slice(0, s));\n const semi = /^[ \\t]*;/.exec(code.slice(e));\n if (commaAfter !== null) {\n removals.push([s, e + commaAfter[0].length]);\n continue;\n }\n if (commaBefore !== null) {\n removals.push([commaBefore.index, e]);\n continue;\n }\n if (semi !== null && !/#[\\w-]+\\s*$/.test(code.slice(0, s))) e += semi[0].length;\n // Take the whitespace on ONE side with the token — trailing first, so\n // `#FEAT-1 #critical` leaves `#critical` at its own indent, and a token at\n // the end of a line does not leave a trailing space behind.\n if (block[e] === \" \" || block[e] === \"\\t\") {\n while (block[e] === \" \" || block[e] === \"\\t\") e += 1;\n } else {\n while (s > 0 && (block[s - 1] === \" \" || block[s - 1] === \"\\t\")) s -= 1;\n }\n removals.push([s, e]);\n }\n if (removals.length === 0) return block;\n\n // A line the strip emptied disappears whole, newline included.\n for (let lineStart = 0; lineStart < block.length; ) {\n const nl = block.indexOf(\"\\n\", lineStart);\n const lineEnd = nl === -1 ? block.length : nl + 1;\n if (\n removals.some(([s, e]) => s >= lineStart && e <= lineEnd) &&\n /^\\s*$/.test(residual(block, lineStart, nl === -1 ? block.length : nl, removals))\n ) {\n removals.push([lineStart, lineEnd]);\n }\n lineStart = lineEnd;\n }\n\n // A body the strip emptied goes too, braces and all — but only one the strip\n // emptied: braces that were authored empty are authored bytes and survive.\n for (let at = code.indexOf(\"{\"); at !== -1; at = code.indexOf(\"{\", at + 1)) {\n const closeAt = matchBrace(code, at);\n if (closeAt === -1) continue;\n if (!removals.some(([s, e]) => s > at && e <= closeAt)) continue;\n if (!/^\\s*$/.test(residual(block, at + 1, closeAt, removals))) continue;\n let s = at;\n while (s > 0 && /\\s/.test(block[s - 1]!)) s -= 1;\n removals.push([s, closeAt + 1]);\n }\n return applyRemovals(block, removals);\n}\n\n/** The text of [from, to) with the removal ranges cut out. */\nfunction residual(text: string, from: number, to: number, removals: Array<[number, number]>): string {\n let out = \"\";\n for (let i = from; i < to; i += 1) {\n if (!removals.some(([s, e]) => i >= s && i < e)) out += text[i];\n }\n return out;\n}\n\nfunction applyRemovals(text: string, removals: Array<[number, number]>): string {\n const sorted = [...removals].sort((a, b) => a[0] - b[0] || b[1] - a[1]);\n let out = \"\";\n let i = 0;\n for (const [s, e] of sorted) {\n if (s > i) out += text.slice(i, s);\n if (e > i) i = e;\n }\n return out + text.slice(i);\n}\n\n/**\n * Rebase a block's indentation: the `base` its lines carried in the delta\n * becomes `target`. The first line arrives with no leading whitespace (the\n * scanner's span starts at the declaration itself), so it only gains `target`.\n *\n * A CRLF delta's blank line is `\"\\r\"`, not `\"\"`, so splitting on `\\n` alone used\n * to hand a non-empty body to the rule below and every blank line inside a\n * spliced block came out carrying the target indent as trailing whitespace. The\n * carriage return is set aside and put back, which leaves the line's own ending\n * exactly as authored for `matchLineEndings` to reconcile.\n */\nfunction reindent(block: string, base: string, target: string): string {\n return block\n .split(\"\\n\")\n .map((line, k) => {\n const cr = line.endsWith(\"\\r\");\n const raw = cr ? line.slice(0, -1) : line;\n const body = k === 0 ? raw : raw.startsWith(base) ? raw.slice(base.length) : raw;\n return (body.length === 0 ? \"\" : target + body) + (cr ? \"\\r\" : \"\");\n })\n .join(\"\\n\");\n}\n"]}
@@ -57,7 +57,7 @@
57
57
  * (`core/usecases/delta/flows.ts`), and it is a views-only document — which is
58
58
  * exactly why it stages beside the map when this one cannot.
59
59
  */
60
- import { maskSource, matchBrace } from "../source-mask.js";
60
+ import { maskSource, topLevelBlocks } from "../source-mask.js";
61
61
  import { LandscapeSpliceError } from "./contract.js";
62
62
  /**
63
63
  * Top-level blocks a delta can declare. `specification` and `model` are absent
@@ -89,23 +89,13 @@ const FLOW_HOME = "features/<FEAT>/usecases/<name>.likec4 — a views-only docum
89
89
  * `scanModel` splices under, and for the same reason: this refuses an archive,
90
90
  * and a refusal a comment can provoke is worse than the silence it replaced.
91
91
  *
92
- * Brace depth is tracked in one forward pass rather than recounted per match:
93
- * only a block at depth 0 is a top-level declaration, and `deployment` at depth
94
- * 1 is an ordinary `specification { deploymentNode … }` or a view predicate.
92
+ * Only a block at depth 0 is a top-level declaration (`topLevelBlocks`), and
93
+ * `deployment` at depth 1 is an ordinary `specification { deploymentNode … }`
94
+ * or a view predicate.
95
95
  */
96
96
  export function assertMergeableDelta(deltaText) {
97
97
  const { code } = maskSource(deltaText);
98
- let depth = 0;
99
- let cursor = 0;
100
- for (const m of code.matchAll(TOP_LEVEL_BLOCK)) {
101
- for (; cursor < m.index; cursor += 1) {
102
- if (code[cursor] === "{")
103
- depth += 1;
104
- else if (code[cursor] === "}")
105
- depth -= 1;
106
- }
107
- if (depth !== 0)
108
- continue;
98
+ for (const { match: m, body: inner } of topLevelBlocks(code, TOP_LEVEL_BLOCK)) {
109
99
  const block = m[1];
110
100
  if (block !== "views") {
111
101
  refuse(`\`${block} { }\` block`, `a top-level \`${block} { }\` block`,
@@ -119,9 +109,6 @@ export function assertMergeableDelta(deltaText) {
119
109
  // such slot and keeps the living home.
120
110
  block === "deployment" ? DEPLOYMENT_HOME : LANDSCAPE_HOME);
121
111
  }
122
- const open = m.index + m[0].length - 1;
123
- const close = matchBrace(code, open);
124
- const inner = code.slice(open + 1, close === -1 ? code.length : close);
125
112
  const authored = AUTHORED_VIEW.exec(inner);
126
113
  if (authored !== null) {
127
114
  const kind = authored[1];
@@ -1 +1 @@
1
- {"version":3,"file":"delta-blocks.js","sourceRoot":"","sources":["../../../../src/core/c4/splice/delta-blocks.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What a delta may declare that the landscape merge cannot carry.\n *\n * `planLandscapeMerge` splices out of the delta's `model { }` block and nothing\n * else. That is correct — the living landscape is a model plus the views its own\n * authors chose — but it used to be SILENT: a delta declaring `deployment { }`\n * or a `dynamic view` archived at exit 0, reported `+N element(s), +M\n * relationship(s)` exactly as usual, and the block was simply gone. The merge's\n * own parse net cannot catch it either, because a landscape missing a deployment\n * model is perfectly legal — there is nothing to fail on. Nobody finds out until\n * somebody goes looking for a diagram that was archived months ago.\n *\n * So the loss is made a refusal, which is the same doctrine as the merge's other\n * mechanical refusals (an unlocatable declaration, two statements on one line):\n * the input cannot be spliced as authored, `--approve` deliberately does not\n * override it — that flag overrides loam's JUDGMENT about coherence, never its\n * ability to carry an axis — and nothing is written.\n *\n * ## Why views are graded and not simply banned\n *\n * `loam new` scaffolds a `views { view <feat> { include * } }` block into every\n * delta.likec4 (commands/new/templates.ts), so refusing the block outright would\n * refuse loam's own scaffold on its first archive. It is there to be RENDERED\n * while the feature is in flight, and it is meant not to travel.\n *\n * The line drawn here is recoverability, and it is the only line that survives\n * the scaffold:\n *\n * - A static `view` is a rendering OF the model. Once the merge lands, the\n * whole model is in landscape.likec4, so the author can restate the view\n * there at any time from information that still exists. Dropping it loses a\n * convenience.\n * - A `dynamic view`'s ordered steps, and a `deployment { }` block's topology,\n * exist in NO other document the fleet keeps. When the merge drops those,\n * the information is gone. That is what gets refused. Rule 26 sharpens the\n * stakes rather than the rule: a `dynamic view`'s steps are now something\n * loam READS, so dropping one silently would discard checked content, not\n * merely a convenience.\n *\n * A residual is accepted knowingly: a delta carrying a SECOND static view still\n * loses it without a word. Refusing that would mean telling an author with two\n * preview views to delete one, which is a false refusal on a harmless file, and\n * the loss there is recoverable by the argument above.\n *\n * ## The dynamic-view refusal is unchanged; its ADVICE moved\n *\n * A `dynamic view` still cannot ride inside `delta.likec4`, and the reason is\n * mechanical rather than a policy about where flows belong: this document\n * re-declares the landscape's own identifiers to anchor its new edges and\n * carries its own `specification` block because LikeC4 parses it standalone, so\n * it cannot be staged beside the map in one project — a duplicate specification\n * is an error blamed on both files, and a re-declared element is a duplicate id.\n * What changed is where the refusal sends the author. It used to say\n * `architecture/landscape.likec4`, which was the only honest answer while the\n * axis had no feature-delta path: a flow could not ship with the change that\n * made it true. `features/<FEAT>/usecases/<name>.likec4` is that path\n * (`core/usecases/delta/flows.ts`), and it is a views-only document — which is\n * exactly why it stages beside the map when this one cannot.\n */\nimport { maskSource, matchBrace } from \"../source-mask.js\";\nimport { LandscapeSpliceError } from \"./contract.js\";\n\n/**\n * Top-level blocks a delta can declare. `specification` and `model` are absent\n * on purpose: the specification is re-declared in every delta because LikeC4\n * parses each one standalone, and the model is the thing being spliced.\n */\nconst TOP_LEVEL_BLOCK = /\\b(deployment|global|views)\\s*\\{/g;\n\n/** A `dynamic view` / `deployment view` inside a views block — the irrecoverable kinds. */\nconst AUTHORED_VIEW = /\\b(dynamic|deployment)\\s+view\\b/;\n\nfunction refuse(block: string, detail: string, home: string): never {\n throw new LandscapeSpliceError(\n `delta.likec4 declares ${detail}, and the landscape merge splices only what is inside \\`model { }\\` — ` +\n `archiving would drop it silently, so nothing was written. Move the ${block} into ` +\n `${home} and re-run the archive.`,\n );\n}\n\n/** Where the living documents keep what this delta cannot carry. */\nconst LANDSCAPE_HOME = \"architecture/landscape.likec4, where the living documents keep it,\";\n\n/** Where a FEATURE keeps TOPOLOGY — the third whole-file slot, added with the deployment axis. */\nconst DEPLOYMENT_HOME =\n \"features/<FEAT>/deployment/<name>.likec4 — a document of its own, which `loam archive` copies into \" +\n \"architecture/ and `loam unarchive` takes back; say `extend` in it to add to a region the living map \" +\n \"already declares —\";\n\n/** Where a FEATURE keeps a flow — a slot of its own, not the living tree. See the header. */\nconst FLOW_HOME =\n \"features/<FEAT>/usecases/<name>.likec4 — a views-only document of its own, which `loam archive` copies into \" +\n \"architecture/usecases/ and `loam unarchive` takes back —\";\n\n/**\n * Refuse a delta whose non-model blocks the merge would discard.\n *\n * Runs over MASKED source, so a `deployment {` written inside a comment or a\n * description string cannot trigger it — the same masking discipline\n * `scanModel` splices under, and for the same reason: this refuses an archive,\n * and a refusal a comment can provoke is worse than the silence it replaced.\n *\n * Brace depth is tracked in one forward pass rather than recounted per match:\n * only a block at depth 0 is a top-level declaration, and `deployment` at depth\n * 1 is an ordinary `specification { deploymentNode … }` or a view predicate.\n */\nexport function assertMergeableDelta(deltaText: string): void {\n const { code } = maskSource(deltaText);\n let depth = 0;\n let cursor = 0;\n for (const m of code.matchAll(TOP_LEVEL_BLOCK)) {\n for (; cursor < m.index; cursor += 1) {\n if (code[cursor] === \"{\") depth += 1;\n else if (code[cursor] === \"}\") depth -= 1;\n }\n if (depth !== 0) continue;\n const block = m[1]!;\n if (block !== \"views\") {\n refuse(\n `\\`${block} { }\\` block`,\n `a top-level \\`${block} { }\\` block`,\n // The refusal is unchanged and always will be — this document\n // re-declares the landscape's identifiers and carries its own\n // `specification`, so it cannot be staged beside the map in one project.\n // What changed is where it sends the author: a feature introducing\n // topology WITH the change that makes it true now has a slot of its\n // own, and pointing at the living landscape was the advice that made\n // the axis's headline case a two-pull-request job. `global { }` has no\n // such slot and keeps the living home.\n block === \"deployment\" ? DEPLOYMENT_HOME : LANDSCAPE_HOME,\n );\n }\n const open = m.index + m[0].length - 1;\n const close = matchBrace(code, open);\n const inner = code.slice(open + 1, close === -1 ? code.length : close);\n const authored = AUTHORED_VIEW.exec(inner);\n if (authored !== null) {\n const kind = authored[1]!;\n refuse(\n `\\`${kind} view\\``,\n `a \\`${kind} view\\` in its \\`views { }\\` block — a view of that kind describes ordering or topology ` +\n `recorded in no other document, unlike the static preview view \\`loam new\\` scaffolds`,\n // A deployment view is topology and belongs in the living map; a dynamic\n // view is a flow, and a flow now has a feature slot of its own. Sending\n // an author to the living landscape for one they are introducing WITH\n // this change was the advice that made the axis's headline case a\n // two-pull-request job.\n kind === \"dynamic\" ? FLOW_HOME : DEPLOYMENT_HOME,\n );\n }\n }\n}\n"]}
1
+ {"version":3,"file":"delta-blocks.js","sourceRoot":"","sources":["../../../../src/core/c4/splice/delta-blocks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD;;;;GAIG;AACH,MAAM,eAAe,GAAG,mCAAmC,CAAC;AAE5D,2FAA2F;AAC3F,MAAM,aAAa,GAAG,iCAAiC,CAAC;AAExD,SAAS,MAAM,CAAC,KAAa,EAAE,MAAc,EAAE,IAAY;IACzD,MAAM,IAAI,oBAAoB,CAC5B,yBAAyB,MAAM,wEAAwE;QACrG,sEAAsE,KAAK,QAAQ;QACnF,GAAG,IAAI,0BAA0B,CACpC,CAAC;AACJ,CAAC;AAED,oEAAoE;AACpE,MAAM,cAAc,GAAG,oEAAoE,CAAC;AAE5F,kGAAkG;AAClG,MAAM,eAAe,GACnB,qGAAqG;IACrG,sGAAsG;IACtG,oBAAoB,CAAC;AAEvB,6FAA6F;AAC7F,MAAM,SAAS,GACb,8GAA8G;IAC9G,0DAA0D,CAAC;AAE7D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IACpD,MAAM,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACvC,KAAK,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,EAAE,CAAC;QAC9E,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACpB,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;YACtB,MAAM,CACJ,KAAK,KAAK,cAAc,EACxB,iBAAiB,KAAK,cAAc;YACpC,8DAA8D;YAC9D,8DAA8D;YAC9D,yEAAyE;YACzE,mEAAmE;YACnE,oEAAoE;YACpE,qEAAqE;YACrE,uEAAuE;YACvE,uCAAuC;YACvC,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,cAAc,CAC1D,CAAC;QACJ,CAAC;QACD,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;YAC1B,MAAM,CACJ,KAAK,IAAI,SAAS,EAClB,OAAO,IAAI,0FAA0F;gBACnG,sFAAsF;YACxF,yEAAyE;YACzE,wEAAwE;YACxE,sEAAsE;YACtE,kEAAkE;YAClE,wBAAwB;YACxB,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CACjD,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["/**\n * What a delta may declare that the landscape merge cannot carry.\n *\n * `planLandscapeMerge` splices out of the delta's `model { }` block and nothing\n * else. That is correct — the living landscape is a model plus the views its own\n * authors chose — but it used to be SILENT: a delta declaring `deployment { }`\n * or a `dynamic view` archived at exit 0, reported `+N element(s), +M\n * relationship(s)` exactly as usual, and the block was simply gone. The merge's\n * own parse net cannot catch it either, because a landscape missing a deployment\n * model is perfectly legal — there is nothing to fail on. Nobody finds out until\n * somebody goes looking for a diagram that was archived months ago.\n *\n * So the loss is made a refusal, which is the same doctrine as the merge's other\n * mechanical refusals (an unlocatable declaration, two statements on one line):\n * the input cannot be spliced as authored, `--approve` deliberately does not\n * override it — that flag overrides loam's JUDGMENT about coherence, never its\n * ability to carry an axis — and nothing is written.\n *\n * ## Why views are graded and not simply banned\n *\n * `loam new` scaffolds a `views { view <feat> { include * } }` block into every\n * delta.likec4 (commands/new/templates.ts), so refusing the block outright would\n * refuse loam's own scaffold on its first archive. It is there to be RENDERED\n * while the feature is in flight, and it is meant not to travel.\n *\n * The line drawn here is recoverability, and it is the only line that survives\n * the scaffold:\n *\n * - A static `view` is a rendering OF the model. Once the merge lands, the\n * whole model is in landscape.likec4, so the author can restate the view\n * there at any time from information that still exists. Dropping it loses a\n * convenience.\n * - A `dynamic view`'s ordered steps, and a `deployment { }` block's topology,\n * exist in NO other document the fleet keeps. When the merge drops those,\n * the information is gone. That is what gets refused. Rule 26 sharpens the\n * stakes rather than the rule: a `dynamic view`'s steps are now something\n * loam READS, so dropping one silently would discard checked content, not\n * merely a convenience.\n *\n * A residual is accepted knowingly: a delta carrying a SECOND static view still\n * loses it without a word. Refusing that would mean telling an author with two\n * preview views to delete one, which is a false refusal on a harmless file, and\n * the loss there is recoverable by the argument above.\n *\n * ## The dynamic-view refusal is unchanged; its ADVICE moved\n *\n * A `dynamic view` still cannot ride inside `delta.likec4`, and the reason is\n * mechanical rather than a policy about where flows belong: this document\n * re-declares the landscape's own identifiers to anchor its new edges and\n * carries its own `specification` block because LikeC4 parses it standalone, so\n * it cannot be staged beside the map in one project — a duplicate specification\n * is an error blamed on both files, and a re-declared element is a duplicate id.\n * What changed is where the refusal sends the author. It used to say\n * `architecture/landscape.likec4`, which was the only honest answer while the\n * axis had no feature-delta path: a flow could not ship with the change that\n * made it true. `features/<FEAT>/usecases/<name>.likec4` is that path\n * (`core/usecases/delta/flows.ts`), and it is a views-only document — which is\n * exactly why it stages beside the map when this one cannot.\n */\nimport { maskSource, topLevelBlocks } from \"../source-mask.js\";\nimport { LandscapeSpliceError } from \"./contract.js\";\n\n/**\n * Top-level blocks a delta can declare. `specification` and `model` are absent\n * on purpose: the specification is re-declared in every delta because LikeC4\n * parses each one standalone, and the model is the thing being spliced.\n */\nconst TOP_LEVEL_BLOCK = /\\b(deployment|global|views)\\s*\\{/g;\n\n/** A `dynamic view` / `deployment view` inside a views block — the irrecoverable kinds. */\nconst AUTHORED_VIEW = /\\b(dynamic|deployment)\\s+view\\b/;\n\nfunction refuse(block: string, detail: string, home: string): never {\n throw new LandscapeSpliceError(\n `delta.likec4 declares ${detail}, and the landscape merge splices only what is inside \\`model { }\\` — ` +\n `archiving would drop it silently, so nothing was written. Move the ${block} into ` +\n `${home} and re-run the archive.`,\n );\n}\n\n/** Where the living documents keep what this delta cannot carry. */\nconst LANDSCAPE_HOME = \"architecture/landscape.likec4, where the living documents keep it,\";\n\n/** Where a FEATURE keeps TOPOLOGY — the third whole-file slot, added with the deployment axis. */\nconst DEPLOYMENT_HOME =\n \"features/<FEAT>/deployment/<name>.likec4 — a document of its own, which `loam archive` copies into \" +\n \"architecture/ and `loam unarchive` takes back; say `extend` in it to add to a region the living map \" +\n \"already declares —\";\n\n/** Where a FEATURE keeps a flow — a slot of its own, not the living tree. See the header. */\nconst FLOW_HOME =\n \"features/<FEAT>/usecases/<name>.likec4 — a views-only document of its own, which `loam archive` copies into \" +\n \"architecture/usecases/ and `loam unarchive` takes back —\";\n\n/**\n * Refuse a delta whose non-model blocks the merge would discard.\n *\n * Runs over MASKED source, so a `deployment {` written inside a comment or a\n * description string cannot trigger it — the same masking discipline\n * `scanModel` splices under, and for the same reason: this refuses an archive,\n * and a refusal a comment can provoke is worse than the silence it replaced.\n *\n * Only a block at depth 0 is a top-level declaration (`topLevelBlocks`), and\n * `deployment` at depth 1 is an ordinary `specification { deploymentNode … }`\n * or a view predicate.\n */\nexport function assertMergeableDelta(deltaText: string): void {\n const { code } = maskSource(deltaText);\n for (const { match: m, body: inner } of topLevelBlocks(code, TOP_LEVEL_BLOCK)) {\n const block = m[1]!;\n if (block !== \"views\") {\n refuse(\n `\\`${block} { }\\` block`,\n `a top-level \\`${block} { }\\` block`,\n // The refusal is unchanged and always will be — this document\n // re-declares the landscape's identifiers and carries its own\n // `specification`, so it cannot be staged beside the map in one project.\n // What changed is where it sends the author: a feature introducing\n // topology WITH the change that makes it true now has a slot of its\n // own, and pointing at the living landscape was the advice that made\n // the axis's headline case a two-pull-request job. `global { }` has no\n // such slot and keeps the living home.\n block === \"deployment\" ? DEPLOYMENT_HOME : LANDSCAPE_HOME,\n );\n }\n const authored = AUTHORED_VIEW.exec(inner);\n if (authored !== null) {\n const kind = authored[1]!;\n refuse(\n `\\`${kind} view\\``,\n `a \\`${kind} view\\` in its \\`views { }\\` block — a view of that kind describes ordering or topology ` +\n `recorded in no other document, unlike the static preview view \\`loam new\\` scaffolds`,\n // A deployment view is topology and belongs in the living map; a dynamic\n // view is a flow, and a flow now has a feature slot of its own. Sending\n // an author to the living landscape for one they are introducing WITH\n // this change was the advice that made the axis's headline case a\n // two-pull-request job.\n kind === \"dynamic\" ? FLOW_HOME : DEPLOYMENT_HOME,\n );\n }\n }\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import { parentIdOf } from "../../kernel/ids/fqn/ancestors.js";
2
2
  import { errorText, loadSource } from "../likec4.js";
3
+ import { firstUnlocated, unlocatedReason } from "../locate/unlocated.js";
3
4
  import { elementService, serviceOf } from "../resolve/service.js";
4
5
  import { scanModel } from "../source-scan.js";
5
6
  import { matchLineEndings, spliceSource } from "./authored-source.js";
@@ -205,7 +206,7 @@ export async function planLandscapeMerge(merge) {
205
206
  // Built fresh at every use, never captured: `content` and `stmts` are rebound
206
207
  // by each rescan, and a region assembled before a splice describes a document
207
208
  // that no longer exists.
208
- const modelRegion = () => ({ text: content, stmts, close: requireModel().close });
209
+ const modelRegion = () => ({ text: content, stmts, blocks: requireModel().blocks });
209
210
  const applyAt = (at, insert) => {
210
211
  content = content.slice(0, at) + insert + content.slice(at);
211
212
  rescan();
@@ -223,15 +224,19 @@ export async function planLandscapeMerge(merge) {
223
224
  // element bound to its service would miss its neighborhood, and a bodyless
224
225
  // parent gaining a body could wrap the wrong declaration. Refuse
225
226
  // mechanically (the parse-net discipline) instead of splicing blind.
227
+ //
228
+ // THAT something is unlocated is decided here, from the parse already in
229
+ // hand; WHAT and why is `firstUnlocated`'s, at the price of a second parse on
230
+ // this path alone. The message used to guess "most often two declarations
231
+ // sharing one line" whatever the map held, and a fleet read it over a
232
+ // declaration on a line of its own in a second `model { }` block the scan
233
+ // did not read then (2026-10): it names LikeC4's line now, and a shared line
234
+ // only when that line shows one.
226
235
  if (livingScan !== null) {
227
236
  const seen = new Set(livingScan.elements.map((e) => e.id));
228
- const invisible = land.elements.find((e) => !seen.has(e.id));
229
- if (invisible !== undefined) {
230
- throw new LandscapeSpliceError(`landscape.likec4 declares '${invisible.id}' in a form placement cannot locate — most often two declarations sharing one line; give each its own line, then re-run`);
231
- }
232
- if (livingScan.rels.length < land.relationships.length) {
233
- throw new LandscapeSpliceError(`landscape.likec4 declares ${land.relationships.length} relationship(s) but placement can locate only ${livingScan.rels.length} — most often two statements sharing one line; give each its own line, then re-run`);
234
- }
237
+ const blind = land.elements.some((e) => !seen.has(e.id)) || livingScan.rels.length < land.relationships.length;
238
+ if (blind)
239
+ throw new LandscapeSpliceError(unlocatedReason("landscape.likec4", await firstUnlocated(text, livingScan)));
235
240
  }
236
241
  const livingParentOf = (parentId) => {
237
242
  if (livingScan === null)
@@ -1 +1 @@
1
- {"version":3,"file":"landscape-merge.js","sourceRoot":"","sources":["../../../../src/core/c4/splice/landscape-merge.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport { parentIdOf } from \"../../kernel/ids/fqn/ancestors.js\";\nimport { errorText, loadSource, type Elem, type Rel } from \"../likec4.js\";\nimport { elementService, serviceOf } from \"../resolve/service.js\";\nimport { scanModel, type ScannedElement, type ScannedModel, type ScannedRel } from \"../source-scan.js\";\nimport { matchLineEndings, spliceSource } from \"./authored-source.js\";\nimport {\n LandscapeSpliceError,\n type ExtendingModel,\n type LandscapeMergeRequest,\n type LandscapePlan,\n type ModelAdditions,\n} from \"./contract.js\";\nimport { assertMergeableDelta } from \"./delta-blocks.js\";\nimport { relSortKey, relStatementKey } from \"./identity/edges.js\";\nimport { newAdditions } from \"./identity/existing.js\";\nimport { planInteriors } from \"./identity/interior.js\";\nimport { ownerOf } from \"./identity/owner.js\";\nimport {\n elementSpot,\n nestedInsert,\n relSpot,\n topStatements,\n type ModelRegion,\n type Spot,\n} from \"./placement.js\";\n\n/* ------------------------------------------------------------------ */\n/* Merging */\n/* ------------------------------------------------------------------ */\n\n/**\n * Plan the merge of the feature's new elements + relationships into the living\n * landscape's `model { ... }` block (preserving the rest of the file).\n *\n * The additions are SPLICED from delta.likec4 as authored — byte for byte,\n * technology, style, icons, links, metadata, nested children and all — never\n * re-serialized from the parsed model: a rebuild keeps only the fields loam\n * models, and every field it forgets is authored detail destroyed. The one\n * edit on the way over is dropping the feature's own tag — the additions are\n * baseline now (SCHEMA.md documents the drop as why unarchive restores bytes\n * instead of recomputing) — and a construct the strip empties goes with it.\n *\n * Placement is deterministic and SERVICE-GROUPED (the spot* helpers in\n * placement.ts):\n * a top-level addition lands beside what already belongs to its service, so\n * two concurrent archives touching different services usually splice on\n * different lines and git merges their PRs — the single shared append point\n * every archive used to hit made two concurrent archives conflict BY\n * CONSTRUCTION. A NESTED element lands inside its parent's block — inside the\n * living parent when the landscape already has it, riding verbatim inside the\n * spliced parent when the parent is new from the same delta — never as a flat\n * dotted id at top level, which LikeC4 rejects. The additions carry no marker\n * comment: which archive added what is the git history's to say.\n *\n * Existence is checked semantically against the parsed landscape AND against\n * every extending model the request carries (by element id/title and by edge\n * identity), so re-archiving is idempotent whichever document the additions\n * landed in — `./identity/existing.ts` holds that phase and its two joins, and\n * this function only turns the collision it reports into the refusal.\n *\n * Splicing is text surgery, so the computed result is PARSED before it is\n * returned: a merged landscape LikeC4 rejects refuses the archive at plan time\n * (merge-failed, nothing written — the unparseable-delta discipline) instead\n * of landing in the living docs.\n *\n * NOT EVERYTHING LANDS HERE. A service whose model EXTENDS this map owns its\n * own interior, and an addition nested under such a service is ROUTED to that\n * model instead (`./identity/owner.ts` decides, `./model/merge.ts` splices).\n * Until it was, a delta's container landed in the map and the service was\n * `c4.invalid` — a duplicate declaration — the moment its model wrote the same\n * container, which is exactly what the adopt brief tells it to do\n * (verification 2026-09-04, E1). With no extending models in the request this\n * function behaves as it always did.\n *\n * Routing per ADDITION is not the whole of it, because a service the feature\n * INTRODUCES carries its interior in one element's authored bytes and those\n * children carry no feature tag of their own. `./identity/interior.ts` decides, once\n * per such block, whether it hands that interior to the model — cut out of what\n * lands on the map — or rides whole; the routing below DEFERS to that decision\n * for everything written inside the block, which is what keeps the two from\n * placing the same child twice.\n */\nexport async function planLandscapeMerge(merge: LandscapeMergeRequest): Promise<LandscapePlan> {\n const { landscapeText: text, deltaText, deltaElements, newEls, newRels, featureId } = merge;\n const models = merge.models ?? [];\n // First, and before the early return for \"nothing to add\": a block this merge\n // cannot carry is lost whether or not the delta also has tagged elements to\n // splice. See delta-blocks.ts.\n assertMergeableDelta(deltaText);\n const land = await loadSource(text);\n if (land.errors.length > 0) {\n throw new LandscapeSpliceError(`landscape.likec4 has ${land.errors.length} error(s) — fix it before archiving`);\n }\n // Service binding for the existence joins AND for routing and placement:\n // living elements first (they win a shared id), the delta's after — a spliced\n // statement's id resolves to its service the moment its bytes land in the scan.\n const bindEls = [...land.elements, ...deltaElements.filter((d) => !land.elements.some((l) => l.id === d.id))];\n // What the living fleet already has — the map AND every extending model, by id\n // and by title. `./identity/existing.ts` holds both joins and their asymmetry.\n const added = newAdditions({\n livingEls: land.elements,\n livingRels: land.relationships,\n bindEls,\n deltaElements,\n candidates: { els: newEls, rels: newRels },\n models,\n });\n if (added.collision !== undefined) {\n const { addition: e, living: m } = added.collision;\n throw new LandscapeSpliceError(\n `the delta's '${e.id}' (bound to service '${e.service}') shares the title '${e.title}' with '${m.id}' (bound to service '${m.service}') — a title join across services would silently drop the addition; ` +\n `retitle one of them, or reuse the id '${m.id}' if they really are the same element`,\n );\n }\n const addedEls = added.els;\n const addedRels = added.rels;\n\n const owner = ownerOf({\n bindEls,\n living: new Set(land.elements.map((e) => e.id)),\n declared: added.declaredIds,\n added: new Set(addedEls.map((e) => e.id)),\n models,\n });\n // Nothing to add: the same shape the merge returned before routing existed,\n // and the reason it is decided HERE rather than after the loops below — a\n // no-op archive must not have to scan the delta, nor answer the landscape\n // guards further down, which refuse documents this merge is not touching.\n // Equivalent to the old \"nothing reached the map and nothing was routed\":\n // every addition ends up in one of those two, so an empty pair means both.\n if (addedEls.length === 0 && addedRels.length === 0) {\n return { content: null, addedEls: [], addedRels: [], models: [] };\n }\n\n const scan = scanModel(deltaText);\n if (scan === null) {\n throw new LandscapeSpliceError(\"delta.likec4 has no model block — nothing to splice the additions from\");\n }\n\n // Everything below either locates a declaration's authored bytes or refuses.\n // `spliced` remembers the delta ranges already carried over, so a child whose\n // parent is itself new is recognised as riding inside the parent's text and\n // is never inserted twice.\n const byId = new Map(scan.elements.map((e) => [e.id, e]));\n // Relationships: match each parsed addition back to its statement in the\n // delta source — full identity (`relStatementKey`), consumed one statement\n // per addition so duplicates stay duplicates. Built before the routing\n // because routing has to know WHERE an edge was written: one drawn inside a\n // block that rides whole is already on the map.\n const pool = new Map<string, ScannedRel[]>();\n for (const s of scan.rels) {\n const k = relStatementKey(s);\n pool.set(k, [...(pool.get(k) ?? []), s]);\n }\n\n const interiors = planInteriors({ scan, deltaElements, owner, addedEls });\n const routed = new Map<string, ModelAdditions>();\n const into = (model: ExtendingModel): ModelAdditions => {\n const existing = routed.get(model.path);\n if (existing !== undefined) return existing;\n const fresh: ModelAdditions = { model, els: [], rels: [] };\n routed.set(model.path, fresh);\n return fresh;\n };\n for (const share of interiors.routed) into(share.model).els.push(...share.els);\n\n const mapEls: Elem[] = [];\n for (const e of addedEls) {\n const src = byId.get(e.id);\n // Written inside a block that has already decided: a split block handed it\n // to the model with its siblings, and a whole one carries it onto the map\n // in the parent's own bytes, where the splice loop's `rides` finds it. Both\n // are placed exactly once, which is the point of asking the block first.\n const fate = src === undefined ? null : interiors.covering(src);\n if (fate === \"split\") continue;\n const model = fate === \"whole\" ? undefined : owner(parentIdOf(e.id));\n if (model === undefined) mapEls.push(e);\n else into(model).els.push(e);\n }\n const mapRels: Rel[] = [];\n for (const r of addedRels) {\n // An edge written inside a block that rides whole names its endpoints by\n // their LOCAL names and reads only there; it stays with its block.\n const stmts = pool.get(relStatementKey(r)) ?? [];\n const inBlock = stmts.length > 0 && stmts.every((s) => interiors.covering(s) !== null);\n // Otherwise the SOURCE decides: a call is drawn where the caller draws its\n // calls, and only when the source is not itself interior does the target's\n // owner get the edge. A service-level edge belongs to neither and stays on\n // the map.\n const model = inBlock ? undefined : owner(parentIdOf(r.source)) ?? owner(parentIdOf(r.target));\n if (model === undefined) mapRels.push(r);\n else into(model).rels.push(r);\n }\n const touchesMap = mapEls.length > 0 || mapRels.length > 0;\n\n const spliced: Array<{ start: number; end: number }> = [];\n const rides = (start: number, end: number): boolean =>\n spliced.some((r) => start >= r.start && end <= r.end);\n\n // The living model, scanned on MASKED source (scanModel) and RE-SCANNED\n // after every splice: each addition lands in the text exactly as the\n // previous one left it, so an archive of N additions produces the same\n // bytes as N single-addition archives run back to back. Placement then\n // composes per statement — the unit the order-independence argument below\n // is stated in — instead of per archive, where a batch computed against a\n // stale layout could interleave with itself. Masking matters — a `model {`\n // spelled inside a comment or string above the real block must not capture\n // the match, or every top-level addition lands inside the comment (legal\n // LikeC4, so the parse net below would pass a landscape containing none of\n // the architecture).\n let content = text;\n let livingScan = scanModel(content);\n let stmts = livingScan === null ? [] : topStatements(livingScan, bindEls);\n const rescan = (): void => {\n livingScan = scanModel(content);\n stmts = livingScan === null ? [] : topStatements(livingScan, bindEls);\n };\n const requireModel = (): ScannedModel => {\n if (livingScan === null) throw new LandscapeSpliceError(\"landscape.likec4 has no model block\");\n return livingScan;\n };\n // Built fresh at every use, never captured: `content` and `stmts` are rebound\n // by each rescan, and a region assembled before a splice describes a document\n // that no longer exists.\n const modelRegion = (): ModelRegion => ({ text: content, stmts, close: requireModel().close });\n const applyAt = (at: number, insert: string): void => {\n content = content.slice(0, at) + insert + content.slice(at);\n rescan();\n };\n const applyTop = (spot: Spot, block: string): void => {\n // A bare spot shares its line with other text (the closing brace, or a\n // statement the block displaces) — it brings its own newlines; a\n // line-start spot slots between lines.\n applyAt(spot.at, spot.bare ? `\\n${block}\\n` : `${block}\\n`);\n };\n\n // Placement walks the scanned statement layout, so a declaration the scan\n // cannot see is one placement would blindly splice around — LikeC4 accepts\n // two declarations on one line, but scanModel's statement head runs to the\n // end of the line, so the second rides invisibly inside the first: an\n // element bound to its service would miss its neighborhood, and a bodyless\n // parent gaining a body could wrap the wrong declaration. Refuse\n // mechanically (the parse-net discipline) instead of splicing blind.\n if (livingScan !== null) {\n const seen = new Set(livingScan.elements.map((e) => e.id));\n const invisible = land.elements.find((e) => !seen.has(e.id));\n if (invisible !== undefined) {\n throw new LandscapeSpliceError(\n `landscape.likec4 declares '${invisible.id}' in a form placement cannot locate — most often two declarations sharing one line; give each its own line, then re-run`,\n );\n }\n if (livingScan.rels.length < land.relationships.length) {\n throw new LandscapeSpliceError(\n `landscape.likec4 declares ${land.relationships.length} relationship(s) but placement can locate only ${livingScan.rels.length} — most often two statements sharing one line; give each its own line, then re-run`,\n );\n }\n }\n\n const livingParentOf = (parentId: string): ScannedElement | null => {\n if (livingScan === null) return null;\n const direct = livingScan.elements.find((e) => e.id === parentId);\n if (direct !== undefined) return direct;\n // The delta may spell an existing element under its own id; the title is\n // the stable cross-namespace name (the same rule the existence check uses).\n const title = deltaElements.find((e) => e.id === parentId)?.title;\n const livingId = title === undefined ? undefined : land.elements.find((e) => e.title === title)?.id;\n if (livingId === undefined) return null;\n return livingScan.elements.find((e) => e.id === livingId) ?? null;\n };\n\n // Ancestors first: a spliced parent covers its children before they are seen.\n const depth = (id: string): number => id.split(\".\").length;\n const sortedEls = [...mapEls].sort(\n (a, b) => depth(a.id) - depth(b.id) || (byId.get(a.id)?.start ?? 0) - (byId.get(b.id)?.start ?? 0),\n );\n for (const e of sortedEls) {\n const src = byId.get(e.id);\n if (src === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate '${e.id}' in delta.likec4 — the landscape merge splices authored source, and this declaration was not found`,\n );\n }\n if (rides(src.start, src.end)) continue;\n // Every split block's children, whichever block they belong to:\n // `spliceSource` keeps only the ranges that fall inside the bytes it is\n // carrying, so a block riding inside ANOTHER new block still loses its own\n // interior on the way to the map.\n const omit = interiors.omit;\n const dot = e.id.lastIndexOf(\".\");\n if (dot === -1) {\n const spot = elementSpot(modelRegion(), e.id, elementService(e));\n applyTop(spot, spliceSource(deltaText, src, { featureId, indent: \" \", omit }));\n spliced.push({ start: src.start, end: src.end });\n continue;\n }\n const parentId = e.id.slice(0, dot);\n const parent = livingParentOf(parentId);\n if (parent === null) {\n throw new LandscapeSpliceError(\n `'${e.id}' nests under '${parentId}', which is neither in the living landscape nor added by this delta — there is nowhere to insert it`,\n );\n }\n const nested = nestedInsert(\n content,\n parent,\n spliceSource(deltaText, src, { featureId, indent: parent.indent + \" \", omit }),\n );\n applyAt(nested.at, nested.insert);\n spliced.push({ start: src.start, end: src.end });\n }\n\n // Each map-bound addition takes its statement out of the pool built above:\n // one statement per addition, so duplicates stay duplicates.\n for (const r of mapRels) {\n const s = pool.get(relStatementKey(r))?.shift();\n if (s === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate the '${r.source} -> ${r.target}' relationship in delta.likec4 — the landscape merge splices authored source, and no matching declaration was found`,\n );\n }\n if (rides(s.start, s.end)) continue;\n const key = relSortKey(deltaElements, r);\n // Deliberately no `known` fleet set: this resolves only the anchor a new\n // relationship lands after (placement.ts's reason — cosmetic grouping,\n // safety-netted by the re-parse below), never which service a check\n // grades.\n const spot = relSpot(modelRegion(), serviceOf(deltaElements, r.source), key);\n applyTop(spot, spliceSource(deltaText, s, { featureId, indent: \" \" }));\n }\n\n // The safety net: prove the computed landscape parses before anything is\n // written. Splice bugs — and legal inputs the living document cannot absorb,\n // like a kind its specification never declares — refuse here, at plan time,\n // instead of corrupting the one file the whole fleet reads. Skipped when\n // every addition was routed away: the text is the one already parsed above,\n // and the models get their own net from the caller, which is the only side\n // that can stage a model beside the map it extends.\n // The splice composed bytes from two documents, and the delta's newlines are\n // not necessarily the map's. Corrected before the net, so what is proven is\n // what would be written.\n content = matchLineEndings(text, content);\n if (touchesMap) {\n const check = await loadSource(content);\n if (check.errors.length > 0) {\n const detail = check.errors\n .slice(0, 3)\n .map(errorText)\n .join(\"; \");\n throw new LandscapeSpliceError(\n `the merged landscape would not parse (${check.errors.length} error(s): ${detail}) — nothing was written. ` +\n `The delta's additions do not fit the living landscape as authored — most often an element kind or tag ` +\n `its specification block does not declare; fix the landscape's specification or the delta, then re-run`,\n );\n }\n }\n\n return { content: touchesMap ? content : null, addedEls: mapEls, addedRels: mapRels, models: [...routed.values()] };\n}\n"]}
1
+ {"version":3,"file":"landscape-merge.js","sourceRoot":"","sources":["../../../../src/core/c4/splice/landscape-merge.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport { parentIdOf } from \"../../kernel/ids/fqn/ancestors.js\";\nimport { errorText, loadSource, type Elem, type Rel } from \"../likec4.js\";\nimport { firstUnlocated, unlocatedReason } from \"../locate/unlocated.js\";\nimport { elementService, serviceOf } from \"../resolve/service.js\";\nimport { scanModel, type ScannedElement, type ScannedModel, type ScannedRel } from \"../source-scan.js\";\nimport { matchLineEndings, spliceSource } from \"./authored-source.js\";\nimport {\n LandscapeSpliceError,\n type ExtendingModel,\n type LandscapeMergeRequest,\n type LandscapePlan,\n type ModelAdditions,\n} from \"./contract.js\";\nimport { assertMergeableDelta } from \"./delta-blocks.js\";\nimport { relSortKey, relStatementKey } from \"./identity/edges.js\";\nimport { newAdditions } from \"./identity/existing.js\";\nimport { planInteriors } from \"./identity/interior.js\";\nimport { ownerOf } from \"./identity/owner.js\";\nimport {\n elementSpot,\n nestedInsert,\n relSpot,\n topStatements,\n type ModelRegion,\n type Spot,\n} from \"./placement.js\";\n\n/* ------------------------------------------------------------------ */\n/* Merging */\n/* ------------------------------------------------------------------ */\n\n/**\n * Plan the merge of the feature's new elements + relationships into the living\n * landscape's `model { ... }` block (preserving the rest of the file).\n *\n * The additions are SPLICED from delta.likec4 as authored — byte for byte,\n * technology, style, icons, links, metadata, nested children and all — never\n * re-serialized from the parsed model: a rebuild keeps only the fields loam\n * models, and every field it forgets is authored detail destroyed. The one\n * edit on the way over is dropping the feature's own tag — the additions are\n * baseline now (SCHEMA.md documents the drop as why unarchive restores bytes\n * instead of recomputing) — and a construct the strip empties goes with it.\n *\n * Placement is deterministic and SERVICE-GROUPED (the spot* helpers in\n * placement.ts):\n * a top-level addition lands beside what already belongs to its service, so\n * two concurrent archives touching different services usually splice on\n * different lines and git merges their PRs — the single shared append point\n * every archive used to hit made two concurrent archives conflict BY\n * CONSTRUCTION. A NESTED element lands inside its parent's block — inside the\n * living parent when the landscape already has it, riding verbatim inside the\n * spliced parent when the parent is new from the same delta — never as a flat\n * dotted id at top level, which LikeC4 rejects. The additions carry no marker\n * comment: which archive added what is the git history's to say.\n *\n * Existence is checked semantically against the parsed landscape AND against\n * every extending model the request carries (by element id/title and by edge\n * identity), so re-archiving is idempotent whichever document the additions\n * landed in — `./identity/existing.ts` holds that phase and its two joins, and\n * this function only turns the collision it reports into the refusal.\n *\n * Splicing is text surgery, so the computed result is PARSED before it is\n * returned: a merged landscape LikeC4 rejects refuses the archive at plan time\n * (merge-failed, nothing written — the unparseable-delta discipline) instead\n * of landing in the living docs.\n *\n * NOT EVERYTHING LANDS HERE. A service whose model EXTENDS this map owns its\n * own interior, and an addition nested under such a service is ROUTED to that\n * model instead (`./identity/owner.ts` decides, `./model/merge.ts` splices).\n * Until it was, a delta's container landed in the map and the service was\n * `c4.invalid` — a duplicate declaration — the moment its model wrote the same\n * container, which is exactly what the adopt brief tells it to do\n * (verification 2026-09-04, E1). With no extending models in the request this\n * function behaves as it always did.\n *\n * Routing per ADDITION is not the whole of it, because a service the feature\n * INTRODUCES carries its interior in one element's authored bytes and those\n * children carry no feature tag of their own. `./identity/interior.ts` decides, once\n * per such block, whether it hands that interior to the model — cut out of what\n * lands on the map — or rides whole; the routing below DEFERS to that decision\n * for everything written inside the block, which is what keeps the two from\n * placing the same child twice.\n */\nexport async function planLandscapeMerge(merge: LandscapeMergeRequest): Promise<LandscapePlan> {\n const { landscapeText: text, deltaText, deltaElements, newEls, newRels, featureId } = merge;\n const models = merge.models ?? [];\n // First, and before the early return for \"nothing to add\": a block this merge\n // cannot carry is lost whether or not the delta also has tagged elements to\n // splice. See delta-blocks.ts.\n assertMergeableDelta(deltaText);\n const land = await loadSource(text);\n if (land.errors.length > 0) {\n throw new LandscapeSpliceError(`landscape.likec4 has ${land.errors.length} error(s) — fix it before archiving`);\n }\n // Service binding for the existence joins AND for routing and placement:\n // living elements first (they win a shared id), the delta's after — a spliced\n // statement's id resolves to its service the moment its bytes land in the scan.\n const bindEls = [...land.elements, ...deltaElements.filter((d) => !land.elements.some((l) => l.id === d.id))];\n // What the living fleet already has — the map AND every extending model, by id\n // and by title. `./identity/existing.ts` holds both joins and their asymmetry.\n const added = newAdditions({\n livingEls: land.elements,\n livingRels: land.relationships,\n bindEls,\n deltaElements,\n candidates: { els: newEls, rels: newRels },\n models,\n });\n if (added.collision !== undefined) {\n const { addition: e, living: m } = added.collision;\n throw new LandscapeSpliceError(\n `the delta's '${e.id}' (bound to service '${e.service}') shares the title '${e.title}' with '${m.id}' (bound to service '${m.service}') — a title join across services would silently drop the addition; ` +\n `retitle one of them, or reuse the id '${m.id}' if they really are the same element`,\n );\n }\n const addedEls = added.els;\n const addedRels = added.rels;\n\n const owner = ownerOf({\n bindEls,\n living: new Set(land.elements.map((e) => e.id)),\n declared: added.declaredIds,\n added: new Set(addedEls.map((e) => e.id)),\n models,\n });\n // Nothing to add: the same shape the merge returned before routing existed,\n // and the reason it is decided HERE rather than after the loops below — a\n // no-op archive must not have to scan the delta, nor answer the landscape\n // guards further down, which refuse documents this merge is not touching.\n // Equivalent to the old \"nothing reached the map and nothing was routed\":\n // every addition ends up in one of those two, so an empty pair means both.\n if (addedEls.length === 0 && addedRels.length === 0) {\n return { content: null, addedEls: [], addedRels: [], models: [] };\n }\n\n const scan = scanModel(deltaText);\n if (scan === null) {\n throw new LandscapeSpliceError(\"delta.likec4 has no model block — nothing to splice the additions from\");\n }\n\n // Everything below either locates a declaration's authored bytes or refuses.\n // `spliced` remembers the delta ranges already carried over, so a child whose\n // parent is itself new is recognised as riding inside the parent's text and\n // is never inserted twice.\n const byId = new Map(scan.elements.map((e) => [e.id, e]));\n // Relationships: match each parsed addition back to its statement in the\n // delta source — full identity (`relStatementKey`), consumed one statement\n // per addition so duplicates stay duplicates. Built before the routing\n // because routing has to know WHERE an edge was written: one drawn inside a\n // block that rides whole is already on the map.\n const pool = new Map<string, ScannedRel[]>();\n for (const s of scan.rels) {\n const k = relStatementKey(s);\n pool.set(k, [...(pool.get(k) ?? []), s]);\n }\n\n const interiors = planInteriors({ scan, deltaElements, owner, addedEls });\n const routed = new Map<string, ModelAdditions>();\n const into = (model: ExtendingModel): ModelAdditions => {\n const existing = routed.get(model.path);\n if (existing !== undefined) return existing;\n const fresh: ModelAdditions = { model, els: [], rels: [] };\n routed.set(model.path, fresh);\n return fresh;\n };\n for (const share of interiors.routed) into(share.model).els.push(...share.els);\n\n const mapEls: Elem[] = [];\n for (const e of addedEls) {\n const src = byId.get(e.id);\n // Written inside a block that has already decided: a split block handed it\n // to the model with its siblings, and a whole one carries it onto the map\n // in the parent's own bytes, where the splice loop's `rides` finds it. Both\n // are placed exactly once, which is the point of asking the block first.\n const fate = src === undefined ? null : interiors.covering(src);\n if (fate === \"split\") continue;\n const model = fate === \"whole\" ? undefined : owner(parentIdOf(e.id));\n if (model === undefined) mapEls.push(e);\n else into(model).els.push(e);\n }\n const mapRels: Rel[] = [];\n for (const r of addedRels) {\n // An edge written inside a block that rides whole names its endpoints by\n // their LOCAL names and reads only there; it stays with its block.\n const stmts = pool.get(relStatementKey(r)) ?? [];\n const inBlock = stmts.length > 0 && stmts.every((s) => interiors.covering(s) !== null);\n // Otherwise the SOURCE decides: a call is drawn where the caller draws its\n // calls, and only when the source is not itself interior does the target's\n // owner get the edge. A service-level edge belongs to neither and stays on\n // the map.\n const model = inBlock ? undefined : owner(parentIdOf(r.source)) ?? owner(parentIdOf(r.target));\n if (model === undefined) mapRels.push(r);\n else into(model).rels.push(r);\n }\n const touchesMap = mapEls.length > 0 || mapRels.length > 0;\n\n const spliced: Array<{ start: number; end: number }> = [];\n const rides = (start: number, end: number): boolean =>\n spliced.some((r) => start >= r.start && end <= r.end);\n\n // The living model, scanned on MASKED source (scanModel) and RE-SCANNED\n // after every splice: each addition lands in the text exactly as the\n // previous one left it, so an archive of N additions produces the same\n // bytes as N single-addition archives run back to back. Placement then\n // composes per statement — the unit the order-independence argument below\n // is stated in — instead of per archive, where a batch computed against a\n // stale layout could interleave with itself. Masking matters — a `model {`\n // spelled inside a comment or string above the real block must not capture\n // the match, or every top-level addition lands inside the comment (legal\n // LikeC4, so the parse net below would pass a landscape containing none of\n // the architecture).\n let content = text;\n let livingScan = scanModel(content);\n let stmts = livingScan === null ? [] : topStatements(livingScan, bindEls);\n const rescan = (): void => {\n livingScan = scanModel(content);\n stmts = livingScan === null ? [] : topStatements(livingScan, bindEls);\n };\n const requireModel = (): ScannedModel => {\n if (livingScan === null) throw new LandscapeSpliceError(\"landscape.likec4 has no model block\");\n return livingScan;\n };\n // Built fresh at every use, never captured: `content` and `stmts` are rebound\n // by each rescan, and a region assembled before a splice describes a document\n // that no longer exists.\n const modelRegion = (): ModelRegion => ({ text: content, stmts, blocks: requireModel().blocks });\n const applyAt = (at: number, insert: string): void => {\n content = content.slice(0, at) + insert + content.slice(at);\n rescan();\n };\n const applyTop = (spot: Spot, block: string): void => {\n // A bare spot shares its line with other text (the closing brace, or a\n // statement the block displaces) — it brings its own newlines; a\n // line-start spot slots between lines.\n applyAt(spot.at, spot.bare ? `\\n${block}\\n` : `${block}\\n`);\n };\n\n // Placement walks the scanned statement layout, so a declaration the scan\n // cannot see is one placement would blindly splice around — LikeC4 accepts\n // two declarations on one line, but scanModel's statement head runs to the\n // end of the line, so the second rides invisibly inside the first: an\n // element bound to its service would miss its neighborhood, and a bodyless\n // parent gaining a body could wrap the wrong declaration. Refuse\n // mechanically (the parse-net discipline) instead of splicing blind.\n //\n // THAT something is unlocated is decided here, from the parse already in\n // hand; WHAT and why is `firstUnlocated`'s, at the price of a second parse on\n // this path alone. The message used to guess \"most often two declarations\n // sharing one line\" whatever the map held, and a fleet read it over a\n // declaration on a line of its own in a second `model { }` block the scan\n // did not read then (2026-10): it names LikeC4's line now, and a shared line\n // only when that line shows one.\n if (livingScan !== null) {\n const seen = new Set(livingScan.elements.map((e) => e.id));\n const blind = land.elements.some((e) => !seen.has(e.id)) || livingScan.rels.length < land.relationships.length;\n if (blind) throw new LandscapeSpliceError(unlocatedReason(\"landscape.likec4\", await firstUnlocated(text, livingScan)));\n }\n\n const livingParentOf = (parentId: string): ScannedElement | null => {\n if (livingScan === null) return null;\n const direct = livingScan.elements.find((e) => e.id === parentId);\n if (direct !== undefined) return direct;\n // The delta may spell an existing element under its own id; the title is\n // the stable cross-namespace name (the same rule the existence check uses).\n const title = deltaElements.find((e) => e.id === parentId)?.title;\n const livingId = title === undefined ? undefined : land.elements.find((e) => e.title === title)?.id;\n if (livingId === undefined) return null;\n return livingScan.elements.find((e) => e.id === livingId) ?? null;\n };\n\n // Ancestors first: a spliced parent covers its children before they are seen.\n const depth = (id: string): number => id.split(\".\").length;\n const sortedEls = [...mapEls].sort(\n (a, b) => depth(a.id) - depth(b.id) || (byId.get(a.id)?.start ?? 0) - (byId.get(b.id)?.start ?? 0),\n );\n for (const e of sortedEls) {\n const src = byId.get(e.id);\n if (src === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate '${e.id}' in delta.likec4 — the landscape merge splices authored source, and this declaration was not found`,\n );\n }\n if (rides(src.start, src.end)) continue;\n // Every split block's children, whichever block they belong to:\n // `spliceSource` keeps only the ranges that fall inside the bytes it is\n // carrying, so a block riding inside ANOTHER new block still loses its own\n // interior on the way to the map.\n const omit = interiors.omit;\n const dot = e.id.lastIndexOf(\".\");\n if (dot === -1) {\n const spot = elementSpot(modelRegion(), e.id, elementService(e));\n applyTop(spot, spliceSource(deltaText, src, { featureId, indent: \" \", omit }));\n spliced.push({ start: src.start, end: src.end });\n continue;\n }\n const parentId = e.id.slice(0, dot);\n const parent = livingParentOf(parentId);\n if (parent === null) {\n throw new LandscapeSpliceError(\n `'${e.id}' nests under '${parentId}', which is neither in the living landscape nor added by this delta — there is nowhere to insert it`,\n );\n }\n const nested = nestedInsert(\n content,\n parent,\n spliceSource(deltaText, src, { featureId, indent: parent.indent + \" \", omit }),\n );\n applyAt(nested.at, nested.insert);\n spliced.push({ start: src.start, end: src.end });\n }\n\n // Each map-bound addition takes its statement out of the pool built above:\n // one statement per addition, so duplicates stay duplicates.\n for (const r of mapRels) {\n const s = pool.get(relStatementKey(r))?.shift();\n if (s === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate the '${r.source} -> ${r.target}' relationship in delta.likec4 — the landscape merge splices authored source, and no matching declaration was found`,\n );\n }\n if (rides(s.start, s.end)) continue;\n const key = relSortKey(deltaElements, r);\n // Deliberately no `known` fleet set: this resolves only the anchor a new\n // relationship lands after (placement.ts's reason — cosmetic grouping,\n // safety-netted by the re-parse below), never which service a check\n // grades.\n const spot = relSpot(modelRegion(), serviceOf(deltaElements, r.source), key);\n applyTop(spot, spliceSource(deltaText, s, { featureId, indent: \" \" }));\n }\n\n // The safety net: prove the computed landscape parses before anything is\n // written. Splice bugs — and legal inputs the living document cannot absorb,\n // like a kind its specification never declares — refuse here, at plan time,\n // instead of corrupting the one file the whole fleet reads. Skipped when\n // every addition was routed away: the text is the one already parsed above,\n // and the models get their own net from the caller, which is the only side\n // that can stage a model beside the map it extends.\n // The splice composed bytes from two documents, and the delta's newlines are\n // not necessarily the map's. Corrected before the net, so what is proven is\n // what would be written.\n content = matchLineEndings(text, content);\n if (touchesMap) {\n const check = await loadSource(content);\n if (check.errors.length > 0) {\n const detail = check.errors\n .slice(0, 3)\n .map(errorText)\n .join(\"; \");\n throw new LandscapeSpliceError(\n `the merged landscape would not parse (${check.errors.length} error(s): ${detail}) — nothing was written. ` +\n `The delta's additions do not fit the living landscape as authored — most often an element kind or tag ` +\n `its specification block does not declare; fix the landscape's specification or the delta, then re-run`,\n );\n }\n }\n\n return { content: touchesMap ? content : null, addedEls: mapEls, addedRels: mapRels, models: [...routed.values()] };\n}\n"]}
@@ -2,7 +2,7 @@ import { scanModel } from "../../source-scan.js";
2
2
  import { matchLineEndings, spliceSource } from "../authored-source.js";
3
3
  import { LandscapeSpliceError } from "../contract.js";
4
4
  import { relStatementKey } from "../identity/edges.js";
5
- import { closeSpot, nestedInsert, spotAfter } from "../placement.js";
5
+ import { closeSpot, HOME_BLOCK, nestedInsert, spotAfter } from "../placement.js";
6
6
  /** The merged model source. Refuses (never guesses) when the delta or the model cannot be read. */
7
7
  export function spliceModel(req) {
8
8
  const { additions, deltaText, featureId } = req;
@@ -56,12 +56,15 @@ export function spliceModel(req) {
56
56
  }
57
57
  if (rides(s.start, s.end))
58
58
  continue;
59
- const base = blockIndent(content, live.close);
59
+ const { close } = live.blocks[HOME_BLOCK];
60
+ const base = blockIndent(content, close);
60
61
  // Top-level in the model block: an edge written inside an `extend` block is
61
62
  // that block's, and anchoring after it would splice into someone's body.
62
- const top = live.rels.filter((x) => !live.elements.some((el) => x.start > el.start && x.start < el.end));
63
+ // And in the HOME block: the anchor's own close is what `spotAfter` clamps
64
+ // to, and an edge last in a later block would otherwise pull this one there.
65
+ const top = live.rels.filter((x) => x.block === HOME_BLOCK && !live.elements.some((el) => x.start > el.start && x.start < el.end));
63
66
  const anchor = top.at(-1);
64
- const spot = anchor === undefined ? closeSpot(content, live.close) : spotAfter(content, live.close, anchor.end);
67
+ const spot = anchor === undefined ? closeSpot(content, close) : spotAfter(content, close, anchor.end);
65
68
  const block = spliceSource(deltaText, s, { featureId, indent: `${base} ` });
66
69
  applyAt(spot.at, spot.bare ? `\n${block}\n` : `${block}\n`);
67
70
  }
@@ -91,9 +94,10 @@ function elementInsert(req) {
91
94
  const nested = nestedInsert(content, declared, block(`${declared.indent} `));
92
95
  return [nested.at, nested.insert];
93
96
  }
94
- const base = blockIndent(content, live.close);
97
+ const { close } = live.blocks[HOME_BLOCK];
98
+ const base = blockIndent(content, close);
95
99
  const body = `${base} extend ${parent} {\n${block(`${base} `)}\n${base} }`;
96
- const spot = closeSpot(content, live.close);
100
+ const spot = closeSpot(content, close);
97
101
  return [spot.at, spot.bare ? `\n${body}\n` : `${body}\n`];
98
102
  }
99
103
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../../../src/core/c4/splice/model/merge.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The other half of the archive's C4 merge: what a feature adds INSIDE a\n * service, spliced into the service's own extending `model.likec4`.\n *\n * `../landscape-merge.ts` routes the additions (`../identity/owner.ts` states\n * the rule) and this carries them over, by the same discipline: authored source,\n * byte for byte,\n * with the feature's own tag stripped and the indentation rebased — never a\n * re-serialization of the parsed model, which keeps only the fields loam models.\n *\n * PLACEMENT IS SIMPLER HERE, and deliberately so. The map groups additions by\n * service because every service writes into it and concurrent archives must\n * merge in git; a service model has ONE service in it, so there is no\n * neighborhood to join. An element lands inside the `extend <fqn> { … }` block\n * that owns its parent — or inside its parent's own block when the model\n * already declares that container — and a model with no `extend` block for the\n * fqn gains one at the end of its `model { }` block, as a model with no `model\n * { }` block at all gains that. A relationship lands after the last top-level\n * relationship of that block, or last in it.\n *\n * WHAT THIS DOES NOT DO IS PROVE THE RESULT. The landscape merge parses its own\n * output because a landscape is a self-contained document; an extending model\n * is not — it is read beside the `architecture/` project, and staging that set\n * means touching the docs repo. So the parse net lives with the caller\n * (`commands/archive/plan/model/extending.ts`), which is also the side that\n * holds the merged MAP the model must be proven against.\n */\nimport type { Elem } from \"../../likec4.js\";\nimport { scanModel, type ScannedModel, type ScannedRel } from \"../../source-scan.js\";\nimport { matchLineEndings, spliceSource } from \"../authored-source.js\";\nimport { LandscapeSpliceError, type ModelAdditions } from \"../contract.js\";\nimport { relStatementKey } from \"../identity/edges.js\";\nimport { closeSpot, nestedInsert, spotAfter } from \"../placement.js\";\n\nexport interface ModelMergeRequest {\n /** One model's share of the merge, as `planLandscapeMerge` routed it. */\n additions: ModelAdditions;\n /** delta.likec4 as authored — the bytes the additions are spliced from. */\n deltaText: string;\n featureId: string;\n}\n\n/** The merged model source. Refuses (never guesses) when the delta or the model cannot be read. */\nexport function spliceModel(req: ModelMergeRequest): string {\n const { additions, deltaText, featureId } = req;\n const { model } = additions;\n const scan = scanModel(deltaText);\n if (scan === null) {\n throw new LandscapeSpliceError(\"delta.likec4 has no model block — nothing to splice the additions from\");\n }\n const byId = new Map(scan.elements.map((e) => [e.id, e]));\n const pool = new Map<string, ScannedRel[]>();\n for (const s of scan.rels) {\n const k = relStatementKey(s);\n pool.set(k, [...(pool.get(k) ?? []), s]);\n }\n\n let content = withModelBlock(model.text);\n let live = read(content, model.path);\n // The delta ranges already carried over, so a child whose parent is itself\n // new is recognised as riding inside the parent's text — the same rule the\n // landscape merge states, and the reason `node` inside a new `cache` is never\n // spliced twice.\n const spliced: Array<{ start: number; end: number }> = [];\n const rides = (start: number, end: number): boolean =>\n spliced.some((r) => start >= r.start && end <= r.end);\n const applyAt = (at: number, insert: string): void => {\n content = content.slice(0, at) + insert + content.slice(at);\n live = read(content, model.path);\n };\n\n // Ancestors first, exactly as the landscape merge orders them: a spliced\n // parent covers its children before they are seen.\n const depth = (id: string): number => id.split(\".\").length;\n const ordered = [...additions.els].sort(\n (a, b) => depth(a.id) - depth(b.id) || (byId.get(a.id)?.start ?? 0) - (byId.get(b.id)?.start ?? 0),\n );\n for (const e of ordered) {\n const src = byId.get(e.id);\n if (src === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate '${e.id}' in delta.likec4 — the model merge splices authored source, and this declaration was not found`,\n );\n }\n if (rides(src.start, src.end)) continue;\n const [at, insert] = elementInsert({\n content,\n live,\n block: (indent) => spliceSource(deltaText, src, { featureId, indent }),\n parent: parentIdOf(e),\n });\n applyAt(at, insert);\n spliced.push({ start: src.start, end: src.end });\n }\n\n for (const r of additions.rels) {\n const s = pool.get(relStatementKey(r))?.shift();\n if (s === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate the '${r.source} -> ${r.target}' relationship in delta.likec4 — the model merge splices authored source, and no matching declaration was found`,\n );\n }\n if (rides(s.start, s.end)) continue;\n const base = blockIndent(content, live.close);\n // Top-level in the model block: an edge written inside an `extend` block is\n // that block's, and anchoring after it would splice into someone's body.\n const top = live.rels.filter((x) => !live.elements.some((el) => x.start > el.start && x.start < el.end));\n const anchor = top.at(-1);\n const spot = anchor === undefined ? closeSpot(content, live.close) : spotAfter(content, live.close, anchor.end);\n const block = spliceSource(deltaText, s, { featureId, indent: `${base} ` });\n applyAt(spot.at, spot.bare ? `\\n${block}\\n` : `${block}\\n`);\n }\n // The delta's newlines are not necessarily this model's, and a merge that left\n // both conventions in one file is noise in every editor and every diff — the\n // same correction the landscape merge makes, from the same helper\n // (verification 2026-09-04, W-CRLF).\n return matchLineEndings(model.text, content);\n}\n\n/** The parent an addition nests under. Routing only ever sends nested ids here. */\nfunction parentIdOf(e: Elem): string {\n return e.id.slice(0, e.id.lastIndexOf(\".\"));\n}\n\ninterface ElementInsert {\n content: string;\n live: ScannedModel;\n /** The authored block at a given indent — computed late, because the indent depends on where it lands. */\n block: (indent: string) => string;\n parent: string;\n}\n\n/**\n * Where one element's block goes, as `(offset, text)`.\n *\n * Two arms, and the second is the one that makes a freshly adopted service\n * work: a model that has never named this container's parent has no `extend`\n * block for it, so the merge writes one rather than refusing. A parent the\n * merged project will not resolve is caught by the caller's parse net, which is\n * the only reader that can see the map and the model together.\n */\nfunction elementInsert(req: ElementInsert): [number, string] {\n const { content, live, block, parent } = req;\n const declared = live.elements.find((x) => x.id === parent);\n if (declared !== undefined) {\n const nested = nestedInsert(content, declared, block(`${declared.indent} `));\n return [nested.at, nested.insert];\n }\n const base = blockIndent(content, live.close);\n const body = `${base} extend ${parent} {\\n${block(`${base} `)}\\n${base} }`;\n const spot = closeSpot(content, live.close);\n return [spot.at, spot.bare ? `\\n${body}\\n` : `${body}\\n`];\n}\n\n/**\n * The model, with a `model { }` block appended when the file has none.\n *\n * `../../service-model/shape.ts` answers `extending` for an empty file, a\n * views-only file and a tags-only `specification { }` — three shapes it calls\n * legal on purpose — so routing hands those models a nested addition, and\n * refusing there took a whole legal shape away from `loam archive` for a\n * document the merge is perfectly able to author (review of E1: before the\n * routing existed, the same delta merged onto the map). It is the call\n * `elementInsert` already makes one level down — a model that has never named\n * the parent gains the `extend` block rather than refusing — and the caller's\n * parse net proves the result either way.\n */\nfunction withModelBlock(text: string): string {\n if (scanModel(text) !== null) return text;\n const pad = text === \"\" || text.endsWith(\"\\n\") ? \"\" : \"\\n\";\n return `${text}${pad}model {\\n}\\n`;\n}\n\n/**\n * The model's `model { }` block, re-scanned after every splice so each addition\n * lands in the text the previous one left — the landscape merge's rule, for the\n * same reason: placement composes per statement, not per archive.\n *\n * `withModelBlock` guarantees the FIRST read finds one, so a null here means a\n * splice destroyed the block it was writing into: mechanical, so it refuses at\n * plan time with nothing written, exactly as the parse nets do.\n */\nfunction read(content: string, path: string): ScannedModel {\n const scan = scanModel(content);\n if (scan === null) {\n throw new LandscapeSpliceError(\n `merging this feature's additions left ${path} without a model block — nothing was written; re-run after reporting it`,\n );\n }\n return scan;\n}\n\n/** The indentation of the line the model block's closing brace sits on, or \"\" when it shares one. */\nfunction blockIndent(text: string, close: number): string {\n const lineStart = text.lastIndexOf(\"\\n\", close - 1) + 1;\n const before = text.slice(lineStart, close);\n return /^[ \\t]*$/.test(before) ? before : \"\";\n}\n"]}
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../../../src/core/c4/splice/model/merge.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The other half of the archive's C4 merge: what a feature adds INSIDE a\n * service, spliced into the service's own extending `model.likec4`.\n *\n * `../landscape-merge.ts` routes the additions (`../identity/owner.ts` states\n * the rule) and this carries them over, by the same discipline: authored source,\n * byte for byte,\n * with the feature's own tag stripped and the indentation rebased — never a\n * re-serialization of the parsed model, which keeps only the fields loam models.\n *\n * PLACEMENT IS SIMPLER HERE, and deliberately so. The map groups additions by\n * service because every service writes into it and concurrent archives must\n * merge in git; a service model has ONE service in it, so there is no\n * neighborhood to join. An element lands inside the `extend <fqn> { … }` block\n * that owns its parent — or inside its parent's own block when the model\n * already declares that container — and a model with no `extend` block for the\n * fqn gains one at the end of its `model { }` block, as a model with no `model\n * { }` block at all gains that. A relationship lands after the last top-level\n * relationship of that block, or last in it. A model written in SEVERAL\n * `model { }` blocks is read whole — a parent's `extend` frame is found in\n * whichever block holds it — and \"its block\" for everything else is\n * `HOME_BLOCK`, the first, for the reasons `../placement.ts` gives the map.\n *\n * WHAT THIS DOES NOT DO IS PROVE THE RESULT. The landscape merge parses its own\n * output because a landscape is a self-contained document; an extending model\n * is not — it is read beside the `architecture/` project, and staging that set\n * means touching the docs repo. So the parse net lives with the caller\n * (`commands/archive/plan/model/extending.ts`), which is also the side that\n * holds the merged MAP the model must be proven against.\n */\nimport type { Elem } from \"../../likec4.js\";\nimport { scanModel, type ScannedModel, type ScannedRel } from \"../../source-scan.js\";\nimport { matchLineEndings, spliceSource } from \"../authored-source.js\";\nimport { LandscapeSpliceError, type ModelAdditions } from \"../contract.js\";\nimport { relStatementKey } from \"../identity/edges.js\";\nimport { closeSpot, HOME_BLOCK, nestedInsert, spotAfter } from \"../placement.js\";\n\nexport interface ModelMergeRequest {\n /** One model's share of the merge, as `planLandscapeMerge` routed it. */\n additions: ModelAdditions;\n /** delta.likec4 as authored — the bytes the additions are spliced from. */\n deltaText: string;\n featureId: string;\n}\n\n/** The merged model source. Refuses (never guesses) when the delta or the model cannot be read. */\nexport function spliceModel(req: ModelMergeRequest): string {\n const { additions, deltaText, featureId } = req;\n const { model } = additions;\n const scan = scanModel(deltaText);\n if (scan === null) {\n throw new LandscapeSpliceError(\"delta.likec4 has no model block — nothing to splice the additions from\");\n }\n const byId = new Map(scan.elements.map((e) => [e.id, e]));\n const pool = new Map<string, ScannedRel[]>();\n for (const s of scan.rels) {\n const k = relStatementKey(s);\n pool.set(k, [...(pool.get(k) ?? []), s]);\n }\n\n let content = withModelBlock(model.text);\n let live = read(content, model.path);\n // The delta ranges already carried over, so a child whose parent is itself\n // new is recognised as riding inside the parent's text — the same rule the\n // landscape merge states, and the reason `node` inside a new `cache` is never\n // spliced twice.\n const spliced: Array<{ start: number; end: number }> = [];\n const rides = (start: number, end: number): boolean =>\n spliced.some((r) => start >= r.start && end <= r.end);\n const applyAt = (at: number, insert: string): void => {\n content = content.slice(0, at) + insert + content.slice(at);\n live = read(content, model.path);\n };\n\n // Ancestors first, exactly as the landscape merge orders them: a spliced\n // parent covers its children before they are seen.\n const depth = (id: string): number => id.split(\".\").length;\n const ordered = [...additions.els].sort(\n (a, b) => depth(a.id) - depth(b.id) || (byId.get(a.id)?.start ?? 0) - (byId.get(b.id)?.start ?? 0),\n );\n for (const e of ordered) {\n const src = byId.get(e.id);\n if (src === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate '${e.id}' in delta.likec4 — the model merge splices authored source, and this declaration was not found`,\n );\n }\n if (rides(src.start, src.end)) continue;\n const [at, insert] = elementInsert({\n content,\n live,\n block: (indent) => spliceSource(deltaText, src, { featureId, indent }),\n parent: parentIdOf(e),\n });\n applyAt(at, insert);\n spliced.push({ start: src.start, end: src.end });\n }\n\n for (const r of additions.rels) {\n const s = pool.get(relStatementKey(r))?.shift();\n if (s === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate the '${r.source} -> ${r.target}' relationship in delta.likec4 — the model merge splices authored source, and no matching declaration was found`,\n );\n }\n if (rides(s.start, s.end)) continue;\n const { close } = live.blocks[HOME_BLOCK]!;\n const base = blockIndent(content, close);\n // Top-level in the model block: an edge written inside an `extend` block is\n // that block's, and anchoring after it would splice into someone's body.\n // And in the HOME block: the anchor's own close is what `spotAfter` clamps\n // to, and an edge last in a later block would otherwise pull this one there.\n const top = live.rels.filter(\n (x) => x.block === HOME_BLOCK && !live.elements.some((el) => x.start > el.start && x.start < el.end),\n );\n const anchor = top.at(-1);\n const spot = anchor === undefined ? closeSpot(content, close) : spotAfter(content, close, anchor.end);\n const block = spliceSource(deltaText, s, { featureId, indent: `${base} ` });\n applyAt(spot.at, spot.bare ? `\\n${block}\\n` : `${block}\\n`);\n }\n // The delta's newlines are not necessarily this model's, and a merge that left\n // both conventions in one file is noise in every editor and every diff — the\n // same correction the landscape merge makes, from the same helper\n // (verification 2026-09-04, W-CRLF).\n return matchLineEndings(model.text, content);\n}\n\n/** The parent an addition nests under. Routing only ever sends nested ids here. */\nfunction parentIdOf(e: Elem): string {\n return e.id.slice(0, e.id.lastIndexOf(\".\"));\n}\n\ninterface ElementInsert {\n content: string;\n live: ScannedModel;\n /** The authored block at a given indent — computed late, because the indent depends on where it lands. */\n block: (indent: string) => string;\n parent: string;\n}\n\n/**\n * Where one element's block goes, as `(offset, text)`.\n *\n * Two arms, and the second is the one that makes a freshly adopted service\n * work: a model that has never named this container's parent has no `extend`\n * block for it, so the merge writes one rather than refusing. A parent the\n * merged project will not resolve is caught by the caller's parse net, which is\n * the only reader that can see the map and the model together.\n */\nfunction elementInsert(req: ElementInsert): [number, string] {\n const { content, live, block, parent } = req;\n const declared = live.elements.find((x) => x.id === parent);\n if (declared !== undefined) {\n const nested = nestedInsert(content, declared, block(`${declared.indent} `));\n return [nested.at, nested.insert];\n }\n const { close } = live.blocks[HOME_BLOCK]!;\n const base = blockIndent(content, close);\n const body = `${base} extend ${parent} {\\n${block(`${base} `)}\\n${base} }`;\n const spot = closeSpot(content, close);\n return [spot.at, spot.bare ? `\\n${body}\\n` : `${body}\\n`];\n}\n\n/**\n * The model, with a `model { }` block appended when the file has none.\n *\n * `../../service-model/shape.ts` answers `extending` for an empty file, a\n * views-only file and a tags-only `specification { }` — three shapes it calls\n * legal on purpose — so routing hands those models a nested addition, and\n * refusing there took a whole legal shape away from `loam archive` for a\n * document the merge is perfectly able to author (review of E1: before the\n * routing existed, the same delta merged onto the map). It is the call\n * `elementInsert` already makes one level down — a model that has never named\n * the parent gains the `extend` block rather than refusing — and the caller's\n * parse net proves the result either way.\n */\nfunction withModelBlock(text: string): string {\n if (scanModel(text) !== null) return text;\n const pad = text === \"\" || text.endsWith(\"\\n\") ? \"\" : \"\\n\";\n return `${text}${pad}model {\\n}\\n`;\n}\n\n/**\n * The model's `model { }` block, re-scanned after every splice so each addition\n * lands in the text the previous one left — the landscape merge's rule, for the\n * same reason: placement composes per statement, not per archive.\n *\n * `withModelBlock` guarantees the FIRST read finds one, so a null here means a\n * splice destroyed the block it was writing into: mechanical, so it refuses at\n * plan time with nothing written, exactly as the parse nets do.\n */\nfunction read(content: string, path: string): ScannedModel {\n const scan = scanModel(content);\n if (scan === null) {\n throw new LandscapeSpliceError(\n `merging this feature's additions left ${path} without a model block — nothing was written; re-run after reporting it`,\n );\n }\n return scan;\n}\n\n/** The indentation of the line the model block's closing brace sits on, or \"\" when it shares one. */\nfunction blockIndent(text: string, close: number): string {\n const lineStart = text.lastIndexOf(\"\\n\", close - 1) + 1;\n const before = text.slice(lineStart, close);\n return /^[ \\t]*$/.test(before) ? before : \"\";\n}\n"]}