@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.
- package/CHANGELOG.md +901 -0
- package/MIGRATING-from-OpenSpec.md +7 -4
- package/QUICKSTART.md +8 -3
- package/README.md +13 -7
- package/ROADMAP.md +264 -11
- package/SCHEMA.md +439 -38
- package/WORKFLOW.md +23 -10
- package/dist/commands/adopt/render.js +47 -8
- package/dist/commands/adopt/render.js.map +1 -1
- package/dist/commands/archive/plan/landscape.js +45 -1
- package/dist/commands/archive/plan/landscape.js.map +1 -1
- package/dist/commands/archive/plan/model/extending.js +85 -0
- package/dist/commands/archive/plan/model/extending.js.map +1 -0
- package/dist/commands/archive/run.js +5 -2
- package/dist/commands/archive/run.js.map +1 -1
- package/dist/commands/context/print.js +11 -1
- package/dist/commands/context/print.js.map +1 -1
- package/dist/commands/doctor.js +46 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explore.js +12 -2
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/list/views.js +5 -1
- package/dist/commands/list/views.js.map +1 -1
- package/dist/commands/seed/plan.js +97 -3
- package/dist/commands/seed/plan.js.map +1 -1
- package/dist/commands/seed/seed.js +7 -2
- package/dist/commands/seed/seed.js.map +1 -1
- package/dist/commands/show/feature.js +2 -1
- package/dist/commands/show/feature.js.map +1 -1
- package/dist/commands/show/marks.js +3 -5
- package/dist/commands/show/marks.js.map +1 -1
- package/dist/commands/show/service.js +39 -18
- package/dist/commands/show/service.js.map +1 -1
- package/dist/commands/subsystem/sync.js +128 -74
- package/dist/commands/subsystem/sync.js.map +1 -1
- package/dist/commands/subsystem/txn/exclude.js +132 -0
- package/dist/commands/subsystem/txn/exclude.js.map +1 -0
- package/dist/commands/subsystem/txn/report.js +124 -0
- package/dist/commands/subsystem/txn/report.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +10 -3
- package/dist/commands/subsystem/txn/txn.js.map +1 -1
- package/dist/commands/subsystem/txn/views.js +113 -16
- package/dist/commands/subsystem/txn/views.js.map +1 -1
- package/dist/commands/validate/arch-coverage.js +16 -9
- package/dist/commands/validate/arch-coverage.js.map +1 -1
- package/dist/commands/validate/checks/fleet-shape.js +30 -77
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
- package/dist/commands/validate/checks/vocabulary.js +4 -19
- package/dist/commands/validate/checks/vocabulary.js.map +1 -1
- package/dist/commands/validate/feature.js +1 -1
- package/dist/commands/validate/feature.js.map +1 -1
- package/dist/commands/validate/fleet/census.js +11 -10
- package/dist/commands/validate/fleet/census.js.map +1 -1
- package/dist/commands/validate/fleet/landscape.js +127 -119
- package/dist/commands/validate/fleet/landscape.js.map +1 -1
- package/dist/commands/validate/fleet/load.js +66 -0
- package/dist/commands/validate/fleet/load.js.map +1 -1
- package/dist/commands/validate/fleet/map/attest.js +103 -0
- package/dist/commands/validate/fleet/map/attest.js.map +1 -0
- package/dist/commands/validate/fleet/map/bindings.js +96 -0
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
- package/dist/commands/validate/fleet/map/consumers.js +298 -0
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
- package/dist/commands/validate/fleet/map/isolation.js +116 -0
- package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
- package/dist/commands/validate/fleet/map/usecases.js +56 -0
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/steps.js +49 -17
- package/dist/commands/validate/fleet/usecases/steps.js.map +1 -1
- package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +13 -9
- package/dist/commands/validate/fleet/views/ids.js.map +1 -1
- package/dist/commands/validate/fleet/views/projects.js +258 -70
- package/dist/commands/validate/fleet/views/projects.js.map +1 -1
- package/dist/commands/validate/fleet/views/root-documents.js +97 -0
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +2 -2
- package/dist/commands/validate/fleet/views/stale.js.map +1 -1
- package/dist/commands/validate/service/model/diverged.js +226 -0
- package/dist/commands/validate/service/model/diverged.js.map +1 -0
- package/dist/commands/validate/service/model/grade.js +163 -0
- package/dist/commands/validate/service/model/grade.js.map +1 -0
- package/dist/commands/validate/service/service.js +110 -34
- package/dist/commands/validate/service/service.js.map +1 -1
- package/dist/commands/validate/service/specs.js +39 -5
- package/dist/commands/validate/service/specs.js.map +1 -1
- package/dist/commands/validate/service/spine.js +41 -3
- package/dist/commands/validate/service/spine.js.map +1 -1
- package/dist/commands/validate/service/usecases/tags.js +113 -0
- package/dist/commands/validate/service/usecases/tags.js.map +1 -0
- package/dist/commands/validate/service/usecases/usecases.js +209 -0
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/validate.js +10 -24
- package/dist/commands/validate/validate.js.map +1 -1
- package/dist/core/agent/agents-md/artifacts.js +1 -0
- package/dist/core/agent/agents-md/artifacts.js.map +1 -1
- package/dist/core/agent/agents-md/command-map.js +18 -4
- package/dist/core/agent/agents-md/command-map.js.map +1 -1
- package/dist/core/agent/agents-md/cycle.js +24 -9
- package/dist/core/agent/agents-md/cycle.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/context.js +4 -3
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
- package/dist/core/agent/agents-md/map/subsystem.js +51 -11
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
- package/dist/core/agent/agents-md/map/usecases.js +45 -3
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
- package/dist/core/agent/agents-md.js +14 -4
- package/dist/core/agent/agents-md.js.map +1 -1
- package/dist/core/agent/support/report.js +39 -5
- package/dist/core/agent/support/report.js.map +1 -1
- package/dist/core/agent/workflows/adopt.js +123 -14
- package/dist/core/agent/workflows/adopt.js.map +1 -1
- package/dist/core/agent/workflows/check.js +35 -20
- package/dist/core/agent/workflows/check.js.map +1 -1
- package/dist/core/agent/workflows/closing.js +3 -1
- package/dist/core/agent/workflows/closing.js.map +1 -1
- package/dist/core/brief/brief.js +63 -11
- package/dist/core/brief/brief.js.map +1 -1
- package/dist/core/brief/checks.js +133 -7
- package/dist/core/brief/checks.js.map +1 -1
- package/dist/core/brief/landscape.js +212 -129
- package/dist/core/brief/landscape.js.map +1 -1
- package/dist/core/brief/map/extend.js +81 -0
- package/dist/core/brief/map/extend.js.map +1 -0
- package/dist/core/brief/map/owed.js +284 -0
- package/dist/core/brief/map/owed.js.map +1 -0
- package/dist/core/brief/targets.js +30 -29
- package/dist/core/brief/targets.js.map +1 -1
- package/dist/core/brief/unchecked.js +12 -2
- package/dist/core/brief/unchecked.js.map +1 -1
- package/dist/core/c4/likec4.js +23 -1
- package/dist/core/c4/likec4.js.map +1 -1
- package/dist/core/c4/parsed/deployment.js +5 -3
- package/dist/core/c4/parsed/deployment.js.map +1 -1
- package/dist/core/c4/parsed/view-ids.js +39 -1
- package/dist/core/c4/parsed/view-ids.js.map +1 -1
- package/dist/core/c4/prefetch/fleet.js +142 -0
- package/dist/core/c4/prefetch/fleet.js.map +1 -0
- package/dist/core/c4/project/architecture.js +52 -4
- package/dist/core/c4/project/architecture.js.map +1 -1
- package/dist/core/c4/project/batch.js +140 -0
- package/dist/core/c4/project/batch.js.map +1 -0
- package/dist/core/c4/project/documents.js +9 -4
- package/dist/core/c4/project/documents.js.map +1 -1
- package/dist/core/c4/project/load.js +77 -38
- package/dist/core/c4/project/load.js.map +1 -1
- package/dist/core/c4/project/staged.js +46 -12
- package/dist/core/c4/project/staged.js.map +1 -1
- package/dist/core/c4/resolve/attested.js +0 -0
- package/dist/core/c4/resolve/attested.js.map +1 -0
- package/dist/core/c4/resolve/service.js +8 -17
- package/dist/core/c4/resolve/service.js.map +1 -1
- package/dist/core/c4/resolve/steps.js +18 -0
- package/dist/core/c4/resolve/steps.js.map +1 -1
- package/dist/core/c4/root-project/exclude.js +352 -0
- package/dist/core/c4/root-project/exclude.js.map +1 -0
- package/dist/core/c4/service-model/documents.js +47 -0
- package/dist/core/c4/service-model/documents.js.map +1 -0
- package/dist/core/c4/service-model/fleet/extending.js +82 -0
- package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
- package/dist/core/c4/service-model/load.js +165 -0
- package/dist/core/c4/service-model/load.js.map +1 -0
- package/dist/core/c4/service-model/renderer.js +128 -0
- package/dist/core/c4/service-model/renderer.js.map +1 -0
- package/dist/core/c4/service-model/shape.js +126 -0
- package/dist/core/c4/service-model/shape.js.map +1 -0
- package/dist/core/c4/service-model/slice.js +188 -0
- package/dist/core/c4/service-model/slice.js.map +1 -0
- package/dist/core/c4/source-scan.js +26 -0
- package/dist/core/c4/source-scan.js.map +1 -1
- package/dist/core/c4/splice/authored-source.js +60 -13
- package/dist/core/c4/splice/authored-source.js.map +1 -1
- package/dist/core/c4/splice/contract.js.map +1 -1
- package/dist/core/c4/splice/identity/declared.js +87 -0
- package/dist/core/c4/splice/identity/declared.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +17 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -1
- package/dist/core/c4/splice/identity/existing.js +80 -0
- package/dist/core/c4/splice/identity/existing.js.map +1 -0
- package/dist/core/c4/splice/identity/interior.js +80 -0
- package/dist/core/c4/splice/identity/interior.js.map +1 -0
- package/dist/core/c4/splice/identity/owner.js +50 -0
- package/dist/core/c4/splice/identity/owner.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +154 -100
- package/dist/core/c4/splice/landscape-merge.js.map +1 -1
- package/dist/core/c4/splice/model/merge.js +140 -0
- package/dist/core/c4/splice/model/merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +14 -4
- package/dist/core/c4/splice/placement.js.map +1 -1
- package/dist/core/c4/workspace.js +2 -1
- package/dist/core/c4/workspace.js.map +1 -1
- package/dist/core/coherence/coherence.js +7 -0
- package/dist/core/coherence/coherence.js.map +1 -1
- package/dist/core/delta/delta.js +9 -0
- package/dist/core/delta/delta.js.map +1 -1
- package/dist/core/deployment/delta.js +4 -0
- package/dist/core/deployment/delta.js.map +1 -1
- package/dist/core/diff/base-state.js +21 -5
- package/dist/core/diff/base-state.js.map +1 -1
- package/dist/core/diff/victims.js +10 -1
- package/dist/core/diff/victims.js.map +1 -1
- package/dist/core/docs.js +29 -24
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/config.js +7 -3
- package/dist/core/doctor/config.js.map +1 -1
- package/dist/core/doctor/doctor.js +36 -8
- package/dist/core/doctor/doctor.js.map +1 -1
- package/dist/core/doctor/report.js.map +1 -1
- package/dist/core/doctor/reports/scan.js +242 -0
- package/dist/core/doctor/reports/scan.js.map +1 -0
- package/dist/core/explain/refusals.js +1 -1
- package/dist/core/explain/refusals.js.map +1 -1
- package/dist/core/explore/explore.js +44 -9
- package/dist/core/explore/explore.js.map +1 -1
- package/dist/core/fleet-context.js +47 -0
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/partners.js +5 -9
- package/dist/core/gate/partners.js.map +1 -1
- package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
- package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
- package/dist/core/pack/living.js +47 -13
- package/dist/core/pack/living.js.map +1 -1
- package/dist/core/pack/pack.js +9 -6
- package/dist/core/pack/pack.js.map +1 -1
- package/dist/core/projection/arch-slice.js +2 -2
- package/dist/core/projection/arch-slice.js.map +1 -1
- package/dist/core/repo/paths.js +11 -9
- package/dist/core/repo/paths.js.map +1 -1
- package/dist/core/repo/tree/render/projects.js +93 -35
- package/dist/core/repo/tree/render/projects.js.map +1 -1
- package/dist/core/repo/tree/render/stale.js +2 -3
- package/dist/core/repo/tree/render/stale.js.map +1 -1
- package/dist/core/repo/tree/render/views.js +51 -3
- package/dist/core/repo/tree/render/views.js.map +1 -1
- package/dist/core/repo/tree/walk.js +45 -2
- package/dist/core/repo/tree/walk.js.map +1 -1
- package/dist/core/scaffold/landscape.js +219 -9
- package/dist/core/scaffold/landscape.js.map +1 -1
- package/dist/core/staging/writes.js.map +1 -1
- package/dist/core/usecases/delta/claims.js +1 -0
- package/dist/core/usecases/delta/claims.js.map +1 -1
- package/dist/core/usecases/delta/overlay.js +4 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -1
- package/dist/core/usecases/fleet.js +18 -6
- package/dist/core/usecases/fleet.js.map +1 -1
- package/dist/core/usecases/operations.js +7 -0
- package/dist/core/usecases/operations.js.map +1 -1
- package/dist/core/usecases/service/exclude.js +119 -0
- package/dist/core/usecases/service/exclude.js.map +1 -0
- package/dist/core/usecases/service/flows.js +161 -0
- package/dist/core/usecases/service/flows.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +10 -0
- package/dist/core/vocabulary/maturity.js.map +1 -1
- package/examples/README.md +24 -6
- package/examples/docs/architecture/landscape.likec4 +41 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +5 -2
- package/examples/docs/likec4.config.json +0 -1
- package/examples/docs/services/checkout-web/model.likec4 +39 -56
- package/examples/docs/services/order-service/arch.spec.md +13 -6
- package/examples/docs/services/order-service/model.likec4 +53 -67
- package/examples/docs/services/payment-service/arch.spec.md +7 -4
- package/examples/docs/services/payment-service/model.likec4 +32 -35
- package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
- package/examples/docs/services/platform/identity-service/model.likec4 +29 -33
- package/examples/docs/services/platform/notification-service/health.yaml +8 -3
- package/examples/docs/services/platform/notification-service/model.likec4 +39 -59
- package/package.json +1 -1
- package/examples/docs/services/checkout-web/likec4.config.json +0 -4
- package/examples/docs/services/order-service/likec4.config.json +0 -4
- package/examples/docs/services/payment-service/likec4.config.json +0 -4
- package/examples/docs/services/platform/identity-service/likec4.config.json +0 -4
- 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
|
|
316
|
-
`
|
|
317
|
-
|
|
318
|
-
`
|
|
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
|
-
|
|
110
|
-
|
|
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
|
[](https://github.com/ybotok/loam/actions/workflows/ci.yml)
|
|
8
8
|
[](https://www.npmjs.com/package/@ybotok/loam)
|
|
9
9
|
|
|
10
|
-
> **Pre-release: `0.2.0-alpha.
|
|
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
|
|
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
|
|
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.
|
|
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 **
|
|
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.
|
|
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 **
|
|
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 **
|
|
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-
|
|
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,
|
|
33
|
-
coverage gate passing with **92.
|
|
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
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
- **
|
|
439
|
-
|
|
440
|
-
|
|
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
|