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

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 (273) hide show
  1. package/CHANGELOG.md +901 -0
  2. package/MIGRATING-from-OpenSpec.md +7 -4
  3. package/QUICKSTART.md +8 -3
  4. package/README.md +13 -7
  5. package/ROADMAP.md +264 -11
  6. package/SCHEMA.md +439 -38
  7. package/WORKFLOW.md +23 -10
  8. package/dist/commands/adopt/render.js +47 -8
  9. package/dist/commands/adopt/render.js.map +1 -1
  10. package/dist/commands/archive/plan/landscape.js +45 -1
  11. package/dist/commands/archive/plan/landscape.js.map +1 -1
  12. package/dist/commands/archive/plan/model/extending.js +85 -0
  13. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  14. package/dist/commands/archive/run.js +5 -2
  15. package/dist/commands/archive/run.js.map +1 -1
  16. package/dist/commands/context/print.js +11 -1
  17. package/dist/commands/context/print.js.map +1 -1
  18. package/dist/commands/doctor.js +46 -0
  19. package/dist/commands/doctor.js.map +1 -1
  20. package/dist/commands/explore.js +12 -2
  21. package/dist/commands/explore.js.map +1 -1
  22. package/dist/commands/list/views.js +5 -1
  23. package/dist/commands/list/views.js.map +1 -1
  24. package/dist/commands/seed/plan.js +97 -3
  25. package/dist/commands/seed/plan.js.map +1 -1
  26. package/dist/commands/seed/seed.js +7 -2
  27. package/dist/commands/seed/seed.js.map +1 -1
  28. package/dist/commands/show/feature.js +2 -1
  29. package/dist/commands/show/feature.js.map +1 -1
  30. package/dist/commands/show/marks.js +3 -5
  31. package/dist/commands/show/marks.js.map +1 -1
  32. package/dist/commands/show/service.js +39 -18
  33. package/dist/commands/show/service.js.map +1 -1
  34. package/dist/commands/subsystem/sync.js +128 -74
  35. package/dist/commands/subsystem/sync.js.map +1 -1
  36. package/dist/commands/subsystem/txn/exclude.js +132 -0
  37. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  38. package/dist/commands/subsystem/txn/report.js +124 -0
  39. package/dist/commands/subsystem/txn/report.js.map +1 -0
  40. package/dist/commands/subsystem/txn/txn.js +10 -3
  41. package/dist/commands/subsystem/txn/txn.js.map +1 -1
  42. package/dist/commands/subsystem/txn/views.js +113 -16
  43. package/dist/commands/subsystem/txn/views.js.map +1 -1
  44. package/dist/commands/validate/arch-coverage.js +16 -9
  45. package/dist/commands/validate/arch-coverage.js.map +1 -1
  46. package/dist/commands/validate/checks/fleet-shape.js +30 -77
  47. package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
  48. package/dist/commands/validate/checks/vocabulary.js +4 -19
  49. package/dist/commands/validate/checks/vocabulary.js.map +1 -1
  50. package/dist/commands/validate/feature.js +1 -1
  51. package/dist/commands/validate/feature.js.map +1 -1
  52. package/dist/commands/validate/fleet/census.js +11 -10
  53. package/dist/commands/validate/fleet/census.js.map +1 -1
  54. package/dist/commands/validate/fleet/landscape.js +127 -119
  55. package/dist/commands/validate/fleet/landscape.js.map +1 -1
  56. package/dist/commands/validate/fleet/load.js +66 -0
  57. package/dist/commands/validate/fleet/load.js.map +1 -1
  58. package/dist/commands/validate/fleet/map/attest.js +103 -0
  59. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  60. package/dist/commands/validate/fleet/map/bindings.js +96 -0
  61. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  62. package/dist/commands/validate/fleet/map/consumers.js +298 -0
  63. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  64. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  65. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  66. package/dist/commands/validate/fleet/map/usecases.js +56 -0
  67. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  68. package/dist/commands/validate/fleet/usecases/steps.js +49 -17
  69. package/dist/commands/validate/fleet/usecases/steps.js.map +1 -1
  70. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  71. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  72. package/dist/commands/validate/fleet/views/ids.js +13 -9
  73. package/dist/commands/validate/fleet/views/ids.js.map +1 -1
  74. package/dist/commands/validate/fleet/views/projects.js +258 -70
  75. package/dist/commands/validate/fleet/views/projects.js.map +1 -1
  76. package/dist/commands/validate/fleet/views/root-documents.js +97 -0
  77. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  78. package/dist/commands/validate/fleet/views/stale.js +2 -2
  79. package/dist/commands/validate/fleet/views/stale.js.map +1 -1
  80. package/dist/commands/validate/service/model/diverged.js +226 -0
  81. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  82. package/dist/commands/validate/service/model/grade.js +163 -0
  83. package/dist/commands/validate/service/model/grade.js.map +1 -0
  84. package/dist/commands/validate/service/service.js +110 -34
  85. package/dist/commands/validate/service/service.js.map +1 -1
  86. package/dist/commands/validate/service/specs.js +39 -5
  87. package/dist/commands/validate/service/specs.js.map +1 -1
  88. package/dist/commands/validate/service/spine.js +41 -3
  89. package/dist/commands/validate/service/spine.js.map +1 -1
  90. package/dist/commands/validate/service/usecases/tags.js +113 -0
  91. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  92. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  93. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  94. package/dist/commands/validate/validate.js +10 -24
  95. package/dist/commands/validate/validate.js.map +1 -1
  96. package/dist/core/agent/agents-md/artifacts.js +1 -0
  97. package/dist/core/agent/agents-md/artifacts.js.map +1 -1
  98. package/dist/core/agent/agents-md/command-map.js +18 -4
  99. package/dist/core/agent/agents-md/command-map.js.map +1 -1
  100. package/dist/core/agent/agents-md/cycle.js +24 -9
  101. package/dist/core/agent/agents-md/cycle.js.map +1 -1
  102. package/dist/core/agent/agents-md/map/lenses/context.js +4 -3
  103. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
  104. package/dist/core/agent/agents-md/map/subsystem.js +51 -11
  105. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
  106. package/dist/core/agent/agents-md/map/usecases.js +45 -3
  107. package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
  108. package/dist/core/agent/agents-md.js +14 -4
  109. package/dist/core/agent/agents-md.js.map +1 -1
  110. package/dist/core/agent/support/report.js +39 -5
  111. package/dist/core/agent/support/report.js.map +1 -1
  112. package/dist/core/agent/workflows/adopt.js +123 -14
  113. package/dist/core/agent/workflows/adopt.js.map +1 -1
  114. package/dist/core/agent/workflows/check.js +35 -20
  115. package/dist/core/agent/workflows/check.js.map +1 -1
  116. package/dist/core/agent/workflows/closing.js +3 -1
  117. package/dist/core/agent/workflows/closing.js.map +1 -1
  118. package/dist/core/brief/brief.js +63 -11
  119. package/dist/core/brief/brief.js.map +1 -1
  120. package/dist/core/brief/checks.js +133 -7
  121. package/dist/core/brief/checks.js.map +1 -1
  122. package/dist/core/brief/landscape.js +212 -129
  123. package/dist/core/brief/landscape.js.map +1 -1
  124. package/dist/core/brief/map/extend.js +81 -0
  125. package/dist/core/brief/map/extend.js.map +1 -0
  126. package/dist/core/brief/map/owed.js +284 -0
  127. package/dist/core/brief/map/owed.js.map +1 -0
  128. package/dist/core/brief/targets.js +30 -29
  129. package/dist/core/brief/targets.js.map +1 -1
  130. package/dist/core/brief/unchecked.js +12 -2
  131. package/dist/core/brief/unchecked.js.map +1 -1
  132. package/dist/core/c4/likec4.js +23 -1
  133. package/dist/core/c4/likec4.js.map +1 -1
  134. package/dist/core/c4/parsed/deployment.js +5 -3
  135. package/dist/core/c4/parsed/deployment.js.map +1 -1
  136. package/dist/core/c4/parsed/view-ids.js +39 -1
  137. package/dist/core/c4/parsed/view-ids.js.map +1 -1
  138. package/dist/core/c4/prefetch/fleet.js +142 -0
  139. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  140. package/dist/core/c4/project/architecture.js +52 -4
  141. package/dist/core/c4/project/architecture.js.map +1 -1
  142. package/dist/core/c4/project/batch.js +140 -0
  143. package/dist/core/c4/project/batch.js.map +1 -0
  144. package/dist/core/c4/project/documents.js +9 -4
  145. package/dist/core/c4/project/documents.js.map +1 -1
  146. package/dist/core/c4/project/load.js +77 -38
  147. package/dist/core/c4/project/load.js.map +1 -1
  148. package/dist/core/c4/project/staged.js +46 -12
  149. package/dist/core/c4/project/staged.js.map +1 -1
  150. package/dist/core/c4/resolve/attested.js +0 -0
  151. package/dist/core/c4/resolve/attested.js.map +1 -0
  152. package/dist/core/c4/resolve/service.js +8 -17
  153. package/dist/core/c4/resolve/service.js.map +1 -1
  154. package/dist/core/c4/resolve/steps.js +18 -0
  155. package/dist/core/c4/resolve/steps.js.map +1 -1
  156. package/dist/core/c4/root-project/exclude.js +352 -0
  157. package/dist/core/c4/root-project/exclude.js.map +1 -0
  158. package/dist/core/c4/service-model/documents.js +47 -0
  159. package/dist/core/c4/service-model/documents.js.map +1 -0
  160. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  161. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  162. package/dist/core/c4/service-model/load.js +165 -0
  163. package/dist/core/c4/service-model/load.js.map +1 -0
  164. package/dist/core/c4/service-model/renderer.js +128 -0
  165. package/dist/core/c4/service-model/renderer.js.map +1 -0
  166. package/dist/core/c4/service-model/shape.js +126 -0
  167. package/dist/core/c4/service-model/shape.js.map +1 -0
  168. package/dist/core/c4/service-model/slice.js +188 -0
  169. package/dist/core/c4/service-model/slice.js.map +1 -0
  170. package/dist/core/c4/source-scan.js +26 -0
  171. package/dist/core/c4/source-scan.js.map +1 -1
  172. package/dist/core/c4/splice/authored-source.js +60 -13
  173. package/dist/core/c4/splice/authored-source.js.map +1 -1
  174. package/dist/core/c4/splice/contract.js.map +1 -1
  175. package/dist/core/c4/splice/identity/declared.js +87 -0
  176. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  177. package/dist/core/c4/splice/identity/edges.js +17 -0
  178. package/dist/core/c4/splice/identity/edges.js.map +1 -1
  179. package/dist/core/c4/splice/identity/existing.js +80 -0
  180. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  181. package/dist/core/c4/splice/identity/interior.js +80 -0
  182. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  183. package/dist/core/c4/splice/identity/owner.js +50 -0
  184. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  185. package/dist/core/c4/splice/landscape-merge.js +154 -100
  186. package/dist/core/c4/splice/landscape-merge.js.map +1 -1
  187. package/dist/core/c4/splice/model/merge.js +140 -0
  188. package/dist/core/c4/splice/model/merge.js.map +1 -0
  189. package/dist/core/c4/splice/placement.js +14 -4
  190. package/dist/core/c4/splice/placement.js.map +1 -1
  191. package/dist/core/c4/workspace.js +2 -1
  192. package/dist/core/c4/workspace.js.map +1 -1
  193. package/dist/core/coherence/coherence.js +7 -0
  194. package/dist/core/coherence/coherence.js.map +1 -1
  195. package/dist/core/delta/delta.js +9 -0
  196. package/dist/core/delta/delta.js.map +1 -1
  197. package/dist/core/deployment/delta.js +4 -0
  198. package/dist/core/deployment/delta.js.map +1 -1
  199. package/dist/core/diff/base-state.js +21 -5
  200. package/dist/core/diff/base-state.js.map +1 -1
  201. package/dist/core/diff/victims.js +10 -1
  202. package/dist/core/diff/victims.js.map +1 -1
  203. package/dist/core/docs.js +29 -24
  204. package/dist/core/docs.js.map +1 -1
  205. package/dist/core/doctor/config.js +7 -3
  206. package/dist/core/doctor/config.js.map +1 -1
  207. package/dist/core/doctor/doctor.js +36 -8
  208. package/dist/core/doctor/doctor.js.map +1 -1
  209. package/dist/core/doctor/report.js.map +1 -1
  210. package/dist/core/doctor/reports/scan.js +242 -0
  211. package/dist/core/doctor/reports/scan.js.map +1 -0
  212. package/dist/core/explain/refusals.js +1 -1
  213. package/dist/core/explain/refusals.js.map +1 -1
  214. package/dist/core/explore/explore.js +44 -9
  215. package/dist/core/explore/explore.js.map +1 -1
  216. package/dist/core/fleet-context.js +47 -0
  217. package/dist/core/fleet-context.js.map +1 -1
  218. package/dist/core/gate/partners.js +5 -9
  219. package/dist/core/gate/partners.js.map +1 -1
  220. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  221. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  222. package/dist/core/pack/living.js +47 -13
  223. package/dist/core/pack/living.js.map +1 -1
  224. package/dist/core/pack/pack.js +9 -6
  225. package/dist/core/pack/pack.js.map +1 -1
  226. package/dist/core/projection/arch-slice.js +2 -2
  227. package/dist/core/projection/arch-slice.js.map +1 -1
  228. package/dist/core/repo/paths.js +11 -9
  229. package/dist/core/repo/paths.js.map +1 -1
  230. package/dist/core/repo/tree/render/projects.js +93 -35
  231. package/dist/core/repo/tree/render/projects.js.map +1 -1
  232. package/dist/core/repo/tree/render/stale.js +2 -3
  233. package/dist/core/repo/tree/render/stale.js.map +1 -1
  234. package/dist/core/repo/tree/render/views.js +51 -3
  235. package/dist/core/repo/tree/render/views.js.map +1 -1
  236. package/dist/core/repo/tree/walk.js +45 -2
  237. package/dist/core/repo/tree/walk.js.map +1 -1
  238. package/dist/core/scaffold/landscape.js +219 -9
  239. package/dist/core/scaffold/landscape.js.map +1 -1
  240. package/dist/core/staging/writes.js.map +1 -1
  241. package/dist/core/usecases/delta/claims.js +1 -0
  242. package/dist/core/usecases/delta/claims.js.map +1 -1
  243. package/dist/core/usecases/delta/overlay.js +4 -0
  244. package/dist/core/usecases/delta/overlay.js.map +1 -1
  245. package/dist/core/usecases/fleet.js +18 -6
  246. package/dist/core/usecases/fleet.js.map +1 -1
  247. package/dist/core/usecases/operations.js +7 -0
  248. package/dist/core/usecases/operations.js.map +1 -1
  249. package/dist/core/usecases/service/exclude.js +119 -0
  250. package/dist/core/usecases/service/exclude.js.map +1 -0
  251. package/dist/core/usecases/service/flows.js +161 -0
  252. package/dist/core/usecases/service/flows.js.map +1 -0
  253. package/dist/core/vocabulary/maturity.js +10 -0
  254. package/dist/core/vocabulary/maturity.js.map +1 -1
  255. package/examples/README.md +24 -6
  256. package/examples/docs/architecture/landscape.likec4 +41 -0
  257. package/examples/docs/architecture/usecases/order-notification.likec4 +5 -2
  258. package/examples/docs/likec4.config.json +0 -1
  259. package/examples/docs/services/checkout-web/model.likec4 +39 -56
  260. package/examples/docs/services/order-service/arch.spec.md +13 -6
  261. package/examples/docs/services/order-service/model.likec4 +53 -67
  262. package/examples/docs/services/payment-service/arch.spec.md +7 -4
  263. package/examples/docs/services/payment-service/model.likec4 +32 -35
  264. package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
  265. package/examples/docs/services/platform/identity-service/model.likec4 +29 -33
  266. package/examples/docs/services/platform/notification-service/health.yaml +8 -3
  267. package/examples/docs/services/platform/notification-service/model.likec4 +39 -59
  268. package/package.json +1 -1
  269. package/examples/docs/services/checkout-web/likec4.config.json +0 -4
  270. package/examples/docs/services/order-service/likec4.config.json +0 -4
  271. package/examples/docs/services/payment-service/likec4.config.json +0 -4
  272. package/examples/docs/services/platform/identity-service/likec4.config.json +0 -4
  273. package/examples/docs/services/platform/notification-service/likec4.config.json +0 -4
