@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
@@ -312,10 +312,13 @@ services, loam frontmatter, Operations/Covers links and feature identity still r
312
312
  specs intentionally remain `status: draft`.
313
313
  - `Operations:` links to provider OpenAPI `operationId`s, and `Covers:` links where architecture
314
314
  requirements are created.
315
- - `architecture/landscape.likec4`, service `model.likec4`, and explicit fleet relationships — then
316
- `loam subsystem sync`, which writes each model's `likec4.config.json` (the staged repo already
317
- carries the root one) so the models render beside the map; `validate --all` warns
318
- `service.likec4-config-missing` for any model still without one.
315
+ - `architecture/landscape.likec4`, service `model.likec4` (written to extend the map's element —
316
+ no `specification` block of its own; SCHEMA.md, "Two shapes of a service model"), and explicit
317
+ fleet relationships — then `loam subsystem sync`, which keeps the root `likec4.config.json`'s
318
+ `exclude` covering exactly the models that stand alone (the staged repo already carries the
319
+ root file), so every model that extends the map renders beside it; `validate --all` warns
320
+ `service.likec4-config-missing` for a standalone model still without a project file of its own,
321
+ and `service.model-unexcluded` for one the root project does not exclude.
319
322
  - Service OpenAPI contracts and provider-before-consumer sequencing where inbound edges already name
320
323
  operations.
321
324
  - LikeC4 and OpenAPI deltas for the already mapped active feature ids (`FEAT-12`, `BUG-42`, and so
package/QUICKSTART.md CHANGED
@@ -103,11 +103,16 @@ Or ask naturally: “Create a loam problem report for what just happened.” The
103
103
  relevant status and the smallest safe reproduction, and writes a separate file:
104
104
 
105
105
  ```text
106
- loam-reports/YYYY-MM-DD-short-symptom.md
106
+ loam-reports/NNN-YYYY-MM-DD-short-symptom.md
107
107
  ```
108
108
 
109
- The report records expected versus actual behavior, stable codes, relevant locations, write state,
110
- classification and missing evidence. It replaces secrets with `<redacted>`, prefers repo-relative
109
+ `NNN` is the report's ordinal — at least three digits, zero-padded, one more than the highest
110
+ already in the directory, which
111
+ `loam doctor` reports together with how many reports are open, sent, fixed or superseded — and a
112
+ `Status: open` line in the header is where the report's own state is kept (`doctor` reads it from
113
+ the header block above the first `##` heading, never from a quoted template inside the body). The report records
114
+ expected versus actual behavior, stable codes, relevant locations, write state, classification and
115
+ missing evidence. It replaces secrets with `<redacted>`, prefers repo-relative
111
116
  paths, does not copy source/spec bodies, does not retry a writer merely to reproduce it, and never
112
117
  uploads or submits anything automatically. Review the file before sharing or committing it.
