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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1026) hide show
  1. package/CHANGELOG.md +2548 -86
  2. package/COMPARISON.md +80 -63
  3. package/CONTRIBUTING.md +84 -0
  4. package/MIGRATING-from-OpenSpec.md +213 -54
  5. package/QUICKSTART.md +125 -0
  6. package/README.md +450 -150
  7. package/ROADMAP.md +494 -0
  8. package/SCHEMA.md +2355 -256
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +701 -0
  11. package/dist/cli.js +113 -19
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +209 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +268 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +77 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/openapi.js +159 -0
  22. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  23. package/dist/commands/archive/plan/gate.js +317 -0
  24. package/dist/commands/archive/plan/gate.js.map +1 -0
  25. package/dist/commands/archive/plan/landscape.js +161 -0
  26. package/dist/commands/archive/plan/landscape.js.map +1 -0
  27. package/dist/commands/archive/plan/refusal.js +111 -0
  28. package/dist/commands/archive/plan/refusal.js.map +1 -0
  29. package/dist/commands/archive/plan/specs.js +237 -0
  30. package/dist/commands/archive/plan/specs.js.map +1 -0
  31. package/dist/commands/archive/plan/state.js +27 -0
  32. package/dist/commands/archive/plan/state.js.map +1 -0
  33. package/dist/commands/archive/run.js +251 -0
  34. package/dist/commands/archive/run.js.map +1 -0
  35. package/dist/commands/context/context.js +99 -0
  36. package/dist/commands/context/context.js.map +1 -0
  37. package/dist/commands/context/print.js +283 -0
  38. package/dist/commands/context/print.js.map +1 -0
  39. package/dist/commands/delta/delta.js +279 -0
  40. package/dist/commands/delta/delta.js.map +1 -0
  41. package/dist/commands/delta/print.js +205 -0
  42. package/dist/commands/delta/print.js.map +1 -0
  43. package/dist/commands/dependencies.js +9 -7
  44. package/dist/commands/dependencies.js.map +1 -1
  45. package/dist/commands/diff/diff.js +93 -0
  46. package/dist/commands/diff/diff.js.map +1 -0
  47. package/dist/commands/diff/print.js +38 -0
  48. package/dist/commands/diff/print.js.map +1 -0
  49. package/dist/commands/doctor.js +5 -4
  50. package/dist/commands/doctor.js.map +1 -1
  51. package/dist/commands/explain/explain.js +151 -0
  52. package/dist/commands/explain/explain.js.map +1 -0
  53. package/dist/commands/explore.js +29 -24
  54. package/dist/commands/explore.js.map +1 -1
  55. package/dist/commands/gate/gate.js +115 -0
  56. package/dist/commands/gate/gate.js.map +1 -0
  57. package/dist/commands/gate/print.js +54 -0
  58. package/dist/commands/gate/print.js.map +1 -0
  59. package/dist/commands/gherkin/commit.js +146 -0
  60. package/dist/commands/gherkin/commit.js.map +1 -0
  61. package/dist/commands/gherkin/gherkin.js +246 -0
  62. package/dist/commands/gherkin/gherkin.js.map +1 -0
  63. package/dist/commands/gherkin/reconcile.js +149 -0
  64. package/dist/commands/gherkin/reconcile.js.map +1 -0
  65. package/dist/commands/gherkin/render.js +77 -0
  66. package/dist/commands/gherkin/render.js.map +1 -0
  67. package/dist/commands/init/example.js +204 -0
  68. package/dist/commands/init/example.js.map +1 -0
  69. package/dist/commands/init/first-hour.js +28 -0
  70. package/dist/commands/init/first-hour.js.map +1 -0
  71. package/dist/commands/{init.js → init/init.js} +146 -71
  72. package/dist/commands/init/init.js.map +1 -0
  73. package/dist/commands/init/mcp.js +131 -0
  74. package/dist/commands/init/mcp.js.map +1 -0
  75. package/dist/commands/init/options.js +78 -0
  76. package/dist/commands/init/options.js.map +1 -0
  77. package/dist/commands/instructions.js +72 -14
  78. package/dist/commands/instructions.js.map +1 -1
  79. package/dist/commands/list/campaign/campaign.js +65 -0
  80. package/dist/commands/list/campaign/campaign.js.map +1 -0
  81. package/dist/commands/list/campaign/owners.js +65 -0
  82. package/dist/commands/list/campaign/owners.js.map +1 -0
  83. package/dist/commands/list/json.js +157 -0
  84. package/dist/commands/list/json.js.map +1 -0
  85. package/dist/commands/list/list.js +343 -0
  86. package/dist/commands/list/list.js.map +1 -0
  87. package/dist/commands/list/print.js +301 -0
  88. package/dist/commands/list/print.js.map +1 -0
  89. package/dist/commands/list/review.js +120 -0
  90. package/dist/commands/list/review.js.map +1 -0
  91. package/dist/commands/list/views.js +105 -0
  92. package/dist/commands/list/views.js.map +1 -0
  93. package/dist/commands/mcp/dispatch.js +183 -0
  94. package/dist/commands/mcp/dispatch.js.map +1 -0
  95. package/dist/commands/mcp/mcp.js +34 -0
  96. package/dist/commands/mcp/mcp.js.map +1 -0
  97. package/dist/commands/mcp/serve.js +55 -0
  98. package/dist/commands/mcp/serve.js.map +1 -0
  99. package/dist/commands/migrate-openspec/materialize/active.js +170 -0
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  101. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  102. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  103. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  104. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  105. package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
  106. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  107. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  108. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  109. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  110. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  111. package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
  112. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  113. package/dist/commands/migrate-openspec/openspec/error.js +19 -0
  114. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  115. package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
  116. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  117. package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
  118. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  119. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  120. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  121. package/dist/commands/migrate-openspec/print.js +89 -0
  122. package/dist/commands/migrate-openspec/print.js.map +1 -0
  123. package/dist/commands/new/commit.js +76 -0
  124. package/dist/commands/new/commit.js.map +1 -0
  125. package/dist/commands/new/new.js +283 -0
  126. package/dist/commands/new/new.js.map +1 -0
  127. package/dist/commands/new/templates.js +355 -0
  128. package/dist/commands/new/templates.js.map +1 -0
  129. package/dist/commands/open.js +203 -0
  130. package/dist/commands/open.js.map +1 -0
  131. package/dist/commands/policy/format.js +152 -0
  132. package/dist/commands/policy/format.js.map +1 -0
  133. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
  134. package/dist/commands/policy/gate.js.map +1 -0
  135. package/dist/commands/rebase/edit.js +106 -0
  136. package/dist/commands/rebase/edit.js.map +1 -0
  137. package/dist/commands/rebase/living.js +185 -0
  138. package/dist/commands/rebase/living.js.map +1 -0
  139. package/dist/commands/rebase/plan.js +245 -0
  140. package/dist/commands/rebase/plan.js.map +1 -0
  141. package/dist/commands/rebase/rebase.js +275 -0
  142. package/dist/commands/rebase/rebase.js.map +1 -0
  143. package/dist/commands/seed/commit.js +192 -0
  144. package/dist/commands/seed/commit.js.map +1 -0
  145. package/dist/commands/seed/plan.js +133 -0
  146. package/dist/commands/seed/plan.js.map +1 -0
  147. package/dist/commands/seed/seed.js +172 -0
  148. package/dist/commands/seed/seed.js.map +1 -0
  149. package/dist/commands/show/feature.js +178 -0
  150. package/dist/commands/show/feature.js.map +1 -0
  151. package/dist/commands/show/marks.js +24 -0
  152. package/dist/commands/show/marks.js.map +1 -0
  153. package/dist/commands/{show.js → show/service.js} +63 -152
  154. package/dist/commands/show/service.js.map +1 -0
  155. package/dist/commands/show/show.js +77 -0
  156. package/dist/commands/show/show.js.map +1 -0
  157. package/dist/commands/status/json.js +45 -0
  158. package/dist/commands/status/json.js.map +1 -0
  159. package/dist/commands/status/print.js +157 -0
  160. package/dist/commands/status/print.js.map +1 -0
  161. package/dist/commands/status/status.js +119 -0
  162. package/dist/commands/status/status.js.map +1 -0
  163. package/dist/commands/steps/steps.js +189 -0
  164. package/dist/commands/steps/steps.js.map +1 -0
  165. package/dist/commands/subsystem/edit.js +192 -0
  166. package/dist/commands/subsystem/edit.js.map +1 -0
  167. package/dist/commands/subsystem/move.js +265 -0
  168. package/dist/commands/subsystem/move.js.map +1 -0
  169. package/dist/commands/subsystem/query.js +115 -0
  170. package/dist/commands/subsystem/query.js.map +1 -0
  171. package/dist/commands/subsystem/subsystem.js +101 -0
  172. package/dist/commands/subsystem/subsystem.js.map +1 -0
  173. package/dist/commands/subsystem/sync.js +103 -0
  174. package/dist/commands/subsystem/sync.js.map +1 -0
  175. package/dist/commands/subsystem/txn/txn.js +94 -0
  176. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  177. package/dist/commands/subsystem/txn/views.js +70 -0
  178. package/dist/commands/subsystem/txn/views.js.map +1 -0
  179. package/dist/commands/unarchive/manifest.js +160 -0
  180. package/dist/commands/unarchive/manifest.js.map +1 -0
  181. package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
  182. package/dist/commands/unarchive/restore.js.map +1 -0
  183. package/dist/commands/unarchive/unarchive.js +67 -0
  184. package/dist/commands/unarchive/unarchive.js.map +1 -0
  185. package/dist/commands/validate/arch-coverage.js +194 -0
  186. package/dist/commands/validate/arch-coverage.js.map +1 -0
  187. package/dist/commands/validate/checks/fleet-shape.js +296 -0
  188. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  189. package/dist/commands/validate/checks/health-deps.js +55 -0
  190. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  191. package/dist/commands/validate/checks/requirements.js +254 -0
  192. package/dist/commands/validate/checks/requirements.js.map +1 -0
  193. package/dist/commands/validate/checks/sources.js +76 -0
  194. package/dist/commands/validate/checks/sources.js.map +1 -0
  195. package/dist/commands/validate/checks/vocabulary.js +31 -0
  196. package/dist/commands/validate/checks/vocabulary.js.map +1 -0
  197. package/dist/commands/validate/feature.js +216 -0
  198. package/dist/commands/validate/feature.js.map +1 -0
  199. package/dist/commands/validate/fleet/census.js +69 -0
  200. package/dist/commands/validate/fleet/census.js.map +1 -0
  201. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  202. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  203. package/dist/commands/validate/fleet/landscape.js +353 -0
  204. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  205. package/dist/commands/validate/fleet/load.js +52 -0
  206. package/dist/commands/validate/fleet/load.js.map +1 -0
  207. package/dist/commands/validate/fleet/obligations.js +236 -0
  208. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  209. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  210. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  211. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  212. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  213. package/dist/commands/validate/fleet/scorecard/print.js +63 -0
  214. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  215. package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
  216. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  217. package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
  218. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
  219. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  220. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  221. package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
  222. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
  223. package/dist/commands/validate/fleet/usecases/steps.js +197 -0
  224. package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
  225. package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
  226. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
  227. package/dist/commands/validate/fleet/views/ids.js +40 -0
  228. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  229. package/dist/commands/validate/fleet/views/stale.js +59 -0
  230. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  231. package/dist/commands/validate/links/corpus.js +92 -0
  232. package/dist/commands/validate/links/corpus.js.map +1 -0
  233. package/dist/commands/validate/links/glossary.js +75 -0
  234. package/dist/commands/validate/links/glossary.js.map +1 -0
  235. package/dist/commands/validate/report.js +269 -0
  236. package/dist/commands/validate/report.js.map +1 -0
  237. package/dist/commands/validate/service/api.js +338 -0
  238. package/dist/commands/validate/service/api.js.map +1 -0
  239. package/dist/commands/validate/service/events/events.js +219 -0
  240. package/dist/commands/validate/service/events/events.js.map +1 -0
  241. package/dist/commands/validate/service/events/message-producers.js +77 -0
  242. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  243. package/dist/commands/validate/service/evidence-pins.js +131 -0
  244. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  245. package/dist/commands/validate/service/service.js +250 -0
  246. package/dist/commands/validate/service/service.js.map +1 -0
  247. package/dist/commands/validate/service/specs.js +219 -0
  248. package/dist/commands/validate/service/specs.js.map +1 -0
  249. package/dist/commands/validate/service/spine.js +113 -0
  250. package/dist/commands/validate/service/spine.js.map +1 -0
  251. package/dist/commands/validate/validate.js +338 -0
  252. package/dist/commands/validate/validate.js.map +1 -0
  253. package/dist/commands/verify/cross/diff.js +182 -0
  254. package/dist/commands/verify/cross/diff.js.map +1 -0
  255. package/dist/commands/verify/evidence/contract.js +32 -0
  256. package/dist/commands/verify/evidence/contract.js.map +1 -0
  257. package/dist/commands/verify/evidence/pins.js +52 -0
  258. package/dist/commands/verify/evidence/pins.js.map +1 -0
  259. package/dist/commands/verify/evidence/read.js +72 -0
  260. package/dist/commands/verify/evidence/read.js.map +1 -0
  261. package/dist/commands/verify/frozen.js +241 -0
  262. package/dist/commands/verify/frozen.js.map +1 -0
  263. package/dist/commands/verify/record.js +226 -0
  264. package/dist/commands/verify/record.js.map +1 -0
  265. package/dist/commands/verify/report.js +223 -0
  266. package/dist/commands/verify/report.js.map +1 -0
  267. package/dist/commands/verify/results.js +246 -0
  268. package/dist/commands/verify/results.js.map +1 -0
  269. package/dist/commands/verify/verify.js +217 -0
  270. package/dist/commands/verify/verify.js.map +1 -0
  271. package/dist/commands/vouch/contract.js +11 -0
  272. package/dist/commands/vouch/contract.js.map +1 -0
  273. package/dist/commands/vouch/pack/contract.js +2 -0
  274. package/dist/commands/vouch/pack/contract.js.map +1 -0
  275. package/dist/commands/vouch/pack/pack.js +266 -0
  276. package/dist/commands/vouch/pack/pack.js.map +1 -0
  277. package/dist/commands/vouch/pack/print.js +271 -0
  278. package/dist/commands/vouch/pack/print.js.map +1 -0
  279. package/dist/commands/vouch/pack/sections.js +142 -0
  280. package/dist/commands/vouch/pack/sections.js.map +1 -0
  281. package/dist/commands/vouch/prompt/confirm.js +46 -0
  282. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  283. package/dist/commands/vouch/report.js +101 -0
  284. package/dist/commands/vouch/report.js.map +1 -0
  285. package/dist/commands/vouch/run.js +285 -0
  286. package/dist/commands/vouch/run.js.map +1 -0
  287. package/dist/commands/vouch/sample/plan.js +125 -0
  288. package/dist/commands/vouch/sample/plan.js.map +1 -0
  289. package/dist/commands/vouch/sample/print.js +109 -0
  290. package/dist/commands/vouch/sample/print.js.map +1 -0
  291. package/dist/commands/vouch/vet/verify.js +123 -0
  292. package/dist/commands/vouch/vet/verify.js.map +1 -0
  293. package/dist/commands/vouch/vouch.js +176 -0
  294. package/dist/commands/vouch/vouch.js.map +1 -0
  295. package/dist/core/agent/agents-md/artifacts.js +220 -0
  296. package/dist/core/agent/agents-md/artifacts.js.map +1 -0
  297. package/dist/core/agent/agents-md/command-map.js +324 -0
  298. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  299. package/dist/core/agent/agents-md/cycle.js +165 -0
  300. package/dist/core/agent/agents-md/cycle.js.map +1 -0
  301. package/dist/core/agent/agents-md/map/explain.js +34 -0
  302. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  303. package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
  304. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  305. package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
  306. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  307. package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
  308. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  309. package/dist/core/agent/agents-md/map/mcp.js +41 -0
  310. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  311. package/dist/core/agent/agents-md/map/status.js +62 -0
  312. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  313. package/dist/core/agent/agents-md/map/subsystem.js +32 -0
  314. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  315. package/dist/core/agent/agents-md/map/usecases.js +60 -0
  316. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  317. package/dist/core/agent/agents-md/refusals.js +246 -0
  318. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  319. package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
  320. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
  321. package/dist/core/agent/agents-md/spine.js +40 -0
  322. package/dist/core/agent/agents-md/spine.js.map +1 -0
  323. package/dist/core/agent/agents-md.js +170 -0
  324. package/dist/core/agent/agents-md.js.map +1 -0
  325. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +50 -0
  326. package/dist/core/agent/agents-stamp.js.map +1 -0
  327. package/dist/core/agent/contract.js +2 -0
  328. package/dist/core/agent/contract.js.map +1 -0
  329. package/dist/core/agent/protocol.js +193 -0
  330. package/dist/core/agent/protocol.js.map +1 -0
  331. package/dist/core/agent/scaffold.js +259 -0
  332. package/dist/core/agent/scaffold.js.map +1 -0
  333. package/dist/core/agent/support/report.js +103 -0
  334. package/dist/core/agent/support/report.js.map +1 -0
  335. package/dist/core/agent/tools/dialects.js +150 -0
  336. package/dist/core/agent/tools/dialects.js.map +1 -0
  337. package/dist/core/agent/tools/registry.js +228 -0
  338. package/dist/core/agent/tools/registry.js.map +1 -0
  339. package/dist/core/agent/workflows/adopt.js +133 -0
  340. package/dist/core/agent/workflows/adopt.js.map +1 -0
  341. package/dist/core/agent/workflows/check.js +334 -0
  342. package/dist/core/agent/workflows/check.js.map +1 -0
  343. package/dist/core/agent/workflows/closing.js +262 -0
  344. package/dist/core/agent/workflows/closing.js.map +1 -0
  345. package/dist/core/agent/workflows/feature.js +105 -0
  346. package/dist/core/agent/workflows/feature.js.map +1 -0
  347. package/dist/core/agent/workflows/implement.js +105 -0
  348. package/dist/core/agent/workflows/implement.js.map +1 -0
  349. package/dist/core/agent/workflows/reference/authoring.js +209 -0
  350. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  351. package/dist/core/agent/workflows/reference/codes.js +65 -0
  352. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  353. package/dist/core/agent/workflows/reference/done-check.js +188 -0
  354. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  355. package/dist/core/agent/workflows/reference/reference.js +16 -0
  356. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  357. package/dist/core/agent/workflows/reference/spine.js +297 -0
  358. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  359. package/dist/core/asyncapi/baseline/plan.js +110 -0
  360. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  361. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  362. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  363. package/dist/core/asyncapi/depth.js +164 -0
  364. package/dist/core/asyncapi/depth.js.map +1 -0
  365. package/dist/core/asyncapi/digest.js +141 -0
  366. package/dist/core/asyncapi/digest.js.map +1 -0
  367. package/dist/core/asyncapi/merge/components.js +91 -0
  368. package/dist/core/asyncapi/merge/components.js.map +1 -0
  369. package/dist/core/asyncapi/merge/error.js +33 -0
  370. package/dist/core/asyncapi/merge/error.js.map +1 -0
  371. package/dist/core/asyncapi/merge/markers.js +308 -0
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  373. package/dist/core/asyncapi/merge/merge.js +215 -0
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  375. package/dist/core/asyncapi/merge/pin.js +107 -0
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  377. package/dist/core/asyncapi/model.js +11 -0
  378. package/dist/core/asyncapi/model.js.map +1 -0
  379. package/dist/core/asyncapi/producers.js +50 -0
  380. package/dist/core/asyncapi/producers.js.map +1 -0
  381. package/dist/core/{asyncapi.js → asyncapi/read.js} +95 -109
  382. package/dist/core/asyncapi/read.js.map +1 -0
  383. package/dist/core/brief/brief.js +225 -0
  384. package/dist/core/brief/brief.js.map +1 -0
  385. package/dist/core/brief/checks.js +250 -0
  386. package/dist/core/brief/checks.js.map +1 -0
  387. package/dist/core/brief/landscape.js +194 -0
  388. package/dist/core/brief/landscape.js.map +1 -0
  389. package/dist/core/brief/targets.js +226 -0
  390. package/dist/core/brief/targets.js.map +1 -0
  391. package/dist/core/brief/unchecked.js +47 -0
  392. package/dist/core/brief/unchecked.js.map +1 -0
  393. package/dist/core/c4/arch.js +282 -0
  394. package/dist/core/c4/arch.js.map +1 -0
  395. package/dist/core/c4/likec4.js +88 -0
  396. package/dist/core/c4/likec4.js.map +1 -0
  397. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  398. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  399. package/dist/core/c4/parsed/specification.js +78 -0
  400. package/dist/core/c4/parsed/specification.js.map +1 -0
  401. package/dist/core/c4/parsed/values.js +57 -0
  402. package/dist/core/c4/parsed/values.js.map +1 -0
  403. package/dist/core/c4/parsed/view-ids.js +75 -0
  404. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  405. package/dist/core/c4/project/architecture.js +45 -0
  406. package/dist/core/c4/project/architecture.js.map +1 -0
  407. package/dist/core/c4/project/documents.js +58 -0
  408. package/dist/core/c4/project/documents.js.map +1 -0
  409. package/dist/core/c4/project/load.js +183 -0
  410. package/dist/core/c4/project/load.js.map +1 -0
  411. package/dist/core/c4/resolve/service.js +113 -0
  412. package/dist/core/c4/resolve/service.js.map +1 -0
  413. package/dist/core/c4/seed/fleet-file.js +201 -0
  414. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  415. package/dist/core/c4/seed/items.js +91 -0
  416. package/dist/core/c4/seed/items.js.map +1 -0
  417. package/dist/core/c4/seed/stamp.js +48 -0
  418. package/dist/core/c4/seed/stamp.js.map +1 -0
  419. package/dist/core/c4/seed/template.js +109 -0
  420. package/dist/core/c4/seed/template.js.map +1 -0
  421. package/dist/core/c4/source-mask.js +82 -0
  422. package/dist/core/c4/source-mask.js.map +1 -0
  423. package/dist/core/c4/source-scan.js +227 -0
  424. package/dist/core/c4/source-scan.js.map +1 -0
  425. package/dist/core/c4/splice/authored-source.js +101 -0
  426. package/dist/core/c4/splice/authored-source.js.map +1 -0
  427. package/dist/core/c4/splice/contract.js +10 -0
  428. package/dist/core/c4/splice/contract.js.map +1 -0
  429. package/dist/core/c4/splice/delta-blocks.js +126 -0
  430. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  431. package/dist/core/c4/splice/identity/edges.js +36 -0
  432. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  433. package/dist/core/c4/splice/landscape-merge.js +269 -0
  434. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  435. package/dist/core/c4/splice/placement.js +194 -0
  436. package/dist/core/c4/splice/placement.js.map +1 -0
  437. package/dist/core/c4/workspace.js +172 -0
  438. package/dist/core/c4/workspace.js.map +1 -0
  439. package/dist/core/capabilities/authoring/notes.js +141 -0
  440. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  441. package/dist/core/capabilities/capabilities.js +124 -0
  442. package/dist/core/capabilities/capabilities.js.map +1 -0
  443. package/dist/core/capabilities/delta/doc.js +50 -0
  444. package/dist/core/capabilities/delta/doc.js.map +1 -0
  445. package/dist/core/capabilities/delta/overlay.js +129 -0
  446. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  447. package/dist/core/capabilities/delta/summary.js +57 -0
  448. package/dist/core/capabilities/delta/summary.js.map +1 -0
  449. package/dist/core/capabilities/delta/tree.js +43 -0
  450. package/dist/core/capabilities/delta/tree.js.map +1 -0
  451. package/dist/core/capabilities/delta/uncovered.js +222 -0
  452. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  453. package/dist/core/capabilities/findings.js +342 -0
  454. package/dist/core/capabilities/findings.js.map +1 -0
  455. package/dist/core/capabilities/realizes/findings.js +181 -0
  456. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  457. package/dist/core/capabilities/realizes/join.js +143 -0
  458. package/dist/core/capabilities/realizes/join.js.map +1 -0
  459. package/dist/core/capabilities/rollup.js +199 -0
  460. package/dist/core/capabilities/rollup.js.map +1 -0
  461. package/dist/core/capabilities/tree.js +126 -0
  462. package/dist/core/capabilities/tree.js.map +1 -0
  463. package/dist/core/capabilities/usecase-join.js +277 -0
  464. package/dist/core/capabilities/usecase-join.js.map +1 -0
  465. package/dist/core/coherence/authoring/scaffold.js +177 -0
  466. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  467. package/dist/core/coherence/authoring/sentinels.js +74 -0
  468. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  469. package/dist/core/coherence/coherence.js +251 -0
  470. package/dist/core/coherence/coherence.js.map +1 -0
  471. package/dist/core/coherence/declared.js +269 -0
  472. package/dist/core/coherence/declared.js.map +1 -0
  473. package/dist/core/coherence/events/declared.js +206 -0
  474. package/dist/core/coherence/events/declared.js.map +1 -0
  475. package/dist/core/coherence/events/events.js +204 -0
  476. package/dist/core/coherence/events/events.js.map +1 -0
  477. package/dist/core/coherence/events/grades.js +166 -0
  478. package/dist/core/coherence/events/grades.js.map +1 -0
  479. package/dist/core/coherence/events/lookups.js +122 -0
  480. package/dist/core/coherence/events/lookups.js.map +1 -0
  481. package/dist/core/coherence/events/merged.js +40 -0
  482. package/dist/core/coherence/events/merged.js.map +1 -0
  483. package/dist/core/coherence/living.js +198 -0
  484. package/dist/core/coherence/living.js.map +1 -0
  485. package/dist/core/coherence/lookups.js +155 -0
  486. package/dist/core/coherence/lookups.js.map +1 -0
  487. package/dist/core/coherence/pending.js +39 -0
  488. package/dist/core/coherence/pending.js.map +1 -0
  489. package/dist/core/conflict-markers.js +60 -0
  490. package/dist/core/conflict-markers.js.map +1 -0
  491. package/dist/core/delta/claims.js +73 -0
  492. package/dist/core/delta/claims.js.map +1 -0
  493. package/dist/core/delta/delta.js +296 -0
  494. package/dist/core/delta/delta.js.map +1 -0
  495. package/dist/core/delta/document.js +177 -0
  496. package/dist/core/delta/document.js.map +1 -0
  497. package/dist/core/delta/scope.js +48 -0
  498. package/dist/core/delta/scope.js.map +1 -0
  499. package/dist/core/delta/select.js +237 -0
  500. package/dist/core/delta/select.js.map +1 -0
  501. package/dist/core/dependencies/dependencies.js +141 -0
  502. package/dist/core/dependencies/dependencies.js.map +1 -0
  503. package/dist/core/dependencies/facts.js +165 -0
  504. package/dist/core/dependencies/facts.js.map +1 -0
  505. package/dist/core/dependencies/fanin.js +88 -0
  506. package/dist/core/dependencies/fanin.js.map +1 -0
  507. package/dist/core/dependencies/graph.js +106 -0
  508. package/dist/core/dependencies/graph.js.map +1 -0
  509. package/dist/core/diff/base-git.js +148 -0
  510. package/dist/core/diff/base-git.js.map +1 -0
  511. package/dist/core/diff/base-state.js +209 -0
  512. package/dist/core/diff/base-state.js.map +1 -0
  513. package/dist/core/diff/current-state.js +96 -0
  514. package/dist/core/diff/current-state.js.map +1 -0
  515. package/dist/core/diff/scope/changed-paths.js +188 -0
  516. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  517. package/dist/core/diff/semantic.js +243 -0
  518. package/dist/core/diff/semantic.js.map +1 -0
  519. package/dist/core/diff/victims.js +247 -0
  520. package/dist/core/diff/victims.js.map +1 -0
  521. package/dist/core/docs.js +7 -64
  522. package/dist/core/docs.js.map +1 -1
  523. package/dist/core/doctor/agents.js +222 -0
  524. package/dist/core/doctor/agents.js.map +1 -0
  525. package/dist/core/doctor/config.js +135 -0
  526. package/dist/core/doctor/config.js.map +1 -0
  527. package/dist/core/doctor/doctor.js +275 -0
  528. package/dist/core/doctor/doctor.js.map +1 -0
  529. package/dist/core/doctor/report.js +13 -0
  530. package/dist/core/doctor/report.js.map +1 -0
  531. package/dist/core/doctor/residue.js +110 -0
  532. package/dist/core/doctor/residue.js.map +1 -0
  533. package/dist/core/document/apply.js +77 -0
  534. package/dist/core/document/apply.js.map +1 -0
  535. package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
  536. package/dist/core/document/frontmatter.js.map +1 -0
  537. package/dist/core/document/grammar/directives.js +143 -0
  538. package/dist/core/document/grammar/directives.js.map +1 -0
  539. package/dist/core/document/parse.js +263 -0
  540. package/dist/core/document/parse.js.map +1 -0
  541. package/dist/core/document/scenarios.js +221 -0
  542. package/dist/core/document/scenarios.js.map +1 -0
  543. package/dist/core/document/spec.js +241 -0
  544. package/dist/core/document/spec.js.map +1 -0
  545. package/dist/core/{config.js → envelope/config.js} +79 -18
  546. package/dist/core/envelope/config.js.map +1 -0
  547. package/dist/core/envelope/json.js +175 -0
  548. package/dist/core/envelope/json.js.map +1 -0
  549. package/dist/core/{version.js → envelope/version.js} +3 -3
  550. package/dist/core/envelope/version.js.map +1 -0
  551. package/dist/core/explain/families.js +175 -0
  552. package/dist/core/explain/families.js.map +1 -0
  553. package/dist/core/explain/fix-tables.js +178 -0
  554. package/dist/core/explain/fix-tables.js.map +1 -0
  555. package/dist/core/explain/lookup.js +181 -0
  556. package/dist/core/explain/lookup.js.map +1 -0
  557. package/dist/core/explain/refusals.js +49 -0
  558. package/dist/core/explain/refusals.js.map +1 -0
  559. package/dist/core/explain/terms.js +144 -0
  560. package/dist/core/explain/terms.js.map +1 -0
  561. package/dist/core/explore/describe.js +105 -0
  562. package/dist/core/explore/describe.js.map +1 -0
  563. package/dist/core/{explore.js → explore/explore.js} +50 -101
  564. package/dist/core/explore/explore.js.map +1 -0
  565. package/dist/core/fleet-context.js +120 -78
  566. package/dist/core/fleet-context.js.map +1 -1
  567. package/dist/core/gate/checks.js +201 -0
  568. package/dist/core/gate/checks.js.map +1 -0
  569. package/dist/core/gate/partners.js +205 -0
  570. package/dist/core/gate/partners.js.map +1 -0
  571. package/dist/core/gate/report.js +47 -0
  572. package/dist/core/gate/report.js.map +1 -0
  573. package/dist/core/gate/verification.js +113 -0
  574. package/dist/core/gate/verification.js.map +1 -0
  575. package/dist/core/gherkin/digest.js +60 -0
  576. package/dist/core/gherkin/digest.js.map +1 -0
  577. package/dist/core/gherkin/emit.js +177 -0
  578. package/dist/core/gherkin/emit.js.map +1 -0
  579. package/dist/core/gherkin/read.js +76 -0
  580. package/dist/core/gherkin/read.js.map +1 -0
  581. package/dist/core/gherkin/stale.js +234 -0
  582. package/dist/core/gherkin/stale.js.map +1 -0
  583. package/dist/core/gherkin/stamp.js +77 -0
  584. package/dist/core/gherkin/stamp.js.map +1 -0
  585. package/dist/core/gherkin/steps/catalogue.js +154 -0
  586. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  587. package/dist/core/gherkin/steps/inventory.js +98 -0
  588. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  589. package/dist/core/gherkin/steps/phrase.js +72 -0
  590. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  591. package/dist/core/glossary/delta.js +106 -0
  592. package/dist/core/glossary/delta.js.map +1 -0
  593. package/dist/core/glossary/tree.js +86 -0
  594. package/dist/core/glossary/tree.js.map +1 -0
  595. package/dist/core/kernel/concurrency.js.map +1 -0
  596. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  597. package/dist/core/kernel/document-bytes.js.map +1 -0
  598. package/dist/core/kernel/fences.js +42 -0
  599. package/dist/core/kernel/fences.js.map +1 -0
  600. package/dist/core/kernel/ids/capability.js +72 -0
  601. package/dist/core/kernel/ids/capability.js.map +1 -0
  602. package/dist/core/kernel/ids/dirs.js +33 -0
  603. package/dist/core/kernel/ids/dirs.js.map +1 -0
  604. package/dist/core/kernel/ids/feature.js +75 -0
  605. package/dist/core/kernel/ids/feature.js.map +1 -0
  606. package/dist/core/kernel/ids/service.js +156 -0
  607. package/dist/core/kernel/ids/service.js.map +1 -0
  608. package/dist/core/kernel/ids/subsystem.js +63 -0
  609. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  610. package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
  611. package/dist/core/kernel/path-safety.js.map +1 -0
  612. package/dist/core/kernel/records.js.map +1 -0
  613. package/dist/core/links/backlinks.js +68 -0
  614. package/dist/core/links/backlinks.js.map +1 -0
  615. package/dist/core/links/case.js +74 -0
  616. package/dist/core/links/case.js.map +1 -0
  617. package/dist/core/links/corpus.js +104 -0
  618. package/dist/core/links/corpus.js.map +1 -0
  619. package/dist/core/links/findings.js +110 -0
  620. package/dist/core/links/findings.js.map +1 -0
  621. package/dist/core/links/parse.js +236 -0
  622. package/dist/core/links/parse.js.map +1 -0
  623. package/dist/core/mcp/argv.js +111 -0
  624. package/dist/core/mcp/argv.js.map +1 -0
  625. package/dist/core/mcp/author-tools.js +72 -0
  626. package/dist/core/mcp/author-tools.js.map +1 -0
  627. package/dist/core/mcp/framing.js +46 -0
  628. package/dist/core/mcp/framing.js.map +1 -0
  629. package/dist/core/mcp/protocol.js +280 -0
  630. package/dist/core/mcp/protocol.js.map +1 -0
  631. package/dist/core/mcp/tools.js +314 -0
  632. package/dist/core/mcp/tools.js.map +1 -0
  633. package/dist/core/obligations/obligations.js +106 -0
  634. package/dist/core/obligations/obligations.js.map +1 -0
  635. package/dist/core/openapi/baseline/gate.js +166 -0
  636. package/dist/core/openapi/baseline/gate.js.map +1 -0
  637. package/dist/core/openapi/baseline/plan.js +112 -0
  638. package/dist/core/openapi/baseline/plan.js.map +1 -0
  639. package/dist/core/openapi/baseline/record.js +175 -0
  640. package/dist/core/openapi/baseline/record.js.map +1 -0
  641. package/dist/core/openapi/depth.js +122 -0
  642. package/dist/core/openapi/depth.js.map +1 -0
  643. package/dist/core/openapi/digest.js +189 -0
  644. package/dist/core/openapi/digest.js.map +1 -0
  645. package/dist/core/{openapi.js → openapi/doc.js} +44 -106
  646. package/dist/core/openapi/doc.js.map +1 -0
  647. package/dist/core/openapi/merge/components.js +234 -0
  648. package/dist/core/openapi/merge/components.js.map +1 -0
  649. package/dist/core/openapi/merge/error.js +26 -0
  650. package/dist/core/openapi/merge/error.js.map +1 -0
  651. package/dist/core/openapi/merge/markers.js +208 -0
  652. package/dist/core/openapi/merge/markers.js.map +1 -0
  653. package/dist/core/openapi/merge/merge.js +256 -0
  654. package/dist/core/openapi/merge/merge.js.map +1 -0
  655. package/dist/core/openapi/merge/pin.js +128 -0
  656. package/dist/core/openapi/merge/pin.js.map +1 -0
  657. package/dist/core/openspec/decide/capabilities.js +244 -0
  658. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  659. package/dist/core/openspec/decide/dispositions.js +63 -0
  660. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  661. package/dist/core/openspec/decide/renames.js +179 -0
  662. package/dist/core/openspec/decide/renames.js.map +1 -0
  663. package/dist/core/openspec/decide/verdict.js +84 -0
  664. package/dist/core/openspec/decide/verdict.js.map +1 -0
  665. package/dist/core/openspec/inventory.js +221 -0
  666. package/dist/core/openspec/inventory.js.map +1 -0
  667. package/dist/core/openspec/model/mapping.js +76 -0
  668. package/dist/core/openspec/model/mapping.js.map +1 -0
  669. package/dist/core/openspec/model/model.js +65 -0
  670. package/dist/core/openspec/model/model.js.map +1 -0
  671. package/dist/core/openspec/scan/changes.js +235 -0
  672. package/dist/core/openspec/scan/changes.js.map +1 -0
  673. package/dist/core/openspec/scan/config.js +200 -0
  674. package/dist/core/openspec/scan/config.js.map +1 -0
  675. package/dist/core/openspec/scan/shape.js +260 -0
  676. package/dist/core/openspec/scan/shape.js.map +1 -0
  677. package/dist/core/openspec/scan/walk.js +133 -0
  678. package/dist/core/openspec/scan/walk.js.map +1 -0
  679. package/dist/core/openspec/scan/workspace.js +71 -0
  680. package/dist/core/openspec/scan/workspace.js.map +1 -0
  681. package/dist/core/owners/codeowners.js +141 -0
  682. package/dist/core/owners/codeowners.js.map +1 -0
  683. package/dist/core/pack/features.js +120 -0
  684. package/dist/core/pack/features.js.map +1 -0
  685. package/dist/core/pack/joins.js +112 -0
  686. package/dist/core/pack/joins.js.map +1 -0
  687. package/dist/core/pack/living.js +118 -0
  688. package/dist/core/pack/living.js.map +1 -0
  689. package/dist/core/pack/pack.js +76 -0
  690. package/dist/core/pack/pack.js.map +1 -0
  691. package/dist/core/permissions/permissions.js +87 -0
  692. package/dist/core/permissions/permissions.js.map +1 -0
  693. package/dist/core/projection/api.js +84 -0
  694. package/dist/core/projection/api.js.map +1 -0
  695. package/dist/core/projection/arch-slice.js +63 -0
  696. package/dist/core/projection/arch-slice.js.map +1 -0
  697. package/dist/core/projection/events.js +34 -0
  698. package/dist/core/projection/events.js.map +1 -0
  699. package/dist/core/provenance/findings.js +208 -0
  700. package/dist/core/provenance/findings.js.map +1 -0
  701. package/dist/core/provenance/git.js +225 -0
  702. package/dist/core/provenance/git.js.map +1 -0
  703. package/dist/core/provenance/gitq/moves.js +182 -0
  704. package/dist/core/provenance/gitq/moves.js.map +1 -0
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  707. package/dist/core/provenance/sample/scope.js +238 -0
  708. package/dist/core/provenance/sample/scope.js.map +1 -0
  709. package/dist/core/provenance/sample/sections.js +61 -0
  710. package/dist/core/provenance/sample/sections.js.map +1 -0
  711. package/dist/core/provenance/sources.js +263 -0
  712. package/dist/core/provenance/sources.js.map +1 -0
  713. package/dist/core/provenance/stamp.js +232 -0
  714. package/dist/core/provenance/stamp.js.map +1 -0
  715. package/dist/core/provenance/walk.js +157 -0
  716. package/dist/core/provenance/walk.js.map +1 -0
  717. package/dist/core/repo/authored/paths.js +192 -0
  718. package/dist/core/repo/authored/paths.js.map +1 -0
  719. package/dist/core/repo/entries.js +126 -0
  720. package/dist/core/repo/entries.js.map +1 -0
  721. package/dist/core/repo/paths.js +236 -0
  722. package/dist/core/repo/paths.js.map +1 -0
  723. package/dist/core/repo/repo.js +248 -0
  724. package/dist/core/repo/repo.js.map +1 -0
  725. package/dist/core/repo/service-target.js +153 -0
  726. package/dist/core/repo/service-target.js.map +1 -0
  727. package/dist/core/repo/state.js +58 -0
  728. package/dist/core/repo/state.js.map +1 -0
  729. package/dist/core/repo/tree/find.js +52 -0
  730. package/dist/core/repo/tree/find.js.map +1 -0
  731. package/dist/core/repo/tree/fs.js +64 -0
  732. package/dist/core/repo/tree/fs.js.map +1 -0
  733. package/dist/core/repo/tree/marker.js +61 -0
  734. package/dist/core/repo/tree/marker.js.map +1 -0
  735. package/dist/core/repo/tree/views.js +172 -0
  736. package/dist/core/repo/tree/views.js.map +1 -0
  737. package/dist/core/repo/tree/walk.js +234 -0
  738. package/dist/core/repo/tree/walk.js.map +1 -0
  739. package/dist/core/results.js +99 -2
  740. package/dist/core/results.js.map +1 -1
  741. package/dist/core/scaffold/landscape.js +131 -0
  742. package/dist/core/scaffold/landscape.js.map +1 -0
  743. package/dist/core/scaffold/readme.js +84 -0
  744. package/dist/core/scaffold/readme.js.map +1 -0
  745. package/dist/core/staging/commit.js +241 -0
  746. package/dist/core/staging/commit.js.map +1 -0
  747. package/dist/core/staging/interrupted.js +96 -0
  748. package/dist/core/staging/interrupted.js.map +1 -0
  749. package/dist/core/staging/lock.js +206 -0
  750. package/dist/core/staging/lock.js.map +1 -0
  751. package/dist/core/staging/recovery/finding.js +35 -0
  752. package/dist/core/staging/recovery/finding.js.map +1 -0
  753. package/dist/core/staging/recovery/intent.js +98 -0
  754. package/dist/core/staging/recovery/intent.js.map +1 -0
  755. package/dist/core/staging/recovery/recover.js +126 -0
  756. package/dist/core/staging/recovery/recover.js.map +1 -0
  757. package/dist/core/staging/recovery/residue.js +62 -0
  758. package/dist/core/staging/recovery/residue.js.map +1 -0
  759. package/dist/core/staging/snapshot.js +202 -0
  760. package/dist/core/staging/snapshot.js.map +1 -0
  761. package/dist/core/staging/txn/forward.js +171 -0
  762. package/dist/core/staging/txn/forward.js.map +1 -0
  763. package/dist/core/staging/txn/journal.js +139 -0
  764. package/dist/core/staging/txn/journal.js.map +1 -0
  765. package/dist/core/staging/txn/transaction.js +75 -0
  766. package/dist/core/staging/txn/transaction.js.map +1 -0
  767. package/dist/core/staging/writes.js +113 -0
  768. package/dist/core/staging/writes.js.map +1 -0
  769. package/dist/core/status/actions/execution.js +49 -0
  770. package/dist/core/status/actions/execution.js.map +1 -0
  771. package/dist/core/status/contracts.js +102 -0
  772. package/dist/core/status/contracts.js.map +1 -0
  773. package/dist/core/status/feature/artifacts.js +171 -0
  774. package/dist/core/status/feature/artifacts.js.map +1 -0
  775. package/dist/core/status/feature/feature.js +207 -0
  776. package/dist/core/status/feature/feature.js.map +1 -0
  777. package/dist/core/status/feature/next.js +150 -0
  778. package/dist/core/status/feature/next.js.map +1 -0
  779. package/dist/core/status/feature/state.js +21 -0
  780. package/dist/core/status/feature/state.js.map +1 -0
  781. package/dist/core/status/fleet/fleet.js +187 -0
  782. package/dist/core/status/fleet/fleet.js.map +1 -0
  783. package/dist/core/status/fleet/next.js +207 -0
  784. package/dist/core/status/fleet/next.js.map +1 -0
  785. package/dist/core/status/interrupted.js +97 -0
  786. package/dist/core/status/interrupted.js.map +1 -0
  787. package/dist/core/status/report.js +31 -0
  788. package/dist/core/status/report.js.map +1 -0
  789. package/dist/core/status/scan.js +41 -0
  790. package/dist/core/status/scan.js.map +1 -0
  791. package/dist/core/status/verification.js +201 -0
  792. package/dist/core/status/verification.js.map +1 -0
  793. package/dist/core/usecases/capability.js +169 -0
  794. package/dist/core/usecases/capability.js.map +1 -0
  795. package/dist/core/usecases/delta/claims.js +116 -0
  796. package/dist/core/usecases/delta/claims.js.map +1 -0
  797. package/dist/core/usecases/delta/flows.js +103 -0
  798. package/dist/core/usecases/delta/flows.js.map +1 -0
  799. package/dist/core/usecases/delta/overlay.js +235 -0
  800. package/dist/core/usecases/delta/overlay.js.map +1 -0
  801. package/dist/core/usecases/fleet.js +137 -0
  802. package/dist/core/usecases/fleet.js.map +1 -0
  803. package/dist/core/usecases/operations.js +111 -0
  804. package/dist/core/usecases/operations.js.map +1 -0
  805. package/dist/core/usecases/place.js +44 -0
  806. package/dist/core/usecases/place.js.map +1 -0
  807. package/dist/core/usecases/touch.js +101 -0
  808. package/dist/core/usecases/touch.js.map +1 -0
  809. package/dist/core/verify/answers.js +173 -0
  810. package/dist/core/verify/answers.js.map +1 -0
  811. package/dist/core/verify/build.js +150 -0
  812. package/dist/core/verify/build.js.map +1 -0
  813. package/dist/core/verify/checklist.js +201 -0
  814. package/dist/core/verify/checklist.js.map +1 -0
  815. package/dist/core/verify/claims/identity.js +61 -0
  816. package/dist/core/verify/claims/identity.js.map +1 -0
  817. package/dist/core/verify/cross/diff.js +97 -0
  818. package/dist/core/verify/cross/diff.js.map +1 -0
  819. package/dist/core/verify/evidence/contract.js +169 -0
  820. package/dist/core/verify/evidence/contract.js.map +1 -0
  821. package/dist/core/verify/file.js +257 -0
  822. package/dist/core/verify/file.js.map +1 -0
  823. package/dist/core/verify/pins/lint.js +157 -0
  824. package/dist/core/verify/pins/lint.js.map +1 -0
  825. package/dist/core/verify/pins/pin.js +95 -0
  826. package/dist/core/verify/pins/pin.js.map +1 -0
  827. package/dist/core/verify/record.js +142 -0
  828. package/dist/core/verify/record.js.map +1 -0
  829. package/dist/core/verify/store/commit.js +89 -0
  830. package/dist/core/verify/store/commit.js.map +1 -0
  831. package/dist/core/verify/store/render.js +57 -0
  832. package/dist/core/verify/store/render.js.map +1 -0
  833. package/dist/core/vocabulary/health.js +91 -0
  834. package/dist/core/vocabulary/health.js.map +1 -0
  835. package/dist/core/vocabulary/issue.js +55 -0
  836. package/dist/core/vocabulary/issue.js.map +1 -0
  837. package/dist/core/vocabulary/maturity.js +145 -0
  838. package/dist/core/vocabulary/maturity.js.map +1 -0
  839. package/dist/core/{report.js → vocabulary/report.js} +30 -2
  840. package/dist/core/vocabulary/report.js.map +1 -0
  841. package/dist/core/vocabulary/steps.js +266 -0
  842. package/dist/core/vocabulary/steps.js.map +1 -0
  843. package/dist/core/workspace/discover.js +239 -0
  844. package/dist/core/workspace/discover.js.map +1 -0
  845. package/dist/core/workspace/render.js +52 -0
  846. package/dist/core/workspace/render.js.map +1 -0
  847. package/examples/README.md +189 -0
  848. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  849. package/examples/docs/architecture/capabilities.yaml +31 -0
  850. package/examples/docs/architecture/landscape.likec4 +280 -0
  851. package/examples/docs/architecture/obligations.yaml +23 -0
  852. package/examples/docs/architecture/permissions.yaml +50 -0
  853. package/examples/docs/architecture/subsystems.likec4 +11 -0
  854. package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
  855. package/examples/docs/capabilities/checkout/spec.md +55 -0
  856. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  857. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  858. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  859. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  860. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
  863. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  864. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  865. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  866. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  867. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  868. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
  869. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  870. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  871. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  872. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  873. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  874. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  875. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  876. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  877. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  878. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  879. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
  880. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  881. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  882. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  883. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  884. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  885. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  886. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  887. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  888. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  889. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  890. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  891. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  892. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  893. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  894. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  895. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  896. package/examples/docs/glossary/order.md +15 -0
  897. package/examples/docs/glossary/payments/authorization.md +14 -0
  898. package/examples/docs/likec4.config.json +9 -0
  899. package/examples/docs/loam.json +3 -0
  900. package/examples/docs/services/checkout-web/model.likec4 +109 -0
  901. package/examples/docs/services/checkout-web/spec.md +91 -0
  902. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  903. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  904. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  905. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  906. package/examples/docs/services/order-service/arch.spec.md +127 -0
  907. package/examples/docs/services/order-service/asyncapi.yaml +108 -0
  908. package/examples/docs/services/order-service/health.yaml +57 -0
  909. package/examples/docs/services/order-service/model.likec4 +138 -0
  910. package/examples/docs/services/order-service/openapi.yaml +257 -0
  911. package/examples/docs/services/order-service/runbook.md +62 -0
  912. package/examples/docs/services/order-service/spec.md +134 -0
  913. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  914. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  915. package/examples/docs/services/payment-service/arch.spec.md +73 -0
  916. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  917. package/examples/docs/services/payment-service/health.yaml +39 -0
  918. package/examples/docs/services/payment-service/model.likec4 +67 -0
  919. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  920. package/examples/docs/services/payment-service/runbook.md +37 -0
  921. package/examples/docs/services/payment-service/spec.md +88 -0
  922. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  923. package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
  924. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  925. package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
  926. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  927. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  928. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  929. package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
  930. package/examples/docs/services/platform/notification-service/health.yaml +35 -0
  931. package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
  932. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  933. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  934. package/examples/docs/services/platform/subsystem.yaml +2 -0
  935. package/examples/fleet.yaml +57 -0
  936. package/package.json +19 -6
  937. package/dist/commands/adopt.js +0 -240
  938. package/dist/commands/adopt.js.map +0 -1
  939. package/dist/commands/archive.js +0 -1313
  940. package/dist/commands/archive.js.map +0 -1
  941. package/dist/commands/delta.js +0 -388
  942. package/dist/commands/delta.js.map +0 -1
  943. package/dist/commands/docs-repo-gate.js.map +0 -1
  944. package/dist/commands/format.js +0 -17
  945. package/dist/commands/format.js.map +0 -1
  946. package/dist/commands/gherkin.js +0 -309
  947. package/dist/commands/gherkin.js.map +0 -1
  948. package/dist/commands/init.js.map +0 -1
  949. package/dist/commands/list.js +0 -295
  950. package/dist/commands/list.js.map +0 -1
  951. package/dist/commands/migrate-openspec.js +0 -950
  952. package/dist/commands/migrate-openspec.js.map +0 -1
  953. package/dist/commands/new.js +0 -413
  954. package/dist/commands/new.js.map +0 -1
  955. package/dist/commands/rebase.js +0 -356
  956. package/dist/commands/rebase.js.map +0 -1
  957. package/dist/commands/show.js.map +0 -1
  958. package/dist/commands/status.js +0 -262
  959. package/dist/commands/status.js.map +0 -1
  960. package/dist/commands/unarchive.js.map +0 -1
  961. package/dist/commands/validate.js +0 -1773
  962. package/dist/commands/validate.js.map +0 -1
  963. package/dist/commands/verify.js +0 -775
  964. package/dist/commands/verify.js.map +0 -1
  965. package/dist/commands/vouch.js +0 -421
  966. package/dist/commands/vouch.js.map +0 -1
  967. package/dist/core/agent.js +0 -2173
  968. package/dist/core/agent.js.map +0 -1
  969. package/dist/core/agents-stamp.js.map +0 -1
  970. package/dist/core/arch.js +0 -130
  971. package/dist/core/arch.js.map +0 -1
  972. package/dist/core/asyncapi.js.map +0 -1
  973. package/dist/core/brief.js +0 -755
  974. package/dist/core/brief.js.map +0 -1
  975. package/dist/core/coherence.js +0 -577
  976. package/dist/core/coherence.js.map +0 -1
  977. package/dist/core/concurrency.js.map +0 -1
  978. package/dist/core/config.js.map +0 -1
  979. package/dist/core/delta.js +0 -476
  980. package/dist/core/delta.js.map +0 -1
  981. package/dist/core/dependencies.js +0 -356
  982. package/dist/core/dependencies.js.map +0 -1
  983. package/dist/core/doctor.js +0 -596
  984. package/dist/core/doctor.js.map +0 -1
  985. package/dist/core/document-bytes.js.map +0 -1
  986. package/dist/core/explore.js.map +0 -1
  987. package/dist/core/frontmatter.js.map +0 -1
  988. package/dist/core/gherkin.js +0 -463
  989. package/dist/core/gherkin.js.map +0 -1
  990. package/dist/core/health.js +0 -67
  991. package/dist/core/health.js.map +0 -1
  992. package/dist/core/ids.js +0 -122
  993. package/dist/core/ids.js.map +0 -1
  994. package/dist/core/issue.js +0 -9
  995. package/dist/core/issue.js.map +0 -1
  996. package/dist/core/json.js +0 -74
  997. package/dist/core/json.js.map +0 -1
  998. package/dist/core/likec4.js +0 -489
  999. package/dist/core/likec4.js.map +0 -1
  1000. package/dist/core/maturity.js +0 -66
  1001. package/dist/core/maturity.js.map +0 -1
  1002. package/dist/core/openapi-merge.js +0 -552
  1003. package/dist/core/openapi-merge.js.map +0 -1
  1004. package/dist/core/openapi.js.map +0 -1
  1005. package/dist/core/openspec-inventory.js +0 -1440
  1006. package/dist/core/openspec-inventory.js.map +0 -1
  1007. package/dist/core/path-safety.js.map +0 -1
  1008. package/dist/core/provenance.js +0 -787
  1009. package/dist/core/provenance.js.map +0 -1
  1010. package/dist/core/records.js.map +0 -1
  1011. package/dist/core/repo.js +0 -438
  1012. package/dist/core/repo.js.map +0 -1
  1013. package/dist/core/report.js.map +0 -1
  1014. package/dist/core/spec.js +0 -505
  1015. package/dist/core/spec.js.map +0 -1
  1016. package/dist/core/staging.js +0 -890
  1017. package/dist/core/staging.js.map +0 -1
  1018. package/dist/core/status.js +0 -1132
  1019. package/dist/core/status.js.map +0 -1
  1020. package/dist/core/steps.js +0 -72
  1021. package/dist/core/steps.js.map +0 -1
  1022. package/dist/core/verify.js +0 -807
  1023. package/dist/core/verify.js.map +0 -1
  1024. package/dist/core/version.js.map +0 -1
  1025. /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
  1026. /package/dist/core/{records.js → kernel/records.js} +0 -0
