@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.2
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 +2635 -86
- package/COMPARISON.md +80 -63
- package/CONTRIBUTING.md +84 -0
- package/MIGRATING-from-OpenSpec.md +213 -54
- package/QUICKSTART.md +125 -0
- package/README.md +450 -150
- package/ROADMAP.md +599 -0
- package/SCHEMA.md +2355 -256
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +701 -0
- package/dist/cli.js +113 -19
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +209 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +268 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +77 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +159 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +323 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +180 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +111 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +237 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +27 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +252 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/context/context.js +99 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +283 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +279 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +205 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +9 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +93 -0
- package/dist/commands/diff/diff.js.map +1 -0
- package/dist/commands/diff/print.js +38 -0
- package/dist/commands/diff/print.js.map +1 -0
- package/dist/commands/doctor.js +5 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +151 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +29 -24
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +115 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +54 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +146 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +246 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +149 -0
- package/dist/commands/gherkin/reconcile.js.map +1 -0
- package/dist/commands/gherkin/render.js +77 -0
- package/dist/commands/gherkin/render.js.map +1 -0
- package/dist/commands/init/example.js +204 -0
- package/dist/commands/init/example.js.map +1 -0
- package/dist/commands/init/first-hour.js +28 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +146 -71
- package/dist/commands/init/init.js.map +1 -0
- package/dist/commands/init/mcp.js +131 -0
- package/dist/commands/init/mcp.js.map +1 -0
- package/dist/commands/init/options.js +78 -0
- package/dist/commands/init/options.js.map +1 -0
- package/dist/commands/instructions.js +72 -14
- package/dist/commands/instructions.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +65 -0
- package/dist/commands/list/campaign/campaign.js.map +1 -0
- package/dist/commands/list/campaign/owners.js +65 -0
- package/dist/commands/list/campaign/owners.js.map +1 -0
- package/dist/commands/list/json.js +157 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +343 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +301 -0
- package/dist/commands/list/print.js.map +1 -0
- package/dist/commands/list/review.js +120 -0
- package/dist/commands/list/review.js.map +1 -0
- package/dist/commands/list/views.js +105 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +183 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +34 -0
- package/dist/commands/mcp/mcp.js.map +1 -0
- package/dist/commands/mcp/serve.js +55 -0
- package/dist/commands/mcp/serve.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/active.js +170 -0
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
- package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/living.js +62 -0
- package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/target.js +219 -0
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +19 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/read.js +49 -0
- package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
- package/dist/commands/migrate-openspec/print.js +89 -0
- package/dist/commands/migrate-openspec/print.js.map +1 -0
- package/dist/commands/new/commit.js +76 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/new.js +283 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +355 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +203 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/policy/format.js +152 -0
- package/dist/commands/policy/format.js.map +1 -0
- package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
- package/dist/commands/policy/gate.js.map +1 -0
- package/dist/commands/rebase/edit.js +106 -0
- package/dist/commands/rebase/edit.js.map +1 -0
- package/dist/commands/rebase/living.js +185 -0
- package/dist/commands/rebase/living.js.map +1 -0
- package/dist/commands/rebase/plan.js +245 -0
- package/dist/commands/rebase/plan.js.map +1 -0
- package/dist/commands/rebase/rebase.js +275 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +192 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +133 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +172 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +178 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/marks.js +24 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/{show.js → show/service.js} +63 -152
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +77 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/json.js +45 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +157 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +119 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +189 -0
- package/dist/commands/steps/steps.js.map +1 -0
- package/dist/commands/subsystem/edit.js +192 -0
- package/dist/commands/subsystem/edit.js.map +1 -0
- package/dist/commands/subsystem/move.js +265 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +115 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +101 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +103 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +94 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +70 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +160 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +67 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +204 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +296 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +55 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +254 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +76 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/checks/vocabulary.js +31 -0
- package/dist/commands/validate/checks/vocabulary.js.map +1 -0
- package/dist/commands/validate/feature.js +216 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +69 -0
- package/dist/commands/validate/fleet/census.js.map +1 -0
- package/dist/commands/validate/fleet/kind-tags.js +39 -0
- package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
- package/dist/commands/validate/fleet/landscape.js +353 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +52 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +270 -0
- package/dist/commands/validate/fleet/obligations.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/print.js +63 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/place.js +13 -0
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/steps.js +197 -0
- package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
- package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +40 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +59 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +92 -0
- package/dist/commands/validate/links/corpus.js.map +1 -0
- package/dist/commands/validate/links/glossary.js +75 -0
- package/dist/commands/validate/links/glossary.js.map +1 -0
- package/dist/commands/validate/report.js +269 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/service/api.js +338 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +219 -0
- package/dist/commands/validate/service/events/events.js.map +1 -0
- package/dist/commands/validate/service/events/message-producers.js +77 -0
- package/dist/commands/validate/service/events/message-producers.js.map +1 -0
- package/dist/commands/validate/service/evidence-pins.js +131 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/service.js +251 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +251 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +113 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/validate.js +338 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +182 -0
- package/dist/commands/verify/cross/diff.js.map +1 -0
- package/dist/commands/verify/evidence/contract.js +32 -0
- package/dist/commands/verify/evidence/contract.js.map +1 -0
- package/dist/commands/verify/evidence/pins.js +52 -0
- package/dist/commands/verify/evidence/pins.js.map +1 -0
- package/dist/commands/verify/evidence/read.js +72 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +241 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +226 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +223 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +246 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +217 -0
- package/dist/commands/verify/verify.js.map +1 -0
- package/dist/commands/vouch/contract.js +11 -0
- package/dist/commands/vouch/contract.js.map +1 -0
- package/dist/commands/vouch/pack/contract.js +2 -0
- package/dist/commands/vouch/pack/contract.js.map +1 -0
- package/dist/commands/vouch/pack/pack.js +266 -0
- package/dist/commands/vouch/pack/pack.js.map +1 -0
- package/dist/commands/vouch/pack/print.js +271 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +142 -0
- package/dist/commands/vouch/pack/sections.js.map +1 -0
- package/dist/commands/vouch/prompt/confirm.js +46 -0
- package/dist/commands/vouch/prompt/confirm.js.map +1 -0
- package/dist/commands/vouch/report.js +101 -0
- package/dist/commands/vouch/report.js.map +1 -0
- package/dist/commands/vouch/run.js +285 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +125 -0
- package/dist/commands/vouch/sample/plan.js.map +1 -0
- package/dist/commands/vouch/sample/print.js +109 -0
- package/dist/commands/vouch/sample/print.js.map +1 -0
- package/dist/commands/vouch/vet/verify.js +123 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +176 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/artifacts.js +220 -0
- package/dist/core/agent/agents-md/artifacts.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +324 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/cycle.js +165 -0
- package/dist/core/agent/agents-md/cycle.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +34 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +41 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +62 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +32 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +60 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +246 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
- package/dist/core/agent/agents-md/spine.js +40 -0
- package/dist/core/agent/agents-md/spine.js.map +1 -0
- package/dist/core/agent/agents-md.js +170 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +50 -0
- package/dist/core/agent/agents-stamp.js.map +1 -0
- package/dist/core/agent/contract.js +2 -0
- package/dist/core/agent/contract.js.map +1 -0
- package/dist/core/agent/protocol.js +193 -0
- package/dist/core/agent/protocol.js.map +1 -0
- package/dist/core/agent/scaffold.js +259 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +103 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +150 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +228 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +133 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +337 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +262 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +105 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +105 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +209 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +65 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +188 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +16 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +297 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +110 -0
- package/dist/core/asyncapi/baseline/plan.js.map +1 -0
- package/dist/core/asyncapi/baseline/surfaces.js +54 -0
- package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
- package/dist/core/asyncapi/depth.js +164 -0
- package/dist/core/asyncapi/depth.js.map +1 -0
- package/dist/core/asyncapi/digest.js +141 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +91 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +33 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +308 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +215 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +107 -0
- package/dist/core/asyncapi/merge/pin.js.map +1 -0
- package/dist/core/asyncapi/model.js +11 -0
- package/dist/core/asyncapi/model.js.map +1 -0
- package/dist/core/asyncapi/producers.js +50 -0
- package/dist/core/asyncapi/producers.js.map +1 -0
- package/dist/core/{asyncapi.js → asyncapi/read.js} +95 -109
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +225 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +250 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +194 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/targets.js +226 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +48 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +174 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/likec4.js +90 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +158 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +57 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +75 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/project/architecture.js +45 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/documents.js +58 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +187 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/project/staged.js +220 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/service.js +159 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/resolve/steps.js +144 -0
- package/dist/core/c4/resolve/steps.js.map +1 -0
- package/dist/core/c4/seed/fleet-file.js +201 -0
- package/dist/core/c4/seed/fleet-file.js.map +1 -0
- package/dist/core/c4/seed/items.js +91 -0
- package/dist/core/c4/seed/items.js.map +1 -0
- package/dist/core/c4/seed/stamp.js +48 -0
- package/dist/core/c4/seed/stamp.js.map +1 -0
- package/dist/core/c4/seed/template.js +109 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/source-mask.js +82 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +227 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +101 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +10 -0
- package/dist/core/c4/splice/contract.js.map +1 -0
- package/dist/core/c4/splice/delta-blocks.js +139 -0
- package/dist/core/c4/splice/delta-blocks.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +36 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +269 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +194 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/workspace.js +174 -0
- package/dist/core/c4/workspace.js.map +1 -0
- package/dist/core/capabilities/authoring/notes.js +141 -0
- package/dist/core/capabilities/authoring/notes.js.map +1 -0
- package/dist/core/capabilities/capabilities.js +124 -0
- package/dist/core/capabilities/capabilities.js.map +1 -0
- package/dist/core/capabilities/delta/doc.js +50 -0
- package/dist/core/capabilities/delta/doc.js.map +1 -0
- package/dist/core/capabilities/delta/overlay.js +129 -0
- package/dist/core/capabilities/delta/overlay.js.map +1 -0
- package/dist/core/capabilities/delta/summary.js +57 -0
- package/dist/core/capabilities/delta/summary.js.map +1 -0
- package/dist/core/capabilities/delta/tree.js +43 -0
- package/dist/core/capabilities/delta/tree.js.map +1 -0
- package/dist/core/capabilities/delta/uncovered.js +222 -0
- package/dist/core/capabilities/delta/uncovered.js.map +1 -0
- package/dist/core/capabilities/findings.js +342 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +181 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +143 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +199 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +126 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +277 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +177 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +74 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/coherence.js +287 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/declared.js +269 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +206 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +204 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +166 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +122 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/merged.js +40 -0
- package/dist/core/coherence/events/merged.js.map +1 -0
- package/dist/core/coherence/living.js +198 -0
- package/dist/core/coherence/living.js.map +1 -0
- package/dist/core/coherence/lookups.js +155 -0
- package/dist/core/coherence/lookups.js.map +1 -0
- package/dist/core/coherence/pending.js +39 -0
- package/dist/core/coherence/pending.js.map +1 -0
- package/dist/core/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.js.map +1 -0
- package/dist/core/delta/claims.js +73 -0
- package/dist/core/delta/claims.js.map +1 -0
- package/dist/core/delta/delta.js +296 -0
- package/dist/core/delta/delta.js.map +1 -0
- package/dist/core/delta/document.js +177 -0
- package/dist/core/delta/document.js.map +1 -0
- package/dist/core/delta/scope.js +48 -0
- package/dist/core/delta/scope.js.map +1 -0
- package/dist/core/delta/select.js +237 -0
- package/dist/core/delta/select.js.map +1 -0
- package/dist/core/dependencies/dependencies.js +141 -0
- package/dist/core/dependencies/dependencies.js.map +1 -0
- package/dist/core/dependencies/facts.js +165 -0
- package/dist/core/dependencies/facts.js.map +1 -0
- package/dist/core/dependencies/fanin.js +88 -0
- package/dist/core/dependencies/fanin.js.map +1 -0
- package/dist/core/dependencies/graph.js +106 -0
- package/dist/core/dependencies/graph.js.map +1 -0
- package/dist/core/deployment/delta.js +188 -0
- package/dist/core/deployment/delta.js.map +1 -0
- package/dist/core/deployment/objects.js +145 -0
- package/dist/core/deployment/objects.js.map +1 -0
- package/dist/core/diff/base-git.js +148 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +209 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/current-state.js +96 -0
- package/dist/core/diff/current-state.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +188 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/semantic.js +243 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/diff/victims.js +247 -0
- package/dist/core/diff/victims.js.map +1 -0
- package/dist/core/docs.js +7 -64
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +222 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +135 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +275 -0
- package/dist/core/doctor/doctor.js.map +1 -0
- package/dist/core/doctor/report.js +13 -0
- package/dist/core/doctor/report.js.map +1 -0
- package/dist/core/doctor/residue.js +110 -0
- package/dist/core/doctor/residue.js.map +1 -0
- package/dist/core/document/apply.js +77 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
- package/dist/core/document/frontmatter.js.map +1 -0
- package/dist/core/document/grammar/directives.js +143 -0
- package/dist/core/document/grammar/directives.js.map +1 -0
- package/dist/core/document/parse.js +263 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +221 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +241 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +79 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +175 -0
- package/dist/core/envelope/json.js.map +1 -0
- package/dist/core/{version.js → envelope/version.js} +3 -3
- package/dist/core/envelope/version.js.map +1 -0
- package/dist/core/explain/families.js +175 -0
- package/dist/core/explain/families.js.map +1 -0
- package/dist/core/explain/fix-tables.js +178 -0
- package/dist/core/explain/fix-tables.js.map +1 -0
- package/dist/core/explain/lookup.js +181 -0
- package/dist/core/explain/lookup.js.map +1 -0
- package/dist/core/explain/refusals.js +49 -0
- package/dist/core/explain/refusals.js.map +1 -0
- package/dist/core/explain/terms.js +144 -0
- package/dist/core/explain/terms.js.map +1 -0
- package/dist/core/explore/describe.js +105 -0
- package/dist/core/explore/describe.js.map +1 -0
- package/dist/core/{explore.js → explore/explore.js} +50 -101
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +120 -78
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +201 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +205 -0
- package/dist/core/gate/partners.js.map +1 -0
- package/dist/core/gate/report.js +47 -0
- package/dist/core/gate/report.js.map +1 -0
- package/dist/core/gate/verification.js +113 -0
- package/dist/core/gate/verification.js.map +1 -0
- package/dist/core/gherkin/digest.js +60 -0
- package/dist/core/gherkin/digest.js.map +1 -0
- package/dist/core/gherkin/emit.js +177 -0
- package/dist/core/gherkin/emit.js.map +1 -0
- package/dist/core/gherkin/read.js +76 -0
- package/dist/core/gherkin/read.js.map +1 -0
- package/dist/core/gherkin/stale.js +234 -0
- package/dist/core/gherkin/stale.js.map +1 -0
- package/dist/core/gherkin/stamp.js +77 -0
- package/dist/core/gherkin/stamp.js.map +1 -0
- package/dist/core/gherkin/steps/catalogue.js +154 -0
- package/dist/core/gherkin/steps/catalogue.js.map +1 -0
- package/dist/core/gherkin/steps/inventory.js +98 -0
- package/dist/core/gherkin/steps/inventory.js.map +1 -0
- package/dist/core/gherkin/steps/phrase.js +72 -0
- package/dist/core/gherkin/steps/phrase.js.map +1 -0
- package/dist/core/glossary/delta.js +106 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +86 -0
- package/dist/core/glossary/tree.js.map +1 -0
- package/dist/core/kernel/concurrency.js.map +1 -0
- package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
- package/dist/core/kernel/document-bytes.js.map +1 -0
- package/dist/core/kernel/fences.js +42 -0
- package/dist/core/kernel/fences.js.map +1 -0
- package/dist/core/kernel/ids/capability.js +72 -0
- package/dist/core/kernel/ids/capability.js.map +1 -0
- package/dist/core/kernel/ids/dirs.js +33 -0
- package/dist/core/kernel/ids/dirs.js.map +1 -0
- package/dist/core/kernel/ids/feature.js +75 -0
- package/dist/core/kernel/ids/feature.js.map +1 -0
- package/dist/core/kernel/ids/service.js +156 -0
- package/dist/core/kernel/ids/service.js.map +1 -0
- package/dist/core/kernel/ids/subsystem.js +63 -0
- package/dist/core/kernel/ids/subsystem.js.map +1 -0
- package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +68 -0
- package/dist/core/links/backlinks.js.map +1 -0
- package/dist/core/links/case.js +74 -0
- package/dist/core/links/case.js.map +1 -0
- package/dist/core/links/corpus.js +104 -0
- package/dist/core/links/corpus.js.map +1 -0
- package/dist/core/links/findings.js +110 -0
- package/dist/core/links/findings.js.map +1 -0
- package/dist/core/links/parse.js +236 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +111 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +72 -0
- package/dist/core/mcp/author-tools.js.map +1 -0
- package/dist/core/mcp/framing.js +46 -0
- package/dist/core/mcp/framing.js.map +1 -0
- package/dist/core/mcp/protocol.js +280 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/tools.js +314 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/obligations/obligations.js +106 -0
- package/dist/core/obligations/obligations.js.map +1 -0
- package/dist/core/openapi/baseline/gate.js +166 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +112 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +175 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/depth.js +122 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +189 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +44 -106
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +234 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +26 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +208 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +256 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +128 -0
- package/dist/core/openapi/merge/pin.js.map +1 -0
- package/dist/core/openspec/decide/capabilities.js +244 -0
- package/dist/core/openspec/decide/capabilities.js.map +1 -0
- package/dist/core/openspec/decide/dispositions.js +63 -0
- package/dist/core/openspec/decide/dispositions.js.map +1 -0
- package/dist/core/openspec/decide/renames.js +179 -0
- package/dist/core/openspec/decide/renames.js.map +1 -0
- package/dist/core/openspec/decide/verdict.js +84 -0
- package/dist/core/openspec/decide/verdict.js.map +1 -0
- package/dist/core/openspec/inventory.js +221 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +76 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +65 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +235 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +200 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +260 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +133 -0
- package/dist/core/openspec/scan/walk.js.map +1 -0
- package/dist/core/openspec/scan/workspace.js +71 -0
- package/dist/core/openspec/scan/workspace.js.map +1 -0
- package/dist/core/owners/codeowners.js +141 -0
- package/dist/core/owners/codeowners.js.map +1 -0
- package/dist/core/pack/features.js +120 -0
- package/dist/core/pack/features.js.map +1 -0
- package/dist/core/pack/joins.js +112 -0
- package/dist/core/pack/joins.js.map +1 -0
- package/dist/core/pack/living.js +137 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +76 -0
- package/dist/core/pack/pack.js.map +1 -0
- package/dist/core/permissions/permissions.js +87 -0
- package/dist/core/permissions/permissions.js.map +1 -0
- package/dist/core/projection/api.js +84 -0
- package/dist/core/projection/api.js.map +1 -0
- package/dist/core/projection/arch-slice.js +63 -0
- package/dist/core/projection/arch-slice.js.map +1 -0
- package/dist/core/projection/events.js +34 -0
- package/dist/core/projection/events.js.map +1 -0
- package/dist/core/provenance/findings.js +208 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +225 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +182 -0
- package/dist/core/provenance/gitq/moves.js.map +1 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
- package/dist/core/provenance/sample/scope.js +238 -0
- package/dist/core/provenance/sample/scope.js.map +1 -0
- package/dist/core/provenance/sample/sections.js +61 -0
- package/dist/core/provenance/sample/sections.js.map +1 -0
- package/dist/core/provenance/sources.js +263 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +232 -0
- package/dist/core/provenance/stamp.js.map +1 -0
- package/dist/core/provenance/walk.js +157 -0
- package/dist/core/provenance/walk.js.map +1 -0
- package/dist/core/repo/authored/paths.js +210 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +277 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +248 -0
- package/dist/core/repo/repo.js.map +1 -0
- package/dist/core/repo/service-target.js +153 -0
- package/dist/core/repo/service-target.js.map +1 -0
- package/dist/core/repo/state.js +58 -0
- package/dist/core/repo/state.js.map +1 -0
- package/dist/core/repo/tree/find.js +52 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +64 -0
- package/dist/core/repo/tree/fs.js.map +1 -0
- package/dist/core/repo/tree/marker.js +61 -0
- package/dist/core/repo/tree/marker.js.map +1 -0
- package/dist/core/repo/tree/views.js +172 -0
- package/dist/core/repo/tree/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +234 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +99 -2
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +131 -0
- package/dist/core/scaffold/landscape.js.map +1 -0
- package/dist/core/scaffold/readme.js +84 -0
- package/dist/core/scaffold/readme.js.map +1 -0
- package/dist/core/staging/commit.js +241 -0
- package/dist/core/staging/commit.js.map +1 -0
- package/dist/core/staging/interrupted.js +96 -0
- package/dist/core/staging/interrupted.js.map +1 -0
- package/dist/core/staging/lock.js +206 -0
- package/dist/core/staging/lock.js.map +1 -0
- package/dist/core/staging/recovery/finding.js +35 -0
- package/dist/core/staging/recovery/finding.js.map +1 -0
- package/dist/core/staging/recovery/intent.js +98 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +126 -0
- package/dist/core/staging/recovery/recover.js.map +1 -0
- package/dist/core/staging/recovery/residue.js +62 -0
- package/dist/core/staging/recovery/residue.js.map +1 -0
- package/dist/core/staging/snapshot.js +202 -0
- package/dist/core/staging/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +171 -0
- package/dist/core/staging/txn/forward.js.map +1 -0
- package/dist/core/staging/txn/journal.js +139 -0
- package/dist/core/staging/txn/journal.js.map +1 -0
- package/dist/core/staging/txn/transaction.js +75 -0
- package/dist/core/staging/txn/transaction.js.map +1 -0
- package/dist/core/staging/writes.js +113 -0
- package/dist/core/staging/writes.js.map +1 -0
- package/dist/core/status/actions/execution.js +49 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +102 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +196 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +207 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +150 -0
- package/dist/core/status/feature/next.js.map +1 -0
- package/dist/core/status/feature/state.js +21 -0
- package/dist/core/status/feature/state.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +197 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +207 -0
- package/dist/core/status/fleet/next.js.map +1 -0
- package/dist/core/status/interrupted.js +97 -0
- package/dist/core/status/interrupted.js.map +1 -0
- package/dist/core/status/report.js +31 -0
- package/dist/core/status/report.js.map +1 -0
- package/dist/core/status/scan.js +41 -0
- package/dist/core/status/scan.js.map +1 -0
- package/dist/core/status/verification.js +201 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/usecases/capability.js +169 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +116 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +103 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +72 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +137 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/operations.js +111 -0
- package/dist/core/usecases/operations.js.map +1 -0
- package/dist/core/usecases/place.js +44 -0
- package/dist/core/usecases/place.js.map +1 -0
- package/dist/core/usecases/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +173 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +150 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +201 -0
- package/dist/core/verify/checklist.js.map +1 -0
- package/dist/core/verify/claims/identity.js +61 -0
- package/dist/core/verify/claims/identity.js.map +1 -0
- package/dist/core/verify/cross/diff.js +97 -0
- package/dist/core/verify/cross/diff.js.map +1 -0
- package/dist/core/verify/evidence/contract.js +169 -0
- package/dist/core/verify/evidence/contract.js.map +1 -0
- package/dist/core/verify/file.js +257 -0
- package/dist/core/verify/file.js.map +1 -0
- package/dist/core/verify/pins/lint.js +157 -0
- package/dist/core/verify/pins/lint.js.map +1 -0
- package/dist/core/verify/pins/pin.js +95 -0
- package/dist/core/verify/pins/pin.js.map +1 -0
- package/dist/core/verify/record.js +142 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +89 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +57 -0
- package/dist/core/verify/store/render.js.map +1 -0
- package/dist/core/vocabulary/health.js +91 -0
- package/dist/core/vocabulary/health.js.map +1 -0
- package/dist/core/vocabulary/issue.js +58 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +145 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/{report.js → vocabulary/report.js} +30 -2
- package/dist/core/vocabulary/report.js.map +1 -0
- package/dist/core/vocabulary/steps.js +266 -0
- package/dist/core/vocabulary/steps.js.map +1 -0
- package/dist/core/workspace/discover.js +239 -0
- package/dist/core/workspace/discover.js.map +1 -0
- package/dist/core/workspace/render.js +52 -0
- package/dist/core/workspace/render.js.map +1 -0
- package/examples/README.md +189 -0
- package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
- package/examples/docs/architecture/capabilities.yaml +31 -0
- package/examples/docs/architecture/landscape.likec4 +280 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/subsystems.likec4 +11 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
- package/examples/docs/capabilities/checkout/spec.md +55 -0
- package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
- package/examples/docs/capabilities/order-notifications/spec.md +43 -0
- package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
- package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
- package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
- package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
- package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
- package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
- package/examples/docs/glossary/order.md +15 -0
- package/examples/docs/glossary/payments/authorization.md +14 -0
- package/examples/docs/likec4.config.json +9 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +109 -0
- package/examples/docs/services/checkout-web/spec.md +91 -0
- package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
- package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
- package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
- package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
- package/examples/docs/services/order-service/arch.spec.md +127 -0
- package/examples/docs/services/order-service/asyncapi.yaml +108 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +138 -0
- package/examples/docs/services/order-service/openapi.yaml +257 -0
- package/examples/docs/services/order-service/runbook.md +62 -0
- package/examples/docs/services/order-service/spec.md +134 -0
- package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
- package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
- package/examples/docs/services/payment-service/arch.spec.md +73 -0
- package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
- package/examples/docs/services/payment-service/health.yaml +39 -0
- package/examples/docs/services/payment-service/model.likec4 +67 -0
- package/examples/docs/services/payment-service/openapi.yaml +151 -0
- package/examples/docs/services/payment-service/runbook.md +37 -0
- package/examples/docs/services/payment-service/spec.md +88 -0
- package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
- package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
- package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
- package/examples/docs/services/platform/identity-service/runbook.md +95 -0
- package/examples/docs/services/platform/identity-service/spec.md +119 -0
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
- package/examples/docs/services/platform/notification-service/health.yaml +35 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
- package/examples/docs/services/platform/notification-service/runbook.md +48 -0
- package/examples/docs/services/platform/notification-service/spec.md +112 -0
- package/examples/docs/services/platform/subsystem.yaml +2 -0
- package/examples/fleet.yaml +57 -0
- package/package.json +19 -6
- package/dist/commands/adopt.js +0 -240
- package/dist/commands/adopt.js.map +0 -1
- package/dist/commands/archive.js +0 -1313
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/delta.js +0 -388
- package/dist/commands/delta.js.map +0 -1
- package/dist/commands/docs-repo-gate.js.map +0 -1
- package/dist/commands/format.js +0 -17
- package/dist/commands/format.js.map +0 -1
- package/dist/commands/gherkin.js +0 -309
- package/dist/commands/gherkin.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/list.js +0 -295
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/migrate-openspec.js +0 -950
- package/dist/commands/migrate-openspec.js.map +0 -1
- package/dist/commands/new.js +0 -413
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/rebase.js +0 -356
- package/dist/commands/rebase.js.map +0 -1
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/status.js +0 -262
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unarchive.js.map +0 -1
- package/dist/commands/validate.js +0 -1773
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/verify.js +0 -775
- package/dist/commands/verify.js.map +0 -1
- package/dist/commands/vouch.js +0 -421
- package/dist/commands/vouch.js.map +0 -1
- package/dist/core/agent.js +0 -2173
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agents-stamp.js.map +0 -1
- package/dist/core/arch.js +0 -130
- package/dist/core/arch.js.map +0 -1
- package/dist/core/asyncapi.js.map +0 -1
- package/dist/core/brief.js +0 -755
- package/dist/core/brief.js.map +0 -1
- package/dist/core/coherence.js +0 -577
- package/dist/core/coherence.js.map +0 -1
- package/dist/core/concurrency.js.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/delta.js +0 -476
- package/dist/core/delta.js.map +0 -1
- package/dist/core/dependencies.js +0 -356
- package/dist/core/dependencies.js.map +0 -1
- package/dist/core/doctor.js +0 -596
- package/dist/core/doctor.js.map +0 -1
- package/dist/core/document-bytes.js.map +0 -1
- package/dist/core/explore.js.map +0 -1
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/gherkin.js +0 -463
- package/dist/core/gherkin.js.map +0 -1
- package/dist/core/health.js +0 -67
- package/dist/core/health.js.map +0 -1
- package/dist/core/ids.js +0 -122
- package/dist/core/ids.js.map +0 -1
- package/dist/core/issue.js +0 -9
- package/dist/core/issue.js.map +0 -1
- package/dist/core/json.js +0 -74
- package/dist/core/json.js.map +0 -1
- package/dist/core/likec4.js +0 -489
- package/dist/core/likec4.js.map +0 -1
- package/dist/core/maturity.js +0 -66
- package/dist/core/maturity.js.map +0 -1
- package/dist/core/openapi-merge.js +0 -552
- package/dist/core/openapi-merge.js.map +0 -1
- package/dist/core/openapi.js.map +0 -1
- package/dist/core/openspec-inventory.js +0 -1440
- package/dist/core/openspec-inventory.js.map +0 -1
- package/dist/core/path-safety.js.map +0 -1
- package/dist/core/provenance.js +0 -787
- package/dist/core/provenance.js.map +0 -1
- package/dist/core/records.js.map +0 -1
- package/dist/core/repo.js +0 -438
- package/dist/core/repo.js.map +0 -1
- package/dist/core/report.js.map +0 -1
- package/dist/core/spec.js +0 -505
- package/dist/core/spec.js.map +0 -1
- package/dist/core/staging.js +0 -890
- package/dist/core/staging.js.map +0 -1
- package/dist/core/status.js +0 -1132
- package/dist/core/status.js.map +0 -1
- package/dist/core/steps.js +0 -72
- package/dist/core/steps.js.map +0 -1
- package/dist/core/verify.js +0 -807
- package/dist/core/verify.js.map +0 -1
- package/dist/core/version.js.map +0 -1
- /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
- /package/dist/core/{records.js → kernel/records.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/core/workspace/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAY1D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAAW,EAAE,QAAgB;IACjE,MAAM,QAAQ,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;IACpG,OAAO,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAmC,EACnC,OAAe;IAEf,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACvC,MAAM;QACN,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,qBAAqB,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC;KACxE,CAAC,CAAC,CAAC;IACJ,MAAM,IAAI,GACR,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;IACjG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC3B,CAAC","sourcesContent":["/**\n * Deterministic `.code-workspace` rendering — pure computation, no printing.\n *\n * The output is a derived file: same members plus same target path must\n * produce the same bytes on every machine, which is why every path is spelled\n * with forward slashes (VS Code and Cursor accept them on Windows too, and\n * they are the one spelling that diffs identically across checkouts) and why\n * the JSON shape follows saveConfig's convention — 2-space indent, trailing\n * newline.\n */\nimport { dirname, isAbsolute, relative } from \"node:path\";\nimport type { WorkspaceMember } from \"./discover.js\";\n\n/** One folder row, still carrying the member it was derived from. */\nexport interface RenderedFolder {\n member: WorkspaceMember;\n /** Exactly what lands in the file's `name`. */\n name: string;\n /** Exactly what lands in the file's `path` — the forward-slash spelling. */\n path: string;\n}\n\n/**\n * The `path` a folder entry gets, from the already-computed relative and the\n * member's absolute path.\n *\n * Split out of `renderWorkspace` because the fallback decision is win32-only\n * on a win32 host — `relative()` answers a cross-drive pair with the ABSOLUTE\n * target, since no `..` chain crosses drives — and a POSIX test host can\n * therefore never steer the platform `relative()` into producing one. Taking\n * `rel` as data lets the suite exercise the branch with win32-shaped input.\n *\n * The drive-letter test backs up `isAbsolute` because that check is also\n * platform-bound: on POSIX, `D:\\other\\svc` reads as a relative name. A POSIX\n * directory literally named `D:` would match too and get the absolute\n * spelling instead of the relative one — a stranger workspace file, but a\n * correct one, and the pathological name is not worth a platform fork here.\n */\nexport function workspacePathSpelling(rel: string, absolute: string): string {\n const spelling = rel === \"\" ? \".\" : isAbsolute(rel) || /^[A-Za-z]:[\\\\/]/.test(rel) ? absolute : rel;\n return spelling.split(/[\\\\/]/).join(\"/\");\n}\n\n/**\n * Render the workspace document for `members`, targeted at `outPath`.\n *\n * Folder paths are relative to the file's own directory, so the committed\n * side-by-side layout opens on every machine that checks it out; a member on\n * another drive keeps its absolute path, because no relative spelling exists.\n * The folders are returned still attached to their members so the command can\n * echo the exact written spelling into its `--json` payload without joining\n * two arrays by position.\n */\nexport function renderWorkspace(\n members: readonly WorkspaceMember[],\n outPath: string,\n): { text: string; folders: RenderedFolder[] } {\n const outDir = dirname(outPath);\n const folders = members.map((member) => ({\n member,\n name: member.name,\n path: workspacePathSpelling(relative(outDir, member.path), member.path),\n }));\n const text =\n JSON.stringify({ folders: folders.map(({ name, path }) => ({ name, path })) }, null, 2) + \"\\n\";\n return { text, folders };\n}\n"]}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# The example fleet
|
|
2
|
+
|
|
3
|
+
`docs/` is a complete, runnable loam docs repo. It is small enough to read in one sitting and large
|
|
4
|
+
enough that every row of [SCHEMA.md](../SCHEMA.md)'s canonical-joins table is exercised by something
|
|
5
|
+
— including the joins that only appear once a fleet has more than two services in it.
|
|
6
|
+
|
|
7
|
+
Run it from a clone. `docs/loam.json` is committed and says `"docsDir": "."`, so the tree governs
|
|
8
|
+
itself: every command below resolves to this fleet because it is run from inside it. There is
|
|
9
|
+
nothing to write first and nothing to delete afterwards.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
cd examples/docs
|
|
13
|
+
loam list # the fleet and its maturity ladder
|
|
14
|
+
loam status # what to do next, derived from the files
|
|
15
|
+
loam validate --all # the gate CI runs
|
|
16
|
+
loam archive FEAT-101 --dry-run # the three-axis merge plan, writing nothing
|
|
17
|
+
loam archive FEAT-112 --dry-run # an operation being retired, writing nothing
|
|
18
|
+
loam verify FEAT-088 # a shipped feature's done-check: attested
|
|
19
|
+
loam verify FEAT-120 # …and its pair, the same check: verified
|
|
20
|
+
loam dependencies # the active-feature graph
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Working on loam itself and running from source, use `npx tsx ../../src/cli.ts <args>` in place of
|
|
24
|
+
`loam`. Not `npm run dev --`: npm runs a script from the package root, so it would leave
|
|
25
|
+
`examples/docs` and resolve some other `loam.json` — the fleet it reported would not be this one.
|
|
26
|
+
|
|
27
|
+
`test/examples.test.ts` pins the validate summary, every finding code and the archive plans
|
|
28
|
+
file-for-file, so nothing below can drift away from the code without a test going red.
|
|
29
|
+
|
|
30
|
+
## What is in it
|
|
31
|
+
|
|
32
|
+
Five services, drawn inside one grouping element so the map looks like ordinary grouped C4:
|
|
33
|
+
|
|
34
|
+
| service | what it is here to show |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `checkout-web` | a UI service: page-specs under `ui/pages/`, no `openapi.yaml` of its own, and the one spec in the fleet that names no `sources` |
|
|
37
|
+
| `order-service` | the busiest spine: four operations, a produced event, a consumed event, and a deprecated operation with a feature already open to retire it |
|
|
38
|
+
| `payment-service` | the outbox, the acquirer, and an `arch.spec.md` whose `Covers:` lines reach the C4 model *and* the health signals |
|
|
39
|
+
| `identity-service` | the permission vocabulary's owner, and a deprecated operation whose consumer has not migrated — filed into `services/platform/` |
|
|
40
|
+
| `notification-service` | a service with no HTTP API at all — three consumed messages, one of them from a producer outside the fleet — filed into `services/platform/` |
|
|
41
|
+
|
|
42
|
+
Around them: `kafka` as an `#external` `#platform` system with a topic per channel (edges point at
|
|
43
|
+
the topic, never at the broker), `stripe` and `salesforce` as external systems, and
|
|
44
|
+
`architecture/permissions.yaml` as the fleet's authorization vocabulary.
|
|
45
|
+
|
|
46
|
+
**Three authored capability documents**, which are the business tree rather than the architecture:
|
|
47
|
+
`capabilities/checkout/spec.md`, `capabilities/identity/tokens/spec.md` and
|
|
48
|
+
`capabilities/order-notifications/spec.md`. The third carries the axis's second realizer: its one
|
|
49
|
+
promise — "a placed order produces exactly one confirmation" — is cross-service by construction, so
|
|
50
|
+
no service's `spec.md` can keep it, and `architecture/usecases/order-notification.likec4` claims it
|
|
51
|
+
with `#req-NOTIFY-ONCE` beside its `#cap-` tag. The other two are kept by service requirements
|
|
52
|
+
through `Realizes:`. Both ids are also declared in `architecture/capabilities.yaml` — the vocabulary
|
|
53
|
+
is the union of the two sides, and a name a document elaborates does not have to leave the YAML,
|
|
54
|
+
which is what keeps the metadata (`description`, `owner`) that a document has no field for. The
|
|
55
|
+
nested one carries the lesson: the id `identity/tokens` keeps its slash everywhere it is written, so
|
|
56
|
+
the tree spells it as directories, and `capabilities/identity/` holding no `spec.md` of its own is a
|
|
57
|
+
GROUP and earns no finding. Each requirement in both files is a promise a customer could check,
|
|
58
|
+
names no service, and carries a `Requirement-ID:` — required here, unlike in a service spec, because
|
|
59
|
+
these documents outlive every service that realizes them.
|
|
60
|
+
|
|
61
|
+
**Two glossary terms**, `glossary/order.md` and the nested `glossary/payments/authorization.md`,
|
|
62
|
+
each cited from the capability documents that use the word. This is the axis's whole mechanism in
|
|
63
|
+
two files: the citation is an ordinary markdown link, so `loam validate` resolves it like any other
|
|
64
|
+
and `loam list glossary` can answer "which documents use this term" as a join rather than a grep.
|
|
65
|
+
The two terms also cite EACH OTHER, which is deliberate — a glossary is a network of definitions —
|
|
66
|
+
and that reciprocal pair is exactly what does NOT count as adoption: both terms stay out of
|
|
67
|
+
`glossary.unlinked` because a capability document cites them, not because they cite each other.
|
|
68
|
+
Delete either of those two capability citations and the example gains a tenth warning.
|
|
69
|
+
|
|
70
|
+
**One architectural obligation, declared and applied and met** — which is three files agreeing, and
|
|
71
|
+
the axis's whole mechanism. `architecture/adrs/0001-transactional-outbox.md` says WHAT was decided;
|
|
72
|
+
`#obl-outbox` on the `payment-service → kafka.paymentEvents` edge in the fleet map says WHERE it
|
|
73
|
+
holds (on the publish edge, not on the service — payment-service also serves an API that owes
|
|
74
|
+
nothing of the kind); `architecture/obligations.yaml` declares the name so a mistyped tag is an
|
|
75
|
+
error rather than a word nobody notices; and `ARCH-PAY-OUTBOX` in payment-service's `arch.spec.md`
|
|
76
|
+
covers that same edge, which is the team saying it is met. Because all four line up, the example is
|
|
77
|
+
SILENT about the outbox — the working join produces no finding, which is what a working join should
|
|
78
|
+
do. The second declaration, `idempotency-key`, is the one that talks: it is declared and placed
|
|
79
|
+
nowhere, and `obligation.unapplied` is the warning in the table below.
|
|
80
|
+
|
|
81
|
+
**On the event spine the arrow follows the message** — producer → topic for `publishes`, topic →
|
|
82
|
+
consumer for `consumes` — and that is load-bearing rather than aesthetic. `publishes` binds the
|
|
83
|
+
edge's source and `consumes` binds its target, so a consume edge drawn the other way round binds to
|
|
84
|
+
nothing: the metadata parses, the document validates, and the check silently grades zero edges.
|
|
85
|
+
Nothing in loam reports that today, which is why the landscape says so in a comment.
|
|
86
|
+
|
|
87
|
+
## Four features, at four points in their life
|
|
88
|
+
|
|
89
|
+
The two archived ones are a **matched pair**, and the pairing is the point: same command, same
|
|
90
|
+
shape of record, two different verdicts. A showcase that demonstrated only one would teach that the
|
|
91
|
+
distinction is decorative — and keeping those two answers apart is most of what loam claims to be
|
|
92
|
+
for.
|
|
93
|
+
|
|
94
|
+
- **`features/archive/FEAT-088-refunds/`** — shipped, and **`attested`**. It was merged by the real
|
|
95
|
+
`loam archive`, so its `.loam-before/` snapshot holds the exact bytes the merge overwrote and
|
|
96
|
+
`loam unarchive FEAT-088` would put them back. Its `verification.yaml` is the done-check written
|
|
97
|
+
down: every claim is confirmed, but the scenario claims rest on an agent's word instead of a
|
|
98
|
+
digest-matched test run. loam does not pretend those are the same thing.
|
|
99
|
+
- **`features/archive/FEAT-120-refund-notification/`** — shipped, and **`verified`**. The sequel
|
|
100
|
+
FEAT-088 left open: the money went back and nobody told the customer. It publishes
|
|
101
|
+
`payment.PaymentRefunded` from payment-service and has notification-service turn it into the
|
|
102
|
+
message the customer is waiting for — so it exercises the event spine end to end, across two
|
|
103
|
+
services, with no HTTP anywhere in it.
|
|
104
|
+
|
|
105
|
+
Its five scenario claims were answered by `--results` from the `scenario-report.json` beside it:
|
|
106
|
+
loam's own runner-neutral `{"loamScenarioReport": 1, …}` shape, which any runner can be adapted
|
|
107
|
+
into. Its two `event.declares` claims still rest on an agent's word. That mix is the honest
|
|
108
|
+
common case — a suite that answers the scenarios, and wiring claims a human vouches for — and it
|
|
109
|
+
still reads `verified`, because the verdict turns on the scenario claims alone.
|
|
110
|
+
- **`features/FEAT-101-payment-splitting/`** — in flight, and the big one: a new service arriving
|
|
111
|
+
with its own requirements, architecture requirements and contract, a C4 delta that splices a
|
|
112
|
+
nested element into the living landscape, a `MODIFIED` requirement that **renames its heading**
|
|
113
|
+
while keeping its `Requirement-ID` — loam's rename mechanism — and an **event-contract delta**
|
|
114
|
+
(`specs/payment-service/asyncapi.yaml`): a complete AsyncAPI 3.0 document restating
|
|
115
|
+
payment-service's living contract under `loam rebase`-written `x-loam-based-on` pins and adding
|
|
116
|
+
one new producer side, so the archive merges the new slots and leaves every pinned quote to the
|
|
117
|
+
living contract's own copy.
|
|
118
|
+
- **`features/FEAT-112-retire-order-v1/`** — in flight, and the smallest legal shape: no
|
|
119
|
+
`delta.likec4` at all, because retiring an operation moves no boxes. It carries the two halves
|
|
120
|
+
loam requires together for a removal — a `REMOVED` requirement and an `x-loam-remove: true` marker
|
|
121
|
+
inside the operation object.
|
|
122
|
+
|
|
123
|
+
## The warnings are the lesson
|
|
124
|
+
|
|
125
|
+
`loam validate --all` reports **0 errors and 10 warnings** here, and every one of them is
|
|
126
|
+
deliberate. An example that reported nothing would teach nothing about what these checks catch:
|
|
127
|
+
|
|
128
|
+
| finding | what it is demonstrating |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `sources.absent` | `checkout-web`'s spec names no `sources`, so nothing ties it to code and `loam vouch` would refuse to stamp it |
|
|
131
|
+
| `spine.op-link-missing` | one landscape edge says it calls payment-service and names no operation, so no check can tell whether the call still exists |
|
|
132
|
+
| `spine.op-deprecated` | payment-service still calls identity-service's `validateToken`, which that contract marks `deprecated: true` — the consumer, not the provider, is the one being told |
|
|
133
|
+
| `api.requirement-deprecated` (×2) | `IDN-VALIDATE-LEGACY` and `ORD-PLACE-V1` each govern only a deprecated operation: promised behaviour on its way out |
|
|
134
|
+
| `permissions.unenforced` | `user/profile:read` is declared in the vocabulary and named by no requirement — the shape a vocabulary drifts into |
|
|
135
|
+
| `capability.unrealized` | `payments/settlement` is declared in `architecture/capabilities.yaml` and no living requirement's `Capability:` line names it — a promise nobody implemented, or a word nobody adopted; `loam list capabilities` shows it as `0 — unrealized` beside the realized ones |
|
|
136
|
+
| `capability.requirement-unrealized` | `checkout#CHECKOUT-PRICE-HONOURED` — one promise inside a capability whose OTHER promise three services realize, so the row above says nothing about it. That contrast IS the demonstration: `capability.unrealized` finds a capability nobody claimed, and only this code finds the gap inside a capability that looks healthy. Three requirements do carry `Realizes:` lines — `WEB-CHECKOUT`, `ORD-PLACE` and `PAY-AUTHORIZE` all name `checkout#CHECKOUT-CHARGE-ONCE` — and the fourth promise is simply not implemented, which is a normal state for a business document written ahead of the fleet |
|
|
137
|
+
| `c4.uncovered` | FEAT-101 adds a `checkout-web → payment-split-service` edge that no arch requirement covers, so its architectural obligations would ship untested |
|
|
138
|
+
| `obligation.unapplied` | `idempotency-key` is declared in `architecture/obligations.yaml` and no `#obl-` tag applies it anywhere on the fleet map — a decision that was reversed and left its word behind, or one nobody has placed yet. Its sibling `outbox` IS placed and IS covered, and says nothing: that contrast is the demonstration |
|
|
139
|
+
|
|
140
|
+
**Two of the five are filed into a subsystem.** `services/platform/` (its `subsystem.yaml` is the
|
|
141
|
+
marker — title and description, never members) groups `identity-service` and `notification-service`,
|
|
142
|
+
while the other three sit unfiled — the permanent, normal state a partially organized fleet lives
|
|
143
|
+
in, counted by `loam list` and never a finding. Placement is not identity: both services' specs,
|
|
144
|
+
contracts and digests are byte-identical to their unfiled days, every command addresses them by bare
|
|
145
|
+
id, and `architecture/subsystems.likec4` — GENERATED by `loam subsystem sync`, one view per
|
|
146
|
+
subsystem, one `include` per line — is the only file the grouping added. Edit the tree with
|
|
147
|
+
`loam subsystem move|rename|rm` and the views file travels in the same transaction; edit it by hand
|
|
148
|
+
and `validate --all` answers `subsystem.views-stale`. (`order-service` and `payment-service` stay
|
|
149
|
+
unfiled deliberately: FEAT-088's committed version-2 snapshot restores them by literal path, and the
|
|
150
|
+
`loam unarchive FEAT-088` walkthrough must keep working byte-for-byte.)
|
|
151
|
+
|
|
152
|
+
Plus one count rather than a finding: `sourcesUnverifiableFromHere: 4`. Four specs name paths in
|
|
153
|
+
their own service repositories, and this is none of those repositories — the fleet gate reports the
|
|
154
|
+
blind spot instead of resolving it. Running `loam validate --service <id>` inside each service repo
|
|
155
|
+
is what closes it.
|
|
156
|
+
|
|
157
|
+
## What the example deliberately does not carry
|
|
158
|
+
|
|
159
|
+
- **`AGENTS.md`.** A real docs repo has one, written by `loam init --docs . --create`. It is left
|
|
160
|
+
out here because a generated `AGENTS.md` carries the version stamp of the binary that wrote it,
|
|
161
|
+
and this tree is committed while the binary keeps moving — a stamped copy in the repository would
|
|
162
|
+
be stale by the next release and would say so to every reader of the example.
|
|
163
|
+
|
|
164
|
+
**`loam.json` used to be left out with it**, on the same "keep the tree a pure set of documents"
|
|
165
|
+
reasoning, and that trade was wrong: without it the example could not be RUN. `loam status` here
|
|
166
|
+
answered "No loam.json found" and exited 1, and the workaround this page printed instead — a
|
|
167
|
+
throwaway `loam.json` at the repository root — then governed every other directory in the clone,
|
|
168
|
+
so `loam init` from anywhere below it refused, and forgetting to delete it silently pointed later
|
|
169
|
+
commands at the example fleet. It is committed now, byte-for-byte the two lines `loam init` writes
|
|
170
|
+
for a docs repo that governs itself, which makes `cd examples/docs` the whole of the setup.
|
|
171
|
+
- **`payment-split-service`'s own `asyncapi.yaml`.** The async axis has the full feature lifecycle
|
|
172
|
+
now — FEAT-101's `specs/payment-service/asyncapi.yaml` demonstrates the merge half on a living
|
|
173
|
+
contract — but the NEW service's contract for the drawn `PaymentSplit` edge is deliberately
|
|
174
|
+
deferred: the edge keeps the message in its title and no `metadata { publishes }`, because that
|
|
175
|
+
metadata is a join and the join demands a contract declaring the send
|
|
176
|
+
(`c4-event.message-undefined` refuses one without it). A
|
|
177
|
+
`specs/payment-split-service/asyncapi.yaml` would ride the archive's creation branch once the
|
|
178
|
+
consumer of `PaymentSplit` exists. The comment in `delta.likec4` says so rather than leaving it to
|
|
179
|
+
be discovered.
|
|
180
|
+
- **A generated Gherkin suite.** `loam gherkin` writes into a *service's* repository, and there are
|
|
181
|
+
none here — this fleet is six repositories, and `docs/` is one of them. The same reason leaves
|
|
182
|
+
`sources` unresolvable and every service `draft`: `loam vouch` only runs where the code is, so no
|
|
183
|
+
SERVICE in this tree can be promoted past `draft`.
|
|
184
|
+
|
|
185
|
+
That is a different word from FEAT-120's `verified` verdict and the two must not be read as one.
|
|
186
|
+
A service's ladder rung (`empty → partial → documented → sourced → vouched`) says a human stamped
|
|
187
|
+
its living spec against the code; a feature's verdict says how its claims were answered. FEAT-120
|
|
188
|
+
is `verified` in a fleet whose services are all `draft`, which is exactly the state a team is in
|
|
189
|
+
the day its first suite goes green.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 0001 — Event publishers write through a transactional outbox
|
|
2
|
+
|
|
3
|
+
Status: accepted
|
|
4
|
+
Date: 2026-08-28
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
A service that writes its own state and then publishes an event about it has two
|
|
9
|
+
places to fail between. The failure is silent and asymmetric: the state change
|
|
10
|
+
lands, the event does not, and every consumer's view of the world is quietly
|
|
11
|
+
wrong until somebody reconciles by hand.
|
|
12
|
+
|
|
13
|
+
## Decision
|
|
14
|
+
|
|
15
|
+
A service that publishes a domain event SHALL write the event and the state
|
|
16
|
+
change it reports in one database transaction, and relay it to the broker
|
|
17
|
+
afterwards. Never a dual write.
|
|
18
|
+
|
|
19
|
+
## Scope
|
|
20
|
+
|
|
21
|
+
This is not a fleet-wide policy every service inherits — that is the shape this
|
|
22
|
+
repository deliberately does not use. It applies where it is tagged: see
|
|
23
|
+
`#obl-outbox` in [the fleet map](../landscape.likec4), which today marks the
|
|
24
|
+
`payment-service → kafka.paymentEvents` edge and nothing else.
|
|
25
|
+
`payment-service`'s [ARCH-PAY-OUTBOX](../../services/payment-service/arch.spec.md)
|
|
26
|
+
is the requirement that keeps it.
|
|
27
|
+
|
|
28
|
+
## Consequences
|
|
29
|
+
|
|
30
|
+
A publisher needs an outbox table and a relay. A consumer must tolerate a
|
|
31
|
+
duplicate: the relay guarantees at-least-once, which is why
|
|
32
|
+
`checkout#CHECKOUT-CHARGE-ONCE` is a promise about the customer's card and not
|
|
33
|
+
about the number of messages.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# The fleet's capability vocabulary, joined to requirements by `Capability:`.
|
|
2
|
+
#
|
|
3
|
+
# Opt-in the OTHER way round from permissions.yaml: the FILE is the opt-in, not the line.
|
|
4
|
+
# A fleet without this file gets no capability findings at all, however many `Capability:`
|
|
5
|
+
# lines its requirements carry; writing it is the moment the axis turns on. `loam validate`
|
|
6
|
+
# then grades both directions — an undeclared name is `capability.unknown` (error, with
|
|
7
|
+
# close-name suggestions), an unreadable file is `capability.invalid` exactly once per run,
|
|
8
|
+
# and a declared capability nothing realizes is `capability.unrealized` (warning, one per
|
|
9
|
+
# capability). `loam list capabilities` reports the whole rollup: which requirements realize
|
|
10
|
+
# each capability, in which services, and how much of that rests on drafts.
|
|
11
|
+
#
|
|
12
|
+
# Ids are flat keys with `/` allowed for nesting — `identity/tokens` is ONE id, exactly the
|
|
13
|
+
# token a requirement writes, never collapsed to `identity`. Descriptions and owners are
|
|
14
|
+
# explanatory; nothing resolves them.
|
|
15
|
+
capabilities:
|
|
16
|
+
checkout:
|
|
17
|
+
description: carry a customer from a filled cart to a confirmed, paid order
|
|
18
|
+
owner: checkout-team
|
|
19
|
+
identity/tokens:
|
|
20
|
+
description: issue and answer for the access tokens every fleet call presents
|
|
21
|
+
owner: platform-identity
|
|
22
|
+
order-notifications:
|
|
23
|
+
description: tell the customer what happened to their order, exactly once per event
|
|
24
|
+
owner: growth-team
|
|
25
|
+
# Declared, and realized by no living requirement anywhere in the fleet — the example's
|
|
26
|
+
# `capability.unrealized` (warning) demonstration. It is the shape this axis exists to
|
|
27
|
+
# make visible: a capability page was agreed in a meeting, the word entered the fleet's
|
|
28
|
+
# vocabulary, and no requirement anywhere claims to implement any part of it.
|
|
29
|
+
payments/settlement:
|
|
30
|
+
description: pay merchants out for captured orders
|
|
31
|
+
owner: payments-team
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
// Global C4 fleet landscape — the LIVING current state.
|
|
2
|
+
// `loam archive` folds a feature's #FEAT-tagged elements/relationships in here.
|
|
3
|
+
// One landscape file, by decision: conflicts resolve through PRs. See SCHEMA.md,
|
|
4
|
+
// "Operating at fleet scale", for the trigger that would change this.
|
|
5
|
+
//
|
|
6
|
+
// `loam validate --all` cross-checks this file against services/: every service
|
|
7
|
+
// directory needs an element here (error), and every element that looks like a
|
|
8
|
+
// service needs a directory (warning). An element is tied to its directory by
|
|
9
|
+
// `metadata { service '<id>' }`, or by its title when there is no binding.
|
|
10
|
+
// Systems that are not ours carry #external and are exempt.
|
|
11
|
+
specification {
|
|
12
|
+
// A grouping element — it stands for no service and owns no directory. The
|
|
13
|
+
// service checks WALK the tree rather than reading only top-level elements:
|
|
14
|
+
// an element is graded at service level when no ancestor already stands for a
|
|
15
|
+
// service, so nesting the fleet inside a boundary costs nothing, and the
|
|
16
|
+
// group itself never raises `landscape.service-undocumented` because it
|
|
17
|
+
// CONTAINS services rather than being one.
|
|
18
|
+
element group
|
|
19
|
+
element softwareSystem
|
|
20
|
+
// Declared here because archive SPLICES a delta's additions verbatim: FEAT-101's
|
|
21
|
+
// new system carries its `api` container along, and the kind has to be legal in
|
|
22
|
+
// THIS document for the merged landscape to parse (archive refuses otherwise).
|
|
23
|
+
element container
|
|
24
|
+
element person
|
|
25
|
+
// A topic is an element, and the kind carries #external rather than each
|
|
26
|
+
// instance doing it: LikeC4 does NOT inherit tags, so a topic nested inside
|
|
27
|
+
// the #external broker is not external itself, and `loam validate --all`
|
|
28
|
+
// would ask for a services/payment.events/ nobody owes
|
|
29
|
+
// (`landscape.service-undocumented`).
|
|
30
|
+
element topic {
|
|
31
|
+
#external
|
|
32
|
+
// The channel is platform too, and the tag has to be HERE rather than on
|
|
33
|
+
// the broker alone: `landscape.platform-candidate` grades each drawn
|
|
34
|
+
// element by how many services consume it, and once the edges point at
|
|
35
|
+
// topics it is the topics that collect three consumers each — tagging only
|
|
36
|
+
// `kafka` would leave three untagged hubs behind.
|
|
37
|
+
#platform
|
|
38
|
+
style {
|
|
39
|
+
shape queue
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
tag external
|
|
43
|
+
// Ubiquitous infrastructure. Three consuming services is where an untagged
|
|
44
|
+
// external hub starts warning (`landscape.platform-candidate`), because that
|
|
45
|
+
// is where one more edge per modelled service stops being a fact about two
|
|
46
|
+
// services and starts being the shape of the map. Tagging keeps both pictures:
|
|
47
|
+
// the fleet view below excludes #platform, and the platform view keeps "who
|
|
48
|
+
// depends on it" answerable during an incident. LikeC4 refuses an undeclared
|
|
49
|
+
// tag, so the declaration here and the tag on the element are both needed.
|
|
50
|
+
tag platform
|
|
51
|
+
// The capability a use case opts in with. `architecture/usecases/` declares
|
|
52
|
+
// no 'specification` of its own — the whole directory is ONE LikeC4 project,
|
|
53
|
+
// and a second declaration there is a duplicate error blamed on both files —
|
|
54
|
+
// so a tag a flow carries is declared here, beside the kinds.
|
|
55
|
+
tag cap-order-notifications
|
|
56
|
+
// The requirement tag beside it: a flow says WHICH of the capability's named
|
|
57
|
+
// promises it keeps, and the id is spelled with every character a tag name
|
|
58
|
+
// cannot carry flattened to `-`. Declared here for the same reason — one
|
|
59
|
+
// specification block serves the whole `architecture/` project.
|
|
60
|
+
tag req-NOTIFY-ONCE
|
|
61
|
+
// An ARCHITECTURAL OBLIGATION, declared in architecture/obligations.yaml and
|
|
62
|
+
// applied HERE, on the objects it holds for. The decision itself is
|
|
63
|
+
// architecture/adrs/0001-transactional-outbox.md; this tag is the architect
|
|
64
|
+
// saying where it applies, and payment-service's ARCH-PAY-OUTBOX is the team
|
|
65
|
+
// saying it is met. Applied to the edge rather than to the service, because
|
|
66
|
+
// an outbox is a property of publishing, and payment-service also calls an
|
|
67
|
+
// API that owes nothing of the kind.
|
|
68
|
+
tag obl-outbox
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
model {
|
|
72
|
+
customer = person 'Customer'
|
|
73
|
+
|
|
74
|
+
// Our own fleet, drawn inside a boundary the way ordinary grouped C4 is. The
|
|
75
|
+
// group has no `metadata { service }` and no directory under services/: it is
|
|
76
|
+
// scenery for the reader, and every check below resolves through it to the
|
|
77
|
+
// element that really stands for each service.
|
|
78
|
+
marketplace = group 'Marketplace' {
|
|
79
|
+
description 'Everything this organisation runs'
|
|
80
|
+
|
|
81
|
+
checkoutWeb = softwareSystem 'checkout-web' {
|
|
82
|
+
description 'Customer-facing checkout UI'
|
|
83
|
+
metadata {
|
|
84
|
+
service 'checkout-web'
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
orderService = softwareSystem 'order-service' {
|
|
88
|
+
description 'Owns the order lifecycle'
|
|
89
|
+
metadata {
|
|
90
|
+
service 'order-service'
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
paymentService = softwareSystem 'payment-service' {
|
|
94
|
+
description 'Owns payment authorization/capture'
|
|
95
|
+
metadata {
|
|
96
|
+
service 'payment-service'
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
identityService = softwareSystem 'identity-service' {
|
|
100
|
+
description 'Issues and introspects access tokens'
|
|
101
|
+
metadata {
|
|
102
|
+
service 'identity-service'
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
notificationService = softwareSystem 'notification-service' {
|
|
106
|
+
description 'Turns events into customer email and push'
|
|
107
|
+
metadata {
|
|
108
|
+
service 'notification-service'
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
kafka = softwareSystem 'kafka' {
|
|
114
|
+
// Not one of ours: no services/kafka/ is expected, and none is asked for.
|
|
115
|
+
#external
|
|
116
|
+
// Three of our services reach it, which is exactly the count at which the
|
|
117
|
+
// untagged version of this element becomes `landscape.platform-candidate`.
|
|
118
|
+
#platform
|
|
119
|
+
description 'Event backbone'
|
|
120
|
+
// Edges point HERE, not at the broker. Two producers make no difference;
|
|
121
|
+
// sixty do — a broker drawn as one element is the node every service in the
|
|
122
|
+
// fleet points at, and a view over it is a star nobody can read. The topic
|
|
123
|
+
// is also the truer target: what a producer and a consumer share is the
|
|
124
|
+
// channel, never the server it happens to live on.
|
|
125
|
+
paymentEvents = topic 'payment.events'
|
|
126
|
+
orderEvents = topic 'order.events'
|
|
127
|
+
crmEvents = topic 'crm.events'
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
stripe = softwareSystem 'stripe' {
|
|
131
|
+
#external
|
|
132
|
+
description 'Card acquirer'
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
salesforce = softwareSystem 'salesforce' {
|
|
136
|
+
#external
|
|
137
|
+
description 'CRM of record — the fleet reads its events and writes none'
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
customer -> marketplace.checkoutWeb 'Uses'
|
|
141
|
+
|
|
142
|
+
// The synchronous spine. Every one of these resolves against the TARGET's
|
|
143
|
+
// openapi.yaml: `loam validate` fails the fleet when an `op` names an
|
|
144
|
+
// operation the callee does not define ('spine.op-undefined`), which is what
|
|
145
|
+
// turns a rename in one repository into a red build in the one that depended
|
|
146
|
+
// on it.
|
|
147
|
+
marketplace.checkoutWeb -> marketplace.orderService 'Calls createOrder' {
|
|
148
|
+
metadata {
|
|
149
|
+
op 'createOrder'
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
marketplace.checkoutWeb -> marketplace.orderService 'Calls getOrder' {
|
|
153
|
+
metadata {
|
|
154
|
+
op 'getOrder'
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Deliberately unlinked, and the example's demonstration of
|
|
158
|
+
// 'spine.op-link-missing` (warn): an edge whose title starts with "Call" and
|
|
159
|
+
// carries no `metadata { op }` is drawn but joined to nothing, so no check can
|
|
160
|
+
// tell whether the operation behind it still exists. Every other call edge
|
|
161
|
+
// here carries its op; this one is what the warning looks like.
|
|
162
|
+
marketplace.checkoutWeb -> marketplace.paymentService 'Calls the payment API'
|
|
163
|
+
marketplace.orderService -> marketplace.paymentService 'Calls authorizePayment' {
|
|
164
|
+
metadata {
|
|
165
|
+
op 'authorizePayment'
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
marketplace.orderService -> marketplace.identityService 'Calls introspectToken' {
|
|
169
|
+
metadata {
|
|
170
|
+
op 'introspectToken'
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// The other half of the deprecation story, and the example's
|
|
174
|
+
// 'spine.op-deprecated` (warn): identity-service still DEFINES validateToken,
|
|
175
|
+
// so the contract holds and this is not an error — but its OpenAPI marks the
|
|
176
|
+
// operation `deprecated: true`, and this edge is the consumer that has not
|
|
177
|
+
// migrated yet. The warning is addressed to payment-service, not to identity.
|
|
178
|
+
marketplace.paymentService -> marketplace.identityService 'Calls validateToken' {
|
|
179
|
+
metadata {
|
|
180
|
+
op 'validateToken'
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// An edge into a system nobody owns a directory for. It carries no `op`
|
|
184
|
+
// because there is no contract in this repository to resolve one against, and
|
|
185
|
+
// it raises no warning because its title does not claim to be a call into a
|
|
186
|
+
// fleet service.
|
|
187
|
+
marketplace.paymentService -> stripe 'Authorizes cards'
|
|
188
|
+
|
|
189
|
+
// The event spine, the async mirror of `metadata { op }`: the name must be a
|
|
190
|
+
// message the PRODUCER's own asyncapi.yaml declares an `action: send` for, or
|
|
191
|
+
// 'spine.message-undefined` fires. A consumer's edge carries
|
|
192
|
+
// `metadata { consumes }` instead, and its name has to have a producer
|
|
193
|
+
// SOMEWHERE in the fleet — the one check no single repository can answer.
|
|
194
|
+
//
|
|
195
|
+
// THE ARROW FOLLOWS THE MESSAGE, and that is load-bearing rather than
|
|
196
|
+
// aesthetic. `publishes` binds the edge's SOURCE and `consumes` binds its
|
|
197
|
+
// TARGET, so a consume edge drawn the other way round — `orderService ->
|
|
198
|
+
// kafka.paymentEvents` — binds to nothing at all: the metadata parses, the
|
|
199
|
+
// document validates, and the check silently grades zero edges. Producer to
|
|
200
|
+
// topic, topic to consumer, every time.
|
|
201
|
+
marketplace.paymentService -> kafka.paymentEvents 'Publishes PaymentAuthorized' {
|
|
202
|
+
#obl-outbox
|
|
203
|
+
metadata {
|
|
204
|
+
publishes 'payment.PaymentAuthorized'
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
marketplace.paymentService -> kafka.paymentEvents 'Publishes PaymentCaptured' {
|
|
208
|
+
metadata {
|
|
209
|
+
publishes 'payment.PaymentCaptured'
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
kafka.paymentEvents -> marketplace.orderService 'PaymentAuthorized advances the order' {
|
|
213
|
+
metadata {
|
|
214
|
+
consumes 'payment.PaymentAuthorized'
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
marketplace.orderService -> kafka.orderEvents 'Publishes OrderPlaced' {
|
|
218
|
+
metadata {
|
|
219
|
+
publishes 'order.OrderPlaced'
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
marketplace.orderService -> marketplace.paymentService 'Calls refundPayment' {
|
|
223
|
+
metadata { op 'refundPayment' }
|
|
224
|
+
}
|
|
225
|
+
kafka.orderEvents -> marketplace.notificationService 'OrderPlaced triggers the confirmation' {
|
|
226
|
+
metadata {
|
|
227
|
+
consumes 'order.OrderPlaced'
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
kafka.paymentEvents -> marketplace.notificationService 'PaymentCaptured triggers the receipt' {
|
|
231
|
+
metadata {
|
|
232
|
+
consumes 'payment.PaymentCaptured'
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
kafka.paymentEvents -> marketplace.notificationService 'PaymentRefunded triggers the refund notice' {
|
|
236
|
+
metadata {
|
|
237
|
+
consumes 'payment.PaymentRefunded'
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// A producer OUTSIDE the fleet, expressed rather than left implicit. Without
|
|
241
|
+
// this edge notification-service's `consumes 'crm.CustomerUpdated'` would be
|
|
242
|
+
// 'spine.message-unproduced` (error) — nobody in the fleet declares it is
|
|
243
|
+
// sent — and the exit ramp people take from that error is deleting the link.
|
|
244
|
+
// The edge moves the contract question to the one file that can settle it:
|
|
245
|
+
// the consumer's own asyncapi.yaml, which must define the payload
|
|
246
|
+
// ('spine.message-external` fires while it does not).
|
|
247
|
+
salesforce -> kafka.crmEvents 'Publishes CustomerUpdated' {
|
|
248
|
+
metadata {
|
|
249
|
+
publishes 'crm.CustomerUpdated'
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
kafka.crmEvents -> marketplace.notificationService 'CustomerUpdated refreshes contact details' {
|
|
253
|
+
metadata {
|
|
254
|
+
consumes 'crm.CustomerUpdated'
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Views are LikeC4's renderer's, never loam's — nothing below is read by any
|
|
260
|
+
// check. Three of them rather than one `include *`, because at fleet scale a
|
|
261
|
+
// single view holding every call is both the slow one to compute and the one
|
|
262
|
+
// nobody can read: the synchronous map, the event spine and the platform
|
|
263
|
+
// dependencies answer different questions and belong on different pages.
|
|
264
|
+
views {
|
|
265
|
+
view landscape {
|
|
266
|
+
title 'Fleet — calls between our own services'
|
|
267
|
+
include *
|
|
268
|
+
exclude element.tag = #external
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
view events {
|
|
272
|
+
title 'Fleet — the event spine'
|
|
273
|
+
include kafka, kafka.*, * -> kafka.*, kafka.* -> *
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
view platform {
|
|
277
|
+
title 'Fleet — who depends on shared infrastructure'
|
|
278
|
+
include element.tag = #platform, * -> element.tag = #platform
|
|
279
|
+
}
|
|
280
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# The fleet's ARCHITECTURAL OBLIGATIONS: rules an architect decided once and
|
|
2
|
+
# applies where they apply. The decision itself lives in an ADR; a `#obl-<id>`
|
|
3
|
+
# tag on architecture/landscape.likec4 says WHERE it holds; and the owning
|
|
4
|
+
# team's `Covers:` line in its arch.spec.md says it is met, with a scenario.
|
|
5
|
+
#
|
|
6
|
+
# The three grades this file earns are the point of declaring names at all: a
|
|
7
|
+
# tag naming nothing here is `obligation.unknown` (error — a typo reads exactly
|
|
8
|
+
# like a rule), a name nothing tags is `obligation.unapplied` (warn), and a
|
|
9
|
+
# tagged object no living requirement covers is `obligation.uncovered` (warn).
|
|
10
|
+
#
|
|
11
|
+
# An id is its own tag suffix, so it may hold letters, digits, `_` and `-` only.
|
|
12
|
+
obligations:
|
|
13
|
+
outbox:
|
|
14
|
+
description: >-
|
|
15
|
+
A service that publishes a domain event writes the event and the state
|
|
16
|
+
change it reports in one transaction, relayed to the broker afterwards —
|
|
17
|
+
never a dual write.
|
|
18
|
+
adr: architecture/adrs/0001-transactional-outbox.md
|
|
19
|
+
idempotency-key:
|
|
20
|
+
description: >-
|
|
21
|
+
A write a caller may retry accepts an idempotency key and returns the
|
|
22
|
+
first result for a repeat. Declared and applied nowhere yet, which is
|
|
23
|
+
what `obligation.unapplied` is for.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# The fleet's authorization vocabulary, joined to requirements by `Requires:`.
|
|
2
|
+
#
|
|
3
|
+
# Opt-in: a fleet with no `Requires:` line owes no file at all. The first such line makes an
|
|
4
|
+
# absent declaration an error rather than letting each service invent a permission locally,
|
|
5
|
+
# which is how one capability ends up spelled three ways across three repositories.
|
|
6
|
+
#
|
|
7
|
+
# The unit is the pair `<subject>/<permission>`. The subject is the entity the check is
|
|
8
|
+
# performed ON — `user` for a customer acting on their own data, `service` for a fleet service
|
|
9
|
+
# acting on its own behalf — not necessarily the caller. `loam validate` grades exactly two
|
|
10
|
+
# things here: that every `Requires:` pair is declared (`permissions.unknown`, error), and that
|
|
11
|
+
# every declared pair is named by some requirement (`permissions.unenforced`, warning — the
|
|
12
|
+
# authorization mirror of `api.ungoverned`).
|
|
13
|
+
#
|
|
14
|
+
# `owned_by` and `enforced_by` are explanatory and are NOT resolved against services/. This is a
|
|
15
|
+
# spelling and coverage join, not an identity-provider audit: nothing here proves the running
|
|
16
|
+
# system implements a declared permission, and pretending otherwise would be the most dangerous
|
|
17
|
+
# green tick in the repository.
|
|
18
|
+
subjects:
|
|
19
|
+
user:
|
|
20
|
+
description: a human account acting on its own data
|
|
21
|
+
service:
|
|
22
|
+
description: a fleet service acting on its own behalf, with a machine token
|
|
23
|
+
|
|
24
|
+
permissions:
|
|
25
|
+
user:
|
|
26
|
+
payments:refund:
|
|
27
|
+
description: refund a captured payment
|
|
28
|
+
owned_by: identity-service
|
|
29
|
+
enforced_by: [payment-service]
|
|
30
|
+
orders:cancel:
|
|
31
|
+
description: cancel an order that has not shipped
|
|
32
|
+
owned_by: identity-service
|
|
33
|
+
enforced_by: [order-service]
|
|
34
|
+
# Declared, and named by no requirement anywhere in the fleet — the example's
|
|
35
|
+
# `permissions.unenforced` (warning) demonstration. It is the shape a vocabulary drifts
|
|
36
|
+
# into: a permission survives the feature that introduced it, the requirement that needed
|
|
37
|
+
# it is rewritten, and the declaration stays behind looking enforced.
|
|
38
|
+
profile:read:
|
|
39
|
+
description: read a customer's own profile
|
|
40
|
+
owned_by: identity-service
|
|
41
|
+
enforced_by: [identity-service]
|
|
42
|
+
service:
|
|
43
|
+
payments:capture:
|
|
44
|
+
description: capture funds a previous authorization reserved
|
|
45
|
+
owned_by: identity-service
|
|
46
|
+
enforced_by: [payment-service]
|
|
47
|
+
tokens:introspect:
|
|
48
|
+
description: ask identity-service what a token currently grants
|
|
49
|
+
owned_by: identity-service
|
|
50
|
+
enforced_by: [identity-service]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// generated by loam — the subsystem tree under services/, one view per subsystem.
|
|
2
|
+
// Do not edit: `loam subsystem sync` regenerates this file from the directories,
|
|
3
|
+
// and `loam validate --all` reports `subsystem.views-stale` when it drifts.
|
|
4
|
+
|
|
5
|
+
views {
|
|
6
|
+
// services/platform
|
|
7
|
+
view subsystem_platform {
|
|
8
|
+
include marketplace.identityService
|
|
9
|
+
include marketplace.notificationService
|
|
10
|
+
}
|
|
11
|
+
}
|