113
118
 
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![CI](https://github.com/ybotok/loam/actions/workflows/ci.yml/badge.svg)](https://github.com/ybotok/loam/actions/workflows/ci.yml)
8
8
  [![npm](https://img.shields.io/npm/v/@ybotok/loam/alpha.svg?label=npm%20alpha)](https://www.npmjs.com/package/@ybotok/loam)
9
9
 
10
- > **Pre-release: `0.2.0-alpha.5`**, the fourth published release of the 0.2 line and the newest published
10
+ > **Pre-release: `0.2.0-alpha.6`**, the fifth published release of the 0.2 line and the newest published
11
11
  > version of [`@ybotok/loam`](https://www.npmjs.com/package/@ybotok/loam). It publishes under the
12
12
  > `alpha` npm dist-tag — which is what the badge above reads: `npm i @ybotok/loam@alpha`, or the
13
13
  > exact version, always installs this line. `latest` is moved onto a release by hand once it has
@@ -71,7 +71,8 @@ Topology changes where loam's checks pay off; it does not change the lifecycle:
71
71
  nesting depth, decides which `services/<id>/` owns an element.
72
72
 
73
73
  For example, the frozen `service` term can name an application while its internal modules remain
74
- ordinary C4 elements:
74
+ ordinary C4 elements. This is `architecture/landscape.likec4`, the fleet map — the one document
75
+ that declares the kinds:
75
76
 
76
77
  ```likec4
77
78
  specification {
@@ -92,6 +93,11 @@ model {
92
93
  }
93
94
  ```
94
95
 
96
+ The modules can equally live in `services/commerce-app/model.likec4`, which is the ordinary place
97
+ for them once the application has one — as an **extending model**, declaring no kinds of its own and
98
+ saying `extend commerce { … }` on the element above. SCHEMA.md's "Two shapes of a service model" has
99
+ that shape, the older one that parses alone, and the rule that picks between them.
100
+
95
101
  An internal edge normally carries no `metadata { op }`: that key specifically joins a call to the
96
102
  governed boundary's OpenAPI contract. An architecture requirement can instead say
97
103
  `Covers: commerce.orders -> commerce.billing`. Fleet-level maturity, dependency and scorecard views
@@ -109,7 +115,7 @@ both halves are written down: the question in the brief or the checklist, the an
109
115
 
110
116
  Most of this category will tell you what it checks. loam ships the other list too, in the binary:
111
117
  **[`src/core/brief/unchecked.ts`](https://github.com/ybotok/loam/blob/main/src/core/brief/unchecked.ts)
112
- is sixteen statements of what no check will ever tell you**, printed into the adoption brief beside
118
+ is seventeen statements of what no check will ever tell you**, printed into the adoption brief beside
113
119
  the checks that do run. It says, in loam's own words, that nothing here knows whether the model is
114
120
  the architecture the code actually has, whether a requirement is *true*, whether an `operationId` is
115
121
  the one the code serves, or whether `sources` names the files anybody read. And it says the one that
@@ -359,7 +365,7 @@ cannot hold.
359
365
  | `loam new <FEAT>` | `--title <text>` `--touches <id>` `--new-service <id>` `--capability <id>` | Scaffold a feature: intent, C4 delta, a requirement delta per service named by `--touches`/`--new-service`, and a capability delta per promise named by `--capability` (all repeatable) |
360
366
  | `loam show <service\|FEAT>` | `--type <kind>` | Everything loam knows about one service or feature. A feature's JSON includes a semantic `review` pack: intent, exact architecture objects, API/event slices, dependencies, artifacts, verification, blockers and next actions. `--type` forces an ambiguous reading |
361
367
  | `loam subsystem <verb> [names...]` | `--into <name>` `--under <name>` `--title <text>` `--description <text>` `--owner <name>` | Manage the grouping tree under `services/` — a navigable tree no identity depends on. `new`/`rm`, `move … --into`, `rename`, `list`, `history`, `sync` |
362
- | `loam adopt` | `--service <id>` `--subsystem <name>` `--targets` | Brief an agent to write this service's baseline into the docs repo as `draft`: the target paths, the grammar of each, what the landscape already says, and the checks that follow. Writes nothing. `--targets` narrows it to what varies by service — the walk, the 37 checks and the sixteen statements of what nothing checks are the same bytes everywhere, so a `full` field names the one run that carries them: 42,873 bytes to 17,805 |
368
+ | `loam adopt` | `--service <id>` `--subsystem <name>` `--targets` | Brief an agent to write this service's baseline into the docs repo as `draft`: the target paths, the grammar of each, what the landscape already says — and, for an element no edge touches, the edges the service's own model.likec4 attests — and the checks that follow. Writes nothing. `--targets` narrows it to what varies by service — the walk, the 52 checks and the seventeen statements of what nothing checks are the same bytes everywhere, so a `full` field names the one run that carries them: 54,833 bytes to 20,062 on the example fleet's payment-service (measured 2026-09-04) |
363
369
  | `loam delta <FEAT>` | `--service <id>` | Project a feature onto one service: the intent, its requirement deltas with every body and Given/When/Then line verbatim, the endpoints it adds or retires, and the edges around it. Doubles as a coding-agent task |
364
370
  | `loam gherkin [<FEAT>]` | `--service <id>` `--dry-run` | Emit spec scenarios as digest-stamped Gherkin `.feature` files into the service repo's `<gherkinDir>/loam/` |
365
371
  | `loam rebase [<FEAT>]` | `--service <id>` `--dry-run` `--living` | Pin the feature to the living versions it was written against, on the requirement axis and the contract axis. `--living` takes no feature: it pins the living corpus's `Realizes:` entries to the capability requirements they name, which is what makes `capability.realizes-stale` able to fire later |
@@ -487,7 +493,7 @@ always preserved byte for byte, with the entry printed for manual merge.
487
493
  maps, what is lost, what must be added.
488
494
  - [ROADMAP.md](ROADMAP.md) — the evidence-backed improvement plan, priorities, non-goals and exit
489
495
  criteria.
490
- - [CHANGELOG.md](CHANGELOG.md) — released beta.1–alpha.5 plus the changes on `main` under
496
+ - [CHANGELOG.md](CHANGELOG.md) — released beta.1–alpha.6 plus the changes on `main` under
491
497
  `[Unreleased]`.
492
498
  - [docs/BENCHMARKS.md](https://github.com/ybotok/loam/blob/main/docs/BENCHMARKS.md) — what a
493
499
  fleet-sized run costs, with the method, the machine and the committed runs behind every number.
@@ -523,12 +529,12 @@ authored-capability axes with the `Realizes:` join, use cases graded as `dynamic
523
529
  `architecture/obligations.yaml` architectural obligations checked through `#obl-` tags and
524
530
  `Covers:`. Known limits, each with its owner in [ROADMAP.md](ROADMAP.md): the scheduled CI
525
531
  `stability` job has still to be observed green. Speculative `render`, health composition and UI
526
- generation come later. Behind that status stand **159 test files** (counted 2026-09-02): the count is graded
532
+ generation come later. Behind that status stand **173 test files** (counted 2026-09-04): the count is graded
527
533
  against a live readdir by `test/docs-facts.test.ts`, so this sentence fails the suite the moment it
528
534
  trails the tree.
529
535
 
530
536
  The package is published as [`@ybotok/loam`](https://www.npmjs.com/package/@ybotok/loam), currently
531
- `0.2.0-alpha.5`: the unscoped `loam` name is taken by an unrelated GDAL wrapper, so the package ships
537
+ `0.2.0-alpha.6`: the unscoped `loam` name is taken by an unrelated GDAL wrapper, so the package ships
532
538
  under the maintainer's own npm user scope. Releases are tag-driven and maintainer-only
533
539
  ([CONTRIBUTING.md](CONTRIBUTING.md)); the version this line names is pinned to `package.json` by a
534
540
  drift test, so it cannot silently trail a release.
package/ROADMAP.md CHANGED
@@ -18,19 +18,19 @@ acceptance tests, and implementation evidence remain ordinary files in repositor
18
18
  state inside a service. The CLI is small enough to audit, and every writer — not only archive — now
19
19
  commits through a locked, journaled transaction that a crash cannot leave half-applied.
20
20
 
21
- The tree contains **429 TypeScript modules in 130 source packages**, with an acyclic package graph
21
+ The tree contains **464 TypeScript modules in 143 source packages**, with an acyclic package graph
22
22
  checked by
23
23
  [scripts/package-graph.mjs](https://github.com/ybotok/loam/blob/main/scripts/package-graph.mjs). The
24
24
  CLI exposes **29 commands** from [src/cli.ts](https://github.com/ybotok/loam/blob/main/src/cli.ts),
25
- and the suite stands at **159 test files**. Those four counts are deliberately stated OUTSIDE the
25
+ and the suite stands at **173 test files**. Those four counts are deliberately stated OUTSIDE the
26
26
  dated snapshot below: each derives from the tree in one readdir, so
27
27
  [test/docs-facts.test.ts](https://github.com/ybotok/loam/blob/main/test/docs-facts.test.ts) grades
28
28
  them live and this paragraph cannot quietly trail the code the way its predecessor did.
29
29
 
30
- _Measured 2026-09-03 at `0.2.0-alpha.5`, and dated because neither number has a cheap derivation:_
30
+ _Measured 2026-09-04 at `0.2.0-alpha.6`, and dated because neither number has a cheap derivation:_
31
31
  lint, typecheck, `npm run arch:check` and `npm run meta:check` green; `npm test` passing
32
- **3,434/3,434 tests**, with two `skipIf(asRoot)` cases the root gate container cannot run; the
33
- coverage gate passing with **92.30% statements, 84.11% branches, 96.64% functions, and 94.24%
32
+ **3,772/3,772 tests**, with two `skipIf(asRoot)` cases the root gate container cannot run; the
33
+ coverage gate passing with **92.78% statements, 84.65% branches, 97.08% functions, and 94.63%
34
34
  lines** against its thresholds of 91 / 82 / 95 / 93; and `npm run release:check` plus
35
35
  `npm run test:package` green against the real tarball.
36
36
 
@@ -127,9 +127,217 @@ exactly the invented need the non-goals forbid.
127
127
  Closed since the 2026-08-18 assessment, each with the commit or commit range that landed it on
128
128
  `main`. [CHANGELOG.md](CHANGELOG.md) is the user-facing record; the full item texts — required
129
129
  changes, exit criteria, and what each review surfaced — are in this file's history (`git show
130
- 5cd3942:ROADMAP.md`). The three use-case entries below carry no range yet: they are green in the
131
- working tree and not committed, and the range goes in with the commit rather than being guessed at
132
- here.
130
+ 5cd3942:ROADMAP.md`). The four 2026-09-03 problem-report entries that follow — the extending model
131
+ and the report ordinal, which open the list — landed together in `f751909`, one change built as
132
+ four disjoint workstreams and gated as one; the three before them — the edgeless brief, the
133
+ intra-service use case, and the styling paragraph under the generated views — landed together in
134
+ `0eaa101` the same way.
135
+
136
+ #### One model, many documents — a service model may extend the fleet map
137
+
138
+ **Landed 2026-09-04** in `f751909`, from three problem reports that turned out to be one cause,
139
+ with a fourth landing beside it in the same change. #010 measured the cause: a service model must
140
+ parse alone, so it re-declares its own `specification` and every partner it names — 78 double
141
+ declarations in a 56-service fleet with four services adopted, projected to ~448 at full adoption —
142
+ and the copies had already diverged, `#platform` missing from every copy of the broker and the
143
+ identity provider but the map's, with no finding code for "two documents describe one element
144
+ differently" because no check read two documents together. #009 measured the symptom: 57 flat
145
+ entries in the renderer's project picker, 52 of them a single box, forced by the per-service
146
+ project file `0.2.0-alpha.5` had to write **because** the models could not share a project. #011 is
147
+ the structural proposal, every claim of it executed against copies of `examples/docs`: `extend`
148
+ resolves across documents of one project, a model rewritten that way makes its containers visible
149
+ in the fleet project with one copy of the broker in the whole model, and deleting a model's
150
+ `specification` under the old loader is eleven `c4.invalid` errors — so the change had to be
151
+ loam's, not a convention a repository could adopt. (#012, reports having no ordinal and loam never
152
+ reading `loam-reports/`, landed in the same commit and has its own entry below.)
153
+
154
+ **What landed.** The shape of a model is now read from the file's own grammar — a top-level
155
+ `specification { }` block containing an `element` declaration means STANDALONE, its absence means
156
+ EXTENDING — and each shape gets the grade the other cannot need: `c4.declaration-diverged` for a
157
+ standalone model whose copies of the map's elements disagree with it, `c4.element-unowned` for an
158
+ extending model that declares an element outside its own. Around them, the renderer wiring
159
+ `loam subsystem sync` now owns end to end (`service.likec4-config-stray`, `service.model-excluded`,
160
+ `service.model-unexcluded`, the narrowed `service.likec4-config-missing`, and the root project's
161
+ `exclude` rewritten to cover exactly the models that stand alone), and `c4.fleet-project-invalid`,
162
+ which loads the fleet project the way the renderer builds it and reports what only that load can
163
+ see. `examples/docs` is migrated whole, and its ten deliberate warnings are unchanged. CHANGELOG
164
+ has every code, key and message; SCHEMA's new "Two shapes of a service model" has the rules and the
165
+ migration recipe.
166
+
167
+ **Rejected, each with the reason.** Migrating repositories automatically — the recipe is documented
168
+ and an agent performs it, because a real model's comments are the team's and not loam's to reflow.
169
+ Making the shape a key in `loam.json` or `likec4.config.json` — the file's grammar already decides
170
+ how it can be read, and a key would be a second answer able to disagree with the first. Widening
171
+ loam's fleet map to the renderer's root project — the map is graded as `architecture/` alone so
172
+ that one broken service model cannot blank the fleet's own picture, which is why a cross-service
173
+ flow in `architecture/usecases/` still names service elements and never a container. Retiring the
174
+ standalone shape — it is what lets a service's docs be validated from the service's own repository,
175
+ and a fleet that wants that keeps it, now with a check on the divergence it costs.
176
+
177
+ **The deliberate remainder**, stated so nobody reads it as an oversight. A cross-service call still
178
+ exists TWICE: container-level in the model, service-level in the map (#011's item 6). The spine,
179
+ the platform census and every other fleet check read the map alone, and `landscape.service-isolated`
180
+ remains the nudge that carries an attested call up into it. Thinning the map to elements plus
181
+ cross-service edges is the [Later](#later--promote-only-from-evidence) "Landscape scaling" row, and
182
+ it is what would remove the duplication. Beside it sits #011's item 5, also deliberate: a
183
+ cross-service flow cannot name a container, because loam grades the fleet map as its own document
184
+ set. Revisit that one when a fleet asks for a cross-service flow whose hops are containers — the
185
+ renderer already resolves such a hop, so the ask will be concrete when it arrives.
186
+
187
+ **Verified 2026-09-04**, and three things the verification changed. The report's own "next thing to
188
+ check" was the one that did not compose: `loam archive` spliced a delta's nested additions into the
189
+ fleet map, and the extending model could then never declare them — the service went `c4.invalid`
190
+ (duplicate) the moment it wrote the container the adopt brief prescribed. The merge now ROUTES each
191
+ addition to the document that owns the interior, and proves the merged model parses beside the
192
+ merged map before writing either. Second, the consumer census read `architecture/` alone, so under
193
+ this shape a private store's consuming edges — which live in the models now — counted for nothing:
194
+ `landscape.datastore-private` went silent or named the wrong service, and a nested store two
195
+ services reach was graded nowhere. It reads every extending model's attested calls now, and
196
+ `landscape.datastore-shared` fires for a nested store. Third, the wiring guard this entry landed
197
+ failed open on every root `exclude` spelling except `services/<tree>/**`, `loam subsystem sync`
198
+ never removed the stray per-service project file it told repositories to delete (and that file
199
+ CLAIMS the model, rather than holding nothing as the design note said), and
200
+ `c4.fleet-project-invalid` enumerated three roots rather than the renderer's — a `.likec4` in a
201
+ subsystem directory was in none of them. All three are closed; CHANGELOG's `[Unreleased]` has the
202
+ codes and keys.
203
+
204
+ **The `import` question is answered.** Reports #010 and #011 left open whether LikeC4's
205
+ cross-project `import` could have delivered this without merging the projects. Measured at the
206
+ 1.59.2 pin: an import resolves REFERENCES across projects, and that is all — it carries no
207
+ `specification`, so a kind or tag the other project declares is not usable in this one, and it does
208
+ not support `extend`. A model importing the map could name the map's elements and still not add a
209
+ container to one. So the choice was never between two mechanisms; one project holding both
210
+ documents is what the shape requires.
211
+
212
+ **Known and carried, 2026-09-04.** The second verification round reproduced these and they were
213
+ NOT fixed. Each is written down with the repro that finds it again, so nobody spends a second
214
+ afternoon rediscovering one. They are carried, not closed.
215
+
216
+ - **Only the basename `likec4.config.json` is surveyed.** LikeC4 1.59.2 also accepts `.likec4rc` and
217
+ six other spellings; drop `{"name":"svc-a"}` into `services/svc-a/.likec4rc` on a synced extending
218
+ fleet and `validate --all`, `doctor` and `subsystem sync` all stay green while the renderer loads
219
+ three projects and refuses without `--project`. Carried on scope: the survey, the stray grade and
220
+ `sync`'s delete list are one table, and widening it is the same change as the two rows below —
221
+ worth doing once, together, with the pin's whole name list measured rather than guessed.
222
+ - **A `likec4.config.json` in a SUBSYSTEM directory claims every model beneath it.** Write one at
223
+ `services/platform/likec4.config.json` over three extending models and all three go
224
+ `Could not resolve reference to Element named 'svc_svc_d'` in the renderer, while loam names
225
+ nothing (`sync` → "nothing to write"). Carried on scope, with the row above: the checks look one
226
+ directory deep, at a service, and seeing this needs a walk of the whole docs tree.
227
+ - **`sync` keeps a config beside a model that is GONE, and that leftover project is not harmless.**
228
+ `rm services/svc-c/model.likec4` with its config left behind: loam is green everywhere, and
229
+ `likec4 validate` — and `likec4 build` — at the docs root then need `--project`. The keep is
230
+ deliberate ("that one really is the team's"), but its premise, that an empty nested project is
231
+ invisible to the renderer, is false at the pin. Carried on a design decision pending: deleting a
232
+ file loam never wrote needs a rule about whose file it is, not a bug fix.
233
+ - **`validate --feature` does not preview a merge refusal.** A delta drawing a cross-interior edge,
234
+ or naming a kind the map does not declare, validates clean and then refuses at `archive`
235
+ (`merge-failed`, nothing written). Carried on scope: the preview needs the archive's own merge
236
+ planner run from the validate path, which is a new seam rather than a message.
237
+ - **In the STANDALONE shape a broken UNTAGGED sibling is invisible to loam.** Make one service
238
+ standalone, `subsystem sync`, then write an unresolvable `services/<id>/usecases/plain.likec4`:
239
+ loam prints `c4.valid` and 0 errors while `likec4 validate --project <id> .` is Invalid. The
240
+ extending shape catches the same file through `c4.fleet-project-invalid`. Carried on scope: the
241
+ per-service load reads the model, and reading the standalone project the renderer builds is a
242
+ second loader.
243
+ - **A root `exclude` that no longer covers `features/**` is silent.** Delete that one entry from
244
+ `examples/docs`' config: loam reports 0 errors and `sync` says "nothing to write", while the
245
+ renderer's fleet project is at 346 errors. The scaffold always writes the entry, so this is a
246
+ hand edit, which is why it is carried rather than fixed — on the evidence bar: no repository has
247
+ hit it, and a grade on an entry loam did not write is a policy claim.
248
+ - **A root config the renderer REJECTS is reported only by `sync`'s note.** `"exclude": "services/**"`
249
+ as a string, or an array-valued `include`, is "loaded 0 projects out of 1" — nothing renders — and
250
+ `validate --all` is green; an unparseable file is the same. Carried on scope: loam reads the file
251
+ for one key, and schema-validating somebody else's config is a dependency on the renderer's own
252
+ schema at the pin.
253
+ - **`LivingSlice.landscape.modelled` is `false` where `adopt` says `null`.** Over an
254
+ `architecture/` project that did not parse, `loam context <svc> --json` says `modelled: false` and
255
+ `loam adopt --service <svc> --json` says `modelled: null` about the same tree. Carried on scope:
256
+ the field is typed non-nullable in the pack, so agreeing with `adopt` is a contract change.
257
+ - **`loam show` never mentions graded intra-service flows.** With a healthy `#req-…`-tagged flow
258
+ beside an extending model — `validate --service` prints "· 1 tagged flow(s) graded" — neither
259
+ `loam show <svc>` nor its `--json` names it anywhere. Carried on scope: `show`'s payload is a
260
+ frozen shape and the flow needs a section of its own.
261
+ - **`loam status` never names the isolated state.** `landscape.service-isolated` is a warning
262
+ `validate --all` prints and `status`'s next-action ladder has no rung for. Carried on a design
263
+ decision pending: the ladder is derived from artifact presence and provenance, and a finding-derived
264
+ rung is a different rule for what `next[0]` means.
265
+ - **The first ever container-level flow a FEATURE brings.** A cross-service flow cannot name a
266
+ container, because loam grades the fleet map as its own document set; the renderer already resolves
267
+ such a hop. Carried deliberately — the [Later](#later--promote-only-from-evidence) "Landscape
268
+ scaling" row owns it, and it is promoted when a fleet asks, not before.
269
+
270
+ #### Problem reports carry an ordinal, and loam reads the directory it prescribes
271
+
272
+ **Landed 2026-09-04**, from one problem report (#012). The `loam-report` protocol prescribed a
273
+ directory, a filename shape and a document structure and then stopped: files were named
274
+ `YYYY-MM-DD-<slug>.md` with a numeric suffix only on collision — a collision breaker, not an
275
+ identifier — so in a directory of eleven reports written in two days, none had one, four shared
276
+ their first eleven characters, and the discriminating part of every name sat far to the right of
277
+ what a terminal, a file picker or a chat message shows. There was no field anywhere in the document
278
+ for the one piece of state a report has (three of the eleven were already closed and one superseded,
279
+ all of it living in whoever remembered), and `validate --all`, `doctor`, `status` and `list`
280
+ mentioned `loam-reports` zero times between them. Landed: an unconditional ordinal at the front of
281
+ the name, which is the computation the protocol already described for its suffix applied where it is
282
+ visible; a `Status:` line in the template with a four-value vocabulary a report closes by editing;
283
+ and `loam doctor` reading the directory — total, per-status counts and the next ordinal — as an
284
+ additive `reports` key and one human row. Rejected: a `loam report list` verb (a new command for a
285
+ count `doctor` was already the place for, on a frozen CLI surface); an index file (the workaround
286
+ this replaces — a second place to keep in step, and the reason the state left the files in the first
287
+ place); grading the corpus (an open report is not a defect in the repository holding it, so `doctor`
288
+ reports it as state and `healthy` never moves); parsing past the first word of the status line (the
289
+ rest is prose an author writes for a reader). Cost: one `readdir` and one small read per report on
290
+ every `loam doctor`, and nothing is transmitted — which is the constraint the protocol is built
291
+ around and the reason the whole fix needed no new state.
292
+
293
+ #### The adopt brief on an edgeless landscape element
294
+
295
+ **Landed 2026-09-03**, from one problem report. `loam adopt` decided whether the fleet map still
296
+ owed a service from element EXISTENCE: a bound element with no edge — what
297
+ `loam seed --from fleet.yaml` leaves for every service absent from `calls:` — read as
298
+ `landscape.instruction: null`, no target, `inbound: []`, `outbound: []` in one payload, so an agent
299
+ following the protocol to the letter wrote a validating baseline and never drew one edge, and
300
+ `loam validate --all` stayed green over it. Landed: a fourth landscape state carried by two
301
+ additive keys (`landscape.touched`, and `landscape.attested` — the calls the service's own
302
+ model.likec4 declares across its boundary, derived once in `core/c4/resolve/attested.ts` for the
303
+ brief and the fleet check alike, so the two can never name different edges); a non-null instruction
304
+ in two arms (carry each attested call up as one edge on the existing element, naming the other
305
+ party as the map spells it; or, with nothing attested, draw NOTHING rather than invent — an edgeless
306
+ element that is true is a fact); the landscape target back as an edge-only `edit` whose shape
307
+ refuses a second element; the `EDGELESS` flag in the text view; the evidence-gated
308
+ `landscape.service-isolated` warning under `--all`; and a seventeenth unchecked statement about
309
+ visibility (placeholder tags, curated views, `include *` over a boundary). Rejected: folding the
310
+ state into `landscape.modelled` (an agent told `false` draws a second box); an unconditional "no
311
+ edge touches it" warning (no correct fix for a worker that calls nothing, and every seeded fleet
312
+ red-ish until adoption); grading the SET DIFFERENCE between the attested calls and the drawn edges
313
+ (loam cannot tell a call the map forgot from one the fleet does not draw at its own altitude, so
314
+ the difference reported as an omission is an invented edge with a code beside it — the check stays
315
+ touched/untouched, and the brief says so out loud); a check on placeholder tags or on what a view
316
+ shows (rule 26 — loam never
317
+ computes what a view shows). Cost: one LikeC4 load of `model.likec4`, only in the edgeless state, a
318
+ memo hit under `--all`.
319
+
320
+ **Corrected 2026-09-04** by the verification of this entry: the brief read
321
+ `architecture/landscape.likec4` alone where the fleet check reads the whole `architecture/` project,
322
+ so a fleet keeping a second `model { }` block in a sibling got a brief demanding edges it had
323
+ already drawn while `validate --all` reported `landscape.matched`. Both now read the project.
324
+
325
+ #### A home for an intra-service use case
326
+
327
+ **Landed 2026-09-03.** Measured: `architecture/usecases/` cannot resolve a container (one such file
328
+ is `landscape.invalid` plus a `spine.landscape-invalid` per service), and a view beside the model
329
+ rendered while nothing graded it. Landed: the service's own LikeC4 project as the slot — every
330
+ `.likec4` beside model.likec4 and any tagged view inside it — graded by `validate --service`/`--all`
331
+ with the five existing `usecase.*` codes, `#req-` scoped by the service's own Requirement-IDs,
332
+ `#cap-` refused by placement, a broken sibling one `usecase.flow-invalid` while the model keeps
333
+ grading; plus the tier-2 skip and the fourth `step-unlinked` guard in the shared graders. Rejected:
334
+ a fixed `usecases/` directory alone (the reporter's `views.likec4` would render ungraded),
335
+ `views.likec4` alone (a second file would be invisible), a new code for the broken sibling (nothing
336
+ branches differently), gating the read on `likec4.config.json` (create-only, deletable). Cost: one
337
+ recursive readdir per service; a workspace only where a view in model.likec4 opts in or a sibling
338
+ mentions a reserved prefix anywhere in its bytes — an untagged sibling is never graded, and once
339
+ the workspace is loaded a project that does not read is one `usecase.flow-invalid` whether or not a
340
+ view opted in.
133
341
 
134
342
  #### The service model, renderable from the fleet root
135
343
 
@@ -177,6 +385,13 @@ that project (LikeC4 projects are separate models); and the project name is not
177
385
  billing-core, `service-fleet` beside `fleet`), disclosed in SCHEMA rather than escaped away,
178
386
  because the picker shows the id.
179
387
 
388
+ **Superseded for extending models, one day later.** The last of those costs — one picker entry per
389
+ adopted service — is what report #009 measured at 57 entries, and the entry that opens this list is
390
+ what removed its cause rather than its symptom: a model that extends the fleet map shares the root
391
+ project with it, so it is owed no project file and adds no entry, and `loam subsystem sync` writes
392
+ the file only for a model that stands alone. Everything measured here still holds for that shape,
393
+ and is why it is still supported; it is no longer what a new model is written as.
394
+
180
395
  #### The generated subsystem views — a label, a boundary, and one reader of the map
181
396
 
182
397
  **Landed 2026-09-03.** Three problem reports from a fleet running loam, one axis. The generated
@@ -197,6 +412,20 @@ use-case document binding one element could produce a `subsystem.views-stale` th
197
412
  `loam subsystem sync` reported as `current` — reproduced on `examples/docs`, and fixed by pointing
198
413
  both sides at the same read.
199
414
 
415
+ **And the repository's palette (2026-09-03).** A generated view can carry no inline `style` rule —
416
+ the file is regenerated wholesale — and the one mechanism LikeC4 gives a view for borrowing a
417
+ repository's styling is a reference to a global style by id, which is a parse error that blanks the
418
+ whole `architecture/` project when nothing declares it. So the convention is one reserved name:
419
+ declare `global { styleGroup subsystems { … } }` anywhere in the `architecture/` project and every
420
+ generated view references it; declare nothing and the file is what it was. Rejected: reading the id
421
+ off a key in `likec4.config.json` (create-only, never re-read, and not a LikeC4 document whose
422
+ contents a parse can check), and "reference the single declared group" (a second group declared for
423
+ a hand-drawn view would silently switch the generated views' styling off and restale the file on a
424
+ change that touched no subsystem). The presence read is a census of the keys of
425
+ `$data.globals.styles`, a declaration read like `specification`; seven tripwire assertions in
426
+ `test/likec4-view-shape.test.ts` pin the shape so a likec4 bump fails there before it reaches a
427
+ generated file.
428
+
200
429
  #### The deployment axis — topology joined to requirements
201
430
 
202
431
  **Promoted 2026-09-02, and authored as a feature in loam's own docs repo** rather than as an item
@@ -435,9 +664,33 @@ item gets promoted — it went from here to `## Now` and from there to
435
664
  for every fleet that never writes one. Promote only on evidence from a second fleet, after living
436
665
  with the disclosure — the first report classified itself `inconclusive`, and one fleet is not
437
666
  enough to qualify an invariant that says placement is never part of any identity.
438
- - **Landscape scaling:** retain one landscape while conflicts are exceptional. If same-service
439
- conflicts become routine — the current trigger in [SCHEMA.md](SCHEMA.md) is weekly rather than
440
- monthly — evaluate service-owned model files plus a thin global cross-service map. Migration must
667
+ - **A feature brings an intra-service flow.** `features/<FEAT>/specs/<svc>/usecases/<name>.likec4`,
668
+ copied create-only by `loam archive` into `services/<…>/<svc>/usecases/` and taken back by
669
+ `loam unarchive`, graded before the copy against the service's own LikeC4 project with the
670
+ feature's `specs/<svc>/` requirement deltas in `#req-` scope — `usecase.flow-exists` and
671
+ `usecase.flow-invalid` reused, never `--approve`-overridable. Deliberately NOT built with the
672
+ living slot (2026-09-03): the version-3 snapshot manifest already carries an artifact path with a
673
+ directory in it, so nothing about the undo changes when it lands, and no model delta exists to
674
+ preview — what it waits for is one fleet asking for a container-level flow to ship in the same
675
+ change as the `arch.spec.md` requirement it answers. Until then a service-local flow is written
676
+ directly into the service directory in the same pull request, where git produces the conflict;
677
+ building the feature route ahead of that evidence is the invented need the non-goals forbid.
678
+ - **Landscape scaling:** retain one landscape while conflicts are exceptional, and half of what
679
+ this row once asked for arrived on 2026-09-04. Per-service internals now live in
680
+ `services/<svc>/model.likec4` by default: `loam archive` routes a delta's fqn-spelled interior
681
+ into the owning service's extending model, and a team adopting a service adds nothing to
682
+ `architecture/landscape.likec4` but one element and its cross-service edges. The map holds a
683
+ service's interior only where a team puts it on purpose — a store nested under its owner so a
684
+ second service can name it (SCHEMA's "Private stores") — or where a delta spells its parent by
685
+ title rather than by the map's id (the archive's documented remainder). What is
686
+ left is the CROSS-SERVICE EDGE, which still exists twice — container-level in the model,
687
+ service-level in the map — and that duplication is **deliberate**, not a leftover: the spine, the
688
+ platform census, `landscape.service-isolated` and every other fleet check read the map alone,
689
+ which is what lets a fleet answer "who calls this service" from one diffable document without
690
+ parsing sixty. Thinning the map to elements plus cross-service edges means teaching those checks
691
+ to read the edges out of the models that attest them, and paying the blast radius that comes with
692
+ it. If same-service conflicts become routine — the current trigger in [SCHEMA.md](SCHEMA.md) is
693
+ weekly rather than monthly — evaluate that. Migration must
441
694
  preserve archive/undo, deterministic resolution, and readable plain files.
442
695
  - **Authored business axis — PROMOTED 2026-08-27, and landed in full; see
443
696
  [Recently landed](#recently-landed).** The gate asked for evidence of authorship: analyst edits