@@ -0,0 +1,194 @@
1
+ /**
2
+ * The fleet-map half of the adoption brief: what `architecture/landscape.likec4`
3
+ * already says about one service — its elements, its inbound and outbound
4
+ * edges, the operations the fleet already calls on it — and the block the
5
+ * service still owes the file when nothing in it resolves to the service yet.
6
+ * Both halves exist to stop an agent inventing a parallel model: the fleet has
7
+ * already drawn some of these boxes and edges, and a baseline has to attach to
8
+ * them.
9
+ */
10
+ import { existsSync } from "node:fs";
11
+ import { loadFile } from "../c4/likec4.js";
12
+ import { elementService, serviceResolver } from "../c4/resolve/service.js";
13
+ import { landscapePath } from "../repo/paths.js";
14
+ import { enumeratedServiceIds, serviceTreePathOf } from "../repo/service-target.js";
15
+ /**
16
+ * The LikeC4 identifier the fleet map's element for a service conventionally
17
+ * carries: the directory name, camel-cased. It is a suggestion and nothing
18
+ * more — `metadata { service '<id>' }` is what actually joins the element to
19
+ * the directory — but a brief that hands over a concrete block gets followed,
20
+ * and one that describes a block in prose gets improvised on.
21
+ */
22
+ function elementIdFor(service) {
23
+ const parts = service.split(/[^A-Za-z0-9]+/).filter((p) => p !== "");
24
+ if (parts.length === 0)
25
+ return "service";
26
+ const head = parts[0].toLowerCase();
27
+ const tail = parts.slice(1).map((p) => p[0].toUpperCase() + p.slice(1).toLowerCase());
28
+ const id = head + tail.join("");
29
+ // LikeC4 identifiers cannot open with a digit; a service id can.
30
+ return /^[0-9]/.test(id) ? `svc${id[0].toUpperCase()}${id.slice(1)}` : id;
31
+ }
32
+ /**
33
+ * The block this service still owes `architecture/landscape.likec4`.
34
+ *
35
+ * `expects` is what the fleet ALREADY calls on the service — those edges exist
36
+ * in the map today, so the example draws the outbound side as a comment rather
37
+ * than telling an agent to duplicate an edge that is already there.
38
+ */
39
+ function landscapeBlock(service, expects, present) {
40
+ const id = elementIdFor(service);
41
+ const calls = expects.length > 0
42
+ ? expects.map((op) => `// <caller> -> ${id} 'Calls ${op}' { metadata { op '${op}' } }`)
43
+ : [`// <caller> -> ${id} 'Calls <operationId>' { metadata { op '<operationId>' } }`];
44
+ const model = [
45
+ "model {",
46
+ ...(present ? [" // ... the fleet's other services stay exactly as they are ...", ""] : []),
47
+ ` ${id} = softwareSystem '${service}' {`,
48
+ " description '<one line: what this service is responsible for>'",
49
+ ` metadata { service '${service}' }`,
50
+ " }",
51
+ "",
52
+ " // every call in or out of it, one edge each:",
53
+ ...calls.map((line) => ` ${line}`),
54
+ "}",
55
+ ];
56
+ // When the file does not exist the example is the WHOLE file, so it carries
57
+ // the `specification` block a bare `model` would be rejected without: the
58
+ // brief must never hand over a document `loam validate` refuses. When the file
59
+ // does exist the example is a fragment to splice, and repeating a
60
+ // `specification` block there would invite a second one.
61
+ return present
62
+ ? model.join("\n")
63
+ : ["specification {", " element softwareSystem", "}", "", ...model].join("\n");
64
+ }
65
+ /** The fleet map's own brief — assembled per service, because the block it owes names the service. */
66
+ export function landscapeArtifact(service, expects, present, servicePath) {
67
+ return {
68
+ artifact: "landscape.likec4",
69
+ required: true,
70
+ purpose: "the fleet map — until an element here resolves to this directory, the service is documented and invisible to every cross-service check",
71
+ shape: [
72
+ "This file is the WHOLE FLEET's, not this service's. Add to it; never rewrite it. Everything already in `model { ... }` belongs to the other services, and replacing the file destroys their map along with their edges.",
73
+ `Add one top-level element for the service, bound to its directory: \`metadata { service '${service}' }\`. Until an element resolves to \`${servicePath}/\`, \`loam validate --all\` reports \`landscape.service-unmodelled\` (error).`,
74
+ "Bind rather than rename: a binding whose id names no directory is `landscape.binding-unknown` (error), and two elements binding the SAME directory is `landscape.binding-duplicate` (warn) — every element→service join then picks one of them arbitrarily.",
75
+ "Draw every cross-service call as an edge carrying the operation it uses: `a -> b 'Calls createSplit' { metadata { op 'createSplit' } }`. The `op` must be an operationId the TARGET's openapi.yaml defines, or `spine.op-undefined` (error) — a broken contract between services.",
76
+ "If the file does not exist yet, create it with a `specification { ... }` block declaring the kinds you use, then the `model { ... }` block. A landscape that does not parse is `landscape.invalid` (error) and blinds every cross-service check at once.",
77
+ ],
78
+ example: landscapeBlock(service, expects, present),
79
+ };
80
+ }
81
+ /**
82
+ * The service ids the resolver may fall back on when an element carries no
83
+ * `metadata { service }` binding — the same positive evidence `validate` and
84
+ * `list` hand it. A docs repo that cannot be enumerated (no `services/` yet:
85
+ * `adopt` runs there) leaves the resolver with bindings alone, which is what it
86
+ * had before.
87
+ */
88
+ async function knownServices(docsDir) {
89
+ return new Set(await enumeratedServiceIds(docsDir));
90
+ }
91
+ /**
92
+ * What the living landscape already says about this service.
93
+ *
94
+ * This is the half of the brief that stops an agent inventing a parallel model:
95
+ * the fleet has already drawn some of these boxes and edges, and the baseline has
96
+ * to attach to them. A landscape that does not parse yields `modelled: null` —
97
+ * "nothing models it" would be a claim about a document nobody could read.
98
+ */
99
+ export async function landscapeContext(docsDir, service) {
100
+ const path = landscapePath(docsDir);
101
+ // The service's own directory, spelled from the enumeration rather than joined
102
+ // at the root: this text is handed to an AGENT that will go and edit files, and
103
+ // a filed service named at `services/<id>/` sends it to create a second
104
+ // directory beside the one that already exists.
105
+ const servicePath = await serviceTreePathOf(docsDir, service);
106
+ const empty = {
107
+ present: existsSync(path),
108
+ parses: false,
109
+ modelled: null,
110
+ elements: [],
111
+ inbound: [],
112
+ outbound: [],
113
+ expects: [],
114
+ instruction: null,
115
+ };
116
+ if (!empty.present)
117
+ return { ...empty, modelled: false, instruction: instructionFor(service, "absent", [], servicePath) };
118
+ const land = await loadFile(path);
119
+ if (land.errors.length > 0)
120
+ return { ...empty, instruction: instructionFor(service, "unparseable", [], servicePath) };
121
+ const mine = (e) => elementService(e) === service;
122
+ const elements = land.elements.filter(mine).map((e) => ({
123
+ id: e.id,
124
+ title: e.title,
125
+ kind: e.kind,
126
+ tags: e.tags,
127
+ bound: e.service !== undefined,
128
+ }));
129
+ // One resolver for the whole scan, built with the real service ids: an edge
130
+ // drawn into a modelled container (`paymentService.api`) is an edge into the
131
+ // service, and `expects` — which now decides whether this service owes an
132
+ // OpenAPI contract at all — has to see it. Building it once also stops the
133
+ // per-edge rebuild the old `serviceOf(land.elements, id)` call did.
134
+ const svcOf = serviceResolver(land.elements, await knownServices(docsDir));
135
+ const inbound = [];
136
+ const outbound = [];
137
+ for (const r of land.relationships) {
138
+ const edge = { op: r.op ?? null, title: r.title ?? null };
139
+ if (svcOf(r.target) === service)
140
+ inbound.push({ from: svcOf(r.source), ...edge });
141
+ else if (svcOf(r.source) === service)
142
+ outbound.push({ to: svcOf(r.target), ...edge });
143
+ }
144
+ const expects = [...new Set(inbound.map((e) => e.op).filter((op) => op !== null))];
145
+ return {
146
+ present: true,
147
+ parses: true,
148
+ modelled: elements.length > 0,
149
+ elements,
150
+ inbound,
151
+ outbound,
152
+ expects,
153
+ instruction: elements.length > 0 ? null : instructionFor(service, "unmodelled", expects, servicePath),
154
+ };
155
+ }
156
+ /**
157
+ * The fleet-map instruction, in the three states a landscape can be in.
158
+ *
159
+ * It says the file, the block, and the consequence, in that order. The
160
+ * consequence is the part agents acted on: "add an element" reads as tidiness,
161
+ * "until you do, `loam validate --all` fails and no cross-service check can see
162
+ * this service" reads as work.
163
+ */
164
+ function instructionFor(service, state, expects, servicePath) {
165
+ const id = elementIdFor(service);
166
+ const bind = `an element bound with \`metadata { service '${service}' }\``;
167
+ const consequence = `Until one resolves, \`loam validate --all\` reports \`landscape.service-unmodelled\` (error) for ` +
168
+ `${servicePath}/: the service is documented and invisible — no edge into it can be checked ` +
169
+ `against its openapi.yaml, and no feature can draw a call to it.`;
170
+ // `expects` is reachable only through elements that already resolve to this
171
+ // service, so it is empty in every state that produces an instruction. It is
172
+ // threaded through anyway rather than dropped: the caller computes it once,
173
+ // and the day an unmodelled service can inherit an edge (a container-level
174
+ // binding, say) the sentence is already here instead of being noticed missing.
175
+ const owed = expects.length > 0
176
+ ? ` The fleet already calls ${expects.map((o) => `'${o}'`).join(", ")} on this service, so those edges exist; your element is what they will resolve to.`
177
+ : "";
178
+ if (state === "absent") {
179
+ return (`architecture/landscape.likec4 does not exist yet. Create it with a \`specification { ... }\` block ` +
180
+ `declaring the kinds you use and a \`model { ... }\` block containing ${bind} ` +
181
+ `(conventionally \`${id} = softwareSystem '${service}'\`), plus one edge per cross-service call, each ` +
182
+ `carrying \`metadata { op '<operationId>' }\`. ${consequence}${owed}`);
183
+ }
184
+ if (state === "unparseable") {
185
+ return (`architecture/landscape.likec4 exists but does not parse (\`landscape.invalid\`), so nothing can be said ` +
186
+ `about what it already models. Fix the parse errors first — they blind every cross-service check at once — ` +
187
+ `then make sure it holds ${bind}. ${consequence}`);
188
+ }
189
+ return (`Nothing in architecture/landscape.likec4 resolves to ${servicePath}/. ADD to that file — do not rewrite ` +
190
+ `it, every other service's map is in there — ${bind}, conventionally ` +
191
+ `\`${id} = softwareSystem '${service}'\`, inside the existing \`model { ... }\` block, and draw each ` +
192
+ `cross-service call as an edge carrying \`metadata { op '<operationId>' }\`. ${consequence}${owed}`);
193
+ }
194
+ //# sourceMappingURL=landscape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landscape.js","sourceRoot":"","sources":["../../../src/core/brief/landscape.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAa,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAIpF;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,OAAe;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IACrE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACvF,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChC,iEAAiE;IACjE,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC7E,CAAC;AAED;;;;;;GAMG;AACH,SAAS,cAAc,CAAC,OAAe,EAAE,OAAiB,EAAE,OAAgB;IAC1E,MAAM,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACjC,MAAM,KAAK,GACT,OAAO,CAAC,MAAM,GAAG,CAAC;QAChB,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,oBAAoB,EAAE,WAAW,EAAE,sBAAsB,EAAE,OAAO,CAAC;QACzF,CAAC,CAAC,CAAC,oBAAoB,EAAE,4DAA4D,CAAC,CAAC;IAC3F,MAAM,KAAK,GAAG;QACZ,SAAS;QACT,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,kEAAkE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5F,KAAK,EAAE,sBAAsB,OAAO,KAAK;QACzC,oEAAoE;QACpE,2BAA2B,OAAO,KAAK;QACvC,KAAK;QACL,EAAE;QACF,iDAAiD;QACjD,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;QACnC,GAAG;KACJ,CAAC;IACF,4EAA4E;IAC5E,0EAA0E;IAC1E,+EAA+E;IAC/E,kEAAkE;IAClE,yDAAyD;IACzD,OAAO,OAAO;QACZ,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QAClB,CAAC,CAAC,CAAC,iBAAiB,EAAE,0BAA0B,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACpF,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,OAAiB,EACjB,OAAgB,EAChB,WAAmB;IAEnB,OAAO;QACL,QAAQ,EAAE,kBAAkB;QAC5B,QAAQ,EAAE,IAAI;QACd,OAAO,EACL,wIAAwI;QAC1I,KAAK,EAAE;YACL,yNAAyN;YACzN,4FAA4F,OAAO,yCAAyC,WAAW,gFAAgF;YACvO,6PAA6P;YAC7P,mRAAmR;YACnR,0PAA0P;SAC3P;QACD,OAAO,EAAE,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;KACnD,CAAC;AACJ,CAAC;AA+CD;;;;;;GAMG;AACH,KAAK,UAAU,aAAa,CAAC,OAAgB;IAC3C,OAAO,IAAI,GAAG,CAAC,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAgB,EAAE,OAAe;IACtE,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACpC,+EAA+E;IAC/E,gFAAgF;IAChF,wEAAwE;IACxE,gDAAgD;IAChD,MAAM,WAAW,GAAG,MAAM,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAqB;QAC9B,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC;QACzB,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,IAAI;QACd,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE,EAAE;QACX,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,IAAI;KAClB,CAAC;IACF,IAAI,CAAC,KAAK,CAAC,OAAO;QAChB,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,cAAc,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,CAAC;IAExG,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QACxB,OAAO,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,WAAW,CAAC,EAAE,CAAC;IAE5F,MAAM,IAAI,GAAG,CAAC,CAAO,EAAW,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC;IACjE,MAAM,QAAQ,GAAuB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1E,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,KAAK,EAAE,CAAC,CAAC,OAAO,KAAK,SAAS;KAC/B,CAAC,CAAC,CAAC;IAEJ,4EAA4E;IAC5E,6EAA6E;IAC7E,0EAA0E;IAC1E,2EAA2E;IAC3E,oEAAoE;IACpE,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3E,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;QAC1D,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,OAAO;YAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;aAC7E,IAAI,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,OAAO;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IACxF,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;IACjG,OAAO;QACL,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC;QAC7B,QAAQ;QACR,OAAO;QACP,QAAQ;QACR,OAAO;QACP,WAAW,EACT,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,CAAC;KAC3F,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,cAAc,CACrB,OAAe,EACf,KAA8C,EAC9C,OAAiB,EACjB,WAAmB;IAEnB,MAAM,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,+CAA+C,OAAO,OAAO,CAAC;IAC3E,MAAM,WAAW,GACf,mGAAmG;QACnG,GAAG,WAAW,8EAA8E;QAC5F,iEAAiE,CAAC;IACpE,4EAA4E;IAC5E,6EAA6E;IAC7E,4EAA4E;IAC5E,2EAA2E;IAC3E,+EAA+E;IAC/E,MAAM,IAAI,GACR,OAAO,CAAC,MAAM,GAAG,CAAC;QAChB,CAAC,CAAC,4BAA4B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,oFAAoF;QACzJ,CAAC,CAAC,EAAE,CAAC;IAET,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvB,OAAO,CACL,qGAAqG;YACrG,wEAAwE,IAAI,GAAG;YAC/E,qBAAqB,EAAE,sBAAsB,OAAO,mDAAmD;YACvG,iDAAiD,WAAW,GAAG,IAAI,EAAE,CACtE,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;QAC5B,OAAO,CACL,0GAA0G;YAC1G,4GAA4G;YAC5G,2BAA2B,IAAI,KAAK,WAAW,EAAE,CAClD,CAAC;IACJ,CAAC;IACD,OAAO,CACL,wDAAwD,WAAW,uCAAuC;QAC1G,+CAA+C,IAAI,mBAAmB;QACtE,KAAK,EAAE,sBAAsB,OAAO,kEAAkE;QACtG,+EAA+E,WAAW,GAAG,IAAI,EAAE,CACpG,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The fleet-map half of the adoption brief: what `architecture/landscape.likec4`\n * already says about one service — its elements, its inbound and outbound\n * edges, the operations the fleet already calls on it — and the block the\n * service still owes the file when nothing in it resolves to the service yet.\n * Both halves exist to stop an agent inventing a parallel model: the fleet has\n * already drawn some of these boxes and edges, and a baseline has to attach to\n * them.\n */\nimport { existsSync } from \"node:fs\";\nimport { loadFile, type Elem } from \"../c4/likec4.js\";\nimport { elementService, serviceResolver } from \"../c4/resolve/service.js\";\nimport { landscapePath } from \"../repo/paths.js\";\nimport { enumeratedServiceIds, serviceTreePathOf } from \"../repo/service-target.js\";\nimport type { BriefTarget } from \"./targets.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\n\n/**\n * The LikeC4 identifier the fleet map's element for a service conventionally\n * carries: the directory name, camel-cased. It is a suggestion and nothing\n * more — `metadata { service '<id>' }` is what actually joins the element to\n * the directory — but a brief that hands over a concrete block gets followed,\n * and one that describes a block in prose gets improvised on.\n */\nfunction elementIdFor(service: string): string {\n const parts = service.split(/[^A-Za-z0-9]+/).filter((p) => p !== \"\");\n if (parts.length === 0) return \"service\";\n const head = parts[0]!.toLowerCase();\n const tail = parts.slice(1).map((p) => p[0]!.toUpperCase() + p.slice(1).toLowerCase());\n const id = head + tail.join(\"\");\n // LikeC4 identifiers cannot open with a digit; a service id can.\n return /^[0-9]/.test(id) ? `svc${id[0]!.toUpperCase()}${id.slice(1)}` : id;\n}\n\n/**\n * The block this service still owes `architecture/landscape.likec4`.\n *\n * `expects` is what the fleet ALREADY calls on the service — those edges exist\n * in the map today, so the example draws the outbound side as a comment rather\n * than telling an agent to duplicate an edge that is already there.\n */\nfunction landscapeBlock(service: string, expects: string[], present: boolean): string {\n const id = elementIdFor(service);\n const calls =\n expects.length > 0\n ? expects.map((op) => `// <caller> -> ${id} 'Calls ${op}' { metadata { op '${op}' } }`)\n : [`// <caller> -> ${id} 'Calls <operationId>' { metadata { op '<operationId>' } }`];\n const model = [\n \"model {\",\n ...(present ? [\" // ... the fleet's other services stay exactly as they are ...\", \"\"] : []),\n ` ${id} = softwareSystem '${service}' {`,\n \" description '<one line: what this service is responsible for>'\",\n ` metadata { service '${service}' }`,\n \" }\",\n \"\",\n \" // every call in or out of it, one edge each:\",\n ...calls.map((line) => ` ${line}`),\n \"}\",\n ];\n // When the file does not exist the example is the WHOLE file, so it carries\n // the `specification` block a bare `model` would be rejected without: the\n // brief must never hand over a document `loam validate` refuses. When the file\n // does exist the example is a fragment to splice, and repeating a\n // `specification` block there would invite a second one.\n return present\n ? model.join(\"\\n\")\n : [\"specification {\", \" element softwareSystem\", \"}\", \"\", ...model].join(\"\\n\");\n}\n\n/** The fleet map's own brief — assembled per service, because the block it owes names the service. */\nexport function landscapeArtifact(\n service: string,\n expects: string[],\n present: boolean,\n servicePath: string,\n): Omit<BriefTarget, \"path\" | \"exists\" | \"action\"> {\n return {\n artifact: \"landscape.likec4\",\n required: true,\n purpose:\n \"the fleet map — until an element here resolves to this directory, the service is documented and invisible to every cross-service check\",\n shape: [\n \"This file is the WHOLE FLEET's, not this service's. Add to it; never rewrite it. Everything already in `model { ... }` belongs to the other services, and replacing the file destroys their map along with their edges.\",\n `Add one top-level element for the service, bound to its directory: \\`metadata { service '${service}' }\\`. Until an element resolves to \\`${servicePath}/\\`, \\`loam validate --all\\` reports \\`landscape.service-unmodelled\\` (error).`,\n \"Bind rather than rename: a binding whose id names no directory is `landscape.binding-unknown` (error), and two elements binding the SAME directory is `landscape.binding-duplicate` (warn) — every element→service join then picks one of them arbitrarily.\",\n \"Draw every cross-service call as an edge carrying the operation it uses: `a -> b 'Calls createSplit' { metadata { op 'createSplit' } }`. The `op` must be an operationId the TARGET's openapi.yaml defines, or `spine.op-undefined` (error) — a broken contract between services.\",\n \"If the file does not exist yet, create it with a `specification { ... }` block declaring the kinds you use, then the `model { ... }` block. A landscape that does not parse is `landscape.invalid` (error) and blinds every cross-service check at once.\",\n ],\n example: landscapeBlock(service, expects, present),\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* What the fleet already says about this service */\n/* ------------------------------------------------------------------ */\n\nexport interface LandscapeElement {\n id: string;\n title: string;\n kind: string;\n tags: string[];\n /** True when the element binds explicitly with `metadata { service }`. */\n bound: boolean;\n}\n\nexport interface LandscapeEdge {\n from?: string;\n to?: string;\n op: string | null;\n title: string | null;\n}\n\nexport interface LandscapeContext {\n present: boolean;\n /** False when the landscape exists but does not parse. */\n parses: boolean;\n /** Whether any element resolves to this service — null when nothing could be read. */\n modelled: boolean | null;\n elements: LandscapeElement[];\n inbound: LandscapeEdge[];\n outbound: LandscapeEdge[];\n /** Operations other services already call on this one: the contract owes them. */\n expects: string[];\n /**\n * The write this service still owes the fleet map, in prose — null once an\n * element resolves to it.\n *\n * It duplicates the `landscape.likec4` target's shape rules on purpose: an\n * agent driving off `--json` reads `landscape` to learn what the fleet\n * already says, and every `targets[]` consumer walks the artifact list. Only\n * one of those two readers used to exist, so `adopt` briefed eight files and\n * never once said the ninth thing — that a documented service nobody drew is\n * invisible to the whole cross-service layer.\n */\n instruction: string | null;\n}\n\n/**\n * The service ids the resolver may fall back on when an element carries no\n * `metadata { service }` binding — the same positive evidence `validate` and\n * `list` hand it. A docs repo that cannot be enumerated (no `services/` yet:\n * `adopt` runs there) leaves the resolver with bindings alone, which is what it\n * had before.\n */\nasync function knownServices(docsDir: DocsDir): Promise<ReadonlySet<string>> {\n return new Set(await enumeratedServiceIds(docsDir));\n}\n\n/**\n * What the living landscape already says about this service.\n *\n * This is the half of the brief that stops an agent inventing a parallel model:\n * the fleet has already drawn some of these boxes and edges, and the baseline has\n * to attach to them. A landscape that does not parse yields `modelled: null` —\n * \"nothing models it\" would be a claim about a document nobody could read.\n */\nexport async function landscapeContext(docsDir: DocsDir, service: string): Promise<LandscapeContext> {\n const path = landscapePath(docsDir);\n // The service's own directory, spelled from the enumeration rather than joined\n // at the root: this text is handed to an AGENT that will go and edit files, and\n // a filed service named at `services/<id>/` sends it to create a second\n // directory beside the one that already exists.\n const servicePath = await serviceTreePathOf(docsDir, service);\n const empty: LandscapeContext = {\n present: existsSync(path),\n parses: false,\n modelled: null,\n elements: [],\n inbound: [],\n outbound: [],\n expects: [],\n instruction: null,\n };\n if (!empty.present)\n return { ...empty, modelled: false, instruction: instructionFor(service, \"absent\", [], servicePath) };\n\n const land = await loadFile(path);\n if (land.errors.length > 0)\n return { ...empty, instruction: instructionFor(service, \"unparseable\", [], servicePath) };\n\n const mine = (e: Elem): boolean => elementService(e) === service;\n const elements: LandscapeElement[] = land.elements.filter(mine).map((e) => ({\n id: e.id,\n title: e.title,\n kind: e.kind,\n tags: e.tags,\n bound: e.service !== undefined,\n }));\n\n // One resolver for the whole scan, built with the real service ids: an edge\n // drawn into a modelled container (`paymentService.api`) is an edge into the\n // service, and `expects` — which now decides whether this service owes an\n // OpenAPI contract at all — has to see it. Building it once also stops the\n // per-edge rebuild the old `serviceOf(land.elements, id)` call did.\n const svcOf = serviceResolver(land.elements, await knownServices(docsDir));\n const inbound: LandscapeEdge[] = [];\n const outbound: LandscapeEdge[] = [];\n for (const r of land.relationships) {\n const edge = { op: r.op ?? null, title: r.title ?? null };\n if (svcOf(r.target) === service) inbound.push({ from: svcOf(r.source), ...edge });\n else if (svcOf(r.source) === service) outbound.push({ to: svcOf(r.target), ...edge });\n }\n\n const expects = [...new Set(inbound.map((e) => e.op).filter((op): op is string => op !== null))];\n return {\n present: true,\n parses: true,\n modelled: elements.length > 0,\n elements,\n inbound,\n outbound,\n expects,\n instruction:\n elements.length > 0 ? null : instructionFor(service, \"unmodelled\", expects, servicePath),\n };\n}\n\n/**\n * The fleet-map instruction, in the three states a landscape can be in.\n *\n * It says the file, the block, and the consequence, in that order. The\n * consequence is the part agents acted on: \"add an element\" reads as tidiness,\n * \"until you do, `loam validate --all` fails and no cross-service check can see\n * this service\" reads as work.\n */\nfunction instructionFor(\n service: string,\n state: \"absent\" | \"unparseable\" | \"unmodelled\",\n expects: string[],\n servicePath: string,\n): string {\n const id = elementIdFor(service);\n const bind = `an element bound with \\`metadata { service '${service}' }\\``;\n const consequence =\n `Until one resolves, \\`loam validate --all\\` reports \\`landscape.service-unmodelled\\` (error) for ` +\n `${servicePath}/: the service is documented and invisible — no edge into it can be checked ` +\n `against its openapi.yaml, and no feature can draw a call to it.`;\n // `expects` is reachable only through elements that already resolve to this\n // service, so it is empty in every state that produces an instruction. It is\n // threaded through anyway rather than dropped: the caller computes it once,\n // and the day an unmodelled service can inherit an edge (a container-level\n // binding, say) the sentence is already here instead of being noticed missing.\n const owed =\n expects.length > 0\n ? ` The fleet already calls ${expects.map((o) => `'${o}'`).join(\", \")} on this service, so those edges exist; your element is what they will resolve to.`\n : \"\";\n\n if (state === \"absent\") {\n return (\n `architecture/landscape.likec4 does not exist yet. Create it with a \\`specification { ... }\\` block ` +\n `declaring the kinds you use and a \\`model { ... }\\` block containing ${bind} ` +\n `(conventionally \\`${id} = softwareSystem '${service}'\\`), plus one edge per cross-service call, each ` +\n `carrying \\`metadata { op '<operationId>' }\\`. ${consequence}${owed}`\n );\n }\n if (state === \"unparseable\") {\n return (\n `architecture/landscape.likec4 exists but does not parse (\\`landscape.invalid\\`), so nothing can be said ` +\n `about what it already models. Fix the parse errors first — they blind every cross-service check at once — ` +\n `then make sure it holds ${bind}. ${consequence}`\n );\n }\n return (\n `Nothing in architecture/landscape.likec4 resolves to ${servicePath}/. ADD to that file — do not rewrite ` +\n `it, every other service's map is in there — ${bind}, conventionally ` +\n `\\`${id} = softwareSystem '${service}'\\`, inside the existing \\`model { ... }\\` block, and draw each ` +\n `cross-service call as an edge carrying \\`metadata { op '<operationId>' }\\`. ${consequence}${owed}`\n );\n}\n"]}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * The artifacts of the adoption brief: what each file under `services/<svc>/`
3
+ * is for, the grammar it has to be written in, and a minimal valid example
4
+ * where showing one is shorter than describing it. Every `shape` rule here is
5
+ * one a later check depends on, and test/agent-contract.test.ts pins the
6
+ * mapping. This module is the list alone — `serviceBrief` (brief.ts) resolves
7
+ * it against a docs repo, and the fleet map's own target, whose block names
8
+ * the service, is assembled per service in landscape.ts.
9
+ */
10
+ /** The artifacts, in the order a baseline is best written in. */
11
+ export const ARTIFACTS = [
12
+ {
13
+ artifact: "model.likec4",
14
+ key: "model",
15
+ required: true,
16
+ purpose: "the service's C4 — what it is, what is inside it, what it talks to",
17
+ // Every rule below is one a later check depends on, and the mapping is
18
+ // pinned in test/agent-contract.test.ts. Rules nobody checks — the `views`
19
+ // block, "exactly one top-level element" — used to sit here reading exactly
20
+ // like the enforced ones, which is how a brief teaches an agent that
21
+ // `loam validate` passing means more than it does. They now live in
22
+ // UNCHECKED, where their status is the point.
23
+ shape: [
24
+ "A `specification { ... }` block declaring every element kind you use (`element softwareSystem`, `element container`). LikeC4 rejects an undeclared kind, and `loam validate --service <id>` reports it as `c4.invalid` with line numbers.",
25
+ "A `model { ... }` block holding the service's element, with containers and components nested inside it. The whole file has to parse — `loam validate` runs LikeC4 in-process and reports `c4.invalid` with line numbers.",
26
+ "The service element binds to this directory: `metadata { service '<id>' }`. Without a binding the element's TITLE has to equal the directory name — and then renaming the box silently unlinks every check that joined the two. The same binding is what makes the FLEET map resolve an element to `services/<id>/`; until one does, `loam validate --all` reports `landscape.service-unmodelled`.",
27
+ "A call to another service is an edge that names the operation it uses: `a -> b 'Calls createSplit' { metadata { op 'createSplit' } }`. Cross-service edges belong in `architecture/landscape.likec4` (a target of its own, below) — this file cannot even resolve the other service's element — and there the `op` must be an operationId the TARGET's openapi.yaml defines, or `spine.op-undefined` fires.",
28
+ ],
29
+ example: `specification {
30
+ element softwareSystem
31
+ element container
32
+ }
33
+
34
+ model {
35
+ paymentService = softwareSystem 'payment-service' {
36
+ description 'Owns payment authorization and capture'
37
+ metadata { service 'payment-service' }
38
+
39
+ api = container 'HTTP API'
40
+ ledger = container 'Ledger store'
41
+ }
42
+ }
43
+
44
+ // Views are LikeC4's, not loam's: loam parses this file and computes no view,
45
+ // and it never reads a STATIC view's contents in any document, so nothing below
46
+ // is read by any check (docs/DESIGN.md rule 26 — the one thing loam does read is
47
+ // a dynamic view's declared steps, and only in the fleet landscape).
48
+ // Keep it for the renderer, which does draw it — 'npx likec4 start services/<id>' from the docs repo, pointed at THIS
49
+ // directory. Not the repo root: every service model declares its own
50
+ // 'specification' block, so the root is scoped to architecture/ (likec4.config.json)
51
+ // and one model at a time is how these files are meant to be read.
52
+ // Scoped to one service 'include *' is cheap; the same line in
53
+ // architecture/landscape.likec4 walks every call in the fleet and takes minutes.
54
+ views {
55
+ view of paymentService {
56
+ include *
57
+ }
58
+ }
59
+ `,
60
+ },
61
+ {
62
+ artifact: "spec.md",
63
+ key: "spec",
64
+ required: true,
65
+ purpose: "the living requirements — what this service is required to do, as it stands today",
66
+ shape: [
67
+ "Frontmatter (below), then a `## Requirements` heading.",
68
+ "`### Requirement: <name>` — ONE observable behaviour, written with SHALL, testable without reading the code. Add `Requirement-ID: <id>` in its body for stable identity across heading renames; legacy requirements without one continue to match by exact name.",
69
+ "At least one `#### Scenario: <name>` per requirement, with Given/When/Then bullets. This is gated (`requirements.missing-scenarios`) — scenarios are the acceptance criteria and the source for tests.",
70
+ "A markdown TABLE in a scenario body becomes the `Examples` of a `Scenario Outline`: the header names the placeholders the steps use (`<permission>`), one row per case. This is how a matrix is written — a permission matrix, a validation matrix, a status-code table is ONE scenario with twenty rows, never twenty scenarios. `loam gherkin` emits the outline, cucumber reports one result per row carrying that scenario's digest tag, and `loam verify --results` confirms the claim only when EVERY row passed. Every row must have the header's column count and a header needs at least one row: a table loam cannot read stays in the description, the scenario then runs once instead of once per case, and the emission says so out loud.",
71
+ "A step takes an ARGUMENT by carrying it INDENTED under the bullet, and this is what lets one scenario assert a whole data pass rather than a sentence. An indented table becomes that step's Gherkin DATA TABLE — `- **Then** the outbox holds:` followed by the rows it must hold; a fenced block becomes its DOCSTRING, indentation intact — `- **When** the caller posts:` followed by the JSON body. Indentation is the entire disambiguation: indented under a step means this step's rows, at the margin means the scenario's cases, and both ride into the scenario digest. Write the ASSERTIONS OUT, one bullet each, including the negative ones (`no row is created in ...`, `... is not invoked`) and each meter separately: a scenario that summarises them reads complete, emits valid Gherkin, grades green, and tests a fraction of what it claims.",
72
+ "`Requires: <subject>/<permission>[, ...]` in the requirement body names the authorization it is gated on, resolved against the FLEET vocabulary in `architecture/permissions.yaml`. An entry that is not declared there is `permissions.unknown` (error) — the same grade as `Operations:`, because an invented permission reads exactly like a real one everywhere downstream. Add the permission to that file when this service enforces one nobody has written down yet; the subject is the entity it is checked ON (`user`, `profile`, `service`), which is not always the caller.",
73
+ "`Capability: <id>[, ...]` in the requirement body names the fleet capabilities this requirement realizes part of, declared in `architecture/capabilities.yaml`. A LIST, because the relation is many-to-many: one requirement commonly closes part of two capabilities. The FILE is this axis's opt-in — a fleet without it gets no capability findings — and once it exists an undeclared name is `capability.unknown` (error). Write the line only where the requirement genuinely carries part of the named capability.",
74
+ "Write the requirement body in EARS form — `WHEN <trigger> THE SYSTEM SHALL <response>`, `IF <precondition> THEN THE SYSTEM SHALL <response>`, `WHERE <feature is included> THE SYSTEM SHALL <response>`, or a bare `THE SYSTEM SHALL <response>` when it is unconditional. **Nothing checks this** — it is a writing convention, and it is here because the grammar forces the trigger and the response to be named separately, while free prose lets a requirement read as complete while stating no condition at all. That is the exact shape a guard collapses into when it is summarised rather than enumerated.",
75
+ "`Operations: <operationId>[, <operationId>]` in the requirement body names the API operations it governs. Every one must exist in this service's openapi.yaml — a name that does not is `spec-api.op-undefined` (error), reported against the LIVING spec, not only inside a feature delta.",
76
+ "Document what the service DOES today, not what it should do. This is the baseline; changes to it belong in a feature delta.",
77
+ ],
78
+ example: `---
79
+ service: payment-service
80
+ status: draft
81
+ owner: payments-team
82
+ sources:
83
+ - src/main/java/com/shop/payment/
84
+ ---
85
+
86
+ # payment-service
87
+
88
+ ## Requirements
89
+
90
+ ### Requirement: Authorize a payment
91
+ WHEN authorization is requested for a captured-eligible order THE SYSTEM SHALL
92
+ authorize it against the issuer before any capture.
93
+
94
+ Operations: authorizePayment
95
+
96
+ #### Scenario: Successful authorization
97
+ - **Given** a valid card and an amount within its limit
98
+ - **When** authorization is requested
99
+ - **Then** the payment is authorized and an authorization id is returned
100
+
101
+ ### Requirement: Refunding is permission-gated
102
+ IF the caller lacks the refund permission THEN THE SYSTEM SHALL refuse the
103
+ request and leave the payment untouched.
104
+
105
+ Operations: refundPayment
106
+
107
+ #### Scenario: Refund by permission
108
+ - **Given** a captured payment
109
+ - **When** a caller holding <permission> requests a refund
110
+ - **Then** the response is <status> and the payment is <state>
111
+
112
+ | permission | status | state |
113
+ |-----------------|--------|----------|
114
+ | payments:refund | 200 | refunded |
115
+ | payments:read | 403 | captured |
116
+ | (none) | 401 | captured |
117
+ `,
118
+ },
119
+ {
120
+ artifact: "arch.spec.md",
121
+ key: "archSpec",
122
+ required: false,
123
+ purpose: "the living architecture requirements — the obligations the business spec never carries: outbox, retries, idempotency, metrics, alerts",
124
+ shape: [
125
+ "Same grammar and frontmatter as spec.md: `## Requirements`, `### Requirement:` + `#### Scenario:` with Given/When/Then. The same checks read it.",
126
+ "A `Covers:` line per requirement names what its scenarios exercise: a C4 element id (`paymentService.db`), an edge (`paymentService -> kafka`), or a health signal from health.yaml (`alert:<id>` / `sli:<id>`). Every entry must resolve, or `covers.unknown` (warn) flags the typo.",
127
+ "Optional, but expected for a service with real architecture: every alert/SLI health.yaml declares wants a covering requirement here (`health.uncovered`, warn) — a signal nothing tests is dashboard decoration.",
128
+ "Write the obligations no business requirement states — the transactional outbox, what a caller's retry may assume, what pages whom. An arch scenario becomes an integration/ops test, not an acceptance test.",
129
+ ],
130
+ example: `---
131
+ service: payment-service
132
+ status: draft
133
+ owner: payments-team
134
+ sources:
135
+ - src/main/java/com/shop/payment/
136
+ ---
137
+
138
+ # payment-service — architecture
139
+
140
+ ## Requirements
141
+
142
+ ### Requirement: Events leave through the transactional outbox
143
+ The service SHALL write a domain event and its state change in one transaction,
144
+ published by an outbox relay — never a dual write.
145
+
146
+ Covers: paymentService.db, paymentService -> kafka
147
+
148
+ #### Scenario: Broker down at commit time
149
+ - **Given** an event in the outbox
150
+ - **When** the broker is unavailable
151
+ - **Then** the state stays committed and the event is published once it returns
152
+ `,
153
+ },
154
+ {
155
+ artifact: "openapi.yaml",
156
+ key: "openapi",
157
+ // Overridden per service in `serviceBrief` (brief.ts): an API is required
158
+ // only where the fleet expects one. See `apiExpected` there.
159
+ required: true,
160
+ purpose: "the API contract — the operations this service exposes",
161
+ shape: [
162
+ "OpenAPI 3.x with a `paths` map.",
163
+ "EVERY operation carries an `operationId`. That token is the spine: the C4 edge's `metadata { op }`, the requirement's `Operations:` line and this `operationId` are one name spelled three times, and they must be identical.",
164
+ "loam reads operationIds, and probes the rest by PRESENCE only: an operation whose responses declare no schema warns (`openapi.response-undescribed`), an internal `$ref` to nothing warns (`openapi.ref-unresolved`). What a declared schema SAYS is still never checked — the schemas are for humans, codegen and review, so getting them wrong is invisible here and expensive later.",
165
+ "Document the endpoints that exist. An operation the fleet already calls (see `landscape.expects`) must be in here, or the contract breaks the moment this lands.",
166
+ // The instruction the brief was missing, and the one that matters most:
167
+ // it used to mark this artifact required unconditionally, in capitals,
168
+ // which for a UI, a worker or a cron told the agent to invent an API into
169
+ // the source of truth. `required` is derived now; this says so in prose
170
+ // as well, because an agent reading the shape rules must not re-derive
171
+ // "MISSING" as "write something".
172
+ "If this service exposes no HTTP API, there is no file to write. Do not invent one — an empty or imagined contract is a claim the whole fleet then joins against. `required` above is derived from the fleet map: it is false exactly when the landscape parses and no edge calls an operation on this service, which is the same evidence that keeps `service.no-openapi` quiet.",
173
+ ],
174
+ },
175
+ {
176
+ artifact: "asyncapi.yaml",
177
+ key: "asyncapi",
178
+ // Never required. Unlike the HTTP contract, whose necessity the fleet map
179
+ // can PROVE (an op-linked edge points here), most services in a legacy fleet
180
+ // touch no topic at all — and a required artifact nobody owes is how a
181
+ // whole adoption wave learns to ignore the brief.
182
+ required: false,
183
+ purpose: "the async contract — the messages this service puts on and takes off the bus",
184
+ shape: [
185
+ "AsyncAPI **3.0** with `channels`, `operations` and `components.messages`. Only 3.0 is read: its operations are named top-level objects carrying `action: send|receive`, which is what makes a message's direction legible. A 2.x document declares no `operations` and reads as a contract with no messages.",
186
+ "EVERY message carries a `name` (or is declared under the key you intend to reference). That token is the spine: the C4 edge's `metadata { publishes }` / `metadata { consumes }`, the requirement's `Publishes:` / `Consumes:` line and this name are one name spelled three times.",
187
+ "Namespace the name by the domain that owns it — `payment.PaymentAuthorized`. One message has exactly one producer; two services declaring they send one name is `asyncapi.message-contested`, and then which contract a consumer reads is a coin flip.",
188
+ "loam reads message names and the `action` of the operation carrying them. **It never joins on anything inside `payload`** — the one look inside is a presence probe: a payload declaring no shape at all warns (`asyncapi.payload-undescribed`), and a payload with a non-JSON `schemaFormat` is skipped outright. Write the payload as JSON Schema today; if the fleet later adopts Avro, that is a `schemaFormat` line here and nothing in loam changes.",
189
+ "Keep payloads in `components.schemas` in THIS file rather than `$ref`-ing an external `.avsc`. External references are out of scope for the merge, exactly as on the OpenAPI axis, so a schema in another file will not travel with the message that needs it.",
190
+ "If this service publishes and consumes nothing, there is no file to write. Do not invent one.",
191
+ ],
192
+ },
193
+ {
194
+ artifact: "adrs/",
195
+ key: "adrsDir",
196
+ required: false,
197
+ purpose: "the decisions behind the shape of the service",
198
+ shape: [
199
+ "One file per decision: `adrs/NNNN-<slug>.md`, MADR-style (context · decision · consequences).",
200
+ "Only decisions whose consequences are still visible in the code. A reconstructed rationale for something nobody decided is fiction, and it is the kind that survives review because it sounds reasonable.",
201
+ "If a decision is evident but its reasoning is not, write the decision and say the reasoning is unknown. That is a fact; a plausible motive is not.",
202
+ ],
203
+ },
204
+ {
205
+ artifact: "runbook.md",
206
+ key: "runbook",
207
+ required: false,
208
+ purpose: "how it is run — deploys, dependencies, what to do when it pages",
209
+ shape: [
210
+ "Frontmatter, then how it is deployed and configured, what it depends on, and what to do about the failures that actually happen.",
211
+ "Written from what is in the repo (pipelines, manifests, alert definitions). Whoever carries the pager verifies it; leave `status: draft` until they have.",
212
+ "A 'configured but not a dependency, and why' list: every capability the configuration wires up that the deploy manifest switches off. Without it, the next reader re-derives the dependency from the config and re-adds what the manifest already removed.",
213
+ ],
214
+ },
215
+ {
216
+ artifact: "health.yaml",
217
+ key: "health",
218
+ required: false,
219
+ purpose: "SLIs, SLOs, checks and the dependencies that are critical",
220
+ shape: [
221
+ "SLIs and SLOs as they have been AGREED, plus health checks and critical dependencies.",
222
+ "If no SLO has ever been agreed, say so and leave it out. An invented 99.9% becomes a number other teams plan against.",
223
+ ],
224
+ },
225
+ ];
226
+ //# sourceMappingURL=targets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targets.js","sourceRoot":"","sources":["../../../src/core/brief/targets.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAiDH,iEAAiE;AACjE,MAAM,CAAC,MAAM,SAAS,GAA8E;IAClG;QACE,QAAQ,EAAE,cAAc;QACxB,GAAG,EAAE,OAAO;QACZ,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE,oEAAoE;QAC7E,uEAAuE;QACvE,2EAA2E;QAC3E,4EAA4E;QAC5E,qEAAqE;QACrE,oEAAoE;QACpE,8CAA8C;QAC9C,KAAK,EAAE;YACL,2OAA2O;YAC3O,0NAA0N;YAC1N,oYAAoY;YACpY,6YAA6Y;SAC9Y;QACD,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BZ;KACE;IACD;QACE,QAAQ,EAAE,SAAS;QACnB,GAAG,EAAE,MAAM;QACX,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE,mFAAmF;QAC5F,KAAK,EAAE;YACL,wDAAwD;YACxD,kQAAkQ;YAClQ,wMAAwM;YACxM,wtBAAwtB;YACxtB,o0BAAo0B;YACp0B,wjBAAwjB;YACxjB,4fAA4f;YAC5f,slBAAslB;YACtlB,6RAA6R;YAC7R,6HAA6H;SAC9H;QACD,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuCZ;KACE;IACD;QACE,QAAQ,EAAE,cAAc;QACxB,GAAG,EAAE,UAAU;QACf,QAAQ,EAAE,KAAK;QACf,OAAO,EACL,uIAAuI;QACzI,KAAK,EAAE;YACL,kJAAkJ;YAClJ,uRAAuR;YACvR,kNAAkN;YAClN,+MAA+M;SAChN;QACD,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;CAsBZ;KACE;IACD;QACE,QAAQ,EAAE,cAAc;QACxB,GAAG,EAAE,SAAS;QACd,0EAA0E;QAC1E,6DAA6D;QAC7D,QAAQ,EAAE,IAAI;QACd,OAAO,EAAE,wDAAwD;QACjE,KAAK,EAAE;YACL,iCAAiC;YACjC,+NAA+N;YAC/N,yXAAyX;YACzX,kKAAkK;YAClK,wEAAwE;YACxE,uEAAuE;YACvE,0EAA0E;YAC1E,wEAAwE;YACxE,uEAAuE;YACvE,kCAAkC;YAClC,kXAAkX;SACnX;KACF;IACD;QACE,QAAQ,EAAE,eAAe;QACzB,GAAG,EAAE,UAAU;QACf,0EAA0E;QAC1E,6EAA6E;QAC7E,uEAAuE;QACvE,kDAAkD;QAClD,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,8EAA8E;QACvF,KAAK,EAAE;YACL,8SAA8S;YAC9S,qRAAqR;YACrR,wPAAwP;YACxP,4bAA4b;YAC5b,gQAAgQ;YAChQ,+FAA+F;SAChG;KACF;IACD;QACE,QAAQ,EAAE,OAAO;QACjB,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,+CAA+C;QACxD,KAAK,EAAE;YACL,+FAA+F;YAC/F,2MAA2M;YAC3M,oJAAoJ;SACrJ;KACF;IACD;QACE,QAAQ,EAAE,YAAY;QACtB,GAAG,EAAE,SAAS;QACd,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,iEAAiE;QAC1E,KAAK,EAAE;YACL,kIAAkI;YAClI,2JAA2J;YAC3J,4PAA4P;SAC7P;KACF;IACD;QACE,QAAQ,EAAE,aAAa;QACvB,GAAG,EAAE,QAAQ;QACb,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,2DAA2D;QACpE,KAAK,EAAE;YACL,uFAAuF;YACvF,uHAAuH;SACxH;KACF;CACF,CAAC","sourcesContent":["/**\n * The artifacts of the adoption brief: what each file under `services/<svc>/`\n * is for, the grammar it has to be written in, and a minimal valid example\n * where showing one is shorter than describing it. Every `shape` rule here is\n * one a later check depends on, and test/agent-contract.test.ts pins the\n * mapping. This module is the list alone — `serviceBrief` (brief.ts) resolves\n * it against a docs repo, and the fleet map's own target, whose block names\n * the service, is assembled per service in landscape.ts.\n */\n\n/* ------------------------------------------------------------------ */\n/* The artifacts */\n/* ------------------------------------------------------------------ */\n\nexport interface BriefTarget {\n /** File name as it appears under `services/<svc>/`. */\n artifact: string;\n /** Repo-relative path to write. */\n path: string;\n exists: boolean;\n /**\n * `create` a missing artifact; `diff` an existing one — never overwrite it.\n *\n * `edit` is the third case and belongs to exactly one target: the fleet map.\n * `architecture/landscape.likec4` is a SHARED document that already holds\n * every other service, so \"diff it and report what disagrees\" is the wrong\n * instruction — the file is not this service's baseline, it is the fleet's,\n * and what this service owes it is an addition inside the existing\n * `model { … }` block. Spelling that as `diff` taught agents to leave the\n * fleet map alone; spelling it as `create` would have taught them to\n * overwrite ten other services.\n */\n action: \"create\" | \"diff\" | \"edit\";\n /**\n * False for artifacts a baseline can legitimately ship without. True means\n * required for a COMPLETE baseline — validate grades a missing spec.md or\n * openapi.yaml as a warn (`service.no-spec` / `service.no-openapi`), not an\n * error: partial adoption is a supported state, and the warns are the\n * progress meter.\n *\n * Constant per artifact except one: `openapi.yaml` is required only where the\n * fleet map shows an API is expected (see `apiExpected` in brief.ts), because\n * the brief is read as an instruction and \"MISSING openapi.yaml\" told an agent\n * to write a contract for a service that serves no requests.\n */\n required: boolean;\n /** What the artifact is for, in one line. */\n purpose: string;\n /** The grammar. Every rule here is one a later check depends on. */\n shape: string[];\n /** A minimal valid instance, where showing one is shorter than describing it. */\n example?: string;\n}\n\n/** Where an artifact lives — `repo/paths.ts` spells the filenames, this only points at them. */\ntype PathKey = \"model\" | \"spec\" | \"archSpec\" | \"openapi\" | \"asyncapi\" | \"adrsDir\" | \"runbook\" | \"health\";\n\n/** The artifacts, in the order a baseline is best written in. */\nexport const ARTIFACTS: Array<Omit<BriefTarget, \"path\" | \"exists\" | \"action\"> & { key: PathKey }> = [\n {\n artifact: \"model.likec4\",\n key: \"model\",\n required: true,\n purpose: \"the service's C4 — what it is, what is inside it, what it talks to\",\n // Every rule below is one a later check depends on, and the mapping is\n // pinned in test/agent-contract.test.ts. Rules nobody checks — the `views`\n // block, \"exactly one top-level element\" — used to sit here reading exactly\n // like the enforced ones, which is how a brief teaches an agent that\n // `loam validate` passing means more than it does. They now live in\n // UNCHECKED, where their status is the point.\n shape: [\n \"A `specification { ... }` block declaring every element kind you use (`element softwareSystem`, `element container`). LikeC4 rejects an undeclared kind, and `loam validate --service <id>` reports it as `c4.invalid` with line numbers.\",\n \"A `model { ... }` block holding the service's element, with containers and components nested inside it. The whole file has to parse — `loam validate` runs LikeC4 in-process and reports `c4.invalid` with line numbers.\",\n \"The service element binds to this directory: `metadata { service '<id>' }`. Without a binding the element's TITLE has to equal the directory name — and then renaming the box silently unlinks every check that joined the two. The same binding is what makes the FLEET map resolve an element to `services/<id>/`; until one does, `loam validate --all` reports `landscape.service-unmodelled`.\",\n \"A call to another service is an edge that names the operation it uses: `a -> b 'Calls createSplit' { metadata { op 'createSplit' } }`. Cross-service edges belong in `architecture/landscape.likec4` (a target of its own, below) — this file cannot even resolve the other service's element — and there the `op` must be an operationId the TARGET's openapi.yaml defines, or `spine.op-undefined` fires.\",\n ],\n example: `specification {\n element softwareSystem\n element container\n}\n\nmodel {\n paymentService = softwareSystem 'payment-service' {\n description 'Owns payment authorization and capture'\n metadata { service 'payment-service' }\n\n api = container 'HTTP API'\n ledger = container 'Ledger store'\n }\n}\n\n// Views are LikeC4's, not loam's: loam parses this file and computes no view,\n// and it never reads a STATIC view's contents in any document, so nothing below\n// is read by any check (docs/DESIGN.md rule 26 — the one thing loam does read is\n// a dynamic view's declared steps, and only in the fleet landscape).\n// Keep it for the renderer, which does draw it — 'npx likec4 start services/<id>' from the docs repo, pointed at THIS\n// directory. Not the repo root: every service model declares its own\n// 'specification' block, so the root is scoped to architecture/ (likec4.config.json)\n// and one model at a time is how these files are meant to be read.\n// Scoped to one service 'include *' is cheap; the same line in\n// architecture/landscape.likec4 walks every call in the fleet and takes minutes.\nviews {\n view of paymentService {\n include *\n }\n}\n`,\n },\n {\n artifact: \"spec.md\",\n key: \"spec\",\n required: true,\n purpose: \"the living requirements — what this service is required to do, as it stands today\",\n shape: [\n \"Frontmatter (below), then a `## Requirements` heading.\",\n \"`### Requirement: <name>` — ONE observable behaviour, written with SHALL, testable without reading the code. Add `Requirement-ID: <id>` in its body for stable identity across heading renames; legacy requirements without one continue to match by exact name.\",\n \"At least one `#### Scenario: <name>` per requirement, with Given/When/Then bullets. This is gated (`requirements.missing-scenarios`) — scenarios are the acceptance criteria and the source for tests.\",\n \"A markdown TABLE in a scenario body becomes the `Examples` of a `Scenario Outline`: the header names the placeholders the steps use (`<permission>`), one row per case. This is how a matrix is written — a permission matrix, a validation matrix, a status-code table is ONE scenario with twenty rows, never twenty scenarios. `loam gherkin` emits the outline, cucumber reports one result per row carrying that scenario's digest tag, and `loam verify --results` confirms the claim only when EVERY row passed. Every row must have the header's column count and a header needs at least one row: a table loam cannot read stays in the description, the scenario then runs once instead of once per case, and the emission says so out loud.\",\n \"A step takes an ARGUMENT by carrying it INDENTED under the bullet, and this is what lets one scenario assert a whole data pass rather than a sentence. An indented table becomes that step's Gherkin DATA TABLE — `- **Then** the outbox holds:` followed by the rows it must hold; a fenced block becomes its DOCSTRING, indentation intact — `- **When** the caller posts:` followed by the JSON body. Indentation is the entire disambiguation: indented under a step means this step's rows, at the margin means the scenario's cases, and both ride into the scenario digest. Write the ASSERTIONS OUT, one bullet each, including the negative ones (`no row is created in ...`, `... is not invoked`) and each meter separately: a scenario that summarises them reads complete, emits valid Gherkin, grades green, and tests a fraction of what it claims.\",\n \"`Requires: <subject>/<permission>[, ...]` in the requirement body names the authorization it is gated on, resolved against the FLEET vocabulary in `architecture/permissions.yaml`. An entry that is not declared there is `permissions.unknown` (error) — the same grade as `Operations:`, because an invented permission reads exactly like a real one everywhere downstream. Add the permission to that file when this service enforces one nobody has written down yet; the subject is the entity it is checked ON (`user`, `profile`, `service`), which is not always the caller.\",\n \"`Capability: <id>[, ...]` in the requirement body names the fleet capabilities this requirement realizes part of, declared in `architecture/capabilities.yaml`. A LIST, because the relation is many-to-many: one requirement commonly closes part of two capabilities. The FILE is this axis's opt-in — a fleet without it gets no capability findings — and once it exists an undeclared name is `capability.unknown` (error). Write the line only where the requirement genuinely carries part of the named capability.\",\n \"Write the requirement body in EARS form — `WHEN <trigger> THE SYSTEM SHALL <response>`, `IF <precondition> THEN THE SYSTEM SHALL <response>`, `WHERE <feature is included> THE SYSTEM SHALL <response>`, or a bare `THE SYSTEM SHALL <response>` when it is unconditional. **Nothing checks this** — it is a writing convention, and it is here because the grammar forces the trigger and the response to be named separately, while free prose lets a requirement read as complete while stating no condition at all. That is the exact shape a guard collapses into when it is summarised rather than enumerated.\",\n \"`Operations: <operationId>[, <operationId>]` in the requirement body names the API operations it governs. Every one must exist in this service's openapi.yaml — a name that does not is `spec-api.op-undefined` (error), reported against the LIVING spec, not only inside a feature delta.\",\n \"Document what the service DOES today, not what it should do. This is the baseline; changes to it belong in a feature delta.\",\n ],\n example: `---\nservice: payment-service\nstatus: draft\nowner: payments-team\nsources:\n - src/main/java/com/shop/payment/\n---\n\n# payment-service\n\n## Requirements\n\n### Requirement: Authorize a payment\nWHEN authorization is requested for a captured-eligible order THE SYSTEM SHALL\nauthorize it against the issuer before any capture.\n\nOperations: authorizePayment\n\n#### Scenario: Successful authorization\n- **Given** a valid card and an amount within its limit\n- **When** authorization is requested\n- **Then** the payment is authorized and an authorization id is returned\n\n### Requirement: Refunding is permission-gated\nIF the caller lacks the refund permission THEN THE SYSTEM SHALL refuse the\nrequest and leave the payment untouched.\n\nOperations: refundPayment\n\n#### Scenario: Refund by permission\n- **Given** a captured payment\n- **When** a caller holding <permission> requests a refund\n- **Then** the response is <status> and the payment is <state>\n\n| permission | status | state |\n|-----------------|--------|----------|\n| payments:refund | 200 | refunded |\n| payments:read | 403 | captured |\n| (none) | 401 | captured |\n`,\n },\n {\n artifact: \"arch.spec.md\",\n key: \"archSpec\",\n required: false,\n purpose:\n \"the living architecture requirements — the obligations the business spec never carries: outbox, retries, idempotency, metrics, alerts\",\n shape: [\n \"Same grammar and frontmatter as spec.md: `## Requirements`, `### Requirement:` + `#### Scenario:` with Given/When/Then. The same checks read it.\",\n \"A `Covers:` line per requirement names what its scenarios exercise: a C4 element id (`paymentService.db`), an edge (`paymentService -> kafka`), or a health signal from health.yaml (`alert:<id>` / `sli:<id>`). Every entry must resolve, or `covers.unknown` (warn) flags the typo.\",\n \"Optional, but expected for a service with real architecture: every alert/SLI health.yaml declares wants a covering requirement here (`health.uncovered`, warn) — a signal nothing tests is dashboard decoration.\",\n \"Write the obligations no business requirement states — the transactional outbox, what a caller's retry may assume, what pages whom. An arch scenario becomes an integration/ops test, not an acceptance test.\",\n ],\n example: `---\nservice: payment-service\nstatus: draft\nowner: payments-team\nsources:\n - src/main/java/com/shop/payment/\n---\n\n# payment-service — architecture\n\n## Requirements\n\n### Requirement: Events leave through the transactional outbox\nThe service SHALL write a domain event and its state change in one transaction,\npublished by an outbox relay — never a dual write.\n\nCovers: paymentService.db, paymentService -> kafka\n\n#### Scenario: Broker down at commit time\n- **Given** an event in the outbox\n- **When** the broker is unavailable\n- **Then** the state stays committed and the event is published once it returns\n`,\n },\n {\n artifact: \"openapi.yaml\",\n key: \"openapi\",\n // Overridden per service in `serviceBrief` (brief.ts): an API is required\n // only where the fleet expects one. See `apiExpected` there.\n required: true,\n purpose: \"the API contract — the operations this service exposes\",\n shape: [\n \"OpenAPI 3.x with a `paths` map.\",\n \"EVERY operation carries an `operationId`. That token is the spine: the C4 edge's `metadata { op }`, the requirement's `Operations:` line and this `operationId` are one name spelled three times, and they must be identical.\",\n \"loam reads operationIds, and probes the rest by PRESENCE only: an operation whose responses declare no schema warns (`openapi.response-undescribed`), an internal `$ref` to nothing warns (`openapi.ref-unresolved`). What a declared schema SAYS is still never checked — the schemas are for humans, codegen and review, so getting them wrong is invisible here and expensive later.\",\n \"Document the endpoints that exist. An operation the fleet already calls (see `landscape.expects`) must be in here, or the contract breaks the moment this lands.\",\n // The instruction the brief was missing, and the one that matters most:\n // it used to mark this artifact required unconditionally, in capitals,\n // which for a UI, a worker or a cron told the agent to invent an API into\n // the source of truth. `required` is derived now; this says so in prose\n // as well, because an agent reading the shape rules must not re-derive\n // \"MISSING\" as \"write something\".\n \"If this service exposes no HTTP API, there is no file to write. Do not invent one — an empty or imagined contract is a claim the whole fleet then joins against. `required` above is derived from the fleet map: it is false exactly when the landscape parses and no edge calls an operation on this service, which is the same evidence that keeps `service.no-openapi` quiet.\",\n ],\n },\n {\n artifact: \"asyncapi.yaml\",\n key: \"asyncapi\",\n // Never required. Unlike the HTTP contract, whose necessity the fleet map\n // can PROVE (an op-linked edge points here), most services in a legacy fleet\n // touch no topic at all — and a required artifact nobody owes is how a\n // whole adoption wave learns to ignore the brief.\n required: false,\n purpose: \"the async contract — the messages this service puts on and takes off the bus\",\n shape: [\n \"AsyncAPI **3.0** with `channels`, `operations` and `components.messages`. Only 3.0 is read: its operations are named top-level objects carrying `action: send|receive`, which is what makes a message's direction legible. A 2.x document declares no `operations` and reads as a contract with no messages.\",\n \"EVERY message carries a `name` (or is declared under the key you intend to reference). That token is the spine: the C4 edge's `metadata { publishes }` / `metadata { consumes }`, the requirement's `Publishes:` / `Consumes:` line and this name are one name spelled three times.\",\n \"Namespace the name by the domain that owns it — `payment.PaymentAuthorized`. One message has exactly one producer; two services declaring they send one name is `asyncapi.message-contested`, and then which contract a consumer reads is a coin flip.\",\n \"loam reads message names and the `action` of the operation carrying them. **It never joins on anything inside `payload`** — the one look inside is a presence probe: a payload declaring no shape at all warns (`asyncapi.payload-undescribed`), and a payload with a non-JSON `schemaFormat` is skipped outright. Write the payload as JSON Schema today; if the fleet later adopts Avro, that is a `schemaFormat` line here and nothing in loam changes.\",\n \"Keep payloads in `components.schemas` in THIS file rather than `$ref`-ing an external `.avsc`. External references are out of scope for the merge, exactly as on the OpenAPI axis, so a schema in another file will not travel with the message that needs it.\",\n \"If this service publishes and consumes nothing, there is no file to write. Do not invent one.\",\n ],\n },\n {\n artifact: \"adrs/\",\n key: \"adrsDir\",\n required: false,\n purpose: \"the decisions behind the shape of the service\",\n shape: [\n \"One file per decision: `adrs/NNNN-<slug>.md`, MADR-style (context · decision · consequences).\",\n \"Only decisions whose consequences are still visible in the code. A reconstructed rationale for something nobody decided is fiction, and it is the kind that survives review because it sounds reasonable.\",\n \"If a decision is evident but its reasoning is not, write the decision and say the reasoning is unknown. That is a fact; a plausible motive is not.\",\n ],\n },\n {\n artifact: \"runbook.md\",\n key: \"runbook\",\n required: false,\n purpose: \"how it is run — deploys, dependencies, what to do when it pages\",\n shape: [\n \"Frontmatter, then how it is deployed and configured, what it depends on, and what to do about the failures that actually happen.\",\n \"Written from what is in the repo (pipelines, manifests, alert definitions). Whoever carries the pager verifies it; leave `status: draft` until they have.\",\n \"A 'configured but not a dependency, and why' list: every capability the configuration wires up that the deploy manifest switches off. Without it, the next reader re-derives the dependency from the config and re-adds what the manifest already removed.\",\n ],\n },\n {\n artifact: \"health.yaml\",\n key: \"health\",\n required: false,\n purpose: \"SLIs, SLOs, checks and the dependencies that are critical\",\n shape: [\n \"SLIs and SLOs as they have been AGREED, plus health checks and critical dependencies.\",\n \"If no SLO has ever been agreed, say so and leave it out. An invented 99.9% becomes a number other teams plan against.\",\n ],\n },\n];\n"]}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * What no check will ever tell you. Read it as the list of ways to be wrong
3
+ * quietly. The checks that do exist — the table an adoption baseline actually
4
+ * meets — live in checks.ts; this module is that table's counterpart, split
5
+ * out so each half can grow without crowding the other.
6
+ *
7
+ * The first two entries are here because they used to be `shape` rules on
8
+ * model.likec4, phrased exactly like the enforced ones. A brief that states an
9
+ * unenforced rule beside four enforced ones is not merely useless — it is the
10
+ * way an agent learns that a green `loam validate` means more than it does.
11
+ * Anything nothing checks belongs on this list, where its status IS the point.
12
+ */
13
+ export const UNCHECKED = [
14
+ // Not merely unchecked — unread. This entry used to end "write one", on the
15
+ // theory that a view is what makes a model legible. It is, to LikeC4's
16
+ // renderer; loam computes none. Saying otherwise taught agents that a views
17
+ // block was owed to loam, and an `include *` over the FLEET map is the one
18
+ // shape that costs minutes rather than milliseconds.
19
+ //
20
+ // Still exactly true of PRESENCE, which is what this entry is about. Rule 26
21
+ // lets loam read a dynamic view's declared steps WHERE ONE EXISTS; nothing
22
+ // grades their absence, and the failure this comment records — agents
23
+ // learning that a views block is owed to loam — is the one rule 26 is
24
+ // written to prevent recurring.
25
+ "Whether model.likec4 declares a `views { ... }` block, or any view at all — and nothing in loam ever will. What loam reads, when a `dynamic view` IS present, is only what its author declared: the view's tags and its ordered steps. It computes no view and renders nothing, and it never grades a model for lacking one — a fleet that draws no diagrams owes loam no views block, today or ever. Views belong to LikeC4's own renderer: write them if you want diagrams, and read them with `npx likec4 start <dir>` pointed at ONE directory — `services/<id>` for a service model, the docs repo root for the fleet map (`likec4.config.json` scopes that root project to `architecture/`). The renderer merges every `.likec4` file it is given into one model, and loam parses each of them alone, so each declares its own `specification` block: point it at a directory holding two of them and every declaration reads as a duplicate. Scope your views too — computing a view is superlinear in the number of edges, and an `include *` over `architecture/landscape.likec4` is the expensive one, because that file holds every call in the fleet.",
26
+ // The readability half of the entry above. They are separate entries because
27
+ // the failures are: one is a view that takes minutes to compute, the other is
28
+ // a view that computes instantly and cannot be read. A fleet acquires the
29
+ // second one the day its second service starts publishing, and every service
30
+ // after that makes it worse by exactly one edge — which is why it arrives as
31
+ // a surprise on a map that was fine last quarter.
32
+ "Whether the fleet map is LEGIBLE — nothing in loam draws it, so nothing in loam notices. The shape that goes first is a shared broker: Kafka, a bus, a gateway, drawn as ONE element, is the node every service in the fleet points at, and a view over it is a star with sixty spokes. Model the TOPIC rather than the broker — `paymentEvents = topic 'payment.events'` nested inside the broker's element, with the edges pointing at `kafka.paymentEvents` — and one hub of degree sixty becomes twelve of degree five, which is also the truer model: the contract a producer and a consumer share is the topic, never the broker. Declare `element topic { #external, style { shape queue } }` in the `specification` block and give the nested elements that kind: LikeC4 does not inherit tags, so a topic under an `#external` broker is NOT external itself and `loam validate --all` asks for a `services/payment.events/` nobody owes (`landscape.service-undocumented`). Then scope the views, which is where the rest of the legibility lives: `exclude element.tag = #external` keeps the fleet overview to the calls between our own services, and a second view over the broker draws the event spine on its own.",
33
+ "Whether the model has exactly ONE top-level element for the service, with its containers nested inside. Five top-level boxes for one service parse, validate and bind exactly as well as one — and then the fleet map, which joins elements to directories, has five candidates for the same service and no way to say which is wrong.",
34
+ "Whether the model is the architecture the code actually has. loam parses model.likec4; it never reads a line of the service.",
35
+ "Whether a requirement is TRUE of the service. `loam validate` checks that a requirement has a scenario, never that either one describes real behaviour.",
36
+ "Whether the scenarios are acceptance criteria somebody could test, or the requirement restated in Given/When/Then.",
37
+ "Whether an operationId is the one the code serves, and whether the request and response schemas resemble what the endpoint really accepts and returns. Presence is probed — an operation with no response schema at all is warned about — but what a declared schema SAYS is never compared with anything; only the operationId joins.",
38
+ "Whether the runbook's steps work, or the health.yaml SLOs are numbers anyone agreed to.",
39
+ "Whether an arch scenario really exercises what its `Covers:` line names. The entries are resolved against the model and health.yaml — never against code, tests, dashboards or alert rules.",
40
+ "Whether an ADR records a decision that was made, or one reconstructed afterwards to justify the code.",
41
+ "COMPLETENESS. Forty behaviours documented as one requirement passes every check loam has. So does a service with one endpoint documented out of thirty.",
42
+ "REPRODUCIBILITY — the bar the artifact set aims at: could a reader answer, without the code, what the service exposes, what it reaches, what shapes it exchanges, how it is run and what pages whom. The depth probes catch an EMPTY contract; nothing measures a shallow one against the service, so green means the files agree with each other, never that they reach the bar.",
43
+ "Whether an arch requirement recording effective configuration or a library's semantics ('retries: -1 is unbounded, proven from the bytecode') is still true of the chart and the classpath. The convention names arch.spec.md as the home for such facts; loam never verifies the values.",
44
+ "Whether a permission in `architecture/permissions.yaml` is one the system actually has. `Requires:` is checked against that file and the file against nothing: a vocabulary that agrees with every requirement citing it can still name three permissions the identity provider retired last year, and `owned_by` / `enforced_by` are read as prose — neither is resolved against `services/`, and a realm is never opened. The check is a spelling guard between documents, exactly as `Operations:` is; whether the word is real is a question only the running system answers.",
45
+ "Whether `sources` names the files you read. loam checks those paths exist — not that they are the ones the document came from.",
46
+ ];
47
+ //# sourceMappingURL=unchecked.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unchecked.js","sourceRoot":"","sources":["../../../src/core/brief/unchecked.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,SAAS,GAAa;IACjC,4EAA4E;IAC5E,uEAAuE;IACvE,4EAA4E;IAC5E,2EAA2E;IAC3E,qDAAqD;IACrD,EAAE;IACF,6EAA6E;IAC7E,2EAA2E;IAC3E,sEAAsE;IACtE,sEAAsE;IACtE,gCAAgC;IAChC,mmCAAmmC;IACnmC,6EAA6E;IAC7E,8EAA8E;IAC9E,0EAA0E;IAC1E,6EAA6E;IAC7E,6EAA6E;IAC7E,kDAAkD;IAClD,oqCAAoqC;IACpqC,wUAAwU;IACxU,8HAA8H;IAC9H,yJAAyJ;IACzJ,oHAAoH;IACpH,wUAAwU;IACxU,yFAAyF;IACzF,6LAA6L;IAC7L,uGAAuG;IACvG,yJAAyJ;IACzJ,mXAAmX;IACnX,2RAA2R;IAC3R,mjBAAmjB;IACnjB,gIAAgI;CACjI,CAAC","sourcesContent":["/**\n * What no check will ever tell you. Read it as the list of ways to be wrong\n * quietly. The checks that do exist — the table an adoption baseline actually\n * meets — live in checks.ts; this module is that table's counterpart, split\n * out so each half can grow without crowding the other.\n *\n * The first two entries are here because they used to be `shape` rules on\n * model.likec4, phrased exactly like the enforced ones. A brief that states an\n * unenforced rule beside four enforced ones is not merely useless — it is the\n * way an agent learns that a green `loam validate` means more than it does.\n * Anything nothing checks belongs on this list, where its status IS the point.\n */\nexport const UNCHECKED: string[] = [\n // Not merely unchecked — unread. This entry used to end \"write one\", on the\n // theory that a view is what makes a model legible. It is, to LikeC4's\n // renderer; loam computes none. Saying otherwise taught agents that a views\n // block was owed to loam, and an `include *` over the FLEET map is the one\n // shape that costs minutes rather than milliseconds.\n //\n // Still exactly true of PRESENCE, which is what this entry is about. Rule 26\n // lets loam read a dynamic view's declared steps WHERE ONE EXISTS; nothing\n // grades their absence, and the failure this comment records — agents\n // learning that a views block is owed to loam — is the one rule 26 is\n // written to prevent recurring.\n \"Whether model.likec4 declares a `views { ... }` block, or any view at all — and nothing in loam ever will. What loam reads, when a `dynamic view` IS present, is only what its author declared: the view's tags and its ordered steps. It computes no view and renders nothing, and it never grades a model for lacking one — a fleet that draws no diagrams owes loam no views block, today or ever. Views belong to LikeC4's own renderer: write them if you want diagrams, and read them with `npx likec4 start <dir>` pointed at ONE directory — `services/<id>` for a service model, the docs repo root for the fleet map (`likec4.config.json` scopes that root project to `architecture/`). The renderer merges every `.likec4` file it is given into one model, and loam parses each of them alone, so each declares its own `specification` block: point it at a directory holding two of them and every declaration reads as a duplicate. Scope your views too — computing a view is superlinear in the number of edges, and an `include *` over `architecture/landscape.likec4` is the expensive one, because that file holds every call in the fleet.\",\n // The readability half of the entry above. They are separate entries because\n // the failures are: one is a view that takes minutes to compute, the other is\n // a view that computes instantly and cannot be read. A fleet acquires the\n // second one the day its second service starts publishing, and every service\n // after that makes it worse by exactly one edge — which is why it arrives as\n // a surprise on a map that was fine last quarter.\n \"Whether the fleet map is LEGIBLE — nothing in loam draws it, so nothing in loam notices. The shape that goes first is a shared broker: Kafka, a bus, a gateway, drawn as ONE element, is the node every service in the fleet points at, and a view over it is a star with sixty spokes. Model the TOPIC rather than the broker — `paymentEvents = topic 'payment.events'` nested inside the broker's element, with the edges pointing at `kafka.paymentEvents` — and one hub of degree sixty becomes twelve of degree five, which is also the truer model: the contract a producer and a consumer share is the topic, never the broker. Declare `element topic { #external, style { shape queue } }` in the `specification` block and give the nested elements that kind: LikeC4 does not inherit tags, so a topic under an `#external` broker is NOT external itself and `loam validate --all` asks for a `services/payment.events/` nobody owes (`landscape.service-undocumented`). Then scope the views, which is where the rest of the legibility lives: `exclude element.tag = #external` keeps the fleet overview to the calls between our own services, and a second view over the broker draws the event spine on its own.\",\n \"Whether the model has exactly ONE top-level element for the service, with its containers nested inside. Five top-level boxes for one service parse, validate and bind exactly as well as one — and then the fleet map, which joins elements to directories, has five candidates for the same service and no way to say which is wrong.\",\n \"Whether the model is the architecture the code actually has. loam parses model.likec4; it never reads a line of the service.\",\n \"Whether a requirement is TRUE of the service. `loam validate` checks that a requirement has a scenario, never that either one describes real behaviour.\",\n \"Whether the scenarios are acceptance criteria somebody could test, or the requirement restated in Given/When/Then.\",\n \"Whether an operationId is the one the code serves, and whether the request and response schemas resemble what the endpoint really accepts and returns. Presence is probed — an operation with no response schema at all is warned about — but what a declared schema SAYS is never compared with anything; only the operationId joins.\",\n \"Whether the runbook's steps work, or the health.yaml SLOs are numbers anyone agreed to.\",\n \"Whether an arch scenario really exercises what its `Covers:` line names. The entries are resolved against the model and health.yaml — never against code, tests, dashboards or alert rules.\",\n \"Whether an ADR records a decision that was made, or one reconstructed afterwards to justify the code.\",\n \"COMPLETENESS. Forty behaviours documented as one requirement passes every check loam has. So does a service with one endpoint documented out of thirty.\",\n \"REPRODUCIBILITY — the bar the artifact set aims at: could a reader answer, without the code, what the service exposes, what it reaches, what shapes it exchanges, how it is run and what pages whom. The depth probes catch an EMPTY contract; nothing measures a shallow one against the service, so green means the files agree with each other, never that they reach the bar.\",\n \"Whether an arch requirement recording effective configuration or a library's semantics ('retries: -1 is unbounded, proven from the bytecode') is still true of the chart and the classpath. The convention names arch.spec.md as the home for such facts; loam never verifies the values.\",\n \"Whether a permission in `architecture/permissions.yaml` is one the system actually has. `Requires:` is checked against that file and the file against nothing: a vocabulary that agrees with every requirement citing it can still name three permissions the identity provider retired last year, and `owned_by` / `enforced_by` are read as prose — neither is resolved against `services/`, and a realm is never opened. The check is a spelling guard between documents, exactly as `Operations:` is; whether the word is real is a question only the running system answers.\",\n \"Whether `sources` names the files you read. loam checks those paths exist — not that they are the ones the document came from.\",\n];\n"]}