@ybotok/loam 0.2.0-alpha.1 → 0.2.0-alpha.13
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 +3448 -0
- package/COMPARISON.md +91 -3
- package/CONTRIBUTING.md +37 -0
- package/MIGRATING-from-OpenSpec.md +47 -23
- package/QUICKSTART.md +189 -12
- package/README.md +274 -65
- package/ROADMAP.md +572 -31
- package/SCHEMA.md +1709 -155
- package/WORKFLOW.md +298 -72
- package/dist/cli.js +26 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +5 -10
- package/dist/commands/adopt/adopt.js.map +1 -1
- package/dist/commands/adopt/render.js +50 -9
- package/dist/commands/adopt/render.js.map +1 -1
- package/dist/commands/archive/archive.js +16 -19
- package/dist/commands/archive/archive.js.map +1 -1
- package/dist/commands/archive/closing.js +42 -0
- package/dist/commands/archive/closing.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +36 -42
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/consumers.js +56 -0
- package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +77 -43
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/document/head.js +151 -0
- package/dist/commands/archive/plan/document/head.js.map +1 -0
- package/dist/commands/archive/plan/document/links.js +284 -0
- package/dist/commands/archive/plan/document/links.js.map +1 -0
- package/dist/commands/archive/plan/document/run.js +136 -0
- package/dist/commands/archive/plan/document/run.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +21 -19
- package/dist/commands/archive/plan/gate.js.map +1 -1
- package/dist/commands/archive/plan/landscape.js +167 -30
- package/dist/commands/archive/plan/landscape.js.map +1 -1
- package/dist/commands/archive/plan/model/extending.js +85 -0
- package/dist/commands/archive/plan/model/extending.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +14 -19
- package/dist/commands/archive/plan/refusal.js.map +1 -1
- package/dist/commands/archive/plan/specs.js +137 -56
- package/dist/commands/archive/plan/specs.js.map +1 -1
- package/dist/commands/archive/plan/state.js +3 -0
- package/dist/commands/archive/plan/state.js.map +1 -1
- package/dist/commands/archive/run.js +134 -30
- package/dist/commands/archive/run.js.map +1 -1
- package/dist/commands/archive/shipped.js +49 -0
- package/dist/commands/archive/shipped.js.map +1 -0
- package/dist/commands/context/context.js +85 -18
- package/dist/commands/context/context.js.map +1 -1
- package/dist/commands/context/print.js +29 -7
- package/dist/commands/context/print.js.map +1 -1
- package/dist/commands/delta/delta.js +102 -14
- package/dist/commands/delta/delta.js.map +1 -1
- package/dist/commands/delta/print.js +17 -1
- package/dist/commands/delta/print.js.map +1 -1
- package/dist/commands/dependencies.js +3 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +20 -27
- package/dist/commands/diff/diff.js.map +1 -1
- package/dist/commands/doctor.js +60 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +89 -13
- package/dist/commands/explain/explain.js.map +1 -1
- package/dist/commands/explore.js +16 -10
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +45 -8
- package/dist/commands/gate/gate.js.map +1 -1
- package/dist/commands/gate/print.js +15 -3
- package/dist/commands/gate/print.js.map +1 -1
- package/dist/commands/gherkin/commit.js +13 -54
- package/dist/commands/gherkin/commit.js.map +1 -1
- package/dist/commands/gherkin/gherkin.js +36 -20
- package/dist/commands/gherkin/gherkin.js.map +1 -1
- package/dist/commands/gherkin/reconcile.js +10 -13
- package/dist/commands/gherkin/reconcile.js.map +1 -1
- package/dist/commands/init/first-hour.js +44 -0
- package/dist/commands/init/first-hour.js.map +1 -1
- package/dist/commands/init/init.js +18 -22
- package/dist/commands/init/init.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +4 -6
- package/dist/commands/list/campaign/campaign.js.map +1 -1
- package/dist/commands/list/json.js +5 -7
- package/dist/commands/list/json.js.map +1 -1
- package/dist/commands/list/list.js +44 -29
- package/dist/commands/list/list.js.map +1 -1
- package/dist/commands/list/print.js +52 -9
- package/dist/commands/list/print.js.map +1 -1
- package/dist/commands/list/suites/suites.js +140 -0
- package/dist/commands/list/suites/suites.js.map +1 -0
- package/dist/commands/list/views.js +37 -34
- package/dist/commands/list/views.js.map +1 -1
- package/dist/commands/mcp/dispatch.js +91 -36
- package/dist/commands/mcp/dispatch.js.map +1 -1
- package/dist/commands/mcp/mcp.js +56 -15
- package/dist/commands/mcp/mcp.js.map +1 -1
- package/dist/commands/mcp/serve.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/active.js +27 -22
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/target.js +2 -2
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/error.js +7 -8
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
- package/dist/commands/new/capability-template.js +118 -0
- package/dist/commands/new/capability-template.js.map +1 -0
- package/dist/commands/new/commit.js +8 -22
- package/dist/commands/new/commit.js.map +1 -1
- package/dist/commands/new/modifies.js +206 -0
- package/dist/commands/new/modifies.js.map +1 -0
- package/dist/commands/new/new.js +59 -14
- package/dist/commands/new/new.js.map +1 -1
- package/dist/commands/new/templates.js +48 -124
- package/dist/commands/new/templates.js.map +1 -1
- package/dist/commands/open.js +3 -7
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/policy/gate.js +27 -0
- package/dist/commands/policy/gate.js.map +1 -1
- package/dist/commands/rebase/plan.js +2 -2
- package/dist/commands/rebase/plan.js.map +1 -1
- package/dist/commands/rebase/rebase.js +60 -35
- package/dist/commands/rebase/rebase.js.map +1 -1
- package/dist/commands/seed/commit.js +55 -26
- package/dist/commands/seed/commit.js.map +1 -1
- package/dist/commands/seed/plan.js +158 -13
- package/dist/commands/seed/plan.js.map +1 -1
- package/dist/commands/seed/seed.js +13 -11
- package/dist/commands/seed/seed.js.map +1 -1
- package/dist/commands/show/feature.js +9 -5
- package/dist/commands/show/feature.js.map +1 -1
- package/dist/commands/show/introduced.js +157 -0
- package/dist/commands/show/introduced.js.map +1 -0
- package/dist/commands/show/marks.js +35 -6
- package/dist/commands/show/marks.js.map +1 -1
- package/dist/commands/show/service.js +41 -33
- package/dist/commands/show/service.js.map +1 -1
- package/dist/commands/show/show.js +17 -7
- package/dist/commands/show/show.js.map +1 -1
- package/dist/commands/status/fleet-next.js +90 -0
- package/dist/commands/status/fleet-next.js.map +1 -0
- package/dist/commands/status/json.js +2 -0
- package/dist/commands/status/json.js.map +1 -1
- package/dist/commands/status/print.js +89 -37
- package/dist/commands/status/print.js.map +1 -1
- package/dist/commands/status/status.js +3 -7
- package/dist/commands/status/status.js.map +1 -1
- package/dist/commands/steps/steps.js +103 -23
- package/dist/commands/steps/steps.js.map +1 -1
- package/dist/commands/subsystem/edit.js +7 -7
- package/dist/commands/subsystem/edit.js.map +1 -1
- package/dist/commands/subsystem/move.js +106 -46
- package/dist/commands/subsystem/move.js.map +1 -1
- package/dist/commands/subsystem/query.js +2 -4
- package/dist/commands/subsystem/query.js.map +1 -1
- package/dist/commands/subsystem/subsystem.js +4 -7
- package/dist/commands/subsystem/subsystem.js.map +1 -1
- package/dist/commands/subsystem/sync.js +289 -74
- package/dist/commands/subsystem/sync.js.map +1 -1
- package/dist/commands/subsystem/txn/exclude.js +132 -0
- package/dist/commands/subsystem/txn/exclude.js.map +1 -0
- package/dist/commands/subsystem/txn/links.js +128 -0
- package/dist/commands/subsystem/txn/links.js.map +1 -0
- package/dist/commands/subsystem/txn/report.js +174 -0
- package/dist/commands/subsystem/txn/report.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +147 -45
- package/dist/commands/subsystem/txn/txn.js.map +1 -1
- package/dist/commands/subsystem/txn/views.js +200 -21
- package/dist/commands/subsystem/txn/views.js.map +1 -1
- package/dist/commands/tasks/actions.js +107 -0
- package/dist/commands/tasks/actions.js.map +1 -0
- package/dist/commands/tasks/render.js +253 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +119 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +42 -26
- package/dist/commands/unarchive/manifest.js.map +1 -1
- package/dist/commands/unarchive/restore.js +83 -33
- package/dist/commands/unarchive/restore.js.map +1 -1
- package/dist/commands/unarchive/unarchive.js +22 -30
- package/dist/commands/unarchive/unarchive.js.map +1 -1
- package/dist/commands/validate/arch-coverage.js +78 -27
- package/dist/commands/validate/arch-coverage.js.map +1 -1
- package/dist/commands/validate/checks/fleet-shape.js +34 -126
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
- package/dist/commands/validate/checks/health-deps.js +9 -6
- package/dist/commands/validate/checks/health-deps.js.map +1 -1
- package/dist/commands/validate/checks/introduced.js +102 -0
- package/dist/commands/validate/checks/introduced.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +18 -8
- package/dist/commands/validate/checks/requirements.js.map +1 -1
- package/dist/commands/validate/checks/sources.js +11 -2
- package/dist/commands/validate/checks/sources.js.map +1 -1
- package/dist/commands/validate/coverage/covers-after.js +105 -0
- package/dist/commands/validate/coverage/covers-after.js.map +1 -0
- package/dist/commands/validate/feature.js +26 -20
- package/dist/commands/validate/feature.js.map +1 -1
- package/dist/commands/validate/fleet/census.js +37 -13
- package/dist/commands/validate/fleet/census.js.map +1 -1
- package/dist/commands/validate/fleet/landscape.js +144 -126
- package/dist/commands/validate/fleet/landscape.js.map +1 -1
- package/dist/commands/validate/fleet/load.js +66 -0
- package/dist/commands/validate/fleet/load.js.map +1 -1
- package/dist/commands/validate/fleet/map/attest.js +98 -0
- package/dist/commands/validate/fleet/map/attest.js.map +1 -0
- package/dist/commands/validate/fleet/map/bindings.js +107 -0
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
- package/dist/commands/validate/fleet/map/consumers.js +244 -0
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
- package/dist/commands/validate/fleet/map/isolation.js +116 -0
- package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
- package/dist/commands/validate/fleet/map/usecases.js +54 -0
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +44 -14
- package/dist/commands/validate/fleet/obligations.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/print.js +10 -2
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -1
- package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +50 -15
- package/dist/commands/validate/fleet/views/ids.js.map +1 -1
- package/dist/commands/validate/fleet/views/projects.js +278 -0
- package/dist/commands/validate/fleet/views/projects.js.map +1 -0
- package/dist/commands/validate/fleet/views/root-documents.js +83 -0
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +40 -47
- package/dist/commands/validate/fleet/views/stale.js.map +1 -1
- package/dist/commands/validate/links/corpus.js +1 -4
- package/dist/commands/validate/links/corpus.js.map +1 -1
- package/dist/commands/validate/links/glossary.js.map +1 -1
- package/dist/commands/validate/render/repeats.js +63 -0
- package/dist/commands/validate/render/repeats.js.map +1 -0
- package/dist/commands/validate/render/rollups.js +115 -0
- package/dist/commands/validate/render/rollups.js.map +1 -0
- package/dist/commands/validate/render/text.js +199 -0
- package/dist/commands/validate/render/text.js.map +1 -0
- package/dist/commands/validate/report.js +36 -160
- package/dist/commands/validate/report.js.map +1 -1
- package/dist/commands/validate/scope.js +113 -0
- package/dist/commands/validate/scope.js.map +1 -0
- package/dist/commands/validate/service/api.js +21 -107
- package/dist/commands/validate/service/api.js.map +1 -1
- package/dist/commands/validate/service/contracts/generated.js +134 -0
- package/dist/commands/validate/service/contracts/generated.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +36 -14
- package/dist/commands/validate/service/events/events.js.map +1 -1
- package/dist/commands/validate/service/events/message-producers.js +1 -1
- package/dist/commands/validate/service/events/message-producers.js.map +1 -1
- package/dist/commands/validate/service/evidence-pins.js +56 -10
- package/dist/commands/validate/service/evidence-pins.js.map +1 -1
- package/dist/commands/validate/service/model/diverged.js +226 -0
- package/dist/commands/validate/service/model/diverged.js.map +1 -0
- package/dist/commands/validate/service/model/grade.js +163 -0
- package/dist/commands/validate/service/model/grade.js.map +1 -0
- package/dist/commands/validate/service/service.js +121 -61
- package/dist/commands/validate/service/service.js.map +1 -1
- package/dist/commands/validate/service/specs.js +88 -28
- package/dist/commands/validate/service/specs.js.map +1 -1
- package/dist/commands/validate/service/spine.js +38 -3
- package/dist/commands/validate/service/spine.js.map +1 -1
- package/dist/commands/validate/service/usecases/tags.js +113 -0
- package/dist/commands/validate/service/usecases/tags.js.map +1 -0
- package/dist/commands/validate/service/usecases/usecases.js +209 -0
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/validate.js +85 -60
- package/dist/commands/validate/validate.js.map +1 -1
- package/dist/commands/verify/cross/diff.js +2 -6
- package/dist/commands/verify/cross/diff.js.map +1 -1
- package/dist/commands/verify/evidence/contract.js +1 -1
- package/dist/commands/verify/evidence/contract.js.map +1 -1
- package/dist/commands/verify/evidence/read.js +12 -3
- package/dist/commands/verify/evidence/read.js.map +1 -1
- package/dist/commands/verify/frozen.js +45 -23
- package/dist/commands/verify/frozen.js.map +1 -1
- package/dist/commands/verify/record.js +69 -17
- package/dist/commands/verify/record.js.map +1 -1
- package/dist/commands/verify/report.js +27 -44
- package/dist/commands/verify/report.js.map +1 -1
- package/dist/commands/verify/results.js +112 -30
- package/dist/commands/verify/results.js.map +1 -1
- package/dist/commands/verify/verify.js +55 -52
- package/dist/commands/verify/verify.js.map +1 -1
- package/dist/commands/vouch/pack/pack.js +2 -2
- package/dist/commands/vouch/pack/pack.js.map +1 -1
- package/dist/commands/vouch/pack/print.js +1 -6
- package/dist/commands/vouch/pack/print.js.map +1 -1
- package/dist/commands/vouch/pack/sections.js +1 -2
- package/dist/commands/vouch/pack/sections.js.map +1 -1
- package/dist/commands/vouch/run.js +26 -81
- package/dist/commands/vouch/run.js.map +1 -1
- package/dist/commands/vouch/sample/plan.js +20 -34
- package/dist/commands/vouch/sample/plan.js.map +1 -1
- package/dist/commands/vouch/vet/verify.js +39 -7
- package/dist/commands/vouch/vet/verify.js.map +1 -1
- package/dist/commands/vouch/vouch.js +10 -17
- package/dist/commands/vouch/vouch.js.map +1 -1
- package/dist/core/agent/agents-md/command-map.js +81 -106
- package/dist/core/agent/agents-md/command-map.js.map +1 -1
- package/dist/core/agent/agents-md/map/explain.js +21 -9
- package/dist/core/agent/agents-md/map/explain.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/context.js +17 -8
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
- package/dist/core/agent/agents-md/map/mcp.js +10 -7
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
- package/dist/core/agent/agents-md/map/status.js +24 -8
- package/dist/core/agent/agents-md/map/status.js.map +1 -1
- package/dist/core/agent/agents-md/map/subsystem.js +80 -8
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
- package/dist/core/agent/agents-md/map/usecases.js +88 -10
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
- package/dist/core/agent/agents-md/refusals.js +49 -22
- package/dist/core/agent/agents-md/refusals.js.map +1 -1
- package/dist/core/agent/agents-md.js +39 -6
- package/dist/core/agent/agents-md.js.map +1 -1
- package/dist/core/agent/agents-stamp.js +10 -0
- package/dist/core/agent/agents-stamp.js.map +1 -1
- package/dist/core/agent/protocol.js +1 -1
- package/dist/core/agent/protocol.js.map +1 -1
- package/dist/core/agent/scaffold.js +10 -15
- package/dist/core/agent/scaffold.js.map +1 -1
- package/dist/core/agent/support/report.js +46 -5
- package/dist/core/agent/support/report.js.map +1 -1
- package/dist/core/agent/tools/dialects.js +1 -0
- package/dist/core/agent/tools/dialects.js.map +1 -1
- package/dist/core/agent/tools/registry.js +41 -76
- package/dist/core/agent/tools/registry.js.map +1 -1
- package/dist/core/agent/workflows/adopt.js +158 -11
- package/dist/core/agent/workflows/adopt.js.map +1 -1
- package/dist/core/agent/workflows/check.js +78 -39
- package/dist/core/agent/workflows/check.js.map +1 -1
- package/dist/core/agent/workflows/closing.js +88 -27
- package/dist/core/agent/workflows/closing.js.map +1 -1
- package/dist/core/agent/workflows/feature.js +128 -13
- package/dist/core/agent/workflows/feature.js.map +1 -1
- package/dist/core/agent/workflows/implement.js +96 -13
- package/dist/core/agent/workflows/implement.js.map +1 -1
- package/dist/core/agent/workflows/reference/authoring.js +106 -4
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
- package/dist/core/agent/workflows/reference/codes.js +8 -6
- package/dist/core/agent/workflows/reference/codes.js.map +1 -1
- package/dist/core/agent/workflows/reference/done-check.js +37 -15
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
- package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +6 -3
- package/dist/core/agent/workflows/reference/reference.js.map +1 -1
- package/dist/core/agent/workflows/reference/spine.js +68 -27
- package/dist/core/agent/workflows/reference/spine.js.map +1 -1
- package/dist/core/asyncapi/baseline/plan.js +14 -81
- package/dist/core/asyncapi/baseline/plan.js.map +1 -1
- package/dist/core/asyncapi/digest.js +30 -25
- package/dist/core/asyncapi/digest.js.map +1 -1
- package/dist/core/asyncapi/merge/components.js +5 -4
- package/dist/core/asyncapi/merge/components.js.map +1 -1
- package/dist/core/asyncapi/merge/error.js +7 -2
- package/dist/core/asyncapi/merge/error.js.map +1 -1
- package/dist/core/asyncapi/merge/markers.js +32 -50
- package/dist/core/asyncapi/merge/markers.js.map +1 -1
- package/dist/core/asyncapi/merge/merge.js +33 -53
- package/dist/core/asyncapi/merge/merge.js.map +1 -1
- package/dist/core/asyncapi/merge/pin.js +12 -36
- package/dist/core/asyncapi/merge/pin.js.map +1 -1
- package/dist/core/asyncapi/model.js.map +1 -1
- package/dist/core/asyncapi/read.js +36 -12
- package/dist/core/asyncapi/read.js.map +1 -1
- package/dist/core/brief/brief.js +96 -36
- package/dist/core/brief/brief.js.map +1 -1
- package/dist/core/brief/checks.js +138 -3
- package/dist/core/brief/checks.js.map +1 -1
- package/dist/core/brief/landscape.js +209 -130
- package/dist/core/brief/landscape.js.map +1 -1
- package/dist/core/brief/map/extend.js +84 -0
- package/dist/core/brief/map/extend.js.map +1 -0
- package/dist/core/brief/map/owed.js +266 -0
- package/dist/core/brief/map/owed.js.map +1 -0
- package/dist/core/brief/targets.js +109 -31
- package/dist/core/brief/targets.js.map +1 -1
- package/dist/core/brief/unchecked.js +14 -3
- package/dist/core/brief/unchecked.js.map +1 -1
- package/dist/core/c4/arch.js +90 -182
- package/dist/core/c4/arch.js.map +1 -1
- package/dist/core/c4/direction/direction.js +114 -0
- package/dist/core/c4/direction/direction.js.map +1 -0
- package/dist/core/c4/likec4.js +169 -14
- package/dist/core/c4/likec4.js.map +1 -1
- package/dist/core/c4/locate/unlocated.js +150 -0
- package/dist/core/c4/locate/unlocated.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +160 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -1
- package/dist/core/c4/parsed/values.js +54 -1
- package/dist/core/c4/parsed/values.js.map +1 -1
- package/dist/core/c4/parsed/view-ids.js +39 -1
- package/dist/core/c4/parsed/view-ids.js.map +1 -1
- package/dist/core/c4/prefetch/fleet.js +134 -0
- package/dist/core/c4/prefetch/fleet.js.map +1 -0
- package/dist/core/c4/project/architecture.js +123 -7
- package/dist/core/c4/project/architecture.js.map +1 -1
- package/dist/core/c4/project/batch.js +140 -0
- package/dist/core/c4/project/batch.js.map +1 -0
- package/dist/core/c4/project/documents.js +43 -12
- package/dist/core/c4/project/documents.js.map +1 -1
- package/dist/core/c4/project/load.js +79 -43
- package/dist/core/c4/project/load.js.map +1 -1
- package/dist/core/c4/project/staged.js +277 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/attested.js +0 -0
- package/dist/core/c4/resolve/attested.js.map +1 -0
- package/dist/core/c4/resolve/external.js +51 -0
- package/dist/core/c4/resolve/external.js.map +1 -0
- package/dist/core/c4/resolve/service.js +78 -17
- package/dist/core/c4/resolve/service.js.map +1 -1
- package/dist/core/c4/resolve/steps.js +290 -0
- package/dist/core/c4/resolve/steps.js.map +1 -0
- package/dist/core/c4/resolve/systems.js +154 -0
- package/dist/core/c4/resolve/systems.js.map +1 -0
- package/dist/core/c4/root-project/exclude.js +352 -0
- package/dist/core/c4/root-project/exclude.js.map +1 -0
- package/dist/core/c4/seed/template.js +65 -1
- package/dist/core/c4/seed/template.js.map +1 -1
- package/dist/core/c4/service-model/created/models.js +96 -0
- package/dist/core/c4/service-model/created/models.js.map +1 -0
- package/dist/core/c4/service-model/documents.js +47 -0
- package/dist/core/c4/service-model/documents.js.map +1 -0
- package/dist/core/c4/service-model/fleet/extending.js +82 -0
- package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
- package/dist/core/c4/service-model/load.js +165 -0
- package/dist/core/c4/service-model/load.js.map +1 -0
- package/dist/core/c4/service-model/renderer.js +128 -0
- package/dist/core/c4/service-model/renderer.js.map +1 -0
- package/dist/core/c4/service-model/shape.js +106 -0
- package/dist/core/c4/service-model/shape.js.map +1 -0
- package/dist/core/c4/service-model/slice.js +188 -0
- package/dist/core/c4/service-model/slice.js.map +1 -0
- package/dist/core/c4/source-mask.js +297 -10
- package/dist/core/c4/source-mask.js.map +1 -1
- package/dist/core/c4/source-scan.js +222 -141
- package/dist/core/c4/source-scan.js.map +1 -1
- package/dist/core/c4/splice/authored-source.js +79 -13
- package/dist/core/c4/splice/authored-source.js.map +1 -1
- package/dist/core/c4/splice/contract.js +20 -0
- package/dist/core/c4/splice/contract.js.map +1 -1
- package/dist/core/c4/splice/delta-blocks.js +20 -20
- package/dist/core/c4/splice/delta-blocks.js.map +1 -1
- package/dist/core/c4/splice/identity/declared.js +87 -0
- package/dist/core/c4/splice/identity/declared.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +37 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -1
- package/dist/core/c4/splice/identity/existing.js +80 -0
- package/dist/core/c4/splice/identity/existing.js.map +1 -0
- package/dist/core/c4/splice/identity/interior.js +80 -0
- package/dist/core/c4/splice/identity/interior.js.map +1 -0
- package/dist/core/c4/splice/identity/owner.js +50 -0
- package/dist/core/c4/splice/identity/owner.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +182 -114
- package/dist/core/c4/splice/landscape-merge.js.map +1 -1
- package/dist/core/c4/splice/model/merge.js +151 -0
- package/dist/core/c4/splice/model/merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +160 -56
- package/dist/core/c4/splice/placement.js.map +1 -1
- package/dist/core/c4/splice/text/spot.js +131 -0
- package/dist/core/c4/splice/text/spot.js.map +1 -0
- package/dist/core/c4/workspace.js +13 -19
- package/dist/core/c4/workspace.js.map +1 -1
- package/dist/core/capabilities/capabilities.js +6 -6
- package/dist/core/capabilities/capabilities.js.map +1 -1
- package/dist/core/capabilities/delta/doc.js +7 -10
- package/dist/core/capabilities/delta/doc.js.map +1 -1
- package/dist/core/capabilities/delta/uncovered.js +2 -2
- package/dist/core/capabilities/delta/uncovered.js.map +1 -1
- package/dist/core/capabilities/findings.js +18 -22
- package/dist/core/capabilities/findings.js.map +1 -1
- package/dist/core/capabilities/realizes/findings.js +12 -19
- package/dist/core/capabilities/realizes/findings.js.map +1 -1
- package/dist/core/capabilities/realizes/join.js +0 -20
- package/dist/core/capabilities/realizes/join.js.map +1 -1
- package/dist/core/capabilities/rollup.js +6 -0
- package/dist/core/capabilities/rollup.js.map +1 -1
- package/dist/core/capabilities/tree.js +6 -28
- package/dist/core/capabilities/tree.js.map +1 -1
- package/dist/core/capabilities/usecase-join.js +3 -13
- package/dist/core/capabilities/usecase-join.js.map +1 -1
- package/dist/core/coherence/authoring/scaffold.js +11 -3
- package/dist/core/coherence/authoring/scaffold.js.map +1 -1
- package/dist/core/coherence/authoring/sentinels.js +2 -1
- package/dist/core/coherence/authoring/sentinels.js.map +1 -1
- package/dist/core/coherence/calls/called.js +52 -0
- package/dist/core/coherence/calls/called.js.map +1 -0
- package/dist/core/coherence/coherence.js +103 -22
- package/dist/core/coherence/coherence.js.map +1 -1
- package/dist/core/coherence/consumed/operations.js +70 -0
- package/dist/core/coherence/consumed/operations.js.map +1 -0
- package/dist/core/coherence/consumed/refusal.js +38 -0
- package/dist/core/coherence/consumed/refusal.js.map +1 -0
- package/dist/core/coherence/covers/health.js +85 -0
- package/dist/core/coherence/covers/health.js.map +1 -0
- package/dist/core/coherence/declared.js +60 -34
- package/dist/core/coherence/declared.js.map +1 -1
- package/dist/core/coherence/events/declared.js +44 -59
- package/dist/core/coherence/events/declared.js.map +1 -1
- package/dist/core/coherence/events/events.js +147 -16
- package/dist/core/coherence/events/events.js.map +1 -1
- package/dist/core/coherence/events/grades.js +31 -8
- package/dist/core/coherence/events/grades.js.map +1 -1
- package/dist/core/coherence/events/lookups.js +28 -87
- package/dist/core/coherence/events/lookups.js.map +1 -1
- package/dist/core/coherence/events/produced.js +100 -0
- package/dist/core/coherence/events/produced.js.map +1 -0
- package/dist/core/coherence/lookups.js +18 -78
- package/dist/core/coherence/lookups.js.map +1 -1
- package/dist/core/coherence/retired/archived.js +285 -0
- package/dist/core/coherence/retired/archived.js.map +1 -0
- package/dist/core/coherence/retired/event-pair.js +62 -0
- package/dist/core/coherence/retired/event-pair.js.map +1 -0
- package/dist/core/coherence/retired/merged.js +79 -0
- package/dist/core/coherence/retired/merged.js.map +1 -0
- package/dist/core/coherence/retired/retirement.js +49 -0
- package/dist/core/coherence/retired/retirement.js.map +1 -0
- package/dist/core/coherence/retired/revival/arrivals.js +131 -0
- package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
- package/dist/core/coherence/retired/revival/revived.js +297 -0
- package/dist/core/coherence/retired/revival/revived.js.map +1 -0
- package/dist/core/consumers/after.js +113 -0
- package/dist/core/consumers/after.js.map +1 -0
- package/dist/core/consumers/consumers.js +296 -0
- package/dist/core/consumers/consumers.js.map +1 -0
- package/dist/core/consumers/current.js +211 -0
- package/dist/core/consumers/current.js.map +1 -0
- package/dist/core/consumers/scan.js +46 -0
- package/dist/core/consumers/scan.js.map +1 -0
- package/dist/core/consumers/state.js +27 -0
- package/dist/core/consumers/state.js.map +1 -0
- package/dist/core/delta/delta.js +51 -6
- package/dist/core/delta/delta.js.map +1 -1
- package/dist/core/dependencies/fanin.js +2 -2
- package/dist/core/dependencies/fanin.js.map +1 -1
- package/dist/core/deployment/delta.js +191 -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 +94 -12
- package/dist/core/diff/base-git.js.map +1 -1
- package/dist/core/diff/base-state.js +49 -21
- package/dist/core/diff/base-state.js.map +1 -1
- package/dist/core/diff/joins.js +136 -0
- package/dist/core/diff/joins.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +22 -6
- package/dist/core/diff/scope/changed-paths.js.map +1 -1
- package/dist/core/diff/scope/edges.js +82 -0
- package/dist/core/diff/scope/edges.js.map +1 -0
- package/dist/core/diff/semantic.js +100 -31
- package/dist/core/diff/semantic.js.map +1 -1
- package/dist/core/docs.js +31 -22
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +34 -18
- package/dist/core/doctor/agents.js.map +1 -1
- package/dist/core/doctor/config.js +7 -3
- package/dist/core/doctor/config.js.map +1 -1
- package/dist/core/doctor/doctor.js +91 -11
- package/dist/core/doctor/doctor.js.map +1 -1
- package/dist/core/doctor/report.js.map +1 -1
- package/dist/core/doctor/reports/scan.js +242 -0
- package/dist/core/doctor/reports/scan.js.map +1 -0
- package/dist/core/document/apply.js +158 -11
- package/dist/core/document/apply.js.map +1 -1
- package/dist/core/document/frontmatter.js +55 -0
- package/dist/core/document/frontmatter.js.map +1 -1
- package/dist/core/document/parse.js +29 -6
- package/dist/core/document/parse.js.map +1 -1
- package/dist/core/document/scenarios.js +17 -0
- package/dist/core/document/scenarios.js.map +1 -1
- package/dist/core/document/spec.js +4 -11
- package/dist/core/document/spec.js.map +1 -1
- package/dist/core/envelope/config.js +10 -0
- package/dist/core/envelope/config.js.map +1 -1
- package/dist/core/envelope/json.js +34 -0
- package/dist/core/envelope/json.js.map +1 -1
- package/dist/core/explain/families.js +26 -21
- package/dist/core/explain/families.js.map +1 -1
- package/dist/core/explain/lookup.js +14 -1
- package/dist/core/explain/lookup.js.map +1 -1
- package/dist/core/explain/refusals.js +5 -5
- package/dist/core/explain/refusals.js.map +1 -1
- package/dist/core/explain/terms/documents.js +227 -0
- package/dist/core/explain/terms/documents.js.map +1 -0
- package/dist/core/explain/terms/done-check.js +144 -0
- package/dist/core/explain/terms/done-check.js.map +1 -0
- package/dist/core/explain/terms/entry.js +14 -0
- package/dist/core/explain/terms/entry.js.map +1 -0
- package/dist/core/explain/terms/stages.js +71 -0
- package/dist/core/explain/terms/stages.js.map +1 -0
- package/dist/core/explain/terms/tasks.js +97 -0
- package/dist/core/explain/terms/tasks.js.map +1 -0
- package/dist/core/explain/terms.js +68 -109
- package/dist/core/explain/terms.js.map +1 -1
- package/dist/core/explore/explore.js +40 -10
- package/dist/core/explore/explore.js.map +1 -1
- package/dist/core/fleet-context.js +81 -95
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +11 -4
- package/dist/core/gate/checks.js.map +1 -1
- package/dist/core/gate/partners.js +69 -28
- package/dist/core/gate/partners.js.map +1 -1
- package/dist/core/gate/report.js.map +1 -1
- package/dist/core/gate/verification.js +75 -12
- package/dist/core/gate/verification.js.map +1 -1
- package/dist/core/gherkin/stale.js +13 -37
- package/dist/core/gherkin/stale.js.map +1 -1
- package/dist/core/glossary/delta.js +10 -7
- package/dist/core/glossary/delta.js.map +1 -1
- package/dist/core/glossary/tree.js +6 -19
- package/dist/core/glossary/tree.js.map +1 -1
- package/dist/core/kernel/concurrency.js +19 -0
- package/dist/core/kernel/concurrency.js.map +1 -1
- package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
- package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
- package/dist/core/kernel/path-safety.js +38 -0
- package/dist/core/kernel/path-safety.js.map +1 -1
- package/dist/core/kernel/records.js +11 -0
- package/dist/core/kernel/records.js.map +1 -1
- package/dist/core/links/backlinks.js +1 -3
- package/dist/core/links/backlinks.js.map +1 -1
- package/dist/core/links/corpus.js +51 -37
- package/dist/core/links/corpus.js.map +1 -1
- package/dist/core/links/findings.js.map +1 -1
- package/dist/core/links/parse.js +38 -9
- package/dist/core/links/parse.js.map +1 -1
- package/dist/core/mcp/argv.js +101 -0
- package/dist/core/mcp/argv.js.map +1 -1
- package/dist/core/mcp/author-tools.js +2 -1
- package/dist/core/mcp/author-tools.js.map +1 -1
- package/dist/core/mcp/protocol.js +2 -2
- package/dist/core/mcp/protocol.js.map +1 -1
- package/dist/core/mcp/tools.js +43 -33
- package/dist/core/mcp/tools.js.map +1 -1
- package/dist/core/openapi/baseline/gate.js +53 -12
- package/dist/core/openapi/baseline/gate.js.map +1 -1
- package/dist/core/openapi/baseline/plan.js +40 -10
- package/dist/core/openapi/baseline/plan.js.map +1 -1
- package/dist/core/openapi/baseline/record.js +0 -1
- package/dist/core/openapi/baseline/record.js.map +1 -1
- package/dist/core/openapi/contract-text.js +33 -0
- package/dist/core/openapi/contract-text.js.map +1 -0
- package/dist/core/openapi/contract-tree.js +301 -0
- package/dist/core/openapi/contract-tree.js.map +1 -0
- package/dist/core/openapi/depth.js +38 -24
- package/dist/core/openapi/depth.js.map +1 -1
- package/dist/core/openapi/digest.js +52 -2
- package/dist/core/openapi/digest.js.map +1 -1
- package/dist/core/openapi/doc.js +12 -4
- package/dist/core/openapi/doc.js.map +1 -1
- package/dist/core/openapi/merge/components.js +25 -60
- package/dist/core/openapi/merge/components.js.map +1 -1
- package/dist/core/openapi/merge/error.js +3 -13
- package/dist/core/openapi/merge/error.js.map +1 -1
- package/dist/core/openapi/merge/markers.js +26 -30
- package/dist/core/openapi/merge/markers.js.map +1 -1
- package/dist/core/openapi/merge/merge.js +28 -52
- package/dist/core/openapi/merge/merge.js.map +1 -1
- package/dist/core/openapi/merge/pin.js +17 -35
- package/dist/core/openapi/merge/pin.js.map +1 -1
- package/dist/core/openspec/decide/verdict.js.map +1 -1
- package/dist/core/openspec/inventory.js +4 -5
- package/dist/core/openspec/inventory.js.map +1 -1
- package/dist/core/openspec/model/mapping.js +30 -28
- package/dist/core/openspec/model/mapping.js.map +1 -1
- package/dist/core/openspec/model/model.js +12 -7
- package/dist/core/openspec/model/model.js.map +1 -1
- package/dist/core/openspec/scan/changes.js +10 -4
- package/dist/core/openspec/scan/changes.js.map +1 -1
- package/dist/core/openspec/scan/config.js +7 -16
- package/dist/core/openspec/scan/config.js.map +1 -1
- package/dist/core/openspec/scan/shape.js +63 -19
- package/dist/core/openspec/scan/shape.js.map +1 -1
- package/dist/core/openspec/scan/walk.js +21 -38
- package/dist/core/openspec/scan/walk.js.map +1 -1
- package/dist/core/pack/living.js +43 -4
- package/dist/core/pack/living.js.map +1 -1
- package/dist/core/pack/pack.js +50 -6
- package/dist/core/pack/pack.js.map +1 -1
- package/dist/core/projection/arch-slice.js +2 -2
- package/dist/core/projection/arch-slice.js.map +1 -1
- package/dist/core/projection/introduced.js +14 -0
- package/dist/core/projection/introduced.js.map +1 -0
- package/dist/core/provenance/findings.js +48 -12
- package/dist/core/provenance/findings.js.map +1 -1
- package/dist/core/provenance/git.js +33 -57
- package/dist/core/provenance/git.js.map +1 -1
- package/dist/core/provenance/gitq/moves.js +71 -114
- package/dist/core/provenance/gitq/moves.js.map +1 -1
- package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
- package/dist/core/provenance/sources.js +23 -6
- package/dist/core/provenance/sources.js.map +1 -1
- package/dist/core/provenance/stamp.js +5 -17
- package/dist/core/provenance/stamp.js.map +1 -1
- package/dist/core/repo/authored/paths.js +18 -0
- package/dist/core/repo/authored/paths.js.map +1 -1
- package/dist/core/repo/entries.js.map +1 -1
- package/dist/core/repo/paths.js +92 -6
- package/dist/core/repo/paths.js.map +1 -1
- package/dist/core/repo/repo.js +74 -14
- package/dist/core/repo/repo.js.map +1 -1
- package/dist/core/repo/tree/find.js +12 -3
- package/dist/core/repo/tree/find.js.map +1 -1
- package/dist/core/repo/tree/fs.js +27 -1
- package/dist/core/repo/tree/fs.js.map +1 -1
- package/dist/core/repo/tree/render/body.js +258 -0
- package/dist/core/repo/tree/render/body.js.map +1 -0
- package/dist/core/repo/tree/render/projects.js +182 -0
- package/dist/core/repo/tree/render/projects.js.map +1 -0
- package/dist/core/repo/tree/render/service/header.js +125 -0
- package/dist/core/repo/tree/render/service/header.js.map +1 -0
- package/dist/core/repo/tree/render/service/peers.js +28 -0
- package/dist/core/repo/tree/render/service/peers.js.map +1 -0
- package/dist/core/repo/tree/render/service/view-id.js +67 -0
- package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
- package/dist/core/repo/tree/render/service/views.js +78 -0
- package/dist/core/repo/tree/render/service/views.js.map +1 -0
- package/dist/core/repo/tree/render/stale.js +42 -0
- package/dist/core/repo/tree/render/stale.js.map +1 -0
- package/dist/core/repo/tree/render/text.js +84 -0
- package/dist/core/repo/tree/render/text.js.map +1 -0
- package/dist/core/repo/tree/render/views.js +293 -0
- package/dist/core/repo/tree/render/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +53 -32
- package/dist/core/repo/tree/walk.js.map +1 -1
- package/dist/core/results.js +47 -12
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +121 -13
- package/dist/core/scaffold/landscape.js.map +1 -1
- package/dist/core/scaffold/legacy.js +271 -0
- package/dist/core/scaffold/legacy.js.map +1 -0
- package/dist/core/staging/commit.js +26 -15
- package/dist/core/staging/commit.js.map +1 -1
- package/dist/core/staging/lock.js +74 -12
- package/dist/core/staging/lock.js.map +1 -1
- package/dist/core/staging/recovery/intent.js +2 -5
- package/dist/core/staging/recovery/intent.js.map +1 -1
- package/dist/core/staging/recovery/recover.js +84 -6
- package/dist/core/staging/recovery/recover.js.map +1 -1
- package/dist/core/staging/snapshot/manifest.js +188 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +39 -45
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +24 -14
- package/dist/core/staging/txn/forward.js.map +1 -1
- package/dist/core/staging/writes.js.map +1 -1
- package/dist/core/status/actions/execution.js +11 -0
- package/dist/core/status/actions/execution.js.map +1 -1
- package/dist/core/status/contracts.js +39 -15
- package/dist/core/status/contracts.js.map +1 -1
- package/dist/core/status/feature/artifacts.js +33 -8
- package/dist/core/status/feature/artifacts.js.map +1 -1
- package/dist/core/status/feature/feature.js +24 -17
- package/dist/core/status/feature/feature.js.map +1 -1
- package/dist/core/status/feature/next.js +20 -7
- package/dist/core/status/feature/next.js.map +1 -1
- package/dist/core/status/feature/words.js +96 -0
- package/dist/core/status/feature/words.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +43 -14
- package/dist/core/status/fleet/fleet.js.map +1 -1
- package/dist/core/status/fleet/next.js +153 -58
- package/dist/core/status/fleet/next.js.map +1 -1
- package/dist/core/status/report.js.map +1 -1
- package/dist/core/status/scan.js.map +1 -1
- package/dist/core/status/verification.js +30 -15
- package/dist/core/status/verification.js.map +1 -1
- package/dist/core/tasks/packet.js +199 -0
- package/dist/core/tasks/packet.js.map +1 -0
- package/dist/core/tasks/record.js +43 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/sources.js +181 -0
- package/dist/core/tasks/sources.js.map +1 -0
- package/dist/core/tasks/stamps.js +76 -0
- package/dist/core/tasks/stamps.js.map +1 -0
- package/dist/core/tasks/unit.js +0 -0
- package/dist/core/tasks/unit.js.map +1 -0
- package/dist/core/usecases/capability.js +11 -14
- package/dist/core/usecases/capability.js.map +1 -1
- package/dist/core/usecases/delta/claims.js +31 -7
- package/dist/core/usecases/delta/claims.js.map +1 -1
- package/dist/core/usecases/delta/flows.js +5 -7
- package/dist/core/usecases/delta/flows.js.map +1 -1
- package/dist/core/usecases/delta/modified.js +315 -0
- package/dist/core/usecases/delta/modified.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +32 -191
- package/dist/core/usecases/delta/overlay.js.map +1 -1
- package/dist/core/usecases/fleet.js +195 -36
- package/dist/core/usecases/fleet.js.map +1 -1
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/capability-tag.js +8 -9
- package/dist/core/usecases/grade/capability-tag.js.map +1 -0
- package/dist/core/usecases/grade/feature.js +88 -0
- package/dist/core/usecases/grade/feature.js.map +1 -0
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/requirement-tag.js +3 -4
- package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/steps.js +102 -33
- package/dist/core/usecases/grade/steps.js.map +1 -0
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/usecases.js +23 -10
- package/dist/core/usecases/grade/usecases.js.map +1 -0
- package/dist/core/usecases/operations.js +26 -14
- package/dist/core/usecases/operations.js.map +1 -1
- package/dist/core/usecases/place.js.map +1 -1
- package/dist/core/usecases/service/exclude.js +119 -0
- package/dist/core/usecases/service/exclude.js.map +1 -0
- package/dist/core/usecases/service/flows.js +164 -0
- package/dist/core/usecases/service/flows.js.map +1 -0
- package/dist/core/usecases/suites/participants.js +83 -0
- package/dist/core/usecases/suites/participants.js.map +1 -0
- package/dist/core/usecases/suites/suites.js +45 -0
- package/dist/core/usecases/suites/suites.js.map +1 -0
- package/dist/core/verify/answers.js +12 -5
- package/dist/core/verify/answers.js.map +1 -1
- package/dist/core/verify/build.js +102 -82
- package/dist/core/verify/build.js.map +1 -1
- package/dist/core/verify/checklist.js +70 -12
- package/dist/core/verify/checklist.js.map +1 -1
- package/dist/core/verify/location.js +67 -0
- package/dist/core/verify/location.js.map +1 -0
- package/dist/core/verify/pins/lint.js +3 -2
- package/dist/core/verify/pins/lint.js.map +1 -1
- package/dist/core/verify/pins/pin.js +1 -1
- package/dist/core/verify/pins/pin.js.map +1 -1
- package/dist/core/verify/read/file.js +224 -0
- package/dist/core/verify/read/file.js.map +1 -0
- package/dist/core/verify/{file.js → read/shape.js} +16 -104
- package/dist/core/verify/read/shape.js.map +1 -0
- package/dist/core/verify/read/union.js +105 -0
- package/dist/core/verify/read/union.js.map +1 -0
- package/dist/core/verify/record.js +35 -12
- package/dist/core/verify/record.js.map +1 -1
- package/dist/core/verify/store/commit.js +40 -30
- package/dist/core/verify/store/commit.js.map +1 -1
- package/dist/core/verify/store/render.js +8 -4
- package/dist/core/verify/store/render.js.map +1 -1
- package/dist/core/vocabulary/issue.js +4 -0
- package/dist/core/vocabulary/issue.js.map +1 -1
- package/dist/core/vocabulary/maturity.js +75 -4
- package/dist/core/vocabulary/maturity.js.map +1 -1
- package/dist/core/vocabulary/report.js +16 -1
- package/dist/core/vocabulary/report.js.map +1 -1
- package/examples/README.md +54 -11
- package/examples/docs/architecture/landscape.likec4 +62 -6
- package/examples/docs/architecture/services.likec4 +70 -0
- package/examples/docs/architecture/subsystems.likec4 +7 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +16 -7
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +4 -1
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
- package/examples/docs/likec4.config.json +0 -1
- package/examples/docs/services/checkout-web/model.likec4 +39 -56
- package/examples/docs/services/order-service/arch.spec.md +13 -6
- package/examples/docs/services/order-service/asyncapi.yaml +3 -2
- package/examples/docs/services/order-service/model.likec4 +58 -70
- package/examples/docs/services/payment-service/arch.spec.md +7 -4
- package/examples/docs/services/payment-service/model.likec4 +38 -37
- package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
- package/examples/docs/services/platform/identity-service/model.likec4 +35 -37
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
- package/examples/docs/services/platform/notification-service/health.yaml +8 -3
- package/examples/docs/services/platform/notification-service/model.likec4 +43 -64
- package/package.json +1 -1
- package/dist/commands/validate/checks/vocabulary.js +0 -31
- package/dist/commands/validate/checks/vocabulary.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/capability-tag.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/steps.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/usecases.js.map +0 -1
- package/dist/core/agent/agents-md/artifacts.js +0 -220
- package/dist/core/agent/agents-md/artifacts.js.map +0 -1
- package/dist/core/agent/agents-md/cycle.js +0 -165
- package/dist/core/agent/agents-md/cycle.js.map +0 -1
- package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
- package/dist/core/agent/agents-md/spine.js +0 -40
- package/dist/core/agent/agents-md/spine.js.map +0 -1
- package/dist/core/coherence/events/merged.js +0 -40
- package/dist/core/coherence/events/merged.js.map +0 -1
- package/dist/core/diff/current-state.js +0 -96
- package/dist/core/diff/current-state.js.map +0 -1
- package/dist/core/diff/victims.js +0 -247
- package/dist/core/diff/victims.js.map +0 -1
- package/dist/core/repo/tree/views.js +0 -172
- package/dist/core/repo/tree/views.js.map +0 -1
- package/dist/core/staging/snapshot.js.map +0 -1
- package/dist/core/verify/file.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"done-check.js","sourceRoot":"","sources":["../../../../../src/core/agent/workflows/reference/done-check.ts"],"names":[],"mappings":"AAcA,MAAM,CAAC,MAAM,eAAe,GAAmB;IAC7C,IAAI,EAAE,iBAAiB;IACvB,WAAW,EACT,4FAA4F;IAC9F,6EAA6E;IAC7E,+CAA+C;IAC/C,YAAY,EAAE,EAAE;IAChB,OAAO,EACL,mOAAmO;IACrO,UAAU,EAAE,mCAAmC;IAC/C,YAAY,EAAE,EAAE;IAChB,KAAK,EAAE,CAAC,gBAAgB,CAAC;IACzB,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+KP;CACA,CAAC","sourcesContent":["/**\n * The `loam-done-check` reference page: how `loam verify` derives its claims,\n * who may answer them, and what separates **verified** from **attested**.\n *\n * It is the longest single section the corpus had after the code inventory —\n * three answer channels, the federated recording form, the evidence pins and\n * the six codes the record itself can carry — and every word of it is read at\n * one moment in the cycle, step 7. AGENTS.md's own step 7 names this page.\n *\n * The text is the AGENTS.md section verbatim. See ./reference.ts for why the\n * four pages exist and what was traded for them.\n */\nimport type { CommandContent } from \"../../contract.js\";\n\nexport const LOAM_DONE_CHECK: CommandContent = {\n name: \"loam-done-check\",\n description:\n \"Reference: the done-check — how `loam verify` derives claims, and verified versus attested\",\n // No arguments: one document, printed whole. See ./spine.ts for why the hint\n // is empty rather than a spelled-out \"<none>\".\n argumentHint: \"\",\n purpose:\n \"What `loam verify` asks, which of the three channels may answer each kind of claim, how a cross-service feature is recorded from each service's own repository, and why an agent's word yields `attested` rather than `verified`.\",\n invocation: \"loam instructions loam-done-check\",\n placeholders: [],\n spine: [\"The done-check\"],\n body: `The done-check: what \\`loam verify\\` asks, who may answer it, and what the answer is worth.\n\n## The done-check\n\n\\`loam verify <FEAT>\\` derives a checklist from the feature's own artifacts —\none claim per new service, per operation the delta adds, per tagged edge that\nnames an operation, and per scenario of every changed requirement, arch.spec.md\ndeltas included (those claims name their file, and the test they ask for is an\nintegration/ops test, not an acceptance test). Each claim has a stable id, so\ntwo runs are diffable and an answer cannot drift onto a different question.\n\nThree answer channels, and they never overlap. The \\`scenario.tested\\` claims\nare the TEST RUNNER's to answer: run the generated suite and pass its report\nback — cucumber JSON (\\`cucumber-js --format json:report.json\\`), or loam's own\nrunner-neutral shape \\`{\"loamScenarioReport\": 1, \"results\": [{\"digest\": \"…\",\n\"status\": \"passed\"}]}\\` that any runner can be adapted into, chosen by its\nmarker key. The digest is the contract, never the dialect: both read\n\\`answered_by: runner\\` because both are a real run reporting that digest green,\nso a JUnit or pytest fleet is not held at \\`attested\\` by a file format —\n\\`loam verify <FEAT> --results report.json\\`. A claim is confirmed only when a\nreport scenario carrying its \\`@loam-digest-<16hex>\\` tag ran at least one step\nand every step passed — every occurrence, when the report holds a re-run, and\nevery before/after hook with it. A failed, undefined, pending or skipped step,\na failed hook, or no matching scenario at all, is \\`unconfirmed\\` with the\nreason. The digest is the only identity: a reworded spec scenario matches\nnothing until the suite is regenerated and re-run. When a report exists,\nALWAYS pass \\`--results\\` — under it the runner owns every scenario claim, and\nan answers-file entry for one is refused.\n\nThe \\`api.exposes\\` claims have a mechanical channel of their own: an API\ncontract-test run, passed back with\n\\`loam verify <FEAT> --contract-results contract.json\\`. loam accepts one\nshape — its own documented contract-results JSON,\n\\`{\"loamContractReport\": 1, \"results\": [{\"operationId\": \"createSplit\",\n\"status\": \"passed\"}]}\\` — emitted from your contract tool's report in one\ntransform (Specmatic's own coverage JSON is refused by design: its \"covered\"\nstatus means exercised, not passed, so reading it would confirm what a red run\nrefuted). An entry whose status is exactly \\`passed\\` confirms the claim whose\noperationId it names — the record says \\`answered_by: external-runner\\` and the\nviews mark the line \\`[contract]\\` — while a failed or unknown status and an\noperation the report never exercised leave the claim \\`unconfirmed\\` with the\nreason; entries naming operations outside the checklist are ignored.\n\\`verify.operation-contested\\` (warn) is \\`verify.digest-contested\\`'s twin on\nthis axis: an operationId is unique per contract document, not per fleet, so\nwhen two services on the checklist expose the same one, a report entry — which\nnames no service — cannot say whose suite exercised it, those claims stay\nunconfirmed, and each service records its own with \\`--service\\`. Under the\nflag the contract report OWNS every api.exposes claim in scope, so an\nanswers-file entry for one is refused (\\`answers-mismatch\\`), and the record\npins the file consumed in \\`contractReport\\` (path, sha256 of the bytes, mtime,\noperation count) exactly as \\`report\\` pins the cucumber one. The verdict\nladder does not move: external evidence never answers a \\`scenario.tested\\`\nclaim, so \\`attested\\` versus \\`verified\\` still turns on scenario claims\nalone.\n\n\\`--record\\` without \\`--results\\` is the fallback for a service with no runnable\nsuite yet: there your word answers the scenario claims too. It still works, and\nit costs something you must know about. The record says who answered\n(\\`answered_by: agent\\`), and that answer changes the VERDICT: a feature whose\nscenario claims rest on an agent's word is **attested**, not verified.\n\\`verify --json\\` reports \\`verdict: \"attested\"\\` with \\`verified: false\\` and an\n\\`attested\\` count, \\`loam status\\` marks it and adds a \\`next.verify-attested\\` step,\nand the notice rides in \\`notices[]\\` under \\`verify.scenario-attested\\` (warn —\nnothing gates on it, because a legacy service with no suite must still be able\nto ship). Answer them mechanically the moment a suite runs:\n\\`loam verify <FEAT> --results <report.json>\\`.\n\nA record that leaves any claim unconfirmed or unanswered carries\n\\`verify.claims-open\\` (warn) in \\`notices[]\\` — the one-line \"not a clean\nresult\" summary with all four counts, on the read view and the frozen\npost-archive view alike; it gates nothing, and a feature with no record at all\nnever carries it, because not-started is not partial.\n\nFederated \\`--record\\` also stamps \\`evidence_pins\\` on each agent-confirmed\ncitation — the cited file's sha256 at the attested commit, the cited line's\ntext, and the literal token the claim asserts (operationId, message name, edge\nop). One notice rides beside the stamp: \\`verify.evidence-token-missing\\` (warn,\nverdict-neutral, gates nothing) says a cited file at the attested commit does\nnot contain the claim's token — read that evidence first, while the answer can\nstill be corrected. \\`loam validate\\`, run later in the service's repo,\nre-checks the pins and reports drift under the \\`evidence.*\\` findings; nothing\nthere moves a verdict either.\n\nTwo more codes belong to the record itself. \\`verify.record-miscounted\\` (error):\na \\`verification.yaml\\` whose \\`summary\\` block contradicts its own \\`claims[]\\` — the\nrecord is refused as unreadable rather than believed in either half, and\nre-recording is the repair, never editing the counts. \\`verify.digest-contested\\`\n(warn): two or more services word a scenario identically, so they share one\n\\`@loam-digest-…\\` tag and no single cucumber report can say whose suite ran it —\nthose scenario claims are left unconfirmed, and each service records its own\nfrom its own repository with \\`--service\\`.\n\nA federated record also says WHAT EACH SERVICE ANSWERED AGAINST. Every\nattestation carries the \\`checklist\\` digest it answered and, when the docs repo\nis a git checkout, the \\`docsCommit\\` that checklist was derived from — so the\nrecord pins both sides, the service repo through \\`commit\\` and the question set\nthrough these two. \\`verify.checklist-forked\\` (warn) is what that buys: it names the\nservices whose attestation answers a DIFFERENT checklist than the feature now\nasks, which the record-level \\`checklist\\` field alone could never show — it\nflagged every service or none, and never said which answers went stale. It is\nmeasured against the present rather than pairwise between attestations, because\nservices that all answered a since-rewritten delta agree with each other and are\nevery one of them stale. Differing \\`docsCommit\\` values are NOT a finding:\nrecording a week apart is normal for a feature in flight.\nNormal mid-rollout and it gates nothing; re-record the services on the older\nversion from their own repositories, or accept the split knowingly.\nAttestations written before the field existed carry no \\`checklist\\` and are not\ncounted as a third version — silence is not disagreement.\n\nA consumed report is written down: \\`report\\` and \\`contractReport\\` on the\nrecord (or on that repository's attestation) each carry the path, a sha256 of\nthe bytes, the file's mtime and how much it held — tagged scenarios for the\none, distinct operationIds for the other. That identifies WHICH file answered\nthe claims, and — when the file is committed — that it matches the attested\ncommit. It does not prove the file came from executing that commit; no digest\ncan.\n\nEverything else you answer from the code, and \\`--record answers.json\\` takes\nthose back, writing \\`features/<FEAT>/verification.yaml\\` — it travels into the\narchive with the feature and reads without loam. Alongside the mechanical\nflags, the answers file must answer exactly the claims no report owns: an\nentry for a report-owned claim is refused (\\`answers-mismatch\\`), and a\nmechanical flag alone is refused while claims outside its kind are\noutstanding. Every recorded verdict says who answered it\n(\\`answered_by: runner | external-runner | agent\\`), so a reviewer can tell a\ngreen run from somebody's word.\n\n**A cross-service feature is verified once per service, and the form matters.**\nThe claims of one feature belong to several services, and each service's code\nlives in its own repository — so the recording form is federated:\n\n\\`\\`\\`sh\n# in EACH affected service's own repo, not in the docs repo:\nloam verify FEAT-101 --service payment-service --results report.json --record answers.json\n# with an API contract suite, its report answers the api.exposes claims too:\nloam verify FEAT-101 --service payment-service --results report.json --contract-results contract.json --record answers.json\n\\`\\`\\`\n\n\\`--service <id>\\` narrows the checklist to that service's claims and binds the\nanswers to this repository's commit, producing one **attestation** per service\ninside a single \\`schema: 2\\` \\`verification.yaml\\`. Re-running it in the next\nrepo adds that repo's attestation and leaves the others standing. Omitting\n\\`--service\\` in a repo whose \\`loam.json\\` declares one substitutes it, so the\nshort form is safe there; a \\`--service\\` naming a service this repo does not\ndeclare is refused (\\`service-mismatch\\`), and \\`--service\\` from a repo that\ndeclares none is refused (\\`repository-unavailable\\`) — an attestation has to be\nbound to the code it is about.\n\n⚠ **The legacy all-at-once form \\`loam verify <FEAT> --record answers.json\\` with\nno \\`--service\\` writes the whole record from one place.** Over a record that\nalready carries other services' attestations it is refused outright\n(\\`record-federated\\`, naming the attestors) rather than merged or migrated — the\nalternative was one repo silently erasing nine others' evidence. Use it only for\na single-service feature that has never been recorded federated. A\n\\`verification.yaml\\` that exists but cannot be read is \\`record-unreadable\\`: it is\nnever overwritten and never reported as \"no record\".\n\nReading is not writing: \\`loam verify <FEAT> --service <id>\\` **without**\n\\`--record\\` is a pure lens on the checklist. A read-only verify checklist needs no\nbinding and works from the docs repo, or from anywhere else — the refusals above\nare about WRITING an attestation, and only about that. Every run lists all\nsubjects in \\`services\\`, and a recorded run reports in \\`discarded\\` every previous\nanswer the new record does not carry.\n\nIt refuses an answer set that does not answer the current checklist: an id that\nis not on it (\\`answers-mismatch\\`), a claim with no answer (same), or a\n\\`confirmed\\` with no evidence (\\`answers-unevidenced\\`). Evidence is \\`file:line\\`.\nA claim you cannot show is \\`unconfirmed\\` with a note saying why — that is a\nsuccessful record, and it is more useful to the next reader than a yes.\n\n**Nothing gates on it.** \\`loam archive\\` will ship an unverified feature. That\nis deliberate: coherence is something loam computed from the documents, and a\nverdict is your word about code loam never read. A gate in front of shipping\nwould only teach everyone that the cheapest way past it is to say yes. The\nrecord is for the reviewer who comes later, so leave it true.\n`,\n};\n"]}
|
|
1
|
+
{"version":3,"file":"done-check.js","sourceRoot":"","sources":["../../../../../src/core/agent/workflows/reference/done-check.ts"],"names":[],"mappings":"AAcA,MAAM,CAAC,MAAM,eAAe,GAAmB;IAC7C,IAAI,EAAE,iBAAiB;IACvB,WAAW,EACT,4FAA4F;IAC9F,6EAA6E;IAC7E,+CAA+C;IAC/C,YAAY,EAAE,EAAE;IAChB,OAAO,EACL,mOAAmO;IACrO,UAAU,EAAE,mCAAmC;IAC/C,YAAY,EAAE,EAAE;IAChB,KAAK,EAAE,CAAC,gBAAgB,CAAC;IACzB,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqMP;CACA,CAAC","sourcesContent":["/**\n * The `loam-done-check` reference page: how `loam verify` derives its claims,\n * who may answer them, and what separates **verified** from **attested**.\n *\n * It is the longest single section the corpus had after the code inventory —\n * three answer channels, the federated recording form, the evidence pins and\n * the six codes the record itself can carry — and every word of it is read at\n * one moment in the cycle, step 7. AGENTS.md's own step 7 names this page.\n *\n * The text is the AGENTS.md section verbatim. See ./reference.ts for why the\n * four pages exist and what was traded for them.\n */\nimport type { CommandContent } from \"../../contract.js\";\n\nexport const LOAM_DONE_CHECK: CommandContent = {\n name: \"loam-done-check\",\n description:\n \"Reference: the done-check — how `loam verify` derives claims, and verified versus attested\",\n // No arguments: one document, printed whole. See ./spine.ts for why the hint\n // is empty rather than a spelled-out \"<none>\".\n argumentHint: \"\",\n purpose:\n \"What `loam verify` asks, which of the three channels may answer each kind of claim, how a cross-service feature is recorded from each service's own repository, and why an agent's word yields `attested` rather than `verified`.\",\n invocation: \"loam instructions loam-done-check\",\n placeholders: [],\n spine: [\"The done-check\"],\n body: `The done-check: what \\`loam verify\\` asks, who may answer it, and what the answer is worth.\n\n## The done-check\n\n\\`loam verify <FEAT>\\` derives a checklist from the feature's own artifacts —\none claim per new service, per operation the delta adds, per tagged edge that\nnames an operation, and per scenario of every changed requirement, arch.spec.md\ndeltas included (those claims name their file, and the test they ask for is an\nintegration/ops test, not an acceptance test). Each claim has a stable id, so\ntwo runs are diffable and an answer cannot drift onto a different question.\n\nThree answer channels, and they never overlap. The \\`scenario.tested\\` claims\nare the TEST RUNNER's to answer: run the generated suite and pass its report\nback — cucumber JSON (\\`cucumber-js --format json:report.json\\`), or loam's own\nrunner-neutral shape \\`{\"loamScenarioReport\": 1, \"results\": [{\"digest\": \"…\",\n\"status\": \"passed\"}]}\\` that any runner can be adapted into, chosen by its\nmarker key. The digest is the contract, never the dialect: both read\n\\`answered_by: runner\\` because both are a real run reporting that digest green,\nso a JUnit or pytest fleet is not held at \\`attested\\` by a file format —\n\\`loam verify <FEAT> --results report.json\\`. A claim is confirmed only when a\nreport scenario carrying its \\`@loam-digest-<16hex>\\` tag ran at least one step\nand every step passed — every occurrence, when the report holds a re-run, and\nevery before/after hook with it — and, in a cucumber report, ran exactly as\nmany steps as the stamped scenario has: a hand-tagged stub is not that\nscenario's run. A failed, undefined, pending or skipped step, a failed hook, a\nstep count that differs, or no matching scenario at all, is \\`unconfirmed\\` with\nthe reason. A report that is not JSON (a JUnit XML file) is refused\n\\`answers-unreadable\\`, naming both shapes. The digest is the only identity: a reworded spec scenario matches\nnothing until the suite is regenerated and re-run. When a report exists,\nALWAYS pass \\`--results\\` — under it the runner owns every scenario claim, and\nan answers-file entry for one is refused.\n\nThe \\`api.exposes\\` claims have a mechanical channel of their own: an API\ncontract-test run, passed back with\n\\`loam verify <FEAT> --contract-results contract.json\\`. loam accepts one\nshape — its own documented contract-results JSON,\n\\`{\"loamContractReport\": 1, \"results\": [{\"operationId\": \"createSplit\",\n\"status\": \"passed\"}]}\\` — emitted from your contract tool's report in one\ntransform (Specmatic's own coverage JSON is refused by design: its \"covered\"\nstatus means exercised, not passed, so reading it would confirm what a red run\nrefuted). An entry whose status is exactly \\`passed\\` confirms the claim whose\noperationId it names — the record says \\`answered_by: external-runner\\` and the\nviews mark the line \\`[contract]\\` — while a failed or unknown status and an\noperation the report never exercised leave the claim \\`unconfirmed\\` with the\nreason; entries naming operations outside the checklist are ignored.\n\\`verify.operation-contested\\` (warn) is \\`verify.digest-contested\\`'s twin on\nthis axis: an operationId is unique per contract document, not per fleet, so\nwhen two services on the checklist expose the same one, a report entry — which\nnames no service — cannot say whose suite exercised it, those claims stay\nunconfirmed, and each service records its own with \\`--service\\`. Under the\nflag the contract report OWNS every api.exposes claim in scope, so an\nanswers-file entry for one is refused (\\`answers-mismatch\\`), and the record\npins the file consumed in \\`contractReport\\` (path, sha256 of the bytes, mtime,\noperation count) exactly as \\`report\\` pins the cucumber one. The verdict\nladder does not move: external evidence never answers a \\`scenario.tested\\`\nclaim, so \\`attested\\` versus \\`verified\\` still turns on scenario claims\nalone.\n\n\\`--record\\` without \\`--results\\` is the fallback for a service with no runnable\nsuite yet: there your word answers the scenario claims too. It still works, and\nit costs something you must know about. The record says who answered\n(\\`answered_by: agent\\`), and that answer changes the VERDICT: a feature whose\nscenario claims rest on an agent's word is **attested**, not verified.\n\\`verify --json\\` reports \\`verdict: \"attested\"\\` with \\`verified: false\\` and an\n\\`attested\\` count, \\`loam status\\` marks it and adds a \\`next.verify-attested\\` step,\nand the notice rides in \\`notices[]\\` under \\`verify.scenario-attested\\` (warn —\nnothing gates on it, because a legacy service with no suite must still be able\nto ship). Answer them mechanically the moment a suite runs:\n\\`loam verify <FEAT> --results <report.json>\\`.\n\nA record that leaves any claim unconfirmed or unanswered carries\n\\`verify.claims-open\\` (warn) in \\`notices[]\\` — the one-line \"not a clean\nresult\" summary with all four counts, on the read view and the frozen\npost-archive view alike; it gates nothing, and a feature with no record at all\nnever carries it, because not-started is not partial.\n\nFederated \\`--record\\` also stamps \\`evidence_pins\\` on each agent-confirmed\ncitation — the cited file's sha256 at the attested commit, the cited line's\ntext, and the literal token the claim asserts (operationId, message name, edge\nop). One notice rides beside the stamp: \\`verify.evidence-token-missing\\` (warn,\nverdict-neutral, gates nothing) says a cited file at the attested commit does\nnot contain the claim's token — read that evidence first, while the answer can\nstill be corrected. \\`loam validate\\`, run later in the service's repo,\nre-checks the pins and reports drift under the \\`evidence.*\\` findings; nothing\nthere moves a verdict either.\n\nTwo more codes belong to the record itself. \\`verify.record-miscounted\\` (error):\na record file whose \\`summary\\` block contradicts its own \\`claims[]\\` — the\nrecord is refused as unreadable rather than believed in either half, and the\nrepair is never editing the counts: a service's own \\`verification/<id>.yaml\\`\nis deleted and recorded again by that service, and the one-file\n\\`verification.yaml\\` is restored from version control and then recorded over.\n\\`verify.digest-contested\\`\n(warn): two or more services word a scenario identically, so they share one\n\\`@loam-digest-…\\` tag and no single cucumber report can say whose suite ran it —\nthose scenario claims are left unconfirmed, and each service records its own\nfrom its own repository with \\`--service\\`.\n\nA federated record also says WHAT EACH SERVICE ANSWERED AGAINST. Every\nattestation carries the \\`checklist\\` digest it answered and, when the docs repo\nis a git checkout, the \\`docsCommit\\` that checklist was derived from — so the\nrecord pins both sides, the service repo through \\`commit\\` and the question set\nthrough these two. \\`verify.checklist-forked\\` (warn) is what that buys: it names the\nservices whose attestation answers a DIFFERENT checklist than the feature now\nasks, which the record-level \\`checklist\\` field alone could never show — it\nflagged every service or none, and never said which answers went stale. It is\nmeasured against the present rather than pairwise between attestations, because\nservices that all answered a since-rewritten delta agree with each other and are\nevery one of them stale. Differing \\`docsCommit\\` values are NOT a finding:\nrecording a week apart is normal for a feature in flight.\nNormal mid-rollout and it gates nothing; re-record the services on the older\nversion from their own repositories. In a record kept as per-service files the\nanswers of the services it names do not count until they do: the record\nanswers the newest version its files answered, and an answer filed against an\nolder one could otherwise fill the slot of the question that replaced it.\nAttestations written before the field existed carry no \\`checklist\\` and are not\ncounted as a third version — silence is not disagreement.\n\nA consumed report is written down: \\`report\\` and \\`contractReport\\` on the\nrecord (or on that repository's attestation) each carry the path, a sha256 of\nthe bytes, the file's mtime and how much it held — tagged scenarios for the\none, distinct operationIds for the other. That identifies WHICH file answered\nthe claims, and — when the file is committed — that it matches the attested\ncommit. It does not prove the file came from executing that commit; no digest\ncan.\n\nEverything else you answer from the code, and \\`--record answers.json\\` takes\nthose back — into \\`features/<FEAT>/verification/<svc>.yaml\\` with \\`--service\\`,\ninto the one file \\`features/<FEAT>/verification.yaml\\` without — and either\ntravels into the archive with the feature and reads without loam. Alongside the mechanical\nflags, the answers file must answer exactly the claims no report owns: an\nentry for a report-owned claim is refused (\\`answers-mismatch\\`), and a\nmechanical flag alone is refused while claims outside its kind are\noutstanding. Every recorded verdict says who answered it\n(\\`answered_by: runner | external-runner | agent\\`), so a reviewer can tell a\ngreen run from somebody's word.\n\n**A cross-service feature is verified once per service, and the form matters.**\nThe claims of one feature belong to several services, and each service's code\nlives in its own repository — so the recording form is federated:\n\n\\`\\`\\`sh\n# in EACH affected service's own repo, not in the docs repo:\nloam verify FEAT-101 --service payment-service --results report.json --record answers.json\n# with an API contract suite, its report answers the api.exposes claims too:\nloam verify FEAT-101 --service payment-service --results report.json --contract-results contract.json --record answers.json\n\\`\\`\\`\n\n\\`--service <id>\\` narrows the checklist to that service's claims and binds the\nanswers to this repository's commit, producing that service's **attestation**\nas a file of its own, \\`features/<FEAT>/verification/<id>.yaml\\`. The directory\nis the record: loam adds the files up when it reads, and the verdict and\ncounts are computed from them, never stored. Re-running it in the next repo\nwrites that repo's file and touches no other — which is why two teams'\nattestations on two docs-repo branches merge cleanly, where one shared file\nconflicted every time. A one-file federated \\`verification.yaml\\` written\nbefore the directory is still read; a service that records again supersedes\nits share of it, and the file goes once every service it names has its own.\nOmitting\n\\`--service\\` in a repo whose \\`loam.json\\` declares one substitutes it, so the\nshort form is safe there; a \\`--service\\` naming a service this repo does not\ndeclare is refused (\\`service-mismatch\\`), and \\`--service\\` from a repo that\ndeclares none is refused (\\`repository-unavailable\\`) — an attestation has to be\nbound to the code it is about.\n\n⚠ **The legacy all-at-once form \\`loam verify <FEAT> --record answers.json\\` with\nno \\`--service\\` writes the whole record from one place.** Over a record that\nalready carries other services' attestations it is refused outright\n(\\`record-federated\\`, naming the attestors) rather than merged or migrated — the\nalternative was one repo silently erasing nine others' evidence. Use it only for\na single-service feature that has never been recorded federated. A record file\nthat exists but cannot be read — broken YAML, git conflict markers, a miscount\n— is \\`record-unreadable\\`: it is never overwritten and never reported as \"no\nrecord\", and the message names the file and the repair that is safe for it. A\nservice's own \\`verification/<id>.yaml\\` holds only that service's word, so that\nservice may delete it and record again; the one-file \\`verification.yaml\\` may\nhold other services' attestations, so it is restored from version control\n(after a merge, the copy on the branch you merged into) and never deleted.\n\nReading is not writing: \\`loam verify <FEAT> --service <id>\\` **without**\n\\`--record\\` is a pure lens on the checklist. A read-only verify checklist needs no\nbinding and works from the docs repo, or from anywhere else — the refusals above\nare about WRITING an attestation, and only about that. Every run lists all\nsubjects in \\`services\\`, and a recorded run reports in \\`discarded\\` every previous\nanswer the new record does not carry.\n\nIt refuses an answer set that does not answer the current checklist: an id that\nis not on it (\\`answers-mismatch\\`), a claim with no answer (same), or a\n\\`confirmed\\` with no evidence (\\`answers-unevidenced\\`). Evidence is \\`file:line\\`.\nA claim you cannot show is \\`unconfirmed\\` with a note saying why — that is a\nsuccessful record, and it is more useful to the next reader than a yes.\n\n**Nothing gates on it.** \\`loam archive\\` will ship an unverified feature. That\nis deliberate: coherence is something loam computed from the documents, and a\nverdict is your word about code loam never read. A gate in front of shipping\nwould only teach everyone that the cheapest way past it is to say yes. The\nrecord is for the reviewer who comes later, so leave it true.\n`,\n};\n"]}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
export const LOAM_DRAWING = {
|
|
2
|
+
name: "loam-drawing",
|
|
3
|
+
description: "Reference: drawing the map so a person can read it — relationship kinds and which way each arrow points, the legend, overview views",
|
|
4
|
+
// A reference page takes no arguments: see ../spine.ts for why the hint is
|
|
5
|
+
// empty rather than a spelled-out "<none>".
|
|
6
|
+
argumentHint: "",
|
|
7
|
+
purpose: "How to draw the C4 model so the picture reads: one relationship kind per kind of traffic and an arrow only where evidence gives one, a legend drawn from real edges, and overview views that each answer one question at one altitude.",
|
|
8
|
+
invocation: "loam instructions loam-drawing",
|
|
9
|
+
placeholders: [],
|
|
10
|
+
spine: [
|
|
11
|
+
"Which way an arrow points — the relationship kinds",
|
|
12
|
+
"The legend",
|
|
13
|
+
"Overview views that read",
|
|
14
|
+
"A feature's message flows",
|
|
15
|
+
],
|
|
16
|
+
body: `Drawing the fleet so that a person can read it: one relationship kind per kind of traffic, an arrow only where evidence gives one, a legend, and overview views that each answer one question.
|
|
17
|
+
|
|
18
|
+
Nothing on this page is graded. loam reads elements and relationships, never a
|
|
19
|
+
view, and no check reads a relationship's kind — so a map can validate clean
|
|
20
|
+
and still be a wall of tiny boxes joined by gray lines. Every spelling below was
|
|
21
|
+
measured at the LikeC4 1.59.2 pin loam ships.
|
|
22
|
+
|
|
23
|
+
## Which way an arrow points — the relationship kinds
|
|
24
|
+
|
|
25
|
+
A plain \`->\` says only that two things are connected. A fleet drawn from
|
|
26
|
+
deployment configuration, which says nothing more than that, ends with every
|
|
27
|
+
arrow pointing into the broker and the stores. So give every relationship ONE
|
|
28
|
+
kind, and give each kind one meaning:
|
|
29
|
+
|
|
30
|
+
- \`publishes\` — producer \`->\` topic, with \`metadata { publishes '<message>' }\`:
|
|
31
|
+
the producer puts the message on the topic.
|
|
32
|
+
- \`delivers\` — topic \`->\` consumer, with \`metadata { consumes '<message>' }\`:
|
|
33
|
+
the broker hands the message to the consumer.
|
|
34
|
+
- \`reads\` — service \`->\` store, its head drawn at the SERVICE end (a tail
|
|
35
|
+
arrow): data flows out of the store into the service.
|
|
36
|
+
- \`writes\` — service \`->\` store, its head at the store: data lands in the store.
|
|
37
|
+
- \`readsWrites\` — service \`->\` store, heads at both ends: both.
|
|
38
|
+
- \`calls\` — caller \`->\` provider, with \`metadata { op '<operationId>' }\`: a
|
|
39
|
+
synchronous request.
|
|
40
|
+
- \`connects\` — gray, dashed, no arrowhead: a connection whose direction nobody
|
|
41
|
+
has established yet.
|
|
42
|
+
|
|
43
|
+
For the store kinds the arrowhead is where the data lands, and putting it there
|
|
44
|
+
is the style's job, never the arrow's: a store edge is ALWAYS written
|
|
45
|
+
service \`->\` store, and a read gets its head at the service end from the
|
|
46
|
+
\`reads\` style. Never flip a store edge to show a read. \`Covers:\` names an
|
|
47
|
+
edge as \`a -> b\`, review order reads a plain edge's source as depending on its
|
|
48
|
+
target, and the consumer census behind \`landscape.datastore-shared\` reads both
|
|
49
|
+
directions only for an element whose kind is \`database\`, \`queue\`, \`topic\`,
|
|
50
|
+
\`cache\` or \`bucket\` — a store drawn as any other kind has a service for a
|
|
51
|
+
consumer only when the store is the edge's TARGET. SCHEMA.md, "Which way an edge
|
|
52
|
+
points", lists every reader.
|
|
53
|
+
|
|
54
|
+
**Never guess a direction.** Give an edge a direction only from evidence:
|
|
55
|
+
|
|
56
|
+
- the service's code: the client that sends, the listener that receives, the
|
|
57
|
+
repository that writes;
|
|
58
|
+
- a configuration name that says which side the service is on —
|
|
59
|
+
\`*_PRODUCER_*\`, \`*_CONSUMER_*\`, a consumer-group id;
|
|
60
|
+
- the service's own \`asyncapi.yaml\`: \`action: send\` publishes,
|
|
61
|
+
\`action: receive\` consumes.
|
|
62
|
+
|
|
63
|
+
Configuration that lists a broker address or a database URL says only that the
|
|
64
|
+
two are connected: draw that as \`connects\`. A \`connects\` edge is an honest
|
|
65
|
+
placeholder, not a defect, and adopting the service from its code is what turns
|
|
66
|
+
it into a real kind (\`loam instructions loam-adopt <id>\`, step 3). A guessed
|
|
67
|
+
\`publishes\` is worse than a \`connects\`: it reads exactly like a right one, it
|
|
68
|
+
binds the event spine, and nobody goes back to check it.
|
|
69
|
+
|
|
70
|
+
Declare the kinds once, in \`architecture/landscape.likec4\`'s own
|
|
71
|
+
\`specification\` block, where every extending model borrows them:
|
|
72
|
+
|
|
73
|
+
specification {
|
|
74
|
+
relationship publishes {
|
|
75
|
+
color amber
|
|
76
|
+
line solid
|
|
77
|
+
head normal
|
|
78
|
+
}
|
|
79
|
+
relationship delivers {
|
|
80
|
+
color amber
|
|
81
|
+
line solid
|
|
82
|
+
head normal
|
|
83
|
+
}
|
|
84
|
+
relationship reads {
|
|
85
|
+
color green
|
|
86
|
+
head none
|
|
87
|
+
tail normal
|
|
88
|
+
}
|
|
89
|
+
relationship writes {
|
|
90
|
+
color green
|
|
91
|
+
head normal
|
|
92
|
+
}
|
|
93
|
+
relationship readsWrites {
|
|
94
|
+
color green
|
|
95
|
+
head normal
|
|
96
|
+
tail normal
|
|
97
|
+
}
|
|
98
|
+
relationship calls {
|
|
99
|
+
color secondary
|
|
100
|
+
line solid
|
|
101
|
+
head normal
|
|
102
|
+
}
|
|
103
|
+
relationship connects {
|
|
104
|
+
color gray
|
|
105
|
+
line dashed
|
|
106
|
+
head none
|
|
107
|
+
tail odot
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
Then name the kind in brackets on each edge:
|
|
112
|
+
|
|
113
|
+
marketplace.checkoutWeb -[calls]-> marketplace.orderService 'createOrder' {
|
|
114
|
+
metadata { op 'createOrder' }
|
|
115
|
+
}
|
|
116
|
+
marketplace.orderService -[publishes]-> kafka.orderEvents 'OrderPlaced' {
|
|
117
|
+
metadata { publishes 'order.OrderPlaced' }
|
|
118
|
+
}
|
|
119
|
+
kafka.orderEvents -[delivers]-> marketplace.paymentService 'OrderPlaced' {
|
|
120
|
+
metadata { consumes 'order.OrderPlaced' }
|
|
121
|
+
}
|
|
122
|
+
marketplace.paymentService -[reads]-> marketplace.ordersDb 'order totals'
|
|
123
|
+
marketplace.orderService -[connects]-> kafka 'broker address in its deployment config'
|
|
124
|
+
|
|
125
|
+
A store a service owns and nests INSIDE its own element cannot take an edge from
|
|
126
|
+
that element: LikeC4 refuses a relationship between a parent and its child
|
|
127
|
+
("Invalid parent-child relationship"). Draw that edge from the container that
|
|
128
|
+
does the work, in the service's own model
|
|
129
|
+
(\`marketplace.orderService.api -[readsWrites]-> marketplace.orderService.db\`),
|
|
130
|
+
or draw the store beside the service.
|
|
131
|
+
|
|
132
|
+
A feature's \`delta.likec4\` parses on its own, so it declares every kind it
|
|
133
|
+
draws in its own \`specification\` block too. **The living map must declare that
|
|
134
|
+
kind BEFORE the feature archives.** \`loam archive\` copies the edge into
|
|
135
|
+
\`architecture/landscape.likec4\` as written and never copies a declaration.
|
|
136
|
+
When the map lacks the kind, the merged map does not parse and the archive
|
|
137
|
+
refuses with \`merge-failed\` ("Could not resolve reference to
|
|
138
|
+
RelationshipKind"), while \`loam validate --feature\` and \`loam status\` still
|
|
139
|
+
called the feature ready. A kind is vocabulary, not a change, so adding it to the
|
|
140
|
+
map's \`specification\` is an ordinary edit to the living map, made in its own
|
|
141
|
+
change.
|
|
142
|
+
|
|
143
|
+
Two spellings to avoid:
|
|
144
|
+
|
|
145
|
+
- **Never put a tag on a kind** (\`relationship publishes { #async }\`). LikeC4
|
|
146
|
+
copies a kind's tags onto every edge of that kind. A \`#<FEAT>\` there makes
|
|
147
|
+
every such edge in the delta part of the change, context included, and an
|
|
148
|
+
\`#obl-\` tag there claims the obligation for every edge of that kind. Tag the
|
|
149
|
+
edge instead.
|
|
150
|
+
- **Never use the dotted form** (\`orderService .publishes kafka.orderEvents\`).
|
|
151
|
+
LikeC4 reads it, but not every loam reader does: \`loam validate --base\` scans
|
|
152
|
+
an extending model without the map's kinds and does not see such an edge.
|
|
153
|
+
Write \`-[publishes]->\`.
|
|
154
|
+
|
|
155
|
+
\`connects\` carries \`tail odot\` on purpose. An edge with no arrowhead at either
|
|
156
|
+
end is laid out with \`constraint=false\` and \`minlen=0\`, and enough of them
|
|
157
|
+
collapse a view into one band. The small circle at the source keeps the edge in
|
|
158
|
+
the layout without claiming a direction.
|
|
159
|
+
|
|
160
|
+
The kind is the picture and the metadata is the join. \`metadata { op }\`,
|
|
161
|
+
\`publishes\` and \`consumes\` are what loam grades (\`loam instructions loam-spine\`).
|
|
162
|
+
A kind changes no grade, so a kind with no metadata beside it is a drawing that
|
|
163
|
+
nothing checks.
|
|
164
|
+
|
|
165
|
+
## The legend
|
|
166
|
+
|
|
167
|
+
Add a \`legend\` view to \`architecture/landscape.likec4\` that draws ONE real
|
|
168
|
+
edge of each kind the map uses. Use real services, a real topic and a real store,
|
|
169
|
+
so that a reader learns the colours from the fleet itself. Name each edge by
|
|
170
|
+
both of its endpoints:
|
|
171
|
+
|
|
172
|
+
view legend {
|
|
173
|
+
title 'Fleet / 0 · Legend'
|
|
174
|
+
include marketplace.checkoutWeb -> marketplace.orderService
|
|
175
|
+
include marketplace.orderService -> kafka.orderEvents
|
|
176
|
+
include kafka.orderEvents -> marketplace.paymentService
|
|
177
|
+
include marketplace.paymentService -> marketplace.ordersDb
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
A view can name only elements the model declares, so the legend is written once
|
|
181
|
+
the map has real edges of each kind, and it gains a line when the map gains a
|
|
182
|
+
kind. \`loam init\` cannot scaffold one, because an empty map has nothing to draw.
|
|
183
|
+
|
|
184
|
+
## Overview views that read
|
|
185
|
+
|
|
186
|
+
A view is a picture for one reader with one question. Every rule below comes
|
|
187
|
+
from an overview that drew the whole fleet and so showed nothing:
|
|
188
|
+
|
|
189
|
+
- **One question per view, at one altitude.** "Who publishes to the broker?" is
|
|
190
|
+
one view, and "who calls whom" is another. A fleet overview draws subsystem
|
|
191
|
+
boxes, not services: the generated \`architecture/subsystems.likec4\` and
|
|
192
|
+
\`architecture/services.likec4\` views are the drill-down. Aim for at most
|
|
193
|
+
about 20 nodes and 25 drawn lines.
|
|
194
|
+
- **Filter by ONE kind, and say it positively.** A view above service altitude
|
|
195
|
+
merges every relationship between two boxes into one drawn line. When those
|
|
196
|
+
relationships are of different kinds, LikeC4 falls back to the default gray
|
|
197
|
+
and the line says nothing. \`where kind is publishes\` keeps the line amber;
|
|
198
|
+
\`where kind is not calls\` and \`where kind is publishes or kind is connects\`
|
|
199
|
+
still merge into gray.
|
|
200
|
+
- **Know the form that draws nothing.** Where \`fleet\`'s children are subsystem
|
|
201
|
+
groups, \`include fleet.* -> * where kind is publishes\` renders an EMPTY view,
|
|
202
|
+
with no error. Use a unary form, a named target or a tag target instead:
|
|
203
|
+
|
|
204
|
+
include fleet.* -> where kind is publishes
|
|
205
|
+
include fleet.* -> element.tag = #broker where kind is publishes
|
|
206
|
+
include kafka -> fleet.* where kind is delivers
|
|
207
|
+
include -> fleet.* where kind is delivers
|
|
208
|
+
|
|
209
|
+
- **Prefer relationship rules to element lists.** An element included directly
|
|
210
|
+
brings every relationship between it and the others: \`include fleet.orders, kafka\`
|
|
211
|
+
draws one merged gray line, where
|
|
212
|
+
\`include fleet.orders -> where kind is publishes\` draws one amber line.
|
|
213
|
+
- **Lay out rows with \`rank\`.** \`rank source { … }\`, \`rank same { … }\` and
|
|
214
|
+
\`rank sink { … }\` put nodes in rows, and the braces are required. A
|
|
215
|
+
\`rank source\` row whose nodes' edges all point INTO them is ignored, so a row
|
|
216
|
+
of consumers belongs at \`sink\`.
|
|
217
|
+
- **Give a direction-less edge a marker.** An edge with no arrowhead at either
|
|
218
|
+
end is laid out unconstrained and collapses the view into one band, so give it
|
|
219
|
+
\`tail odot\`, as the \`connects\` style above does.
|
|
220
|
+
- **Titles make folders.** LikeC4 splits a title on \`/\` into browser folders
|
|
221
|
+
and lists sub-folders before views, so number the views you want read in
|
|
222
|
+
order: \`title 'Fleet / 1 · Who publishes'\`.
|
|
223
|
+
- **Never author \`view … of\` a subsystem or service element.** The generated
|
|
224
|
+
views own that drill-down, and an authored one in a file that sorts before
|
|
225
|
+
them — \`landscape.likec4\` does — takes the click from every other view that
|
|
226
|
+
draws the element.
|
|
227
|
+
- **No \`xs\` nodes across a whole fleet, and no \`include parent.**\` with
|
|
228
|
+
excludes.** Together they drew a 68-node band at 2.5 pixels per label, a view
|
|
229
|
+
nobody can read.
|
|
230
|
+
|
|
231
|
+
## A feature's message flows
|
|
232
|
+
|
|
233
|
+
A feature delta draws a message the way the map does: through the broker. Write
|
|
234
|
+
\`orderService -[publishes]-> kafka.orderEvents\` and
|
|
235
|
+
\`kafka.orderEvents -[delivers]-> notificationService\`, never
|
|
236
|
+
\`orderService -> notificationService\` for an event. A direct edge reads as a
|
|
237
|
+
call, sits outside the event spine, and draws a second picture of the topic the
|
|
238
|
+
map already draws. Point at the topic the living map nests in the broker, leave
|
|
239
|
+
that context untagged, and tag only the edges the feature adds.
|
|
240
|
+
|
|
241
|
+
A producer outside the fleet is an \`#external\` element, and the edge it
|
|
242
|
+
publishes on carries the metadata (\`loam instructions loam-spine\`, "A message
|
|
243
|
+
produced outside the fleet", has the full join):
|
|
244
|
+
|
|
245
|
+
crm = softwareSystem 'crm' {
|
|
246
|
+
#external
|
|
247
|
+
}
|
|
248
|
+
crm -[publishes]-> kafka.crmEvents 'CustomerUpdated' {
|
|
249
|
+
metadata { publishes 'crm.CustomerUpdated' }
|
|
250
|
+
}
|
|
251
|
+
`,
|
|
252
|
+
};
|
|
253
|
+
//# sourceMappingURL=drawing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drawing.js","sourceRoot":"","sources":["../../../../../../src/core/agent/workflows/reference/drawing/drawing.ts"],"names":[],"mappings":"AA6BA,MAAM,CAAC,MAAM,YAAY,GAAmB;IAC1C,IAAI,EAAE,cAAc;IACpB,WAAW,EACT,qIAAqI;IACvI,2EAA2E;IAC3E,4CAA4C;IAC5C,YAAY,EAAE,EAAE;IAChB,OAAO,EACL,wOAAwO;IAC1O,UAAU,EAAE,gCAAgC;IAC5C,YAAY,EAAE,EAAE;IAChB,KAAK,EAAE;QACL,oDAAoD;QACpD,YAAY;QACZ,0BAA0B;QAC1B,2BAA2B;KAC5B;IACD,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2OP;CACA,CAAC","sourcesContent":["/**\n * The `loam-drawing` reference page: how to draw the C4 model so that a person\n * can read the picture — one relationship kind per kind of traffic, an arrow\n * that points where the evidence says, a legend, and overview views that each\n * answer one question.\n *\n * WHY A PAGE. A large real fleet was drawn by agents following loam's pages,\n * and every document validated while the pictures were unreadable: every arrow\n * pointed into the broker and the stores (deployment configuration says only\n * that two things are connected, and the agents turned that into a direction),\n * the overview views were walls of tiny boxes, and the lines were the default\n * gray because LikeC4 merges relationships of different kinds into one line\n * with no style. Nothing loam grades could have caught any of it — loam reads\n * elements and relationships and never a view, and no check reads a\n * relationship's KIND — so the only place the lesson can live is the text an\n * agent reads before it draws. That text is consulted at a moment the agent\n * can name (\"I am drawing an edge\", \"I am writing a view\"), which is the split\n * rule in ../reference.ts: a reference page, not AGENTS.md.\n *\n * WHY ITS OWN PACKAGE. ../ sits at the five-file cap, and this page is a\n * subject of its own rather than a section of an existing one: loam-spine says\n * which joins the metadata makes, and this page says how the picture is drawn\n * around them. Every LikeC4 spelling below was measured at the 1.59.2 pin\n * (`likec4 validate`, `export json`, `gen dot`) on a neutral fleet shaped like\n * examples/docs — never on the fleet the lesson came from, which is\n * confidential and must not reach this repository in any form.\n */\nimport type { CommandContent } from \"../../../contract.js\";\n\nexport const LOAM_DRAWING: CommandContent = {\n name: \"loam-drawing\",\n description:\n \"Reference: drawing the map so a person can read it — relationship kinds and which way each arrow points, the legend, overview views\",\n // A reference page takes no arguments: see ../spine.ts for why the hint is\n // empty rather than a spelled-out \"<none>\".\n argumentHint: \"\",\n purpose:\n \"How to draw the C4 model so the picture reads: one relationship kind per kind of traffic and an arrow only where evidence gives one, a legend drawn from real edges, and overview views that each answer one question at one altitude.\",\n invocation: \"loam instructions loam-drawing\",\n placeholders: [],\n spine: [\n \"Which way an arrow points — the relationship kinds\",\n \"The legend\",\n \"Overview views that read\",\n \"A feature's message flows\",\n ],\n body: `Drawing the fleet so that a person can read it: one relationship kind per kind of traffic, an arrow only where evidence gives one, a legend, and overview views that each answer one question.\n\nNothing on this page is graded. loam reads elements and relationships, never a\nview, and no check reads a relationship's kind — so a map can validate clean\nand still be a wall of tiny boxes joined by gray lines. Every spelling below was\nmeasured at the LikeC4 1.59.2 pin loam ships.\n\n## Which way an arrow points — the relationship kinds\n\nA plain \\`->\\` says only that two things are connected. A fleet drawn from\ndeployment configuration, which says nothing more than that, ends with every\narrow pointing into the broker and the stores. So give every relationship ONE\nkind, and give each kind one meaning:\n\n- \\`publishes\\` — producer \\`->\\` topic, with \\`metadata { publishes '<message>' }\\`:\n the producer puts the message on the topic.\n- \\`delivers\\` — topic \\`->\\` consumer, with \\`metadata { consumes '<message>' }\\`:\n the broker hands the message to the consumer.\n- \\`reads\\` — service \\`->\\` store, its head drawn at the SERVICE end (a tail\n arrow): data flows out of the store into the service.\n- \\`writes\\` — service \\`->\\` store, its head at the store: data lands in the store.\n- \\`readsWrites\\` — service \\`->\\` store, heads at both ends: both.\n- \\`calls\\` — caller \\`->\\` provider, with \\`metadata { op '<operationId>' }\\`: a\n synchronous request.\n- \\`connects\\` — gray, dashed, no arrowhead: a connection whose direction nobody\n has established yet.\n\nFor the store kinds the arrowhead is where the data lands, and putting it there\nis the style's job, never the arrow's: a store edge is ALWAYS written\nservice \\`->\\` store, and a read gets its head at the service end from the\n\\`reads\\` style. Never flip a store edge to show a read. \\`Covers:\\` names an\nedge as \\`a -> b\\`, review order reads a plain edge's source as depending on its\ntarget, and the consumer census behind \\`landscape.datastore-shared\\` reads both\ndirections only for an element whose kind is \\`database\\`, \\`queue\\`, \\`topic\\`,\n\\`cache\\` or \\`bucket\\` — a store drawn as any other kind has a service for a\nconsumer only when the store is the edge's TARGET. SCHEMA.md, \"Which way an edge\npoints\", lists every reader.\n\n**Never guess a direction.** Give an edge a direction only from evidence:\n\n- the service's code: the client that sends, the listener that receives, the\n repository that writes;\n- a configuration name that says which side the service is on —\n \\`*_PRODUCER_*\\`, \\`*_CONSUMER_*\\`, a consumer-group id;\n- the service's own \\`asyncapi.yaml\\`: \\`action: send\\` publishes,\n \\`action: receive\\` consumes.\n\nConfiguration that lists a broker address or a database URL says only that the\ntwo are connected: draw that as \\`connects\\`. A \\`connects\\` edge is an honest\nplaceholder, not a defect, and adopting the service from its code is what turns\nit into a real kind (\\`loam instructions loam-adopt <id>\\`, step 3). A guessed\n\\`publishes\\` is worse than a \\`connects\\`: it reads exactly like a right one, it\nbinds the event spine, and nobody goes back to check it.\n\nDeclare the kinds once, in \\`architecture/landscape.likec4\\`'s own\n\\`specification\\` block, where every extending model borrows them:\n\n specification {\n relationship publishes {\n color amber\n line solid\n head normal\n }\n relationship delivers {\n color amber\n line solid\n head normal\n }\n relationship reads {\n color green\n head none\n tail normal\n }\n relationship writes {\n color green\n head normal\n }\n relationship readsWrites {\n color green\n head normal\n tail normal\n }\n relationship calls {\n color secondary\n line solid\n head normal\n }\n relationship connects {\n color gray\n line dashed\n head none\n tail odot\n }\n }\n\nThen name the kind in brackets on each edge:\n\n marketplace.checkoutWeb -[calls]-> marketplace.orderService 'createOrder' {\n metadata { op 'createOrder' }\n }\n marketplace.orderService -[publishes]-> kafka.orderEvents 'OrderPlaced' {\n metadata { publishes 'order.OrderPlaced' }\n }\n kafka.orderEvents -[delivers]-> marketplace.paymentService 'OrderPlaced' {\n metadata { consumes 'order.OrderPlaced' }\n }\n marketplace.paymentService -[reads]-> marketplace.ordersDb 'order totals'\n marketplace.orderService -[connects]-> kafka 'broker address in its deployment config'\n\nA store a service owns and nests INSIDE its own element cannot take an edge from\nthat element: LikeC4 refuses a relationship between a parent and its child\n(\"Invalid parent-child relationship\"). Draw that edge from the container that\ndoes the work, in the service's own model\n(\\`marketplace.orderService.api -[readsWrites]-> marketplace.orderService.db\\`),\nor draw the store beside the service.\n\nA feature's \\`delta.likec4\\` parses on its own, so it declares every kind it\ndraws in its own \\`specification\\` block too. **The living map must declare that\nkind BEFORE the feature archives.** \\`loam archive\\` copies the edge into\n\\`architecture/landscape.likec4\\` as written and never copies a declaration.\nWhen the map lacks the kind, the merged map does not parse and the archive\nrefuses with \\`merge-failed\\` (\"Could not resolve reference to\nRelationshipKind\"), while \\`loam validate --feature\\` and \\`loam status\\` still\ncalled the feature ready. A kind is vocabulary, not a change, so adding it to the\nmap's \\`specification\\` is an ordinary edit to the living map, made in its own\nchange.\n\nTwo spellings to avoid:\n\n- **Never put a tag on a kind** (\\`relationship publishes { #async }\\`). LikeC4\n copies a kind's tags onto every edge of that kind. A \\`#<FEAT>\\` there makes\n every such edge in the delta part of the change, context included, and an\n \\`#obl-\\` tag there claims the obligation for every edge of that kind. Tag the\n edge instead.\n- **Never use the dotted form** (\\`orderService .publishes kafka.orderEvents\\`).\n LikeC4 reads it, but not every loam reader does: \\`loam validate --base\\` scans\n an extending model without the map's kinds and does not see such an edge.\n Write \\`-[publishes]->\\`.\n\n\\`connects\\` carries \\`tail odot\\` on purpose. An edge with no arrowhead at either\nend is laid out with \\`constraint=false\\` and \\`minlen=0\\`, and enough of them\ncollapse a view into one band. The small circle at the source keeps the edge in\nthe layout without claiming a direction.\n\nThe kind is the picture and the metadata is the join. \\`metadata { op }\\`,\n\\`publishes\\` and \\`consumes\\` are what loam grades (\\`loam instructions loam-spine\\`).\nA kind changes no grade, so a kind with no metadata beside it is a drawing that\nnothing checks.\n\n## The legend\n\nAdd a \\`legend\\` view to \\`architecture/landscape.likec4\\` that draws ONE real\nedge of each kind the map uses. Use real services, a real topic and a real store,\nso that a reader learns the colours from the fleet itself. Name each edge by\nboth of its endpoints:\n\n view legend {\n title 'Fleet / 0 · Legend'\n include marketplace.checkoutWeb -> marketplace.orderService\n include marketplace.orderService -> kafka.orderEvents\n include kafka.orderEvents -> marketplace.paymentService\n include marketplace.paymentService -> marketplace.ordersDb\n }\n\nA view can name only elements the model declares, so the legend is written once\nthe map has real edges of each kind, and it gains a line when the map gains a\nkind. \\`loam init\\` cannot scaffold one, because an empty map has nothing to draw.\n\n## Overview views that read\n\nA view is a picture for one reader with one question. Every rule below comes\nfrom an overview that drew the whole fleet and so showed nothing:\n\n- **One question per view, at one altitude.** \"Who publishes to the broker?\" is\n one view, and \"who calls whom\" is another. A fleet overview draws subsystem\n boxes, not services: the generated \\`architecture/subsystems.likec4\\` and\n \\`architecture/services.likec4\\` views are the drill-down. Aim for at most\n about 20 nodes and 25 drawn lines.\n- **Filter by ONE kind, and say it positively.** A view above service altitude\n merges every relationship between two boxes into one drawn line. When those\n relationships are of different kinds, LikeC4 falls back to the default gray\n and the line says nothing. \\`where kind is publishes\\` keeps the line amber;\n \\`where kind is not calls\\` and \\`where kind is publishes or kind is connects\\`\n still merge into gray.\n- **Know the form that draws nothing.** Where \\`fleet\\`'s children are subsystem\n groups, \\`include fleet.* -> * where kind is publishes\\` renders an EMPTY view,\n with no error. Use a unary form, a named target or a tag target instead:\n\n include fleet.* -> where kind is publishes\n include fleet.* -> element.tag = #broker where kind is publishes\n include kafka -> fleet.* where kind is delivers\n include -> fleet.* where kind is delivers\n\n- **Prefer relationship rules to element lists.** An element included directly\n brings every relationship between it and the others: \\`include fleet.orders, kafka\\`\n draws one merged gray line, where\n \\`include fleet.orders -> where kind is publishes\\` draws one amber line.\n- **Lay out rows with \\`rank\\`.** \\`rank source { … }\\`, \\`rank same { … }\\` and\n \\`rank sink { … }\\` put nodes in rows, and the braces are required. A\n \\`rank source\\` row whose nodes' edges all point INTO them is ignored, so a row\n of consumers belongs at \\`sink\\`.\n- **Give a direction-less edge a marker.** An edge with no arrowhead at either\n end is laid out unconstrained and collapses the view into one band, so give it\n \\`tail odot\\`, as the \\`connects\\` style above does.\n- **Titles make folders.** LikeC4 splits a title on \\`/\\` into browser folders\n and lists sub-folders before views, so number the views you want read in\n order: \\`title 'Fleet / 1 · Who publishes'\\`.\n- **Never author \\`view … of\\` a subsystem or service element.** The generated\n views own that drill-down, and an authored one in a file that sorts before\n them — \\`landscape.likec4\\` does — takes the click from every other view that\n draws the element.\n- **No \\`xs\\` nodes across a whole fleet, and no \\`include parent.**\\` with\n excludes.** Together they drew a 68-node band at 2.5 pixels per label, a view\n nobody can read.\n\n## A feature's message flows\n\nA feature delta draws a message the way the map does: through the broker. Write\n\\`orderService -[publishes]-> kafka.orderEvents\\` and\n\\`kafka.orderEvents -[delivers]-> notificationService\\`, never\n\\`orderService -> notificationService\\` for an event. A direct edge reads as a\ncall, sits outside the event spine, and draws a second picture of the topic the\nmap already draws. Point at the topic the living map nests in the broker, leave\nthat context untagged, and tag only the edges the feature adds.\n\nA producer outside the fleet is an \\`#external\\` element, and the edge it\npublishes on carries the metadata (\\`loam instructions loam-spine\\`, \"A message\nproduced outside the fleet\", has the full join):\n\n crm = softwareSystem 'crm' {\n #external\n }\n crm -[publishes]-> kafka.crmEvents 'CustomerUpdated' {\n metadata { publishes 'crm.CustomerUpdated' }\n }\n`,\n};\n"]}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { LOAM_AUTHORING } from "./authoring.js";
|
|
2
2
|
import { LOAM_CODES } from "./codes.js";
|
|
3
3
|
import { LOAM_DONE_CHECK } from "./done-check.js";
|
|
4
|
+
import { LOAM_DRAWING } from "./drawing/drawing.js";
|
|
4
5
|
import { LOAM_SPINE } from "./spine.js";
|
|
5
6
|
/**
|
|
6
|
-
* The
|
|
7
|
-
* order their sections stood in the document they left, so a
|
|
8
|
-
* the file finds them where they were.
|
|
7
|
+
* The five pages, in the order AGENTS.md's own index names them. The first four
|
|
8
|
+
* stand in the order their sections stood in the document they left, so a
|
|
9
|
+
* reader who knew the file finds them where they were. The drawing page comes
|
|
10
|
+
* last because it never stood there.
|
|
9
11
|
*/
|
|
10
12
|
export const REFERENCES = [
|
|
11
13
|
LOAM_CODES,
|
|
12
14
|
LOAM_SPINE,
|
|
13
15
|
LOAM_AUTHORING,
|
|
14
16
|
LOAM_DONE_CHECK,
|
|
17
|
+
LOAM_DRAWING,
|
|
15
18
|
];
|
|
16
19
|
//# sourceMappingURL=reference.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reference.js","sourceRoot":"","sources":["../../../../../src/core/agent/workflows/reference/reference.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reference.js","sourceRoot":"","sources":["../../../../../src/core/agent/workflows/reference/reference.ts"],"names":[],"mappings":"AAiEA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAqB;IAC1C,UAAU;IACV,UAAU;IACV,cAAc;IACd,eAAe;IACf,YAAY;CACb,CAAC","sourcesContent":["/**\n * Why the reference pages exist, what decided which content became one, and the\n * list itself.\n *\n * THE MEASUREMENT. AGENTS.md is auto-loaded from the working directory by every\n * agents.md-aware host, on every session, and `loam init` writes it once and\n * never refreshes it. It had reached 109,399 bytes. Codex truncates the\n * AGENTS.md chain at 32,768 bytes and Windsurf caps a workspace rule file at\n * 12,000 characters — both silently, with no error and no way for the reader to\n * tell which half it was holding. Roughly seventy percent of the document was\n * being dropped on those two hosts, and which seventy percent depended on the\n * host rather than on what the reader needed.\n *\n * THE SPLIT RULE, which is not \"move the big parts\". Two kinds of content were\n * mixed in one file:\n *\n * - what a reader needs to FORM a question — the layout, the cycle, which\n * element is which service, what gates and what only advises, what the words\n * mean. Without it an agent cannot ask anything, so it cannot be behind a\n * command it does not know to run. That stays in AGENTS.md;\n * - what a reader CONSULTS at a moment it can name — the grammars for writing\n * one document, the inventory of what a command can report, the done-check's\n * channels. The moment is nameable (\"I am writing an arch.spec.md\", \"a run\n * reported something\"), so the page can be fetched then, and paying for it on\n * every invocation of every session bought nothing.\n *\n * That rule is why the binding rule — which element IS which service — stayed\n * in AGENTS.md while the rest of the ID spine left (it is ORIENTATION's\n * `## The identity rule` in ../../agents-md.ts now, condensed from the section\n * that used to stay behind), and why the per-invocation code inventory left\n * while the facts about the `--json` envelope stayed. Size followed from the\n * rule; it did not drive it.\n *\n * WHAT A PAGE COSTS AND WHAT IT BUYS. A page printed by the binary describes\n * the loam you are about to run, not the one that scaffolded the repository —\n * which is strictly better than a file `loam init` writes once and never\n * refreshes, and is why `agents.stale` exists at all. What it costs is\n * discoverability: a reference nobody can find is content deleted with extra\n * steps. Three things pay that back, and all three are asserted rather than\n * hoped for — AGENTS.md's own \"Reference pages\" section names each page\n * with the exact command (test/agents.test.ts), bare `loam instructions` lists\n * them beside the workflows (test/instructions.test.ts), and every stable code\n * that left is still in the corpus test/codes-drift.test.ts reads, because\n * {@link REFERENCES} feeds `PROTOCOLS`.\n *\n * WHAT A PAGE IS NOT. It is not a workflow. It has no steps, takes no\n * arguments, and `loam init` writes NO file for it — ../../protocol.ts feeds\n * this list to `PROTOCOLS` and `placeholderProblems` and to nothing else, so\n * `SLASH_COMMANDS` and `plannedCommandFiles` never see it and no repository\n * gains a generated artifact. Four pages are four more files in every repo loam\n * touches, and the whole point of the move was to stop shipping bytes nobody\n * asked for.\n *\n * THE MOVE WAS A MOVE. Every page's text is its AGENTS.md section verbatim.\n * Nothing was rewritten on the way, because a paraphrase is a second copy that\n * can drift — and removing one of those is what this whole change is for.\n *\n * THE FIFTH PAGE WAS NEVER A SECTION. `loam-drawing` (./drawing/drawing.ts)\n * was written as a page from the start: how to draw the map so that a person\n * can read it is consulted at the moment an edge or a view is drawn, which is\n * the split rule above, and no AGENTS.md section ever held it. It came from a\n * real fleet whose documents all validated while every picture of it was\n * unreadable. The page carries the rest of that story.\n */\nimport type { CommandContent } from \"../../contract.js\";\nimport { LOAM_AUTHORING } from \"./authoring.js\";\nimport { LOAM_CODES } from \"./codes.js\";\nimport { LOAM_DONE_CHECK } from \"./done-check.js\";\nimport { LOAM_DRAWING } from \"./drawing/drawing.js\";\nimport { LOAM_SPINE } from \"./spine.js\";\n\n/**\n * The five pages, in the order AGENTS.md's own index names them. The first four\n * stand in the order their sections stood in the document they left, so a\n * reader who knew the file finds them where they were. The drawing page comes\n * last because it never stood there.\n */\nexport const REFERENCES: CommandContent[] = [\n LOAM_CODES,\n LOAM_SPINE,\n LOAM_AUTHORING,\n LOAM_DONE_CHECK,\n LOAM_DRAWING,\n];\n"]}
|
|
@@ -101,9 +101,12 @@ heading refuses the archive here as it does in a spec delta, and
|
|
|
101
101
|
\`spec.md\` — an empty one is not a delta, so the merge would carry nothing.
|
|
102
102
|
\`loam archive\` merges it into the living document in the same
|
|
103
103
|
transaction as the service merge, creating \`capabilities/<id>/spec.md\` — and
|
|
104
|
-
so the whole tree — when this is the first feature to mention it
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
so the whole tree — when this is the first feature to mention it. Only what
|
|
105
|
+
the delta marks as the document's own comes across: its H1 as the title
|
|
106
|
+
(unless it names the feature or calls itself a delta — then the title is the
|
|
107
|
+
id), its \`## Purpose\` section as the narrative, and a line linking back to the
|
|
108
|
+
archived delta for everything else, because loam merges requirements and never
|
|
109
|
+
prose; after that the narrative is yours to edit in place. The document's three rules above are
|
|
107
110
|
graded on the delta BEFORE the merge, so a capability requirement filed at the
|
|
108
111
|
wrong altitude is refused while you still hold it. Editing the living document
|
|
109
112
|
directly is still legal; the delta is what makes two features touching one
|
|
@@ -199,16 +202,44 @@ the shape that reverts someone else's landed change at exit 0. A migrated
|
|
|
199
202
|
corpus is not stranded by this: \`loam rebase <FEAT>\` pins every delta in one
|
|
200
203
|
command, and a human's \`--approve\` archives unpinned when the loss is meant.
|
|
201
204
|
|
|
202
|
-
### The same pin on the contract axis
|
|
203
|
-
|
|
204
|
-
A feature's \`openapi.yaml\` is a
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
operation
|
|
210
|
-
|
|
211
|
-
|
|
205
|
+
### The same pin on the contract axis
|
|
206
|
+
|
|
207
|
+
A feature's \`openapi.yaml\` is a self-contained document holding ONLY what the
|
|
208
|
+
feature adds, changes or removes — not a copy of the living contract. The merge
|
|
209
|
+
walks only the paths and methods the delta spells: an operation you leave out
|
|
210
|
+
stays exactly as the living contract has it, a local \`$ref\`
|
|
211
|
+
(\`#/components/schemas/Order\`) resolves into the living document, and a new
|
|
212
|
+
operation has no living version to pin — an add-only delta needs no rebase.
|
|
213
|
+
|
|
214
|
+
What the merge does upsert is every operation the document DOES spell. So an
|
|
215
|
+
operation you quote without changing it — copied for context, or a whole
|
|
216
|
+
contract pasted in — is a collision waiting for someone else's edit: two
|
|
217
|
+
features over one service, each quoting the operation the other edits, destroy
|
|
218
|
+
each other, and the second to archive pushes its authoring-time copy back over
|
|
219
|
+
whatever landed in between. Quote nothing you do not change. Each quote costs a
|
|
220
|
+
pin, and a parallel feature that REMOVES the quoted operation makes it worse
|
|
221
|
+
either way: pinned, the quote is \`openapi.baseline-invalid\`, an error that
|
|
222
|
+
blocks your archive, and \`openapi.op-revived\` beside it; unpinned, it is
|
|
223
|
+
\`openapi.op-revived\` alone — a warning that gates, because the merge would
|
|
224
|
+
read the dead operation as a new one and put it back (\`asyncapi.slot-revived\`
|
|
225
|
+
is the same finding on a channel, operation or message slot). A parallel
|
|
226
|
+
feature that MOVES the operation to another address does the same to a quote
|
|
227
|
+
of the old one, which archived would answer the operationId at both. The fix
|
|
228
|
+
for both is to delete the quote. Keep it only when the feature brings a
|
|
229
|
+
retired operation back ON PURPOSE: then drop any pin, and a human archives
|
|
230
|
+
with \`--approve\`. \`loam rebase\` never pins a retired operation as new —
|
|
231
|
+
nothing lives at its slot, so there is no version to pin — and prints the same
|
|
232
|
+
finding (\`revived[]\` in \`--json\`), so the decision stays with you. It judges
|
|
233
|
+
the delta as it will write it, pins included: a quote of an address another
|
|
234
|
+
operation lives at now — one a move vacated, since re-occupied — IS repinned,
|
|
235
|
+
over the operation living there, which makes it an edit the merge would write;
|
|
236
|
+
the revival that edit makes is reported by that rebase (or its \`--dry-run\`),
|
|
237
|
+
not first by the next validate. The check reads the removal
|
|
238
|
+
markers of the features under \`features/archive/\` — a removal made by
|
|
239
|
+
hand-editing a living contract is invisible to it.
|
|
240
|
+
|
|
241
|
+
The guard against that collision, for every living operation the delta does
|
|
242
|
+
spell, is a pin — a vendor extension beside \`x-loam-remove\`:
|
|
212
243
|
|
|
213
244
|
\`\`\`yaml
|
|
214
245
|
paths:
|
|
@@ -218,8 +249,9 @@ paths:
|
|
|
218
249
|
x-loam-based-on: 86feabe621ed887d
|
|
219
250
|
\`\`\`
|
|
220
251
|
|
|
221
|
-
\`loam rebase\` writes one on
|
|
222
|
-
|
|
252
|
+
\`loam rebase\` writes one on every operation in the delta the living contract
|
|
253
|
+
already holds, pinned to the living version; what the feature adds gets none.
|
|
254
|
+
That is what lets the merge tell a QUOTE from an EDIT:
|
|
223
255
|
|
|
224
256
|
- pin equals the operation's own content → you quoted it → **the merge skips it
|
|
225
257
|
entirely** and the living contract keeps whatever it holds. Archive prints
|
|
@@ -228,12 +260,15 @@ version. That is what lets the merge tell a QUOTE from an EDIT:
|
|
|
228
260
|
- pin matches neither → you edited it AND somebody landed a change to it →
|
|
229
261
|
\`openapi.baseline-stale\`, refused.
|
|
230
262
|
|
|
231
|
-
|
|
232
|
-
\`servers\`) and
|
|
233
|
-
|
|
234
|
-
\`
|
|
235
|
-
|
|
236
|
-
|
|
263
|
+
The two surfaces an in-operation key cannot reach — path-level keys
|
|
264
|
+
(\`parameters\`, \`servers\`, \`summary\`, \`x-*\`) and every
|
|
265
|
+
\`components/<kind>/<name>\` — are pinned the same way through one root record,
|
|
266
|
+
\`x-loam-baselines\`, which \`loam rebase\` also writes and the merge strips: a
|
|
267
|
+
quoted key or component is skipped, an edited one is written and warned as
|
|
268
|
+
\`openapi.path-item-modified\` / \`openapi.component-modified\`. A new component
|
|
269
|
+
is copied in when something the merge writes references it; a living one you
|
|
270
|
+
only \`$ref\` needs no copy in the delta at all. Removal markers carry no pin;
|
|
271
|
+
\`openapi.remove-target-mismatch\` is what guards those.
|
|
237
272
|
|
|
238
273
|
## Drawing a shared broker
|
|
239
274
|
|
|
@@ -248,19 +283,25 @@ element and point the edges at it — \`paymentService -> kafka.paymentEvents\`,
|
|
|
248
283
|
\`paymentService -> kafka\`. One hub of degree sixty becomes twelve of degree
|
|
249
284
|
five, and it is the truer model besides: what a producer and a consumer share is
|
|
250
285
|
the topic, never the broker. Every check joins the same way, because an edge into
|
|
251
|
-
a nested element resolves to the element that owns it. Declare the kind once
|
|
252
|
-
tag it there —
|
|
286
|
+
a nested element resolves to the element that owns it. Declare the kind once —
|
|
253
287
|
|
|
254
288
|
specification {
|
|
255
289
|
element topic {
|
|
256
|
-
#external
|
|
257
290
|
style { shape queue }
|
|
258
291
|
}
|
|
259
292
|
}
|
|
260
293
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
294
|
+
The KIND is what does the work: since 2026-09-07 loam reads \`database\`, \`queue\`,
|
|
295
|
+
\`topic\`, \`cache\` and \`bucket\` as infrastructure rather than as candidate
|
|
296
|
+
services, so a topic drawn this way is out of the service census and nobody is
|
|
297
|
+
asked for a \`services/payment.events/\` (measured: the same element spelled
|
|
298
|
+
\`container\` earns \`landscape.service-undocumented\`, spelled \`topic\` it earns
|
|
299
|
+
nothing). This used to need \`#external\` ON THE KIND as a workaround, because
|
|
300
|
+
**LikeC4 does not inherit tags** and a topic nested inside an \`#external\` broker
|
|
301
|
+
is not external itself. That workaround is no longer owed. Tag the kind
|
|
302
|
+
\`#external\` if you want the topics out of the fleet VIEW as well — that is what
|
|
303
|
+
the next paragraph's \`exclude\` reads, and it is a rendering choice now rather
|
|
304
|
+
than a way to silence a check.
|
|
264
305
|
|
|
265
306
|
**Scope the views.** \`exclude element.tag = #external\` keeps the fleet overview to
|
|
266
307
|
the calls between our own services; a second view over the broker draws the event
|