@@ -25,22 +25,62 @@ export const SUBSYSTEM_COMMANDS = `- \`loam subsystem <verb>\` manages the group
25
25
  \`unfiledServices\`); \`history <name>\` asks git how a service or subsystem
26
26
  moved and answers nothing — exit 0, no finding — when git will not say;
27
27
  \`sync\` regenerates \`architecture/subsystems.likec4\`, the one repair for
28
- \`subsystem.views-stale\`, and also writes one create-only
29
- \`services/<…>/<id>/likec4.config.json\` per service model (never rewritten, never
30
- removed; the team may edit it; commit the new files before a \`move\`, which
31
- refuses over untracked paths) — the one thing that makes a model renderable
32
- from the docs root beside the fleet map, and the repair for
33
- \`service.likec4-config-missing\`. A flat fleet with no subsystems still owes
34
- this run: the verb is the tree's, the file is the renderer's. With more than
35
- one project \`likec4 validate\` at the docs root needs \`--project <name>\`
36
- (\`build\` and \`export\` take every project); a
37
- landscape view claiming a generated id is
28
+ \`subsystem.views-stale\`, and also maintains the RENDERER's wiring for the
29
+ service models. Which wiring a model needs is decided by the file's own
30
+ grammar, never by a config key: a model that declares its own
31
+ \`specification { element … }\` block STANDS ALONE — it cannot share a project
32
+ with the fleet map, since every kind it declares would be a duplicate there —
33
+ and a model with no such block EXTENDS the map with
34
+ \`extend <fully-qualified id> { … }\` and parses only INSIDE the root project.
35
+ So \`sync\` writes one create-only \`services/<…>/<id>/likec4.config.json\` per
36
+ STANDALONE model (never rewritten; the team may edit it; commit
37
+ the new files before a \`move\`, which refuses over untracked paths), DELETES one
38
+ sitting beside an EXTENDING model (that nested project claims the model out of
39
+ the root project, so \`likec4 validate .\` refuses without \`--project\` and,
40
+ wherever that project claims the model, \`export json --project fleet\` loses
41
+ the service's containers; \`--json\` lists what it removed as \`projects.removed\`), and rewrites
42
+ the root \`likec4.config.json\`'s \`exclude\` to hold \`services/<tree>/**\` for
43
+ exactly those models, keeping every entry that is not about \`services/\` in the
44
+ order the team wrote it. It rewrites that list when at least one extending model
45
+ exists, or when a standalone model's directory is not covered — an older repo
46
+ whose models all stand alone behind \`services/**\` is never touched. \`--json\`
47
+ carries the result as \`projects.exclude\`, and the text view prints one line when
48
+ it rewrote. Between them these repair four warnings:
49
+ \`service.likec4-config-missing\` (a standalone model with no project file),
50
+ \`service.likec4-config-stray\` (a project file beside an extending model),
51
+ \`service.model-excluded\` (an extending model the root \`exclude\` hides from the
52
+ renderer) and \`service.model-unexcluded\` (a standalone model it does not hide,
53
+ which blanks the whole root project). A flat fleet with no subsystems still owes
54
+ this run: the verb is the tree's, the files are the renderer's. A fleet whose
55
+ models all extend the map ends with ONE project and one picker entry, and
56
+ \`likec4 validate\` at the docs root needs no flag; each standalone model adds a
57
+ project, and with more than one \`likec4 validate\` needs \`--project <name>\`
58
+ (\`build\` and \`export\` take every project). A view id claimed twice inside one
59
+ project — the landscape and an extending model both minting it, or either
60
+ claiming a generated one — is
38
61
  \`subsystem.view-id-collision\`. Each generated view is titled by its PATH —
39
62
  every marked ancestor's label and its own, which the renderer reads as
40
63
  folders — where a label is the marker's \`title\` or the directory name; the
41
64
  marker's \`description\` rides along. So editing \`subsystem.yaml\` changes
42
65
  what the renderer LABELS the group, a parent's title changes every view
43
- beneath it, and either makes the file stale until the next \`sync\`. It is generated wholesale:
66
+ beneath it, and either makes the file stale until the next \`sync\`. The
67
+ generated file is NEVER part of the fleet-project load
68
+ (\`c4.fleet-project-invalid\` reads every other \`.likec4\` the root project holds);
69
+ \`subsystem.views-stale\` is the only check that reads it, by byte comparison.
70
+ Each view
71
+ carries \`global style subsystems\` — written after its title, the one line
72
+ LikeC4 gives a view for borrowing a palette — exactly when the \`architecture/\`
73
+ project declares a global style with that id (\`global { styleGroup subsystems
74
+ { style element.tag = #external { color gray } } }\`, in the landscape or in
75
+ ANY \`.likec4\` under \`architecture/\` the root \`exclude\` does not cover — a
76
+ \`palette.likec4\` beside the map counts); nothing otherwise, and loam never reads
77
+ what the group says. Declaring it is the whole opt-in and makes the file stale
78
+ once, until the next \`sync\`. When the project declares style groups under other
79
+ names only, the file opens with one comment line naming them and saying none is
80
+ \`subsystems\`, and the views carry the renderer's defaults — so declaring a group
81
+ under ANY name restales the file, because that comment is part of the bytes.
82
+ \`sync\` refuses to rewrite it at all while \`architecture/\` does not parse
83
+ (\`action: "blocked"\`): fix the map first. It is generated wholesale:
44
84
  an authored diagram of the same services belongs in the landscape or in a
45
85
  file of your own name, never here. \`loam adopt --subsystem <name>\` briefs a new
46
86
  service's baseline directly into a group, so adoption need not land unfiled.
@@ -1 +1 @@
1
- {"version":3,"file":"subsystem.js","sourceRoot":"","sources":["../../../../../src/core/agent/agents-md/map/subsystem.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoCjC,CAAC","sourcesContent":["/**\n * The `loam subsystem` half of the command map — its own section module\n * because command-map.ts sat against the file-line limit and the agents-md\n * package against the five-file cap, so the tree surface's documentation\n * lives one package down and is concatenated after the map.\n *\n * Same assembly contract as every section: ../agents-md.ts concatenates with\n * NO join separator, so this string starts at the first character of its\n * opening line and ends with the newline that closes its last one.\n */\nexport const SUBSYSTEM_COMMANDS = `- \\`loam subsystem <verb>\\` manages the grouping tree under \\`services/\\` — the\n navigable tree no identity depends on: a service id stays its leaf directory\n name, every join key is byte-identical before and after a move, and the tree\n carries no policy. Verbs: \\`new <name> [--under <sub>] [--title] [--description]\n [--owner]\\` creates a group (an empty one is legal — its \\`subsystem.yaml\\` is a\n marker, never a member list); \\`move <name>... --into <sub|.>\\` relocates\n services and whole subtrees in ONE journaled transaction over the renames\n plus the regenerated views file (\\`--into .\\` unfiles; the renames and the\n regenerated views file are staged in git without committing, where git answers); \\`rename <old> <new>\\` renames a\n group through the same transaction (services are never renamed — the id is\n the identity); \\`rm <name>\\` removes an EMPTY group; \\`list\\` shows the tree\n with member counts and the unfiled count (unfiled is permanent and normal —\n a count, never a finding; \\`loam list --json\\` carries the same facts as\n additive keys \\`services[].subsystem\\`, \\`subsystems[]\\` and\n \\`unfiledServices\\`); \\`history <name>\\` asks git how a service or subsystem\n moved and answers nothing — exit 0, no finding — when git will not say;\n \\`sync\\` regenerates \\`architecture/subsystems.likec4\\`, the one repair for\n \\`subsystem.views-stale\\`, and also writes one create-only\n \\`services/<…>/<id>/likec4.config.json\\` per service model (never rewritten, never\n removed; the team may edit it; commit the new files before a \\`move\\`, which\n refuses over untracked paths) — the one thing that makes a model renderable\n from the docs root beside the fleet map, and the repair for\n \\`service.likec4-config-missing\\`. A flat fleet with no subsystems still owes\n this run: the verb is the tree's, the file is the renderer's. With more than\n one project \\`likec4 validate\\` at the docs root needs \\`--project <name>\\`\n (\\`build\\` and \\`export\\` take every project); a\n landscape view claiming a generated id is\n \\`subsystem.view-id-collision\\`. Each generated view is titled by its PATH —\n every marked ancestor's label and its own, which the renderer reads as\n folders — where a label is the marker's \\`title\\` or the directory name; the\n marker's \\`description\\` rides along. So editing \\`subsystem.yaml\\` changes\n what the renderer LABELS the group, a parent's title changes every view\n beneath it, and either makes the file stale until the next \\`sync\\`. It is generated wholesale:\n an authored diagram of the same services belongs in the landscape or in a\n file of your own name, never here. \\`loam adopt --subsystem <name>\\` briefs a new\n service's baseline directly into a group, so adoption need not land unfiled.\n`;\n"]}
1
+ {"version":3,"file":"subsystem.js","sourceRoot":"","sources":["../../../../../src/core/agent/agents-md/map/subsystem.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4EjC,CAAC","sourcesContent":["/**\n * The `loam subsystem` half of the command map — its own section module\n * because command-map.ts sat against the file-line limit and the agents-md\n * package against the five-file cap, so the tree surface's documentation\n * lives one package down and is concatenated after the map.\n *\n * Same assembly contract as every section: ../agents-md.ts concatenates with\n * NO join separator, so this string starts at the first character of its\n * opening line and ends with the newline that closes its last one.\n */\nexport const SUBSYSTEM_COMMANDS = `- \\`loam subsystem <verb>\\` manages the grouping tree under \\`services/\\` — the\n navigable tree no identity depends on: a service id stays its leaf directory\n name, every join key is byte-identical before and after a move, and the tree\n carries no policy. Verbs: \\`new <name> [--under <sub>] [--title] [--description]\n [--owner]\\` creates a group (an empty one is legal — its \\`subsystem.yaml\\` is a\n marker, never a member list); \\`move <name>... --into <sub|.>\\` relocates\n services and whole subtrees in ONE journaled transaction over the renames\n plus the regenerated views file (\\`--into .\\` unfiles; the renames and the\n regenerated views file are staged in git without committing, where git answers); \\`rename <old> <new>\\` renames a\n group through the same transaction (services are never renamed — the id is\n the identity); \\`rm <name>\\` removes an EMPTY group; \\`list\\` shows the tree\n with member counts and the unfiled count (unfiled is permanent and normal —\n a count, never a finding; \\`loam list --json\\` carries the same facts as\n additive keys \\`services[].subsystem\\`, \\`subsystems[]\\` and\n \\`unfiledServices\\`); \\`history <name>\\` asks git how a service or subsystem\n moved and answers nothing — exit 0, no finding — when git will not say;\n \\`sync\\` regenerates \\`architecture/subsystems.likec4\\`, the one repair for\n \\`subsystem.views-stale\\`, and also maintains the RENDERER's wiring for the\n service models. Which wiring a model needs is decided by the file's own\n grammar, never by a config key: a model that declares its own\n \\`specification { element … }\\` block STANDS ALONE — it cannot share a project\n with the fleet map, since every kind it declares would be a duplicate there —\n and a model with no such block EXTENDS the map with\n \\`extend <fully-qualified id> { … }\\` and parses only INSIDE the root project.\n So \\`sync\\` writes one create-only \\`services/<…>/<id>/likec4.config.json\\` per\n STANDALONE model (never rewritten; the team may edit it; commit\n the new files before a \\`move\\`, which refuses over untracked paths), DELETES one\n sitting beside an EXTENDING model (that nested project claims the model out of\n the root project, so \\`likec4 validate .\\` refuses without \\`--project\\` and,\n wherever that project claims the model, \\`export json --project fleet\\` loses\n the service's containers; \\`--json\\` lists what it removed as \\`projects.removed\\`), and rewrites\n the root \\`likec4.config.json\\`'s \\`exclude\\` to hold \\`services/<tree>/**\\` for\n exactly those models, keeping every entry that is not about \\`services/\\` in the\n order the team wrote it. It rewrites that list when at least one extending model\n exists, or when a standalone model's directory is not covered — an older repo\n whose models all stand alone behind \\`services/**\\` is never touched. \\`--json\\`\n carries the result as \\`projects.exclude\\`, and the text view prints one line when\n it rewrote. Between them these repair four warnings:\n \\`service.likec4-config-missing\\` (a standalone model with no project file),\n \\`service.likec4-config-stray\\` (a project file beside an extending model),\n \\`service.model-excluded\\` (an extending model the root \\`exclude\\` hides from the\n renderer) and \\`service.model-unexcluded\\` (a standalone model it does not hide,\n which blanks the whole root project). A flat fleet with no subsystems still owes\n this run: the verb is the tree's, the files are the renderer's. A fleet whose\n models all extend the map ends with ONE project and one picker entry, and\n \\`likec4 validate\\` at the docs root needs no flag; each standalone model adds a\n project, and with more than one \\`likec4 validate\\` needs \\`--project <name>\\`\n (\\`build\\` and \\`export\\` take every project). A view id claimed twice inside one\n project — the landscape and an extending model both minting it, or either\n claiming a generated one — is\n \\`subsystem.view-id-collision\\`. Each generated view is titled by its PATH —\n every marked ancestor's label and its own, which the renderer reads as\n folders — where a label is the marker's \\`title\\` or the directory name; the\n marker's \\`description\\` rides along. So editing \\`subsystem.yaml\\` changes\n what the renderer LABELS the group, a parent's title changes every view\n beneath it, and either makes the file stale until the next \\`sync\\`. The\n generated file is NEVER part of the fleet-project load\n (\\`c4.fleet-project-invalid\\` reads every other \\`.likec4\\` the root project holds);\n \\`subsystem.views-stale\\` is the only check that reads it, by byte comparison.\n Each view\n carries \\`global style subsystems\\` — written after its title, the one line\n LikeC4 gives a view for borrowing a palette — exactly when the \\`architecture/\\`\n project declares a global style with that id (\\`global { styleGroup subsystems\n { style element.tag = #external { color gray } } }\\`, in the landscape or in\n ANY \\`.likec4\\` under \\`architecture/\\` the root \\`exclude\\` does not cover — a\n \\`palette.likec4\\` beside the map counts); nothing otherwise, and loam never reads\n what the group says. Declaring it is the whole opt-in and makes the file stale\n once, until the next \\`sync\\`. When the project declares style groups under other\n names only, the file opens with one comment line naming them and saying none is\n \\`subsystems\\`, and the views carry the renderer's defaults — so declaring a group\n under ANY name restales the file, because that comment is part of the bytes.\n \\`sync\\` refuses to rewrite it at all while \\`architecture/\\` does not parse\n (\\`action: \"blocked\"\\`): fix the map first. It is generated wholesale:\n an authored diagram of the same services belongs in the landscape or in a\n file of your own name, never here. \\`loam adopt --subsystem <name>\\` briefs a new\n service's baseline directly into a group, so adoption need not land unfiled.\n`;\n"]}
@@ -23,7 +23,13 @@ export const USECASE_VIEWS = `- Business use cases are \`dynamic view\`s, and \`
23
23
  tag the view \`#cap-<capability>\` to have it graded. The tag spells a declared
24
24
  capability id with every \`/\` flattened to \`-\` (a LikeC4 tag name cannot carry a
25
25
  slash), and it must be declared as a \`tag\` in the one \`specification\` block the
26
- project has, since LikeC4 refuses an undeclared tag. EITHER reserved prefix
26
+ \`architecture/\` project has, since LikeC4 refuses an undeclared tag. loam grades
27
+ the fleet map as THAT project and nothing else — the landscape plus its
28
+ siblings, never a service model — so a hop here names SERVICE elements: a step
29
+ naming a container that a service's extending model declares resolves in the
30
+ renderer's wider root project and is \`landscape.invalid\` for loam, which takes
31
+ the whole fleet map down. Container-level flows live beside the model that
32
+ declares them (below). EITHER reserved prefix
27
33
  opts a view in — a view carrying only \`#req-<requirement>\` is graded too, and
28
34
  earns \`usecase.requirement-unresolved\` for the \`#cap-\` tag it is missing
29
35
  rather than silence. An UNTAGGED dynamic view is somebody's hand-drawn diagram
@@ -38,6 +44,37 @@ export const USECASE_VIEWS = `- Business use cases are \`dynamic view\`s, and \`
38
44
  hop written \`a <- b\` is attributed to the call it answers, so spell replies
39
45
  that way rather than as fresh hops. Every message names the file the view was
40
46
  written in, never the landscape.
47
+ - A flow behind ONE service's own requirement — the hop sequence over its
48
+ containers that an arch.spec.md \`Covers:\` names — lives in that service's own
49
+ LikeC4 project: any \`.likec4\` beside \`services/<…>/<svc>/model.likec4\`
50
+ (\`usecases/<name>.likec4\` by convention, or \`views.likec4\`), or a \`dynamic view\`
51
+ inside model.likec4 itself; loam reads exactly what the renderer's per-service
52
+ project reads. Never \`architecture/usecases/\`, which cannot resolve a container
53
+ and turns the whole fleet \`landscape.invalid\`. Tag it \`#req-<Requirement-ID>\`
54
+ (the id flattened as above). The tag has to be DECLARED where that project can
55
+ see it: in model.likec4's own \`specification\` block when the model declares one
56
+ and therefore stands alone; in \`architecture/landscape.likec4\`'s block when the
57
+ model EXTENDS the map, or in a tags-only \`specification { tag req-… }\` beside
58
+ the \`extend\`, which is legal and lands the tag in the project's specification.
59
+ Declaring it in BOTH is a duplicate, and the code is the one that lands where
60
+ the second declaration's FILE is: \`c4.invalid\` (an error, and the model's
61
+ grading is suspended behind it) when the tags-only block is in model.likec4,
62
+ \`usecase.flow-invalid\` when it is in a sibling. \`c4.fleet-project-invalid\` is
63
+ the fleet-scope class one step out — two SERVICES each declaring the same tag
64
+ locally, which no per-service project sees.
65
+ Then \`loam validate --service <svc>\` grades it — under
66
+ \`--all\`, per service: \`usecase.step-unbacked\` and \`usecase.step-contested\`
67
+ against model.likec4, \`usecase.requirement-unresolved\` against THIS service's
68
+ spec.md and arch.spec.md ids, and \`usecase.flow-invalid\` when a sibling file
69
+ breaks the project (model.likec4 is still graded alone). \`usecase.step-unlinked\`
70
+ never fires on a hop whose caller and provider resolve to the same service — a
71
+ service owes no operationId to itself — while a hop from such a flow into another
72
+ service's element (a stand-in the model declares for a sibling, with no
73
+ \`metadata { op }\`) still warns, exactly as on the fleet map. A \`#cap-\` tag on
74
+ such a flow is \`usecase.capability-unresolved\`: a capability is claimed on the
75
+ fleet map, never inside one service. A resolved service-local \`#req-\` keeps its
76
+ own grade and nothing else — it is not \`keptBy\`, not \`Covers:\`, and no feature
77
+ carries one yet.
41
78
  - A FEATURE brings a flow the way it brings every other axis: write it at
42
79
  \`features/<FEAT>/usecases/<name>.likec4\` — the same views-only document, in the
43
80
  feature's own directory — and \`loam archive\` copies it into
@@ -52,9 +89,14 @@ export const USECASE_VIEWS = `- Business use cases are \`dynamic view\`s, and \`
52
89
  that file — the merge is a whole-file copy, so edit the living one directly
53
90
  instead) and \`usecase.flow-invalid\` (loam could not read the flows against that
54
91
  post-merge map — most often a hop naming an element neither the living
55
- landscape nor the delta declares). Do NOT put a \`dynamic view\` inside
92
+ landscape nor the delta declares; the merge preview stages no service model, so
93
+ a container an extending model declares is not among them either). Do NOT put a
94
+ \`dynamic view\` inside
56
95
  \`delta.likec4\`: that document re-declares the landscape's own identifiers and
57
96
  carries its own \`specification\` block, so it cannot be read beside the map, and
58
- the archive refuses it by name.
97
+ the archive refuses it by name. A feature's \`delta.likec4\` keeps that shape
98
+ whatever shape the service models take — \`features/**\` stays excluded from the
99
+ root LikeC4 project, and the delta is pointed at alone
100
+ (\`npx likec4 start features/<FEAT>\`).
59
101
  `;
60
102
  //# sourceMappingURL=usecases.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"usecases.js","sourceRoot":"","sources":["../../../../../src/core/agent/agents-md/map/usecases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwC5B,CAAC","sourcesContent":["/**\n * The use-case axis of the command map — its own section module for\n * `./subsystem.ts`'s exact reason: command-map.ts sat against the file-line\n * limit and the agents-md package against the five-file cap, so a family added\n * to the `validate --all` cross-check documents itself one package down and is\n * concatenated after the map. The four `usecase.*` codes are what\n * test/codes-drift.test.ts finds here.\n *\n * They are LISTED and not glossed: their fix rows live in the /loam-check\n * table and `loam explain usecase.step-unbacked` prints them, so writing the\n * meanings out again here is the duplication ../../command-map.ts's header\n * describes. What stays is what `explain` does not say — how to opt a view in,\n * and that an untagged dynamic view is never graded at all.\n *\n * Same assembly contract as every section: ../../agents-md.ts concatenates with\n * NO join separator, so this string starts at the first character of its opening\n * line and ends with the newline that closes its last one.\n */\nexport const USECASE_VIEWS = `- Business use cases are \\`dynamic view\\`s, and \\`loam validate --all\\` grades the\n ones that opt in. Write the flow in a file of its own —\n \\`architecture/usecases/<name>.likec4\\`, a \\`views { }\\` block over the landscape's\n elements, which loam reads as ONE LikeC4 project together with the map — and\n tag the view \\`#cap-<capability>\\` to have it graded. The tag spells a declared\n capability id with every \\`/\\` flattened to \\`-\\` (a LikeC4 tag name cannot carry a\n slash), and it must be declared as a \\`tag\\` in the one \\`specification\\` block the\n project has, since LikeC4 refuses an undeclared tag. EITHER reserved prefix\n opts a view in — a view carrying only \\`#req-<requirement>\\` is graded too, and\n earns \\`usecase.requirement-unresolved\\` for the \\`#cap-\\` tag it is missing\n rather than silence. An UNTAGGED dynamic view is somebody's hand-drawn diagram\n and is never graded — that opt-in is what lets a fleet full of existing\n diagrams upgrade without turning red, and \\`loam validate\\`, \\`loam diff\\`,\n \\`loam delta\\`, \\`loam status\\`, \\`loam context\\` and \\`loam list capabilities\\` all\n read the same opt-in, so a flow one of them sees is a flow all of them see. On a tagged\n view: \\`usecase.capability-unresolved\\`, \\`usecase.step-unbacked\\`,\n \\`usecase.step-contested\\` and \\`usecase.step-unlinked\\`. The first is silent\n while architecture/capabilities.yaml is absent or unreadable, like the rest of\n the capability axis; the three step codes are about the model, and a return\n hop written \\`a <- b\\` is attributed to the call it answers, so spell replies\n that way rather than as fresh hops. Every message names the file the view was\n written in, never the landscape.\n- A FEATURE brings a flow the way it brings every other axis: write it at\n \\`features/<FEAT>/usecases/<name>.likec4\\` — the same views-only document, in the\n feature's own directory — and \\`loam archive\\` copies it into\n \\`architecture/usecases/\\` while \\`loam unarchive\\` takes it back. That is what lets\n an analyst add a cross-service requirement and an architect answer it with the\n flow that keeps it IN ONE CHANGE: the \\`#req-\\` tag resolves against this\n feature's own \\`capabilities/<cap>/spec.md\\` delta as well as the living tree, and\n \\`capability.uncovered\\` counts the flow as cover. The flow is graded against the\n map the same merge would leave behind, so a hop may name a service this\n feature's \\`delta.likec4\\` adds. Two refusals guard it, and \\`--approve\\` moves\n neither: \\`usecase.flow-exists\\` (the living \\`architecture/usecases/\\` already has\n that file — the merge is a whole-file copy, so edit the living one directly\n instead) and \\`usecase.flow-invalid\\` (loam could not read the flows against that\n post-merge map — most often a hop naming an element neither the living\n landscape nor the delta declares). Do NOT put a \\`dynamic view\\` inside\n \\`delta.likec4\\`: that document re-declares the landscape's own identifiers and\n carries its own \\`specification\\` block, so it cannot be read beside the map, and\n the archive refuses it by name.\n`;\n"]}
1
+ {"version":3,"file":"usecases.js","sourceRoot":"","sources":["../../../../../src/core/agent/agents-md/map/usecases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkF5B,CAAC","sourcesContent":["/**\n * The use-case axis of the command map — its own section module for\n * `./subsystem.ts`'s exact reason: command-map.ts sat against the file-line\n * limit and the agents-md package against the five-file cap, so a family added\n * to the `validate --all` cross-check documents itself one package down and is\n * concatenated after the map. The four `usecase.*` codes are what\n * test/codes-drift.test.ts finds here.\n *\n * They are LISTED and not glossed: their fix rows live in the /loam-check\n * table and `loam explain usecase.step-unbacked` prints them, so writing the\n * meanings out again here is the duplication ../../command-map.ts's header\n * describes. What stays is what `explain` does not say — how to opt a view in,\n * and that an untagged dynamic view is never graded at all.\n *\n * Same assembly contract as every section: ../../agents-md.ts concatenates with\n * NO join separator, so this string starts at the first character of its opening\n * line and ends with the newline that closes its last one.\n */\nexport const USECASE_VIEWS = `- Business use cases are \\`dynamic view\\`s, and \\`loam validate --all\\` grades the\n ones that opt in. Write the flow in a file of its own —\n \\`architecture/usecases/<name>.likec4\\`, a \\`views { }\\` block over the landscape's\n elements, which loam reads as ONE LikeC4 project together with the map — and\n tag the view \\`#cap-<capability>\\` to have it graded. The tag spells a declared\n capability id with every \\`/\\` flattened to \\`-\\` (a LikeC4 tag name cannot carry a\n slash), and it must be declared as a \\`tag\\` in the one \\`specification\\` block the\n \\`architecture/\\` project has, since LikeC4 refuses an undeclared tag. loam grades\n the fleet map as THAT project and nothing else — the landscape plus its\n siblings, never a service model — so a hop here names SERVICE elements: a step\n naming a container that a service's extending model declares resolves in the\n renderer's wider root project and is \\`landscape.invalid\\` for loam, which takes\n the whole fleet map down. Container-level flows live beside the model that\n declares them (below). EITHER reserved prefix\n opts a view in — a view carrying only \\`#req-<requirement>\\` is graded too, and\n earns \\`usecase.requirement-unresolved\\` for the \\`#cap-\\` tag it is missing\n rather than silence. An UNTAGGED dynamic view is somebody's hand-drawn diagram\n and is never graded — that opt-in is what lets a fleet full of existing\n diagrams upgrade without turning red, and \\`loam validate\\`, \\`loam diff\\`,\n \\`loam delta\\`, \\`loam status\\`, \\`loam context\\` and \\`loam list capabilities\\` all\n read the same opt-in, so a flow one of them sees is a flow all of them see. On a tagged\n view: \\`usecase.capability-unresolved\\`, \\`usecase.step-unbacked\\`,\n \\`usecase.step-contested\\` and \\`usecase.step-unlinked\\`. The first is silent\n while architecture/capabilities.yaml is absent or unreadable, like the rest of\n the capability axis; the three step codes are about the model, and a return\n hop written \\`a <- b\\` is attributed to the call it answers, so spell replies\n that way rather than as fresh hops. Every message names the file the view was\n written in, never the landscape.\n- A flow behind ONE service's own requirement — the hop sequence over its\n containers that an arch.spec.md \\`Covers:\\` names — lives in that service's own\n LikeC4 project: any \\`.likec4\\` beside \\`services/<…>/<svc>/model.likec4\\`\n (\\`usecases/<name>.likec4\\` by convention, or \\`views.likec4\\`), or a \\`dynamic view\\`\n inside model.likec4 itself; loam reads exactly what the renderer's per-service\n project reads. Never \\`architecture/usecases/\\`, which cannot resolve a container\n and turns the whole fleet \\`landscape.invalid\\`. Tag it \\`#req-<Requirement-ID>\\`\n (the id flattened as above). The tag has to be DECLARED where that project can\n see it: in model.likec4's own \\`specification\\` block when the model declares one\n and therefore stands alone; in \\`architecture/landscape.likec4\\`'s block when the\n model EXTENDS the map, or in a tags-only \\`specification { tag req-… }\\` beside\n the \\`extend\\`, which is legal and lands the tag in the project's specification.\n Declaring it in BOTH is a duplicate, and the code is the one that lands where\n the second declaration's FILE is: \\`c4.invalid\\` (an error, and the model's\n grading is suspended behind it) when the tags-only block is in model.likec4,\n \\`usecase.flow-invalid\\` when it is in a sibling. \\`c4.fleet-project-invalid\\` is\n the fleet-scope class one step out — two SERVICES each declaring the same tag\n locally, which no per-service project sees.\n Then \\`loam validate --service <svc>\\` grades it — under\n \\`--all\\`, per service: \\`usecase.step-unbacked\\` and \\`usecase.step-contested\\`\n against model.likec4, \\`usecase.requirement-unresolved\\` against THIS service's\n spec.md and arch.spec.md ids, and \\`usecase.flow-invalid\\` when a sibling file\n breaks the project (model.likec4 is still graded alone). \\`usecase.step-unlinked\\`\n never fires on a hop whose caller and provider resolve to the same service — a\n service owes no operationId to itself — while a hop from such a flow into another\n service's element (a stand-in the model declares for a sibling, with no\n \\`metadata { op }\\`) still warns, exactly as on the fleet map. A \\`#cap-\\` tag on\n such a flow is \\`usecase.capability-unresolved\\`: a capability is claimed on the\n fleet map, never inside one service. A resolved service-local \\`#req-\\` keeps its\n own grade and nothing else — it is not \\`keptBy\\`, not \\`Covers:\\`, and no feature\n carries one yet.\n- A FEATURE brings a flow the way it brings every other axis: write it at\n \\`features/<FEAT>/usecases/<name>.likec4\\` — the same views-only document, in the\n feature's own directory — and \\`loam archive\\` copies it into\n \\`architecture/usecases/\\` while \\`loam unarchive\\` takes it back. That is what lets\n an analyst add a cross-service requirement and an architect answer it with the\n flow that keeps it IN ONE CHANGE: the \\`#req-\\` tag resolves against this\n feature's own \\`capabilities/<cap>/spec.md\\` delta as well as the living tree, and\n \\`capability.uncovered\\` counts the flow as cover. The flow is graded against the\n map the same merge would leave behind, so a hop may name a service this\n feature's \\`delta.likec4\\` adds. Two refusals guard it, and \\`--approve\\` moves\n neither: \\`usecase.flow-exists\\` (the living \\`architecture/usecases/\\` already has\n that file — the merge is a whole-file copy, so edit the living one directly\n instead) and \\`usecase.flow-invalid\\` (loam could not read the flows against that\n post-merge map — most often a hop naming an element neither the living\n landscape nor the delta declares; the merge preview stages no service model, so\n a container an extending model declares is not among them either). Do NOT put a\n \\`dynamic view\\` inside\n \\`delta.likec4\\`: that document re-declares the landscape's own identifiers and\n carries its own \\`specification\\` block, so it cannot be read beside the map, and\n the archive refuses it by name. A feature's \\`delta.likec4\\` keeps that shape\n whatever shape the service models take — \\`features/**\\` stays excluded from the\n root LikeC4 project, and the delta is pointed at alone\n (\\`npx likec4 start features/<FEAT>\\`).\n`;\n"]}
@@ -20,10 +20,15 @@ loam has no server or database. Delete it and the documents still make sense.
20
20
  \`architecture/adrs/\` optional system-level decisions — only their links are graded.
21
21
  \`architecture/subsystems.likec4\` is GENERATED by \`loam subsystem sync\` from the
22
22
  directory tree under \`services/\` — one view per subsystem, a scoping aid, never
23
- hand-edited and never a second fleet map. A diagram you author belongs in the
23
+ hand-edited and never a second fleet map; its one styling opt-in is a
24
+ \`global { styleGroup subsystems { … } }\` declared in any \`.likec4\` under
25
+ \`architecture/\`, which \`sync\` then references. A diagram you author belongs in the
24
26
  landscape or in a file of your own name beside it.
25
27
  \`services/<id>/\` holds a boundary's living \`model.likec4\`, \`spec.md\`,
26
- \`arch.spec.md\`, OpenAPI, AsyncAPI, runbook and health facts.
28
+ \`arch.spec.md\`, OpenAPI, AsyncAPI, runbook and health facts — and
29
+ \`services/<…>/<id>/usecases/*.likec4\`, the slot for a \`dynamic view\` over that
30
+ service's OWN containers, tagged \`#req-<Requirement-ID>\`; a flow that crosses
31
+ services lives in \`architecture/usecases/\` and is tagged \`#cap-\` instead.
27
32
  \`features/<FEAT>/\` holds a change in flight: \`intent.md\`, \`delta.likec4\`,
28
33
  per-service requirement and contract deltas, and \`verification.yaml\`.
29
34
  \`features/archive/\` is shipped history.
@@ -78,7 +83,10 @@ decision or human-only act; the user does not have to type every loam command.
78
83
  If loam or an agent integration behaves unexpectedly, invoke \`/loam-report\` (or
79
84
  load \`$loam-report\` on a skills-only host). It collects a sanitized, reproducible
80
85
  Markdown report under \`loam-reports/\` without repairing the repository, retrying a
81
- writer or uploading anything. This is support, not a seventh lifecycle step.
86
+ writer or uploading anything. Reports are numbered — \`loam-reports/NNN-YYYY-MM-DD-<slug>.md\`,
87
+ cited by ordinal — and carry a \`Status:\` line, so \`loam doctor\` counts the
88
+ directory and says which ordinal the next report takes. This is support, not a
89
+ seventh lifecycle step.
82
90
 
83
91
  ## The cycle
84
92
 
@@ -86,7 +94,9 @@ writer or uploading anything. This is support, not a seventh lifecycle step.
86
94
  \`loam init --docs <path-to-docs-repo> --service <id>\`, then \`loam doctor\`.
87
95
  1. **Adopt** — for an undocumented boundary load \`loam instructions loam-adopt
88
96
  <id>\`, then use \`loam adopt --service <id> --json\`. Write drafts; a person,
89
- never an agent, later vouches for them.
97
+ never an agent, later vouches for them. Draw the map's edges in the same pass:
98
+ the brief's \`landscape.touched\` is the only place an edgeless element is named,
99
+ and \`landscape.service-isolated\` (fleet scope) goes quiet on the first edge.
90
100
  2. **Understand** — start or resume with \`loam status --json\`; its ordered
91
101
  \`next[]\` is the work queue. Read \`next[0].execution\`: run it only when
92
102
  \`runnable\` is true; otherwise use \`kind\`, \`cwd\`, \`needs\` and \`after\`
@@ -1 +1 @@
1
- {"version":3,"file":"agents-md.js","sourceRoot":"","sources":["../../../src/core/agent/agents-md.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiKnB,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,eAAe,CAAC,YAAY,CAAC,KAAK,WAAW,EAAE,CAAC","sourcesContent":["/**\n * The small, always-loaded orientation contract for a loam docs repository.\n *\n * Detailed grammars and workflows live behind `loam instructions`: those pages\n * describe the binary that is about to run, while this file is written once and\n * may be loaded into every agent turn for years. Keep only enough here to form\n * the next question, find the relevant page, and avoid an unsafe write.\n */\nimport { agentsStampLine } from \"./agents-stamp.js\";\nimport { LOAM_VERSION } from \"../envelope/version.js\";\n\nconst ORIENTATION = `# Working in this docs repo\n\nThis is a **loam** docs repo: plain files are the shared source of truth for a governed software\nfleet's architecture, requirements, contracts and verification evidence. A service may be a modular monolith, a network service, a CLI or a worker.\nloam has no server or database. Delete it and the documents still make sense.\n\n## What is where\n\n\\`architecture/landscape.likec4\\` is the fleet map, and\n\\`architecture/adrs/\\` optional system-level decisions — only their links are graded.\n\\`architecture/subsystems.likec4\\` is GENERATED by \\`loam subsystem sync\\` from the\ndirectory tree under \\`services/\\` — one view per subsystem, a scoping aid, never\nhand-edited and never a second fleet map. A diagram you author belongs in the\nlandscape or in a file of your own name beside it.\n\\`services/<id>/\\` holds a boundary's living \\`model.likec4\\`, \\`spec.md\\`,\n\\`arch.spec.md\\`, OpenAPI, AsyncAPI, runbook and health facts.\n\\`features/<FEAT>/\\` holds a change in flight: \\`intent.md\\`, \\`delta.likec4\\`,\nper-service requirement and contract deltas, and \\`verification.yaml\\`.\n\\`features/archive/\\` is shipped history.\n\nLiving documents are the complete current state. A feature document is a diff\nagainst them, reviewed as a diff; \\`loam archive\\` folds it into living state.\nDo not hand-edit the living landscape to add a feature change.\n\n## Linking between documents\n\nDocuments join with **standard markdown links** whose targets are real relative\npaths, for example \\`[decision](../adrs/ADR-001.md)\\`. They render in pull-request\nreview instead of showing literal brackets,\nand make “does this link resolve” a filesystem question; \\`[[Wikilinks]]\\` would\nrequire shortest-unique-path guessing.\nObsidian supports markdown links, autocomplete and rename-tracking when its\nwikilink setting is off. \\`link.unresolved\\` grades missing targets and CASE\n**is** graded; links outside this repository, \\`#section\\` targets, a fenced code\nblock or an inline code span are deliberately not graded.\n\n## \\`loam.json\\` — the wiring\n\nEvery repository commits its own \\`loam.json\\`:\n\n\\`{ \"docsDir\": \"../docs\", \"service\": \"payment-service\", \"gherkinDir\": \"features\" }\\`\n\n\\`docsDir\\` is stored exactly as it was passed and resolved against the directory\nholding the \\`loam.json\\`, so a relative path survives a clone; an absolute one\nraises \\`doctor.docs-absolute\\`. \\`service\\` binds a service checkout to the one boundary\nit may write evidence for. \\`gherkinDir\\` is optional. \\`agentTools\\` and\n\\`agentProfile\\` record which agent surfaces and workflow subset init manages;\n\\`agentFiles\\` records digests so unchanged generated pointers can refresh while\ncustomized ones remain untouched. With no config, loam refuses with \\`no-config\\`\nrather than guessing.\n\n\\`loam init --docs <dir>\\` **joins** an existing docs repo. Add \\`--create\\` only\nwhen creating a new one; a typo must not scaffold a second source of truth.\n\n## Starting from chat\n\nThere are two equivalent entry points into the same version-matched protocol.\nPrefer the explicit one when a user wants a predictable lifecycle: invoke\n\\`/loam-feature <FEAT> \"<title>\"\\` to propose, \\`/loam-implement <FEAT> [service]\\`\nto build, \\`/loam-check\\` and \\`/loam-verify <FEAT>\\` to grade it, and\n\\`/loam-ship <FEAT>\\` to finish. Most hosts use that flat slash\nspelling; Gemini uses \\`/loam:feature\\`, Amazon Q uses \\`@loam-feature\\`, and a\nskills-only host can invoke \\`$loam-feature\\`. Natural-language requests may load\nthe matching Agent Skill instead. Once either entry point is selected, the agent\ndrives the internal status/edit/validate loop and asks the user only for a real\ndecision or human-only act; the user does not have to type every loam command.\n\nIf loam or an agent integration behaves unexpectedly, invoke \\`/loam-report\\` (or\nload \\`$loam-report\\` on a skills-only host). It collects a sanitized, reproducible\nMarkdown report under \\`loam-reports/\\` without repairing the repository, retrying a\nwriter or uploading anything. This is support, not a seventh lifecycle step.\n\n## The cycle\n\n0. **Wire the repo** — in each service checkout run\n \\`loam init --docs <path-to-docs-repo> --service <id>\\`, then \\`loam doctor\\`.\n1. **Adopt** — for an undocumented boundary load \\`loam instructions loam-adopt\n <id>\\`, then use \\`loam adopt --service <id> --json\\`. Write drafts; a person,\n never an agent, later vouches for them.\n2. **Understand** — start or resume with \\`loam status --json\\`; its ordered\n \\`next[]\\` is the work queue. Read \\`next[0].execution\\`: run it only when\n \\`runnable\\` is true; otherwise use \\`kind\\`, \\`cwd\\`, \\`needs\\` and \\`after\\`\n to complete the edit or external-repo step. Use \\`loam list --json\\`, \\`loam show <id> --json\\`\n and \\`loam explore <id> --json\\` before proposing a change. Never propose a\n change to a service you have not read.\n3. **Scaffold** — load \\`loam instructions loam-feature <FEAT>\\`, then run\n \\`loam new <FEAT> --title \"...\" --touches <service>\\`.\n4. **Author** — fill the scaffolded TODOs and run \\`loam rebase <FEAT>\\` after\n reading the living baselines. The exact joins and authoring grammars are in\n the reference pages below.\n5. **Check** — load \\`loam instructions loam-check --no-fix-tables\\`, run\n \\`loam validate <FEAT> --json\\`, and use \\`loam explain <code>\\` for reported\n codes. \\`loam dependencies --json\\` names features that must archive first.\n6. **Build** — load \\`loam instructions loam-implement <FEAT>\\`.\n \\`loam delta <FEAT> --service <id> --json\\` is one service's task; in that\n service checkout, \\`loam gherkin <FEAT>\\` emits its executable scenarios.\n7. **Verify** — \\`loam verify <FEAT> --json\\` is the checklist. Record evidence\n from each affected service's own checkout. Read\n \\`loam instructions loam-done-check\\` before recording anything.\n8. **Ship** — load \\`loam instructions loam-ship <FEAT>\\`; begin with\n \\`loam archive <FEAT> --dry-run --json\\`, then archive only after the code is\n merged and the plan is the one reviewed.\n\n## Reading loam's output\n\nEvery command takes \\`--json\\`. The envelope has \\`contractVersion\\`, \\`ok\\` and,\non refusal, \\`error.code\\`. Unknown flags are \\`invalid-option\\`; \\`--help\\` and\n\\`--version\\` pass through. Branch on stable codes, never message prose.\n\nValidation \\`findings[]\\` carry \\`severity\\`; archive-related findings also carry\n\\`gates\\`. Severity and gating are two different questions: errors invalidate,\nwhile \\`gates: true\\` makes archive refuse — archive is gated on coherence, so a\ngating finding stops it whatever its severity. Advisory warnings never block.\n\\`--approve\\` overrides the gating issues — only those that are judgement calls —\nand never a mechanical loss. For example \\`delta.requirement-not-merged\\` warns but gates;\n\\`living.requirement-outside-requirements\\` cannot be approved, while\n\\`openapi.op-modified\\` is reviewable.\n\n\\`loam status --json\\` orders executable next actions. Findings include structured\n\\`locations[]\\`; use their paths instead of extracting filenames from prose.\n\\`loam show <FEAT> --json\\` includes a \\`review\\` pack with intent, architecture,\ncontracts, dependencies, verification, blockers and the same next actions.\n\\`loam explain <code> --json\\`\nreturns one code's meaning and fix; \\`loam explain --codes --json\\` lists them.\nWhich codes an INVOCATION can raise is in \\`loam instructions loam-codes\\`.\n\n## The identity rule\n\nA service is the element whose \\`metadata { service '<id>' }\\` matches its\n\\`services/<id>/\\` directory. An exact element id is the legacy fallback. Never\ninfer identity from display names or containment. Relationships join to contracts\nthrough exact ids: OpenAPI \\`operationId\\`, requirement \\`Operations:\\`, and C4\n\\`metadata { op '...' }\\`. Consult \\`loam instructions loam-spine\\` before editing\na join.\n\n## Reference pages — fetch when needed\n\n- \\`loam instructions loam-codes\\` — finding/refusal inventory and fixes.\n- \\`loam instructions loam-spine\\` — operation, message, coverage, permission,\n capability and baseline joins.\n- \\`loam instructions loam-authoring\\` — arch requirements, generated Gherkin\n and frontmatter/vouch grammar.\n- \\`loam instructions loam-done-check\\` — verification evidence and verdicts.\n\nBare \\`loam instructions\\` lists the six workflows, the separate \\`loam-report\\`\nsupport protocol and these references. Generated agent command/skill files are\nsmall pointers to them, so the runtime page wins if an old pointer disagrees with\nthe installed binary. MCP clients can read the same pages as\n\\`loam://orientation\\` and \\`loam://instructions/<name>\\` resources.\n\n## Safety and hand-back\n\nloam's writers are journaled, but the lifecycle still matters. Do not run\n\\`loam vouch\\` for a human, do not invent evidence, do not archive before code is\nmerged, and do not edit generated files under \\`<gherkinDir>/loam/\\` by hand.\n\\`loam unarchive <FEAT>\\` is the supported undo. To abandon a feature that was\nnever archived, review it and use \\`git rm -r features/<FEAT>\\`; loam deliberately\nhas no destructive drop command.\n\nFinish by reporting remaining warnings, unverifiable claims, files or directories\nyou did not inspect, and the exact human action still owed.\n`;\n\nexport const AGENTS_MD = `${agentsStampLine(LOAM_VERSION)}\\n${ORIENTATION}`;\n"]}
1
+ {"version":3,"file":"agents-md.js","sourceRoot":"","sources":["../../../src/core/agent/agents-md.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAEtD,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2KnB,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,eAAe,CAAC,YAAY,CAAC,KAAK,WAAW,EAAE,CAAC","sourcesContent":["/**\n * The small, always-loaded orientation contract for a loam docs repository.\n *\n * Detailed grammars and workflows live behind `loam instructions`: those pages\n * describe the binary that is about to run, while this file is written once and\n * may be loaded into every agent turn for years. Keep only enough here to form\n * the next question, find the relevant page, and avoid an unsafe write.\n */\nimport { agentsStampLine } from \"./agents-stamp.js\";\nimport { LOAM_VERSION } from \"../envelope/version.js\";\n\nconst ORIENTATION = `# Working in this docs repo\n\nThis is a **loam** docs repo: plain files are the shared source of truth for a governed software\nfleet's architecture, requirements, contracts and verification evidence. A service may be a modular monolith, a network service, a CLI or a worker.\nloam has no server or database. Delete it and the documents still make sense.\n\n## What is where\n\n\\`architecture/landscape.likec4\\` is the fleet map, and\n\\`architecture/adrs/\\` optional system-level decisions — only their links are graded.\n\\`architecture/subsystems.likec4\\` is GENERATED by \\`loam subsystem sync\\` from the\ndirectory tree under \\`services/\\` — one view per subsystem, a scoping aid, never\nhand-edited and never a second fleet map; its one styling opt-in is a\n\\`global { styleGroup subsystems { … } }\\` declared in any \\`.likec4\\` under\n\\`architecture/\\`, which \\`sync\\` then references. A diagram you author belongs in the\nlandscape or in a file of your own name beside it.\n\\`services/<id>/\\` holds a boundary's living \\`model.likec4\\`, \\`spec.md\\`,\n\\`arch.spec.md\\`, OpenAPI, AsyncAPI, runbook and health facts — and\n\\`services/<…>/<id>/usecases/*.likec4\\`, the slot for a \\`dynamic view\\` over that\nservice's OWN containers, tagged \\`#req-<Requirement-ID>\\`; a flow that crosses\nservices lives in \\`architecture/usecases/\\` and is tagged \\`#cap-\\` instead.\n\\`features/<FEAT>/\\` holds a change in flight: \\`intent.md\\`, \\`delta.likec4\\`,\nper-service requirement and contract deltas, and \\`verification.yaml\\`.\n\\`features/archive/\\` is shipped history.\n\nLiving documents are the complete current state. A feature document is a diff\nagainst them, reviewed as a diff; \\`loam archive\\` folds it into living state.\nDo not hand-edit the living landscape to add a feature change.\n\n## Linking between documents\n\nDocuments join with **standard markdown links** whose targets are real relative\npaths, for example \\`[decision](../adrs/ADR-001.md)\\`. They render in pull-request\nreview instead of showing literal brackets,\nand make “does this link resolve” a filesystem question; \\`[[Wikilinks]]\\` would\nrequire shortest-unique-path guessing.\nObsidian supports markdown links, autocomplete and rename-tracking when its\nwikilink setting is off. \\`link.unresolved\\` grades missing targets and CASE\n**is** graded; links outside this repository, \\`#section\\` targets, a fenced code\nblock or an inline code span are deliberately not graded.\n\n## \\`loam.json\\` — the wiring\n\nEvery repository commits its own \\`loam.json\\`:\n\n\\`{ \"docsDir\": \"../docs\", \"service\": \"payment-service\", \"gherkinDir\": \"features\" }\\`\n\n\\`docsDir\\` is stored exactly as it was passed and resolved against the directory\nholding the \\`loam.json\\`, so a relative path survives a clone; an absolute one\nraises \\`doctor.docs-absolute\\`. \\`service\\` binds a service checkout to the one boundary\nit may write evidence for. \\`gherkinDir\\` is optional. \\`agentTools\\` and\n\\`agentProfile\\` record which agent surfaces and workflow subset init manages;\n\\`agentFiles\\` records digests so unchanged generated pointers can refresh while\ncustomized ones remain untouched. With no config, loam refuses with \\`no-config\\`\nrather than guessing.\n\n\\`loam init --docs <dir>\\` **joins** an existing docs repo. Add \\`--create\\` only\nwhen creating a new one; a typo must not scaffold a second source of truth.\n\n## Starting from chat\n\nThere are two equivalent entry points into the same version-matched protocol.\nPrefer the explicit one when a user wants a predictable lifecycle: invoke\n\\`/loam-feature <FEAT> \"<title>\"\\` to propose, \\`/loam-implement <FEAT> [service]\\`\nto build, \\`/loam-check\\` and \\`/loam-verify <FEAT>\\` to grade it, and\n\\`/loam-ship <FEAT>\\` to finish. Most hosts use that flat slash\nspelling; Gemini uses \\`/loam:feature\\`, Amazon Q uses \\`@loam-feature\\`, and a\nskills-only host can invoke \\`$loam-feature\\`. Natural-language requests may load\nthe matching Agent Skill instead. Once either entry point is selected, the agent\ndrives the internal status/edit/validate loop and asks the user only for a real\ndecision or human-only act; the user does not have to type every loam command.\n\nIf loam or an agent integration behaves unexpectedly, invoke \\`/loam-report\\` (or\nload \\`$loam-report\\` on a skills-only host). It collects a sanitized, reproducible\nMarkdown report under \\`loam-reports/\\` without repairing the repository, retrying a\nwriter or uploading anything. Reports are numbered — \\`loam-reports/NNN-YYYY-MM-DD-<slug>.md\\`,\ncited by ordinal — and carry a \\`Status:\\` line, so \\`loam doctor\\` counts the\ndirectory and says which ordinal the next report takes. This is support, not a\nseventh lifecycle step.\n\n## The cycle\n\n0. **Wire the repo** — in each service checkout run\n \\`loam init --docs <path-to-docs-repo> --service <id>\\`, then \\`loam doctor\\`.\n1. **Adopt** — for an undocumented boundary load \\`loam instructions loam-adopt\n <id>\\`, then use \\`loam adopt --service <id> --json\\`. Write drafts; a person,\n never an agent, later vouches for them. Draw the map's edges in the same pass:\n the brief's \\`landscape.touched\\` is the only place an edgeless element is named,\n and \\`landscape.service-isolated\\` (fleet scope) goes quiet on the first edge.\n2. **Understand** — start or resume with \\`loam status --json\\`; its ordered\n \\`next[]\\` is the work queue. Read \\`next[0].execution\\`: run it only when\n \\`runnable\\` is true; otherwise use \\`kind\\`, \\`cwd\\`, \\`needs\\` and \\`after\\`\n to complete the edit or external-repo step. Use \\`loam list --json\\`, \\`loam show <id> --json\\`\n and \\`loam explore <id> --json\\` before proposing a change. Never propose a\n change to a service you have not read.\n3. **Scaffold** — load \\`loam instructions loam-feature <FEAT>\\`, then run\n \\`loam new <FEAT> --title \"...\" --touches <service>\\`.\n4. **Author** — fill the scaffolded TODOs and run \\`loam rebase <FEAT>\\` after\n reading the living baselines. The exact joins and authoring grammars are in\n the reference pages below.\n5. **Check** — load \\`loam instructions loam-check --no-fix-tables\\`, run\n \\`loam validate <FEAT> --json\\`, and use \\`loam explain <code>\\` for reported\n codes. \\`loam dependencies --json\\` names features that must archive first.\n6. **Build** — load \\`loam instructions loam-implement <FEAT>\\`.\n \\`loam delta <FEAT> --service <id> --json\\` is one service's task; in that\n service checkout, \\`loam gherkin <FEAT>\\` emits its executable scenarios.\n7. **Verify** — \\`loam verify <FEAT> --json\\` is the checklist. Record evidence\n from each affected service's own checkout. Read\n \\`loam instructions loam-done-check\\` before recording anything.\n8. **Ship** — load \\`loam instructions loam-ship <FEAT>\\`; begin with\n \\`loam archive <FEAT> --dry-run --json\\`, then archive only after the code is\n merged and the plan is the one reviewed.\n\n## Reading loam's output\n\nEvery command takes \\`--json\\`. The envelope has \\`contractVersion\\`, \\`ok\\` and,\non refusal, \\`error.code\\`. Unknown flags are \\`invalid-option\\`; \\`--help\\` and\n\\`--version\\` pass through. Branch on stable codes, never message prose.\n\nValidation \\`findings[]\\` carry \\`severity\\`; archive-related findings also carry\n\\`gates\\`. Severity and gating are two different questions: errors invalidate,\nwhile \\`gates: true\\` makes archive refuse — archive is gated on coherence, so a\ngating finding stops it whatever its severity. Advisory warnings never block.\n\\`--approve\\` overrides the gating issues — only those that are judgement calls —\nand never a mechanical loss. For example \\`delta.requirement-not-merged\\` warns but gates;\n\\`living.requirement-outside-requirements\\` cannot be approved, while\n\\`openapi.op-modified\\` is reviewable.\n\n\\`loam status --json\\` orders executable next actions. Findings include structured\n\\`locations[]\\`; use their paths instead of extracting filenames from prose.\n\\`loam show <FEAT> --json\\` includes a \\`review\\` pack with intent, architecture,\ncontracts, dependencies, verification, blockers and the same next actions.\n\\`loam explain <code> --json\\`\nreturns one code's meaning and fix; \\`loam explain --codes --json\\` lists them.\nWhich codes an INVOCATION can raise is in \\`loam instructions loam-codes\\`.\n\n## The identity rule\n\nA service is the element whose \\`metadata { service '<id>' }\\` matches its\n\\`services/<id>/\\` directory. An exact element id is the legacy fallback. Never\ninfer identity from display names or containment. Relationships join to contracts\nthrough exact ids: OpenAPI \\`operationId\\`, requirement \\`Operations:\\`, and C4\n\\`metadata { op '...' }\\`. Consult \\`loam instructions loam-spine\\` before editing\na join.\n\n## Reference pages — fetch when needed\n\n- \\`loam instructions loam-codes\\` — finding/refusal inventory and fixes.\n- \\`loam instructions loam-spine\\` — operation, message, coverage, permission,\n capability and baseline joins.\n- \\`loam instructions loam-authoring\\` — arch requirements, generated Gherkin\n and frontmatter/vouch grammar.\n- \\`loam instructions loam-done-check\\` — verification evidence and verdicts.\n\nBare \\`loam instructions\\` lists the six workflows, the separate \\`loam-report\\`\nsupport protocol and these references. Generated agent command/skill files are\nsmall pointers to them, so the runtime page wins if an old pointer disagrees with\nthe installed binary. MCP clients can read the same pages as\n\\`loam://orientation\\` and \\`loam://instructions/<name>\\` resources.\n\n## Safety and hand-back\n\nloam's writers are journaled, but the lifecycle still matters. Do not run\n\\`loam vouch\\` for a human, do not invent evidence, do not archive before code is\nmerged, and do not edit generated files under \\`<gherkinDir>/loam/\\` by hand.\n\\`loam unarchive <FEAT>\\` is the supported undo. To abandon a feature that was\nnever archived, review it and use \\`git rm -r features/<FEAT>\\`; loam deliberately\nhas no destructive drop command.\n\nFinish by reporting remaining warnings, unverifiable claims, files or directories\nyou did not inspect, and the exact human action still owed.\n`;\n\nexport const AGENTS_MD = `${agentsStampLine(LOAM_VERSION)}\\n${ORIENTATION}`;\n"]}
@@ -63,11 +63,31 @@ more for secrets before handing it back.
63
63
 
64
64
  ## Write one separate report
65
65
 
66
- Create \`loam-reports/YYYY-MM-DD-<short-slug>.md\` at the current repository root. Use a short neutral
67
- slug based on the symptom, not a customer, person or secret. Never overwrite a different incident;
68
- add a numeric suffix when the path exists. Reports are ordinary project files so the team can
69
- review or commit them deliberately, but do not upload, submit an issue, send telemetry, or contact
70
- any service automatically.
66
+ Create \`loam-reports/NNN-YYYY-MM-DD-<short-slug>.md\` in the directory holding the \`loam.json\` that
67
+ resolved — or, when a \`loam.json\` was found but does not parse, beside that file, so a report about
68
+ the broken config joins the corpus already there; only when there is no config file at or above you
69
+ is it the directory you run in.
70
+ \`loam doctor --json\` hands you that whole directory — that root WITH \`loam-reports/\`
71
+ already on the end — as \`reports.dir\`: write inside the path it gives, never joined onto
72
+ \`loam-reports/\` a second time. \`NNN\` is an ordinal of at least three digits, zero-padded, one more
73
+ than the highest already in that directory — read \`reports.next\` from the same output, which says
74
+ \`001\` when the directory is empty or absent, and widens past three digits rather than reusing a
75
+ number once the corpus gets there. Use a short neutral slug based on the symptom, not a customer,
76
+ person or secret. Never
77
+ overwrite a different incident: a path that already exists means a concurrent report claimed that
78
+ ordinal, so take the next one rather than adding a suffix. That check is on the PATH, and the
79
+ promise is about the ordinal, so re-run \`loam doctor --json\` after writing: if two entries carry
80
+ the same \`ordinal\`, the one with the later \`Recorded\` timestamp renames itself to the next free
81
+ number. The ordinal is the report's handle —
82
+ cite one by its number in a commit message, an issue, or another report's cross-references, and
83
+ never by filename, which is free to be renamed. The ordinal is unique within that directory, not
84
+ across a fleet: a service repository and the docs repository each number their own, so when two
85
+ repositories are in play cite \`<repo>/loam-reports/NNN\`.
86
+
87
+ Reports are ordinary project files so the team can review or commit them deliberately, but
88
+ do not upload, submit an issue, send telemetry, or contact any service automatically.
89
+ \`loam doctor\` reads the directory — how many reports it holds, how many are in each status, and
90
+ which ordinal comes next — and that is a local read of local files: nothing is transmitted.
71
91
 
72
92
  Use this shape, omitting only fields that truly cannot be known and marking them \`not collected\`:
73
93
 
@@ -75,6 +95,7 @@ Use this shape, omitting only fields that truly cannot be known and marking them
75
95
 
76
96
  - Recorded: <ISO-8601 timestamp>
77
97
  - Classification: <one value above>
98
+ - Status: open
78
99
  - Repository role: <docs | service | combined | unresolved>
79
100
  - loam version: <version>
80
101
  - Entry point: <chat command, skill, or CLI command; sanitized>
@@ -91,6 +112,19 @@ Use this shape, omitting only fields that truly cannot be known and marking them
91
112
  ## Missing evidence
92
113
  ## Sanitization
93
114
 
115
+ \`Status\` is written as \`open\` and stays the report's own record of where it got to. The vocabulary
116
+ is \`open\`, \`sent\` (handed to loam's author — the person forwarding a report sets this, never the
117
+ agent writing it), \`fixed in <version>\`, and \`superseded by <NNN>\` naming the report that
118
+ replaced this one. Close a report by editing its own \`Status\` line: there is no index to keep in
119
+ step, and \`loam doctor\` counts the directory by reading that line's first word, so
120
+ \`fixed in 0.2.0-alpha.5\` counts as fixed. It reads that line from the HEADER FIELD BLOCK only —
121
+ the lines above the first \`##\` heading, quoted code skipped in either markdown spelling: a fence
122
+ (closed only by a run of the same character at least as long as the one that opened it, so a
123
+ \`\`\` inside a \`\`\`\` block is content) and an indented block, which is the shape THIS template is
124
+ printed in above. So a report that quotes this template, however it quotes it, still counts as
125
+ whatever its own header says. A report written before this
126
+ field existed has no \`Status\` line and counts as unstated.
127
+
94
128
  In \`Machine contract\`, include exit code plus the stable envelope fields and relevant finding
95
129
  codes/locations; do not paste an entire large JSON payload. In \`Sanitization\`, list the kinds of
96
130
  values removed without revealing them. If no workaround is known, say so rather than inventing one.
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../../src/core/agent/support/report.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAmB;IACzC,IAAI,EAAE,aAAa;IACnB,WAAW,EACT,uFAAuF;IACzF,YAAY,EAAE,EAAE;IAChB,OAAO,EACL,oOAAoO;IACtO,UAAU,EAAE,+BAA+B;IAC3C,YAAY,EAAE,EAAE;IAChB,KAAK,EAAE;QACL,+EAA+E;QAC/E,iFAAiF;QACjF,yFAAyF;QACzF,gFAAgF;QAChF,wFAAwF;KACzF;IACD,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiFP;CACA,CAAC","sourcesContent":["import type { CommandContent } from \"../contract.js\";\n\n/**\n * The incident-reporting protocol: preserve a small, sanitized reproducer when\n * loam or its agent integration behaves unexpectedly, without turning loam\n * into a telemetry service or retrying a risky write.\n */\nexport const LOAM_REPORT: CommandContent = {\n name: \"loam-report\",\n description:\n \"Record unexpected loam or agent behavior as a sanitized, reproducible Markdown report\",\n argumentHint: \"\",\n purpose:\n \"Collect one unexpected loam or agent-integration incident into a separate, reviewable Markdown file. This is local diagnostics only: redact secrets, never upload automatically, and never repeat a writer merely to reproduce it.\",\n invocation: \"loam instructions loam-report\",\n placeholders: [],\n spine: [\n \"preserve the user's original symptom and expected result before investigating\",\n \"collect the binary version, wiring diagnosis and the smallest safe reproduction\",\n \"classify the failure without repairing, retrying a writer or changing project documents\",\n \"sanitize commands, paths and output, then write one report under loam-reports/\",\n \"hand back the report path, classification and any evidence that could not be collected\",\n ],\n body: `Record one incident where loam, a generated command/skill, or the agent following it\nbehaved unexpectedly. The result is a local diagnostic document, not a repair and not telemetry.\nDo not change architecture/spec files while collecting it.\n\n## Preserve the symptom first\n\nBefore running anything, write down the user's original request, what they expected, what actually\nhappened, the command or chat entry point involved, and whether any files may already have changed.\nDo not improve or reinterpret the failing command yet: a cleaned-up command is not a reproduction.\n\nClassify the incident as one of these, using \\`inconclusive\\` until the evidence supports another:\n\n- \\`loam-product\\` — the binary violated its documented contract or produced internally inconsistent output;\n- \\`project-data\\` — the binary correctly reported invalid, incomplete or stale repository documents;\n- \\`agent-workflow\\` — the generated command/skill was missing, stale, misrouted or followed incorrectly;\n- \\`host-infrastructure\\` — permissions, filesystem, process, shell or tool-host behavior prevented the run;\n- \\`inconclusive\\` — the available evidence does not distinguish the above.\n\n## Collect only safe evidence\n\n1. Run \\`loam --version\\` and record the result.\n2. Run \\`loam doctor --json\\`. If it succeeds, keep \\`healthy\\`, the finding codes and their structured\n locations/fixes, the resolved repository role, and the write-path state. If it refuses, keep\n \\`error.code\\` and the sanitized message. Do not apply the fixes during reporting.\n3. When the repository is wired, run \\`loam status --json\\` and keep only the state and next-action\n rows relevant to this incident. A refusal is evidence too; keep its \\`error.code\\`.\n4. Re-run the original operation only when it is read-only and safe. Never re-run \\`init\\`, \\`new\\`,\n \\`rebase\\`, \\`subsystem\\`, \\`archive\\`, \\`unarchive\\`, \\`vouch\\`, a recording form of \\`verify\\`, or\n any other writer merely to make it fail twice. For a writer, record its original exit/output and\n inspect \\`doctor\\`, \\`status\\` and version only. Do not repair, roll back or delete anything unless\n the user separately asks for that action.\n5. Prefer the JSON envelope: record \\`contractVersion\\`, \\`ok\\`, \\`command\\`, \\`error.code\\`, finding\n codes and \\`locations[]\\`. Quote only the smallest stdout/stderr excerpt that demonstrates the\n symptom. State what was omitted.\n\n## Sanitize before writing\n\nNever include credentials, tokens, cookies, authorization headers, private keys, environment dumps,\nor values of variables whose names contain \\`TOKEN\\`, \\`SECRET\\`, \\`PASSWORD\\`, \\`AUTH\\`, \\`COOKIE\\` or\n\\`KEY\\`. Replace each value with \\`<redacted>\\`. Replace the user's home directory with \\`<home>\\` and\nprefer repository-relative paths. Do not copy source files, architecture/spec bodies, or a complete\ncommand output when a code and short excerpt prove the same fact. Review the finished report once\nmore for secrets before handing it back.\n\n## Write one separate report\n\nCreate \\`loam-reports/YYYY-MM-DD-<short-slug>.md\\` at the current repository root. Use a short neutral\nslug based on the symptom, not a customer, person or secret. Never overwrite a different incident;\nadd a numeric suffix when the path exists. Reports are ordinary project files so the team can\nreview or commit them deliberately, but do not upload, submit an issue, send telemetry, or contact\nany service automatically.\n\nUse this shape, omitting only fields that truly cannot be known and marking them \\`not collected\\`:\n\n # loam problem report: <short title>\n\n - Recorded: <ISO-8601 timestamp>\n - Classification: <one value above>\n - Repository role: <docs | service | combined | unresolved>\n - loam version: <version>\n - Entry point: <chat command, skill, or CLI command; sanitized>\n - Side effects observed: <none known | paths changed | unknown>\n\n ## Summary\n ## Expected\n ## Actual\n ## Minimal safe reproduction\n ## Machine contract\n ## Doctor and status evidence\n ## Files changed or write state\n ## Workaround\n ## Missing evidence\n ## Sanitization\n\nIn \\`Machine contract\\`, include exit code plus the stable envelope fields and relevant finding\ncodes/locations; do not paste an entire large JSON payload. In \\`Sanitization\\`, list the kinds of\nvalues removed without revealing them. If no workaround is known, say so rather than inventing one.\n\nFinish by telling the user the report path, classification, whether project files changed, and which\nevidence was unavailable. Keep diagnosis separate from certainty: a plausible cause belongs under\n\\`Summary\\` as a hypothesis until the reproduction proves it.\n`,\n};\n"]}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../../src/core/agent/support/report.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAmB;IACzC,IAAI,EAAE,aAAa;IACnB,WAAW,EACT,uFAAuF;IACzF,YAAY,EAAE,EAAE;IAChB,OAAO,EACL,oOAAoO;IACtO,UAAU,EAAE,+BAA+B;IAC3C,YAAY,EAAE,EAAE;IAChB,KAAK,EAAE;QACL,+EAA+E;QAC/E,iFAAiF;QACjF,yFAAyF;QACzF,gFAAgF;QAChF,wFAAwF;KACzF;IACD,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmHP;CACA,CAAC","sourcesContent":["import type { CommandContent } from \"../contract.js\";\n\n/**\n * The incident-reporting protocol: preserve a small, sanitized reproducer when\n * loam or its agent integration behaves unexpectedly, without turning loam\n * into a telemetry service or retrying a risky write.\n */\nexport const LOAM_REPORT: CommandContent = {\n name: \"loam-report\",\n description:\n \"Record unexpected loam or agent behavior as a sanitized, reproducible Markdown report\",\n argumentHint: \"\",\n purpose:\n \"Collect one unexpected loam or agent-integration incident into a separate, reviewable Markdown file. This is local diagnostics only: redact secrets, never upload automatically, and never repeat a writer merely to reproduce it.\",\n invocation: \"loam instructions loam-report\",\n placeholders: [],\n spine: [\n \"preserve the user's original symptom and expected result before investigating\",\n \"collect the binary version, wiring diagnosis and the smallest safe reproduction\",\n \"classify the failure without repairing, retrying a writer or changing project documents\",\n \"sanitize commands, paths and output, then write one report under loam-reports/\",\n \"hand back the report path, classification and any evidence that could not be collected\",\n ],\n body: `Record one incident where loam, a generated command/skill, or the agent following it\nbehaved unexpectedly. The result is a local diagnostic document, not a repair and not telemetry.\nDo not change architecture/spec files while collecting it.\n\n## Preserve the symptom first\n\nBefore running anything, write down the user's original request, what they expected, what actually\nhappened, the command or chat entry point involved, and whether any files may already have changed.\nDo not improve or reinterpret the failing command yet: a cleaned-up command is not a reproduction.\n\nClassify the incident as one of these, using \\`inconclusive\\` until the evidence supports another:\n\n- \\`loam-product\\` — the binary violated its documented contract or produced internally inconsistent output;\n- \\`project-data\\` — the binary correctly reported invalid, incomplete or stale repository documents;\n- \\`agent-workflow\\` — the generated command/skill was missing, stale, misrouted or followed incorrectly;\n- \\`host-infrastructure\\` — permissions, filesystem, process, shell or tool-host behavior prevented the run;\n- \\`inconclusive\\` — the available evidence does not distinguish the above.\n\n## Collect only safe evidence\n\n1. Run \\`loam --version\\` and record the result.\n2. Run \\`loam doctor --json\\`. If it succeeds, keep \\`healthy\\`, the finding codes and their structured\n locations/fixes, the resolved repository role, and the write-path state. If it refuses, keep\n \\`error.code\\` and the sanitized message. Do not apply the fixes during reporting.\n3. When the repository is wired, run \\`loam status --json\\` and keep only the state and next-action\n rows relevant to this incident. A refusal is evidence too; keep its \\`error.code\\`.\n4. Re-run the original operation only when it is read-only and safe. Never re-run \\`init\\`, \\`new\\`,\n \\`rebase\\`, \\`subsystem\\`, \\`archive\\`, \\`unarchive\\`, \\`vouch\\`, a recording form of \\`verify\\`, or\n any other writer merely to make it fail twice. For a writer, record its original exit/output and\n inspect \\`doctor\\`, \\`status\\` and version only. Do not repair, roll back or delete anything unless\n the user separately asks for that action.\n5. Prefer the JSON envelope: record \\`contractVersion\\`, \\`ok\\`, \\`command\\`, \\`error.code\\`, finding\n codes and \\`locations[]\\`. Quote only the smallest stdout/stderr excerpt that demonstrates the\n symptom. State what was omitted.\n\n## Sanitize before writing\n\nNever include credentials, tokens, cookies, authorization headers, private keys, environment dumps,\nor values of variables whose names contain \\`TOKEN\\`, \\`SECRET\\`, \\`PASSWORD\\`, \\`AUTH\\`, \\`COOKIE\\` or\n\\`KEY\\`. Replace each value with \\`<redacted>\\`. Replace the user's home directory with \\`<home>\\` and\nprefer repository-relative paths. Do not copy source files, architecture/spec bodies, or a complete\ncommand output when a code and short excerpt prove the same fact. Review the finished report once\nmore for secrets before handing it back.\n\n## Write one separate report\n\nCreate \\`loam-reports/NNN-YYYY-MM-DD-<short-slug>.md\\` in the directory holding the \\`loam.json\\` that\nresolved — or, when a \\`loam.json\\` was found but does not parse, beside that file, so a report about\nthe broken config joins the corpus already there; only when there is no config file at or above you\nis it the directory you run in.\n\\`loam doctor --json\\` hands you that whole directory — that root WITH \\`loam-reports/\\`\nalready on the end — as \\`reports.dir\\`: write inside the path it gives, never joined onto\n\\`loam-reports/\\` a second time. \\`NNN\\` is an ordinal of at least three digits, zero-padded, one more\nthan the highest already in that directory — read \\`reports.next\\` from the same output, which says\n\\`001\\` when the directory is empty or absent, and widens past three digits rather than reusing a\nnumber once the corpus gets there. Use a short neutral slug based on the symptom, not a customer,\nperson or secret. Never\noverwrite a different incident: a path that already exists means a concurrent report claimed that\nordinal, so take the next one rather than adding a suffix. That check is on the PATH, and the\npromise is about the ordinal, so re-run \\`loam doctor --json\\` after writing: if two entries carry\nthe same \\`ordinal\\`, the one with the later \\`Recorded\\` timestamp renames itself to the next free\nnumber. The ordinal is the report's handle —\ncite one by its number in a commit message, an issue, or another report's cross-references, and\nnever by filename, which is free to be renamed. The ordinal is unique within that directory, not\nacross a fleet: a service repository and the docs repository each number their own, so when two\nrepositories are in play cite \\`<repo>/loam-reports/NNN\\`.\n\nReports are ordinary project files so the team can review or commit them deliberately, but\ndo not upload, submit an issue, send telemetry, or contact any service automatically.\n\\`loam doctor\\` reads the directory — how many reports it holds, how many are in each status, and\nwhich ordinal comes next — and that is a local read of local files: nothing is transmitted.\n\nUse this shape, omitting only fields that truly cannot be known and marking them \\`not collected\\`:\n\n # loam problem report: <short title>\n\n - Recorded: <ISO-8601 timestamp>\n - Classification: <one value above>\n - Status: open\n - Repository role: <docs | service | combined | unresolved>\n - loam version: <version>\n - Entry point: <chat command, skill, or CLI command; sanitized>\n - Side effects observed: <none known | paths changed | unknown>\n\n ## Summary\n ## Expected\n ## Actual\n ## Minimal safe reproduction\n ## Machine contract\n ## Doctor and status evidence\n ## Files changed or write state\n ## Workaround\n ## Missing evidence\n ## Sanitization\n\n\\`Status\\` is written as \\`open\\` and stays the report's own record of where it got to. The vocabulary\nis \\`open\\`, \\`sent\\` (handed to loam's author — the person forwarding a report sets this, never the\nagent writing it), \\`fixed in <version>\\`, and \\`superseded by <NNN>\\` naming the report that\nreplaced this one. Close a report by editing its own \\`Status\\` line: there is no index to keep in\nstep, and \\`loam doctor\\` counts the directory by reading that line's first word, so\n\\`fixed in 0.2.0-alpha.5\\` counts as fixed. It reads that line from the HEADER FIELD BLOCK only —\nthe lines above the first \\`##\\` heading, quoted code skipped in either markdown spelling: a fence\n(closed only by a run of the same character at least as long as the one that opened it, so a\n\\`\\`\\` inside a \\`\\`\\`\\` block is content) and an indented block, which is the shape THIS template is\nprinted in above. So a report that quotes this template, however it quotes it, still counts as\nwhatever its own header says. A report written before this\nfield existed has no \\`Status\\` line and counts as unstated.\n\nIn \\`Machine contract\\`, include exit code plus the stable envelope fields and relevant finding\ncodes/locations; do not paste an entire large JSON payload. In \\`Sanitization\\`, list the kinds of\nvalues removed without revealing them. If no workaround is known, say so rather than inventing one.\n\nFinish by telling the user the report path, classification, whether project files changed, and which\nevidence was unavailable. Keep diagnosis separate from certainty: a plausible cause belongs under\n\\`Summary\\` as a hypothesis until the reproduction proves it.\n`,\n};\n"]}
@@ -10,7 +10,7 @@ export const LOAM_ADOPT = {
10
10
  "wire this repo (`loam init`, then `loam doctor`) if it has no ./loam.json yet",
11
11
  "`loam adopt` — the brief: the order to read the service in, every file to write, the grammar of each, and what the fleet map already says",
12
12
  "walk the service in the brief's order — shape first, then one surface at a time — keeping the list of every path you open, because that list becomes `sources`",
13
- "write the artifacts, everything `status: draft`, then `loam subsystem sync` for the per-service LikeC4 project file — loam's, never yours",
13
+ "write the artifacts, everything `status: draft` — the model EXTENDS the fleet map — then `loam subsystem sync` for the renderer wiring, which is loam's and never yours",
14
14
  "validate the service, then validate the whole fleet — a baseline that passes one and fails the other is documented and invisible",
15
15
  "hand back with what you could not determine from the code, which directories you never opened, the branch-to-scenario count per operation, and three behaviours your documents do not describe — then let a human vouch",
16
16
  ],
@@ -43,6 +43,13 @@ thin baseline that validates is thin, not done.
43
43
  read it, diff your findings against it, report what disagrees. Do not replace it.
44
44
  \`action: "edit"\` appears on exactly one target — \`architecture/landscape.likec4\`,
45
45
  the WHOLE FLEET's map: add this service's element and edges to it, never rewrite it.
46
+ It appears while nothing resolves to the service AND while the element that does
47
+ has no edge touching it; \`targets[].shape\` says which of the two you are in.
48
+ It does NOT appear when loam could not READ the map (\`landscape.modelled: null\`
49
+ — a broken landscape, or a broken sibling under \`architecture/\`): nothing is
50
+ known about what the map already draws, so no write to the whole fleet's map is
51
+ briefed. \`landscape.instruction\` carries the answer and names the documents that
52
+ failed; fix those and re-run.
46
53
  - \`targets[].shape\` — the grammar of each artifact, and \`example\` where one is
47
54
  shorter than a description. Every rule there is one a later check depends on;
48
55
  rules nothing checks are in \`unchecked[]\` instead, and are still worth following.
@@ -50,7 +57,13 @@ thin baseline that validates is thin, not done.
50
57
  Bind to them; do not draw a second version of the same box. \`landscape.expects\`
51
58
  lists operations other services already call — your openapi.yaml owes them.
52
59
  \`landscape.instruction\` is the write the fleet map still owes this service; it
53
- is \`null\` once an element resolves to it, and only then.
60
+ is \`null\` once an element resolves to it AND at least one edge ANYWHERE in the
61
+ \`architecture/\` project touches that element (\`landscape.touched\`), and only
62
+ then — one edge closes the state, so draw every call in one pass.
63
+ \`landscape.attested\` lists the
64
+ calls \`services/$1/model.likec4\` already declares across its boundary — those
65
+ are the edges the map owes, collapsed to the service; an empty list on a
66
+ service with no model is not licence to invent one, and the instruction says so.
54
67
  - \`frontmatter\` — what to put in the header of every markdown artifact.
55
68
  - \`checks[]\` — what \`loam validate\` will run. \`unchecked[]\` — what it will not.
56
69
  2. Read \`AGENTS.md\` at the docs repo root, then walk the service — \`walk[]\` in the
@@ -70,31 +83,127 @@ thin baseline that validates is thin, not done.
70
83
  tying the document to the repository. Never pad it with paths you did not read:
71
84
  it is a record, and \`loam vouch\` hashes exactly what it names.
72
85
  3. Write the artifacts under \`services/$1/\`, in the order the brief lists them, and
73
- make the landscape edit the brief asks for. Then run \`loam subsystem sync\` (from
86
+ make the landscape edit the brief asks for — the element where none resolves, the
87
+ edges where the element stands alone, and the map's own housekeeping
88
+ \`unchecked[]\` names: a placeholder tag to clear, a curated view to add the
89
+ element to.
90
+ **model.likec4 EXTENDS the fleet map.** It declares no \`specification\` block and
91
+ no copy of anything the map already draws: its whole body is
92
+ \`model { extend <fqn> { …containers… } }\`, where \`<fqn>\` is the FULLY-QUALIFIED
93
+ id of the element bound to \`services/$1/\` (the brief's \`landscape.elements\` names
94
+ it; \`extend orderService\` resolves to nothing when the id is
95
+ \`marketplace.orderService\`). Kinds and tags come from
96
+ \`architecture/landscape.likec4\` — a kind you need and the map does not declare
97
+ (\`element database\`, \`element queue\`) is added THERE, once, in the same landscape
98
+ edit. Cross-boundary edges are written OUTSIDE the extend block, from the container
99
+ that makes the call to the other party's element as the map spells it; an element
100
+ this file declares outside its own is \`c4.element-unowned\` (warn), and which fix
101
+ applies depends on whose it is — a store or component this service OWNS belongs
102
+ INSIDE the \`extend\` block (its id becomes \`<fqn>.<name>\`), a system the service
103
+ merely reaches is declared in the map instead, and another service's internals
104
+ belong in that service's model. If you are DIFFING an existing model
105
+ that carries its own \`specification\`, leave it alone: that shape is still legal
106
+ and still parsed on its own, and \`c4.declaration-diverged\` is what reports where
107
+ its copies of the map's elements have drifted. Migrating one is the recipe in
108
+ SCHEMA.md, "Two shapes of a service model" — not something to do inside an
109
+ adoption you were not asked to widen.
110
+ A flow behind one of your arch.spec.md requirements — a \`dynamic view\`
111
+ over this service's own containers — goes in a \`.likec4\` beside model.likec4
112
+ (\`services/$1/usecases/<name>.likec4\` by convention; \`views.likec4\` reads the
113
+ same, because the renderer's per-service project reads every \`.likec4\` under the
114
+ directory and so does loam), tagged \`#req-<Requirement-ID>\` of a requirement in
115
+ this service's spec.md or arch.spec.md, with the tag declared in the map's
116
+ \`specification\` block or in a tags-only \`specification { tag req-… }\` beside the
117
+ \`extend\` — in exactly ONE of the two. Declared in both, the model's own project
118
+ holds the tag twice: the error lands on whichever document carries the second
119
+ declaration, as \`c4.invalid\` (an error, and the model's grading is suspended
120
+ behind it) when that is model.likec4, or as \`usecase.flow-invalid\` when it is the
121
+ sibling. Step 4 grades it. It never goes in \`architecture/usecases/\`,
122
+ which cannot see your containers and turns the whole fleet \`landscape.invalid\`; a
123
+ flow that crosses services goes there and is tagged \`#cap-\`. Never a \`#cap-\` tag
124
+ beside a model. Then run \`loam subsystem sync\` (from
74
125
  this repo or the docs repo — it resolves \`docsDir\`): once the docs root carries
75
- the \`likec4.config.json\` step 0's doctor asks for, it writes
76
- \`services/$1/likec4.config.json\` — and the same file beside any other service
77
- model in the docs repo still missing one — the LikeC4 project that makes a
78
- model.likec4 renderable beside the fleet map from the docs root. Those files are
79
- loam's — never write one yourself, never list it in \`sources\`, never diff it —
80
- and \`sync\` leaves them untracked for you to commit.
126
+ the \`likec4.config.json\` step 0's doctor asks for, it keeps that file's
127
+ \`exclude\` list covering exactly the service directories whose models stand alone —
128
+ so an extending model stays inside the root project, where it is the only place it
129
+ parses and where the renderer draws it beside the map — and writes
130
+ \`services/<…>/<id>/likec4.config.json\` beside each STANDALONE model that has none.
131
+ Both are loam's — never write one yourself, never list it in \`sources\`, never
132
+ diff it, never hand-edit the root \`exclude\`'s \`services/\` entries — and \`sync\`
133
+ leaves what it wrote untracked for you to commit. A repo whose models all extend
134
+ the map usually has nothing for \`sync\` to write here, and that is the healthy
135
+ state, not a skipped step.
81
136
  Everything \`status: draft\`. Never write \`last_verified\`, \`sources_digest\`,
82
137
  \`content_digest\` or \`sources_files\`.
83
- 4. \`loam validate --service $1 --json\`. Fix every error. \`sources.unvouched\` is
138
+ 4. \`loam validate --service $1 --json\`. Fix every error. \`c4.valid\` reading
139
+ "extends the fleet map" is the confirmation that the model was read as one
140
+ document with the map; \`c4.invalid\` on this run means the model plus the map do
141
+ not parse together, and every error is YOURS even where the message names
142
+ \`architecture/landscape.likec4\` — the map parses clean on its own, or
143
+ \`spine.landscape-invalid\` would say so instead and this model could not be read
144
+ at all. \`c4.element-unowned\` (warn) is an element you declared outside the
145
+ element you extend — nest it inside the \`extend\` block if this service owns it,
146
+ declare it in the map if the service only reaches it. \`sources.unvouched\` is
84
147
  expected on a fresh baseline — it closes when a person vouches, not when you do.
85
148
  \`sources.unwalked\` is the walk graded against the repository: its \`details\` name
86
149
  the top-level paths git tracks and \`sources\` never reached into. Treat each one
87
150
  as a place to go back to, not as a line to silence — the fix is reading it, or
88
151
  one sentence in step 6 saying why this document does not owe it.
152
+ \`usecase.*\` findings on this run are about the flows beside model.likec4:
153
+ \`usecase.step-unbacked\` is a hop no relationship in model.likec4 backs,
154
+ \`usecase.step-contested\` two edges backing one hop and naming different
155
+ operations, \`usecase.requirement-unresolved\` a \`#req-\` tag naming no
156
+ \`Requirement-ID:\` of this service's spec.md or arch.spec.md,
157
+ \`usecase.capability-unresolved\` a \`#cap-\` tag beside a model (drop it — a
158
+ capability is claimed on the fleet map, never inside one service), and
159
+ \`usecase.flow-invalid\` a file beside the model that does not read — the flows
160
+ were not graded, the model still was. \`usecase.step-unlinked\` never fires on a hop
161
+ whose caller and provider resolve to the same service — a service owes no
162
+ operationId to itself — but a hop from such a flow into another service's element
163
+ (a stand-in model.likec4 declares for a sibling, with no \`metadata { op }\`) still
164
+ warns here, exactly as it does on the fleet map.
89
165
  5. \`loam validate --all --json\` in the docs repo. This is the run that grades the
90
166
  fleet map: \`landscape.service-unmodelled\` means the element never landed,
91
167
  \`landscape.binding-unknown\` / \`landscape.binding-duplicate\` mean it landed wrong,
92
168
  and \`landscape.missing\` means there is no map at all. A baseline that passes step 4
93
169
  and fails this one is documented and invisible.
94
- \`service.likec4-config-missing\` (a warning) means step 3's sync did not run; the
95
- fix is that command.
96
- Done, stated once: step 4 clean when run from inside the service's own repo, and
97
- this run reporting no \`landscape.*\` finding and no \`service.likec4-config-missing\`.
170
+ \`landscape.service-isolated\` (a warning) means the element landed with no edge
171
+ anywhere in \`architecture/\` while \`services/$1/model.likec4\` declares calls across
172
+ its boundary — the map owes those edges. It goes quiet on the FIRST edge, so draw
173
+ every call the brief listed in one pass: nothing will name the ones you leave out.
174
+ A service whose model declares no such call and whose element
175
+ has no edge is SILENT here: \`landscape.touched: false\` in step 1's brief is the
176
+ only place that state is named, so read it before this run rather than hoping
177
+ for it in it.
178
+ Six warnings on this run are about the RENDERER's wiring rather than about any
179
+ document, and one command fixes four of them: \`service.model-excluded\` (the root
180
+ \`likec4.config.json\` excludes a directory holding a model that extends the map, so
181
+ the renderer never loads it), \`service.model-unexcluded\` (its mirror, and the most
182
+ damaging — a model that STANDS ALONE whose directory the root \`exclude\` does not
183
+ cover merges into the root project and duplicates every kind the map declares,
184
+ which blanks the whole project rather than one service),
185
+ \`service.likec4-config-stray\` (a project file beside an extending model, which
186
+ claims the model out of the root project),
187
+ \`service.likec4-config-missing\` (a model that stands alone with no project file of
188
+ its own) and, when the first four are clear, \`c4.fleet-project-invalid\` — every
189
+ document reads clean where loam grades it and the ONE project the renderer builds
190
+ out of the map plus every extending model does not parse, because something is
191
+ declared in two of them. The first four: run \`loam subsystem sync\` — it rewrites
192
+ the root \`exclude\`, writes the missing project file and DELETES the stray one. The
193
+ fifth is an authoring fix: the message names the file and line, and the answer is
194
+ to declare the tag or element once, in the map or in the single service that owns it.
195
+ A sixth reads the same list and is NOT one of sync's: \`landscape.excluded\` says the
196
+ root \`exclude\` covers \`architecture/landscape.likec4\` itself, so the renderer has no
197
+ map to draw at all and every extending model in the root project resolves against
198
+ nothing — delete or narrow that entry by hand, at the line the finding quotes. While
199
+ it stands, \`c4.fleet-project-invalid\` is not graded at all: that check reads the
200
+ renderer's project, so the one entry would come back once per model instead of once as
201
+ the cause. Fix it first, then re-run and read the fifth.
202
+ Done, stated once: step 4 clean when run from inside the service's own repo, this
203
+ run reporting no \`landscape.*\` finding, no \`service.*\` renderer warning and no
204
+ \`c4.fleet-project-invalid\`, and
205
+ step 1's brief re-run reporting \`landscape.touched: true\` — or, for a service that
206
+ truly makes and receives no call, a stated reason its element is edgeless.
98
207
  The fleet run is never SILENT —
99
208
  \`sources.unverifiable-from-here\` (severity ok) appears per service as a
100
209
  confirmation, not work — so "keep going until validation is quiet" is the wrong