@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
|
@@ -9,11 +9,10 @@
|
|
|
9
9
|
* `unreadableLandscape` in `./load.ts`.
|
|
10
10
|
*/
|
|
11
11
|
import { existsSync } from "node:fs";
|
|
12
|
-
import { relative } from "node:path";
|
|
13
12
|
import { readFile } from "node:fs/promises";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { landscapePath as landscapeFile } from "../../../core/repo/paths.js";
|
|
13
|
+
import {} from "../../../core/c4/likec4.js";
|
|
14
|
+
import { serviceResolver } from "../../../core/c4/resolve/service.js";
|
|
15
|
+
import { landscapePath as landscapeFile, servicePathsAt } from "../../../core/repo/paths.js";
|
|
17
16
|
import { serviceIdFindings } from "../../../core/repo/entries.js";
|
|
18
17
|
import { listFleetTree, listServices } from "../../../core/repo/repo.js";
|
|
19
18
|
import {} from "../../../core/vocabulary/report.js";
|
|
@@ -26,17 +25,20 @@ import { obligationFindings, obligationVocabularyFindings } from "./obligations.
|
|
|
26
25
|
import { readObligations } from "../../../core/obligations/obligations.js";
|
|
27
26
|
import { obligationsPath } from "../../../core/repo/paths.js";
|
|
28
27
|
import { EXTERNAL_TAG } from "../../../core/vocabulary/maturity.js";
|
|
29
|
-
import { errorText } from "
|
|
28
|
+
import { brokenDocumentPaths, errorText } from "../../../core/c4/likec4.js";
|
|
30
29
|
import { serviceTreePath } from "../../../core/kernel/ids/dirs.js";
|
|
31
|
-
import { drawnSystems, serviceLevelElements } from "./census.js";
|
|
30
|
+
import { drawnSystems, serviceLevelElements, standsForService } from "./census.js";
|
|
32
31
|
import { unreadableLandscape } from "./load.js";
|
|
33
32
|
import { kindTagFindings } from "./kind-tags.js";
|
|
34
|
-
import {
|
|
33
|
+
import { mapAttestation } from "./map/attest.js";
|
|
34
|
+
import { bindingFindings } from "./map/bindings.js";
|
|
35
|
+
import { consumerCensus, datastoreFindings } from "./map/consumers.js";
|
|
36
|
+
import { isolationFindings } from "./map/isolation.js";
|
|
37
|
+
import { fleetUseCaseFindings } from "./map/usecases.js";
|
|
35
38
|
import { viewIdFindings } from "./views/ids.js";
|
|
36
39
|
import { viewsStaleFindings } from "./views/stale.js";
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
import { parseRequirements, readRequirementsDocument } from "../../../core/document/parse.js";
|
|
40
|
+
import { projectFindings } from "./views/projects.js";
|
|
41
|
+
import { fleetProjectFindings } from "./views/fleet-project.js";
|
|
40
42
|
import { isUseCase } from "../../../core/usecases/fleet.js";
|
|
41
43
|
/**
|
|
42
44
|
* The fleet's flows as a grade may read them, or `null` when loam cannot see
|
|
@@ -45,8 +47,8 @@ import { isUseCase } from "../../../core/usecases/fleet.js";
|
|
|
45
47
|
*
|
|
46
48
|
* `capability.requirement-unrealized` says a business promise is kept by
|
|
47
49
|
* nobody. A use case is one of the two things that can keep it, so a run that
|
|
48
|
-
* could not read the flows must not make that claim: no
|
|
49
|
-
*
|
|
50
|
+
* could not read the flows must not make that claim: no map at all (`null`)
|
|
51
|
+
* and a project that did not parse are both "loam did not look", never
|
|
50
52
|
* "there is nothing there". A preload that DID parse and declares no views is a
|
|
51
53
|
* real, empty answer and grades normally.
|
|
52
54
|
*
|
|
@@ -58,7 +60,7 @@ import { isUseCase } from "../../../core/usecases/fleet.js";
|
|
|
58
60
|
* is exactly that input.
|
|
59
61
|
*/
|
|
60
62
|
function gradableFlows(preloaded) {
|
|
61
|
-
if (preloaded === null || preloaded
|
|
63
|
+
if (preloaded === null || preloaded.errors.length > 0)
|
|
62
64
|
return null;
|
|
63
65
|
return (preloaded.views ?? []).filter(isUseCase);
|
|
64
66
|
}
|
|
@@ -111,6 +113,23 @@ export async function validateLandscape(docsDir, preloaded, fleet) {
|
|
|
111
113
|
// the fleet gate refuse while still naming every service it found.
|
|
112
114
|
const tree = await listFleetTree(docsDir, fleet);
|
|
113
115
|
findings.push(...tree.findings);
|
|
116
|
+
// Which SHAPE each model has, read once for the whole target: it decides four
|
|
117
|
+
// of the grades below (`views/projects.ts`) and which documents the merged
|
|
118
|
+
// project holds (`views/fleet-project.ts`). Over the full enumeration, which
|
|
119
|
+
// is what `entries` is here even under `--base` — `validate --all` narrows the
|
|
120
|
+
// TARGETS it grades and never the fleet the renderer would load.
|
|
121
|
+
const models = entries.map((entry) => servicePathsAt(entry.dir).model);
|
|
122
|
+
const shapes = await fleet.modelShapes(models);
|
|
123
|
+
// A model and the renderer's project files disagreeing is a fact about
|
|
124
|
+
// `services/` too, graded here for `service.id-invalid`'s reason: it holds
|
|
125
|
+
// whether or not the map parses. One warning per service per disagreement;
|
|
126
|
+
// views/projects.ts says why a warning, why this run and not `doctor`, why
|
|
127
|
+
// the root-file gate, and why the grade is KEPT rather than spread and
|
|
128
|
+
// dropped — one of the five gates the merged-project load below, and
|
|
129
|
+
// re-deriving that fact there would let a cause and its 161-warning cascade
|
|
130
|
+
// disagree about which state the run is in.
|
|
131
|
+
const projects = await projectFindings(docsDir, entries, shapes);
|
|
132
|
+
findings.push(...projects.findings);
|
|
114
133
|
// Before the landscape's own early returns: the authorization and capability
|
|
115
134
|
// vocabularies are fleet facts that do not depend on the map existing or parsing.
|
|
116
135
|
findings.push(...(await permissionFindings(docsDir, entries, fleet)));
|
|
@@ -167,7 +186,7 @@ export async function validateLandscape(docsDir, preloaded, fleet) {
|
|
|
167
186
|
findings.push(conflict);
|
|
168
187
|
return report;
|
|
169
188
|
}
|
|
170
|
-
land = preloaded ?? (
|
|
189
|
+
land = preloaded ?? (await fleet.loadLikeC4(path));
|
|
171
190
|
}
|
|
172
191
|
catch (err) {
|
|
173
192
|
land = unreadableLandscape(err);
|
|
@@ -182,27 +201,74 @@ export async function validateLandscape(docsDir, preloaded, fleet) {
|
|
|
182
201
|
// landscape by default — a use case with a typo'd element used to be
|
|
183
202
|
// reported as the landscape having errors, which sent the author to the
|
|
184
203
|
// wrong file with a line number that pointed at somebody else's text.
|
|
185
|
-
const broken =
|
|
186
|
-
const
|
|
187
|
-
|
|
204
|
+
const broken = brokenDocumentPaths(docsDir, land.errors);
|
|
205
|
+
const named = broken.length === 0 ? "architecture/landscape.likec4" : broken.join(", ");
|
|
206
|
+
// The verb agrees with the LIST, not with the count after it: `named` is a
|
|
207
|
+
// comma-joined series once two documents broke, and "a, b has 6 error(s)"
|
|
208
|
+
// is a sentence a reader trips over. The service arm (`service/spine.ts`)
|
|
209
|
+
// picks the verb the same way off the same list, and these two messages are
|
|
210
|
+
// read side by side in one report — a run where the fleet line says "has"
|
|
211
|
+
// and the service line says "have" about the same two files reads as two
|
|
212
|
+
// different findings.
|
|
213
|
+
const verb = broken.length > 1 ? "have" : "has";
|
|
188
214
|
findings.push({
|
|
189
215
|
severity: "error",
|
|
190
216
|
code: "landscape.invalid",
|
|
191
|
-
|
|
217
|
+
// The tail is general on purpose. It used to speak about use-case flows
|
|
218
|
+
// alone, so an author whose MODEL EDGE named a container was told to move
|
|
219
|
+
// a flow that does not exist (#01). Both shapes are the same defect: loam
|
|
220
|
+
// grades the `architecture/` project, the renderer loads that project plus
|
|
221
|
+
// every extending model, and a reference to a container only the model
|
|
222
|
+
// declares therefore resolves there and not here.
|
|
223
|
+
message: `landscape: ${named} ${verb} ${land.errors.length} error(s) — cross-check with services/ impossible. ` +
|
|
224
|
+
"An unresolved name that a service's extending model declares — a use-case hop or an edge " +
|
|
225
|
+
"naming `<service-fqn>.<container>` — renders for the renderer and resolves for nobody here: " +
|
|
226
|
+
"name the SERVICE on the map, and the container in that service's own model (a container-level " +
|
|
227
|
+
"flow lives beside the model that declares it)",
|
|
192
228
|
// Every line carries its own file, because one project's errors can come
|
|
193
|
-
// from more than one document and a bare `L8:` is unactionable then.
|
|
194
|
-
|
|
229
|
+
// from more than one document and a bare `L8:` is unactionable then. The
|
|
230
|
+
// prefix is `brokenDocumentPaths`'s spelling of that one error's document,
|
|
231
|
+
// so the message's file list and each line's prefix are one rule.
|
|
232
|
+
details: land.errors.map((e) => {
|
|
233
|
+
const [file] = broken.length < 2 ? [] : brokenDocumentPaths(docsDir, [e]);
|
|
234
|
+
return file === undefined ? errorText(e) : `${file} ${errorText(e)}`;
|
|
235
|
+
}),
|
|
195
236
|
});
|
|
196
237
|
return report;
|
|
197
238
|
}
|
|
198
|
-
// The generated
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
|
|
239
|
+
// The generated views files, graded only now that the landscape has parsed:
|
|
240
|
+
// the expected bytes are a function of (tree, landscape elements, the global
|
|
241
|
+
// style ids the map declares) — the whole doc goes across so the grader and
|
|
242
|
+
// `sync` read one record. There are TWO generated files now
|
|
243
|
+
// (`subsystems.likec4` and `services.likec4`) and this pushes ONE error PER
|
|
244
|
+
// STALE FILE, each naming its own file; `views/stale.ts` says why a content
|
|
245
|
+
// compare, and why two files share one code but never one finding.
|
|
246
|
+
findings.push(...(await viewsStaleFindings(docsDir, tree, land)));
|
|
247
|
+
// The renderer's own reading of the tree: the map, every extending model and
|
|
248
|
+
// every `.likec4` beside one, merged into ONE project. It answers two
|
|
249
|
+
// questions at once and only one of them can be true at a time — either that
|
|
250
|
+
// project does not parse (`c4.fleet-project-invalid`), or it parsed and its
|
|
251
|
+
// view-id census is the real one.
|
|
252
|
+
const merged = await fleetProjectFindings({
|
|
253
|
+
docsDir, entries, shapes, fleet, tree,
|
|
254
|
+
architecture: land,
|
|
255
|
+
mapExcluded: projects.mapExcluded,
|
|
256
|
+
known: new Set(entries.map((s) => s.id)),
|
|
257
|
+
});
|
|
258
|
+
if (merged.kind === "invalid")
|
|
259
|
+
findings.push(...merged.findings);
|
|
202
260
|
// Beside staleness, and for the same file: an authored view id that collides
|
|
203
|
-
// with one loam mints into it takes the whole
|
|
204
|
-
//
|
|
205
|
-
|
|
261
|
+
// with one loam mints into it takes the whole root project down in the
|
|
262
|
+
// renderer while every check here stays green — see views/ids.ts. The census
|
|
263
|
+
// is the merged project's when there is one; otherwise the `architecture/`
|
|
264
|
+
// project's alone, whose claims are spelled relative to that directory and are
|
|
265
|
+
// made docs-relative here.
|
|
266
|
+
// `land` goes across for the SERVICE half of the reservation: an id is minted
|
|
267
|
+
// per service the map DRAWS, so the census needs the render's own element join.
|
|
268
|
+
const claims = merged.kind === "clean"
|
|
269
|
+
? merged.viewIds
|
|
270
|
+
: land.viewIds?.map((claim) => ({ ...claim, sourcePath: `architecture/${claim.sourcePath}` }));
|
|
271
|
+
findings.push(...viewIdFindings(claims, tree, land));
|
|
206
272
|
// The three obligation questions that need the map — where each declared rule
|
|
207
273
|
// is applied, which tags resolve to nothing, and which applications no living
|
|
208
274
|
// arch requirement covers. Here rather than beside the vocabulary above
|
|
@@ -229,118 +295,70 @@ export async function validateLandscape(docsDir, preloaded, fleet) {
|
|
|
229
295
|
// can never disagree about what an element stands for.
|
|
230
296
|
const landSvcOf = serviceResolver(land.elements, services);
|
|
231
297
|
const modelled = new Set(land.elements.map((e) => landSvcOf(e.id)));
|
|
232
|
-
//
|
|
233
|
-
// `
|
|
234
|
-
//
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
code: "landscape.service-unmodelled",
|
|
264
|
-
subject: id,
|
|
265
|
-
message: `landscape: ${pathOf(id)}/ exists but nothing in architecture/landscape.likec4 models it — add an element, or bind one with metadata { service '${id}' }`,
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
// A binding is a claim about this repo wherever it is written — including
|
|
269
|
-
// inside another element, which the old top-level filter never looked at, so
|
|
270
|
-
// a typo one level down bound an edge to a service that does not exist and
|
|
271
|
-
// nothing said so. Every element with a binding answers for it, at any depth.
|
|
272
|
-
for (const e of land.elements) {
|
|
273
|
-
if (e.tags.includes(EXTERNAL_TAG) || e.service === undefined)
|
|
274
|
-
continue;
|
|
275
|
-
if (services.has(e.service))
|
|
276
|
-
continue;
|
|
277
|
-
findings.push({
|
|
278
|
-
severity: "error",
|
|
279
|
-
code: "landscape.binding-unknown",
|
|
280
|
-
subject: e.service,
|
|
281
|
-
message: `landscape: '${e.title}' binds to service '${e.service}', but services/${e.service}/ does not exist`,
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
// Walked over the SYSTEM census — the same derivation the scorecard counts,
|
|
285
|
-
// so the map's exemptions and the fleet rollup cannot drift — with the two
|
|
286
|
-
// residual skips that are not exemptions: a bound element is the binding
|
|
287
|
-
// pass's subject above, and a title naming a real directory is documented.
|
|
288
|
-
for (const e of drawnSystems(land.elements, services)) {
|
|
289
|
-
if (e.service !== undefined)
|
|
290
|
-
continue; // graded by the binding pass above
|
|
291
|
-
if (services.has(e.title))
|
|
292
|
-
continue;
|
|
293
|
-
findings.push({
|
|
294
|
-
severity: "warn",
|
|
295
|
-
code: "landscape.service-undocumented",
|
|
296
|
-
subject: e.title,
|
|
297
|
-
message: `landscape: '${e.title}' has no services/${e.title}/ — bind it with metadata { service '<id>' }, or tag it #${EXTERNAL_TAG} if it is not ours`,
|
|
298
|
-
});
|
|
299
|
-
}
|
|
298
|
+
// The same set with `#external` removed — the isolation check's input, and
|
|
299
|
+
// NOT `service-unmodelled`'s: a foreign box bound to one of our directories
|
|
300
|
+
// still means the directory is drawn, but "deliberately not ours" must not
|
|
301
|
+
// make it a subject of an advisory about our own map (R4/W12). The two
|
|
302
|
+
// binding passes have always skipped the tag; this is the third.
|
|
303
|
+
const external = new Set(land.elements.filter((e) => e.tags.includes(EXTERNAL_TAG)).map((e) => e.id));
|
|
304
|
+
const ours = new Set(land.elements.filter((e) => !external.has(e.id)).map((e) => landSvcOf(e.id)));
|
|
305
|
+
// The element↔directory passes: two boxes for one directory, a directory
|
|
306
|
+
// nobody drew, a binding naming nothing, and an element nobody owns.
|
|
307
|
+
const systems = drawnSystems(land.elements, services);
|
|
308
|
+
findings.push(...bindingFindings({ elements: land.elements, drawn, systems, services, modelled, pathOf }));
|
|
309
|
+
// What the fleet's own models say, read once for the two checks below that
|
|
310
|
+
// need it: a map edge is not the only evidence that a service consumes
|
|
311
|
+
// something, nor the only evidence that it calls out (map/attest.ts).
|
|
312
|
+
const drawnIds = new Set(drawn.map((e) => e.id));
|
|
313
|
+
// `census.ts`'s predicate, handed down rather than respelled: a `fleet/map/`
|
|
314
|
+
// module may not import `fleet/`, and the store grades were skipping a
|
|
315
|
+
// datastore that IS a service in one of their two halves only.
|
|
316
|
+
const isService = (e) => standsForService(e, services);
|
|
317
|
+
const attestation = await mapAttestation({
|
|
318
|
+
docsDir,
|
|
319
|
+
entries,
|
|
320
|
+
services,
|
|
321
|
+
resolve: landSvcOf,
|
|
322
|
+
standsForService: isService,
|
|
323
|
+
drawnIds,
|
|
324
|
+
fleet,
|
|
325
|
+
});
|
|
326
|
+
const attested = attestation.models;
|
|
327
|
+
const mapFacts = { relationships: land.relationships, elements: land.elements, services, resolve: landSvcOf };
|
|
328
|
+
const consumers = consumerCensus({ ...mapFacts, standsForService: isService, attested });
|
|
300
329
|
// The shape advisories run LAST, over the same drawn set and resolver the
|
|
301
330
|
// structural checks used. Any one of them suppresses `landscape.matched`
|
|
302
331
|
// below on purpose: a map with a shape warning did not fully "agree".
|
|
303
|
-
findings.push(...fleetShapeFindings({ drawn,
|
|
332
|
+
findings.push(...fleetShapeFindings({ drawn, services, consumers }));
|
|
333
|
+
const { nestedStores } = attestation;
|
|
334
|
+
findings.push(...datastoreFindings({
|
|
335
|
+
drawn,
|
|
336
|
+
elements: land.elements,
|
|
337
|
+
nestedStores,
|
|
338
|
+
services,
|
|
339
|
+
resolve: landSvcOf,
|
|
340
|
+
standsForService: isService,
|
|
341
|
+
consumers,
|
|
342
|
+
}));
|
|
343
|
+
// A drawn service nothing reaches, graded only where its own model attests
|
|
344
|
+
// a call across its boundary — map/isolation.ts says why the evidence gate.
|
|
345
|
+
findings.push(...isolationFindings({ land, modelled: ours, external, attested, resolve: landSvcOf, pathOf }));
|
|
304
346
|
// The use cases the SAME `architecture/` project declares — every
|
|
305
347
|
// `dynamic view` in the landscape and in every `architecture/usecases/*.likec4`
|
|
306
|
-
// — graded against the model above (
|
|
348
|
+
// — graded against the model above (`map/usecases.ts` holds the call and the
|
|
349
|
+
// two vocabulary reads it needs; `core/usecases/grade/usecases.ts` owns the opt-in and
|
|
307
350
|
// the grades). They ride this target for `viewsStaleFindings`' reason: a view
|
|
308
351
|
// belongs to no service, and only the fleet run has both the whole model and
|
|
309
352
|
// the enumerated `services/` in view at once.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
// file-naming rule made mechanical instead of remembered: only the PROJECT
|
|
313
|
-
// load gives a view the `sourcePath` a finding has to name, while the
|
|
314
|
-
// single-file fallback a few lines above calls every document `source.c4` —
|
|
315
|
-
// so a message built from that load would send its reader to
|
|
316
|
-
// `architecture/source.c4`, a file that has never existed. No preload, no
|
|
317
|
-
// grading, and nothing to get wrong.
|
|
318
|
-
//
|
|
319
|
-
// Read second, and the ladder APPLIED BY ITS OWN FUNCTION rather than
|
|
320
|
-
// re-spelled here: an absent or unreadable capabilities.yaml means silence for
|
|
321
|
-
// the whole family, not a fleet full of unresolved tags, so `null` travels
|
|
322
|
-
// rather than an empty list — which the join would read as "the fleet declares
|
|
323
|
-
// no capabilities" and grade every tag against. `gradableCapabilityIds` is the
|
|
324
|
-
// one statement of that rule (`core/capabilities/findings.ts`), and this is a
|
|
325
|
-
// caller of it precisely so a fourth un-gradable vocabulary state cannot be
|
|
326
|
-
// fixed in core while the command layer keeps handing the join a whole key set.
|
|
327
|
-
// `capabilityFleetFindings` above has already paid for this read through the
|
|
328
|
-
// fleet context's memo.
|
|
329
|
-
const vocabulary = fleet === undefined ? await readCapabilityVocabulary(docsDir) : await fleet.capabilities(docsDir);
|
|
330
|
-
// The requirement index behind the `#req-` tag, read here rather than inside
|
|
331
|
-
// the use-case package so that package never learns what a capability
|
|
332
|
-
// document is. Under `--all` every document was already parsed by
|
|
333
|
-
// `capabilityFleetFindings` above and the fleet memo answers from cache.
|
|
334
|
-
const capabilityReqs = await capabilityRequirementIndex(vocabulary, fleet === undefined ? async (p) => parseRequirements(await readRequirementsDocument(p)) : (p) => fleet.readRequirements(p));
|
|
335
|
-
findings.push(...useCaseFindings({
|
|
353
|
+
findings.push(...(await fleetUseCaseFindings({
|
|
354
|
+
docsDir,
|
|
336
355
|
views: preloaded?.views ?? [],
|
|
337
356
|
elements: land.elements,
|
|
338
357
|
relationships: land.relationships,
|
|
339
358
|
services,
|
|
340
359
|
resolve: landSvcOf,
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}));
|
|
360
|
+
fleet,
|
|
361
|
+
})));
|
|
344
362
|
if (findings.length === 0) {
|
|
345
363
|
findings.push({
|
|
346
364
|
severity: "ok",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"landscape.js","sourceRoot":"","sources":["../../../../src/commands/validate/fleet/landscape.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The fleet target: `services/` and architecture/landscape.likec4 graded\n * against each other, plus the two exemptions that decide which drawn element\n * answers for a service directory at all.\n *\n * The landscape is the one artifact no service owns — parsed once for the whole\n * run and graded on a target of its own, outside the dispatcher's `guarded`.\n * That is why its IO containment lives in this package instead: see\n * `unreadableLandscape` in `./load.ts`.\n */\nimport { existsSync } from \"node:fs\";\nimport { relative } from \"node:path\";\nimport { readFile } from \"node:fs/promises\";\nimport { loadFile, type Elem, type LoadedDoc } from \"../../../core/c4/likec4.js\";\nimport { elementService, serviceResolver } from \"../../../core/c4/resolve/service.js\";\nimport { landscapePath as landscapeFile } from \"../../../core/repo/paths.js\";\nimport { serviceIdFindings } from \"../../../core/repo/entries.js\";\nimport { listFleetTree, listServices } from \"../../../core/repo/repo.js\";\nimport { type Finding, type TargetReport } from \"../../../core/vocabulary/report.js\";\nimport { landscapeConflictFinding } from \"../../../core/conflict-markers.js\";\nimport { FleetContext } from \"../../../core/fleet-context.js\";\nimport { capabilityFleetFindings, fleetShapeFindings, permissionFindings } from \"../checks/fleet-shape.js\";\nimport { fleetLinkFindings } from \"../links/corpus.js\";\nimport { glossaryFindings } from \"../links/glossary.js\";\nimport { obligationFindings, obligationVocabularyFindings } from \"./obligations.js\";\nimport { readObligations } from \"../../../core/obligations/obligations.js\";\nimport { obligationsPath } from \"../../../core/repo/paths.js\";\nimport { EXTERNAL_TAG } from \"../../../core/vocabulary/maturity.js\";\nimport { errorText } from \"../checks/vocabulary.js\";\nimport { serviceTreePath, type DocsDir } from \"../../../core/kernel/ids/dirs.js\";\nimport { drawnSystems, serviceLevelElements } from \"./census.js\";\nimport { unreadableLandscape } from \"./load.js\";\nimport { kindTagFindings } from \"./kind-tags.js\";\nimport { useCaseFindings } from \"./usecases/usecases.js\";\nimport { viewIdFindings } from \"./views/ids.js\";\nimport { viewsStaleFindings } from \"./views/stale.js\";\nimport { readCapabilityVocabulary } from \"../../../core/capabilities/capabilities.js\";\nimport { capabilityRequirementIndex, gradableCapabilityIds } from \"../../../core/capabilities/findings.js\";\nimport { parseRequirements, readRequirementsDocument } from \"../../../core/document/parse.js\";\nimport type { ParsedView } from \"../../../core/c4/parsed/dynamic-views.js\";\nimport { isUseCase } from \"../../../core/usecases/fleet.js\";\n\n/**\n * The fleet's flows as a grade may read them, or `null` when loam cannot see\n * them at all — the same `null`-suspends idiom `gradableCapabilityIds` uses,\n * and here it guards one specific wrong answer.\n *\n * `capability.requirement-unrealized` says a business promise is kept by\n * nobody. A use case is one of the two things that can keep it, so a run that\n * could not read the flows must not make that claim: no preload (a single-target\n * run) and a project that did not parse are both \"loam did not look\", never\n * \"there is nothing there\". A preload that DID parse and declares no views is a\n * real, empty answer and grades normally.\n *\n * Filtered through `isUseCase` — the same opt-in `readUseCases` applies before\n * `loam list capabilities` asks this question — because the two surfaces must\n * never disagree about `keptBy`. Handing the unfiltered preload over was\n * harmless only by luck: an untagged view yields no claims, so the answers\n * matched for want of an input that could tell them apart. A `#req-`-only view\n * is exactly that input.\n */\nfunction gradableFlows(preloaded: LoadedDoc | null | undefined): readonly ParsedView[] | null {\n if (preloaded === null || preloaded === undefined || preloaded.errors.length > 0) return null;\n return (preloaded.views ?? []).filter(isUseCase);\n}\n\n/**\n * The fleet cross-check: `services/` and the landscape both claim to name the\n * fleet, and nothing used to compare them. A directory nobody drew and an element\n * with nothing behind it were equally invisible.\n *\n * The two directions are graded differently because the evidence differs. A\n * directory that exists is a fact, so a landscape missing it is an error — every\n * view derived from that landscape is then incomplete. An element with no\n * directory may legitimately be someone else's system, so it warns, and\n * `#external` says \"deliberately not ours\" and silences it. An explicit\n * `metadata { service '<id>' }` naming nothing is an error either way: a binding\n * is a claim about this repo, not a guess at one.\n *\n * An ABSENT landscape is a finding, not a skipped check. It used to return null\n * — no target, no findings, and a fleet gate that went green over a docs repo\n * with no fleet map at all, which is the single artifact every derived view and\n * every spine check is computed from. It is graded by what its absence proves:\n * with services in `services/` it is an ERROR (a fleet that exists is undrawn),\n * with none it is a WARNING (a docs repo before its first adopt legitimately\n * has nothing to draw, but the file still belongs there — `loam init` scaffolds\n * it, and a repo missing it will silently accept never getting one).\n *\n * `preloaded` is the already-parsed landscape under --all — the same doc every\n * service check gets.\n */\nexport async function validateLandscape(\n docsDir: DocsDir,\n preloaded?: LoadedDoc | null,\n fleet?: FleetContext,\n): Promise<TargetReport> {\n const path = landscapeFile(docsDir);\n const findings: Finding[] = [];\n const report: TargetReport = {\n kind: \"landscape\",\n id: \"landscape\",\n path: \"architecture/landscape.likec4\",\n findings,\n };\n\n // The SET of service directories is this target's other subject, so it is\n // graded before the map is even opened: `service.id-invalid` is a fact about\n // `services/` that holds whether or not a landscape exists or parses, and\n // both of those return early below. Emitted here and nowhere else — the\n // enumeration is what makes the id a question, and one finding per fleet is\n // what the rename fixes.\n const entries = await listServices(docsDir, fleet);\n findings.push(...serviceIdFindings(entries));\n // The tree walk's own findings ride the same fleet target, before the map's\n // early returns for the same reason `service.id-invalid` does: a stranded,\n // colliding or mismarked directory is a fact about `services/` that holds\n // whether or not a landscape exists or parses — and a broken tree must make\n // the fleet gate refuse while still naming every service it found.\n const tree = await listFleetTree(docsDir, fleet);\n findings.push(...tree.findings);\n // Before the landscape's own early returns: the authorization and capability\n // vocabularies are fleet facts that do not depend on the map existing or parsing.\n findings.push(...(await permissionFindings(docsDir, entries, fleet)));\n findings.push(...(await capabilityFleetFindings(docsDir, entries, fleet, gradableFlows(preloaded))));\n // The documents that belong to no service and no feature — the fleet's ADRs\n // and the living capability tree — are graded for their links here, once,\n // for the same reason the two vocabularies above are: a fleet fact repeated\n // on every service target is the report.\n findings.push(...(await fleetLinkFindings({ docsDir, fleet })));\n // The glossary is graded on who cites it, which is a question only the whole\n // repository answers — so it belongs here, beside the two vocabularies, and\n // nowhere else.\n findings.push(...(await glossaryFindings(docsDir, fleet)));\n // The architectural obligation vocabulary, read ONCE here and handed to the\n // map half below: its own two verdicts hold whether or not the landscape\n // exists or parses, and a run where somebody is fixing the map must still be\n // told that this file does not read.\n const obligations = await readObligations(obligationsPath(docsDir));\n findings.push(...obligationVocabularyFindings(docsDir, obligations));\n\n if (!existsSync(path)) {\n const count = entries.length;\n findings.push({\n severity: count > 0 ? \"error\" : \"warn\",\n code: \"landscape.missing\",\n message:\n `landscape: architecture/landscape.likec4 does not exist — ` +\n (count > 0\n ? `${count} service(s) are adopted and nothing draws the fleet. `\n : \"nothing draws the fleet. \") +\n \"It is the one map every derived view and the C4↔API spine are computed from: \" +\n \"write a `specification { element softwareSystem }` + `model { … }` document there \" +\n \"with one element per services/<id>/, bound with `metadata { service '<id>' }`.\",\n });\n return report;\n }\n\n // Conflict markers before the parse — `loam doctor`'s order, and for its\n // reason: the markers are the cause and the parse errors are the cascade.\n // Nothing may be concluded from a file that is two halves of two different\n // maps, least of all that a service nobody drew is unmodelled, so this\n // returns the way `landscape.invalid` does. An error, gating by the default\n // rule and deliberately not carrying `gates` — that field is coherence's,\n // and the archive gate has to ask this question itself (it does not yet).\n // Read plainly rather than through FleetContext: this target runs outside\n // `guarded`, and a document refused for its encoding would surface here as\n // the whole run's `repository-unavailable` instead of one finding.\n //\n // Both reads are contained for that same reason — see `unreadableLandscape`.\n // The conflict-marker read is the FIRST touch of the file, so it is the one\n // that fails when the file cannot be opened at all, and it runs before\n // `preloaded ??` can spare it.\n let land: LoadedDoc;\n try {\n const conflict = landscapeConflictFinding(\n \"architecture/landscape.likec4\",\n await readFile(path, \"utf8\"),\n );\n if (conflict !== null) {\n findings.push(conflict);\n return report;\n }\n land = preloaded ?? (fleet === undefined ? await loadFile(path) : await fleet.loadLikeC4(path));\n } catch (err) {\n land = unreadableLandscape(err);\n }\n if (land.errors.length > 0) {\n // Nothing may be concluded from a document that did not parse — in particular\n // not that every service is unmodelled.\n //\n // The fleet map is a PROJECT now, not a file: `architecture/landscape.likec4`\n // plus every `architecture/usecases/*.likec4`, merged the way the renderer\n // merges them. So the message names the FILES that broke rather than the\n // landscape by default — a use case with a typo'd element used to be\n // reported as the landscape having errors, which sent the author to the\n // wrong file with a line number that pointed at somebody else's text.\n const broken = [...new Set(land.errors.map((e) => e.sourceFsPath).filter((p): p is string => p !== undefined))];\n const spell = (abs: string): string => relative(docsDir, abs).split(/[\\\\/]/).join(\"/\");\n const named = broken.length === 0 ? \"architecture/landscape.likec4\" : broken.map(spell).sort().join(\", \");\n findings.push({\n severity: \"error\",\n code: \"landscape.invalid\",\n message: `landscape: ${named} has ${land.errors.length} error(s) — cross-check with services/ impossible`,\n // Every line carries its own file, because one project's errors can come\n // from more than one document and a bare `L8:` is unactionable then.\n details: land.errors.map((e) =>\n e.sourceFsPath === undefined || broken.length < 2 ? errorText(e) : `${spell(e.sourceFsPath)} ${errorText(e)}`,\n ),\n });\n return report;\n }\n\n // The generated subsystem views, graded only now that the landscape has\n // parsed: the expected bytes are a function of (tree, landscape elements) —\n // `views/stale.ts` says why a byte compare and why exactly one finding.\n findings.push(...(await viewsStaleFindings(docsDir, tree, land.elements)));\n // Beside staleness, and for the same file: an authored view id that collides\n // with one loam mints into it takes the whole architecture/ project down in\n // the renderer while every check here stays green — see views/ids.ts.\n findings.push(...viewIdFindings(land.viewIds, tree));\n // The three obligation questions that need the map — where each declared rule\n // is applied, which tags resolve to nothing, and which applications no living\n // arch requirement covers. Here rather than beside the vocabulary above\n // because all three are about the parsed landscape, and `land` is only\n // trustworthy past this point.\n findings.push(...(await obligationFindings({ docsDir, vocabulary: obligations, land, services: entries, fleet })));\n\n const services: ReadonlySet<string> = new Set(entries.map((s) => s.id));\n // Where each service actually sits, for every finding below that names a\n // directory a reader is meant to open. `services/<id>/` is right only for an\n // unfiled fleet; a filed service lives at `services/<subsystem>/…/<id>/`, and\n // a finding pointing at the root form sends the fix to a path that does not\n // exist. Built once here because three checks below need the same answer.\n const pathOf = (id: string): string => {\n const entry = entries.find((s) => s.id === id);\n return entry === undefined ? `services/${id}` : serviceTreePath(entry);\n };\n // Ahead of every exemption below, because it is the one defect that can make\n // all of them lie at once: a tag loam grades on, declared on a KIND, landing\n // on an element that stands for one of our own directories — see kind-tags.ts.\n findings.push(...kindTagFindings({ specification: land.specification, elements: land.elements, services }));\n const drawn = serviceLevelElements(land.elements, services);\n // Which services the landscape models, answered by the same resolver every\n // edge join uses — so \"modelled\" here and \"inbound edge\" in the spine check\n // can never disagree about what an element stands for.\n const landSvcOf = serviceResolver(land.elements, services);\n const modelled: ReadonlySet<string> = new Set(land.elements.map((e) => landSvcOf(e.id)));\n\n // Two boxes standing for one service directory. Every join in loam is\n // `element -> service`, computed by picking the FIRST element that resolves —\n // so with two of them, which one wins is readdir order, and the edges of the\n // loser are attributed to a service they do not belong to. Silent until now,\n // and unfixable by staring at either element on its own.\n const perService = new Map<string, Elem[]>();\n for (const e of drawn) {\n if (e.tags.includes(EXTERNAL_TAG)) continue;\n const id = elementService(e);\n perService.set(id, [...(perService.get(id) ?? []), e]);\n }\n for (const [id, elems] of perService) {\n if (elems.length < 2) continue;\n // A collision only matters where it decides something: a real directory to\n // attribute to, or a binding somebody wrote down on purpose.\n if (!services.has(id) && !elems.some((e) => e.service !== undefined)) continue;\n findings.push({\n severity: \"warn\",\n code: \"landscape.binding-duplicate\",\n subject: id,\n message: `landscape: ${elems.length} elements resolve to service '${id}' (${elems.map((e) => e.id).join(\", \")}) — every element→service join picks one of them arbitrarily, so the others' edges are filed under a service that does not own them; keep one element per services/<id>/`,\n });\n }\n\n for (const id of services) {\n if (modelled.has(id)) continue;\n findings.push({\n severity: \"error\",\n code: \"landscape.service-unmodelled\",\n subject: id,\n message: `landscape: ${pathOf(id)}/ exists but nothing in architecture/landscape.likec4 models it — add an element, or bind one with metadata { service '${id}' }`,\n });\n }\n\n // A binding is a claim about this repo wherever it is written — including\n // inside another element, which the old top-level filter never looked at, so\n // a typo one level down bound an edge to a service that does not exist and\n // nothing said so. Every element with a binding answers for it, at any depth.\n for (const e of land.elements) {\n if (e.tags.includes(EXTERNAL_TAG) || e.service === undefined) continue;\n if (services.has(e.service)) continue;\n findings.push({\n severity: \"error\",\n code: \"landscape.binding-unknown\",\n subject: e.service,\n message: `landscape: '${e.title}' binds to service '${e.service}', but services/${e.service}/ does not exist`,\n });\n }\n\n // Walked over the SYSTEM census — the same derivation the scorecard counts,\n // so the map's exemptions and the fleet rollup cannot drift — with the two\n // residual skips that are not exemptions: a bound element is the binding\n // pass's subject above, and a title naming a real directory is documented.\n for (const e of drawnSystems(land.elements, services)) {\n if (e.service !== undefined) continue; // graded by the binding pass above\n if (services.has(e.title)) continue;\n findings.push({\n severity: \"warn\",\n code: \"landscape.service-undocumented\",\n subject: e.title,\n message: `landscape: '${e.title}' has no services/${e.title}/ — bind it with metadata { service '<id>' }, or tag it #${EXTERNAL_TAG} if it is not ours`,\n });\n }\n\n // The shape advisories run LAST, over the same drawn set and resolver the\n // structural checks used. Any one of them suppresses `landscape.matched`\n // below on purpose: a map with a shape warning did not fully \"agree\".\n findings.push(\n ...fleetShapeFindings({ drawn, relationships: land.relationships, services, resolve: landSvcOf, pathOf }),\n );\n\n // The use cases the SAME `architecture/` project declares — every\n // `dynamic view` in the landscape and in every `architecture/usecases/*.likec4`\n // — graded against the model above (usecases/usecases.ts owns the opt-in and\n // the grades). They ride this target for `viewsStaleFindings`' reason: a view\n // belongs to no service, and only the fleet run has both the whole model and\n // the enumerated `services/` in view at once.\n //\n // The views come from `preloaded` rather than from `land`, and that is the\n // file-naming rule made mechanical instead of remembered: only the PROJECT\n // load gives a view the `sourcePath` a finding has to name, while the\n // single-file fallback a few lines above calls every document `source.c4` —\n // so a message built from that load would send its reader to\n // `architecture/source.c4`, a file that has never existed. No preload, no\n // grading, and nothing to get wrong.\n //\n // Read second, and the ladder APPLIED BY ITS OWN FUNCTION rather than\n // re-spelled here: an absent or unreadable capabilities.yaml means silence for\n // the whole family, not a fleet full of unresolved tags, so `null` travels\n // rather than an empty list — which the join would read as \"the fleet declares\n // no capabilities\" and grade every tag against. `gradableCapabilityIds` is the\n // one statement of that rule (`core/capabilities/findings.ts`), and this is a\n // caller of it precisely so a fourth un-gradable vocabulary state cannot be\n // fixed in core while the command layer keeps handing the join a whole key set.\n // `capabilityFleetFindings` above has already paid for this read through the\n // fleet context's memo.\n const vocabulary =\n fleet === undefined ? await readCapabilityVocabulary(docsDir) : await fleet.capabilities(docsDir);\n // The requirement index behind the `#req-` tag, read here rather than inside\n // the use-case package so that package never learns what a capability\n // document is. Under `--all` every document was already parsed by\n // `capabilityFleetFindings` above and the fleet memo answers from cache.\n const capabilityReqs = await capabilityRequirementIndex(\n vocabulary,\n fleet === undefined ? async (p) => parseRequirements(await readRequirementsDocument(p)) : (p) => fleet.readRequirements(p),\n );\n findings.push(\n ...useCaseFindings({\n views: preloaded?.views ?? [],\n elements: land.elements,\n relationships: land.relationships,\n services,\n resolve: landSvcOf,\n capabilities: gradableCapabilityIds(vocabulary),\n requirementsOf: (capability) => capabilityReqs.byCapability.get(capability),\n }),\n );\n\n if (findings.length === 0) {\n findings.push({\n severity: \"ok\",\n code: \"landscape.matched\",\n message: `landscape: ${services.size} service(s) modelled — architecture/landscape.likec4 and services/ agree`,\n });\n }\n return report;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"landscape.js","sourceRoot":"","sources":["../../../../src/commands/validate/fleet/landscape.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The fleet target: `services/` and architecture/landscape.likec4 graded\n * against each other, plus the two exemptions that decide which drawn element\n * answers for a service directory at all.\n *\n * The landscape is the one artifact no service owns — parsed once for the whole\n * run and graded on a target of its own, outside the dispatcher's `guarded`.\n * That is why its IO containment lives in this package instead: see\n * `unreadableLandscape` in `./load.ts`.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { type Elem, type LoadedDoc } from \"../../../core/c4/likec4.js\";\nimport { serviceResolver } from \"../../../core/c4/resolve/service.js\";\nimport { landscapePath as landscapeFile, servicePathsAt } from \"../../../core/repo/paths.js\";\nimport { serviceIdFindings } from \"../../../core/repo/entries.js\";\nimport { listFleetTree, listServices } from \"../../../core/repo/repo.js\";\nimport { type Finding, type TargetReport } from \"../../../core/vocabulary/report.js\";\nimport { landscapeConflictFinding } from \"../../../core/conflict-markers.js\";\nimport { FleetContext } from \"../../../core/fleet-context.js\";\nimport { capabilityFleetFindings, fleetShapeFindings, permissionFindings } from \"../checks/fleet-shape.js\";\nimport { fleetLinkFindings } from \"../links/corpus.js\";\nimport { glossaryFindings } from \"../links/glossary.js\";\nimport { obligationFindings, obligationVocabularyFindings } from \"./obligations.js\";\nimport { readObligations } from \"../../../core/obligations/obligations.js\";\nimport { obligationsPath } from \"../../../core/repo/paths.js\";\nimport { EXTERNAL_TAG } from \"../../../core/vocabulary/maturity.js\";\nimport { brokenDocumentPaths, errorText } from \"../../../core/c4/likec4.js\";\nimport { serviceTreePath, type DocsDir } from \"../../../core/kernel/ids/dirs.js\";\nimport { drawnSystems, serviceLevelElements, standsForService } from \"./census.js\";\nimport { unreadableLandscape } from \"./load.js\";\nimport { kindTagFindings } from \"./kind-tags.js\";\nimport { mapAttestation } from \"./map/attest.js\";\nimport { bindingFindings } from \"./map/bindings.js\";\nimport { consumerCensus, datastoreFindings } from \"./map/consumers.js\";\nimport { isolationFindings } from \"./map/isolation.js\";\nimport { fleetUseCaseFindings } from \"./map/usecases.js\";\nimport { viewIdFindings } from \"./views/ids.js\";\nimport { viewsStaleFindings } from \"./views/stale.js\";\nimport { projectFindings } from \"./views/projects.js\";\nimport { fleetProjectFindings } from \"./views/fleet-project.js\";\nimport type { ParsedView } from \"../../../core/c4/parsed/dynamic-views.js\";\nimport { isUseCase } from \"../../../core/usecases/fleet.js\";\n\n/**\n * The fleet's flows as a grade may read them, or `null` when loam cannot see\n * them at all — the same `null`-suspends idiom `gradableCapabilityIds` uses,\n * and here it guards one specific wrong answer.\n *\n * `capability.requirement-unrealized` says a business promise is kept by\n * nobody. A use case is one of the two things that can keep it, so a run that\n * could not read the flows must not make that claim: no map at all (`null`)\n * and a project that did not parse are both \"loam did not look\", never\n * \"there is nothing there\". A preload that DID parse and declares no views is a\n * real, empty answer and grades normally.\n *\n * Filtered through `isUseCase` — the same opt-in `readUseCases` applies before\n * `loam list capabilities` asks this question — because the two surfaces must\n * never disagree about `keptBy`. Handing the unfiltered preload over was\n * harmless only by luck: an untagged view yields no claims, so the answers\n * matched for want of an input that could tell them apart. A `#req-`-only view\n * is exactly that input.\n */\nfunction gradableFlows(preloaded: LoadedDoc | null): readonly ParsedView[] | null {\n if (preloaded === null || preloaded.errors.length > 0) return null;\n return (preloaded.views ?? []).filter(isUseCase);\n}\n\n/**\n * The fleet cross-check: `services/` and the landscape both claim to name the\n * fleet, and nothing used to compare them. A directory nobody drew and an element\n * with nothing behind it were equally invisible.\n *\n * The two directions are graded differently because the evidence differs. A\n * directory that exists is a fact, so a landscape missing it is an error — every\n * view derived from that landscape is then incomplete. An element with no\n * directory may legitimately be someone else's system, so it warns, and\n * `#external` says \"deliberately not ours\" and silences it. An explicit\n * `metadata { service '<id>' }` naming nothing is an error either way: a binding\n * is a claim about this repo, not a guess at one.\n *\n * An ABSENT landscape is a finding, not a skipped check. It used to return null\n * — no target, no findings, and a fleet gate that went green over a docs repo\n * with no fleet map at all, which is the single artifact every derived view and\n * every spine check is computed from. It is graded by what its absence proves:\n * with services in `services/` it is an ERROR (a fleet that exists is undrawn),\n * with none it is a WARNING (a docs repo before its first adopt legitimately\n * has nothing to draw, but the file still belongs there — `loam init` scaffolds\n * it, and a repo missing it will silently accept never getting one).\n *\n * `preloaded` is the already-parsed landscape under --all — the same doc every\n * service check gets.\n */\nexport async function validateLandscape(\n docsDir: DocsDir,\n preloaded: LoadedDoc | null,\n fleet: FleetContext,\n): Promise<TargetReport> {\n const path = landscapeFile(docsDir);\n const findings: Finding[] = [];\n const report: TargetReport = {\n kind: \"landscape\",\n id: \"landscape\",\n path: \"architecture/landscape.likec4\",\n findings,\n };\n\n // The SET of service directories is this target's other subject, so it is\n // graded before the map is even opened: `service.id-invalid` is a fact about\n // `services/` that holds whether or not a landscape exists or parses, and\n // both of those return early below. Emitted here and nowhere else — the\n // enumeration is what makes the id a question, and one finding per fleet is\n // what the rename fixes.\n const entries = await listServices(docsDir, fleet);\n findings.push(...serviceIdFindings(entries));\n // The tree walk's own findings ride the same fleet target, before the map's\n // early returns for the same reason `service.id-invalid` does: a stranded,\n // colliding or mismarked directory is a fact about `services/` that holds\n // whether or not a landscape exists or parses — and a broken tree must make\n // the fleet gate refuse while still naming every service it found.\n const tree = await listFleetTree(docsDir, fleet);\n findings.push(...tree.findings);\n // Which SHAPE each model has, read once for the whole target: it decides four\n // of the grades below (`views/projects.ts`) and which documents the merged\n // project holds (`views/fleet-project.ts`). Over the full enumeration, which\n // is what `entries` is here even under `--base` — `validate --all` narrows the\n // TARGETS it grades and never the fleet the renderer would load.\n const models = entries.map((entry) => servicePathsAt(entry.dir).model);\n const shapes = await fleet.modelShapes(models);\n // A model and the renderer's project files disagreeing is a fact about\n // `services/` too, graded here for `service.id-invalid`'s reason: it holds\n // whether or not the map parses. One warning per service per disagreement;\n // views/projects.ts says why a warning, why this run and not `doctor`, why\n // the root-file gate, and why the grade is KEPT rather than spread and\n // dropped — one of the five gates the merged-project load below, and\n // re-deriving that fact there would let a cause and its 161-warning cascade\n // disagree about which state the run is in.\n const projects = await projectFindings(docsDir, entries, shapes);\n findings.push(...projects.findings);\n // Before the landscape's own early returns: the authorization and capability\n // vocabularies are fleet facts that do not depend on the map existing or parsing.\n findings.push(...(await permissionFindings(docsDir, entries, fleet)));\n findings.push(...(await capabilityFleetFindings(docsDir, entries, fleet, gradableFlows(preloaded))));\n // The documents that belong to no service and no feature — the fleet's ADRs\n // and the living capability tree — are graded for their links here, once,\n // for the same reason the two vocabularies above are: a fleet fact repeated\n // on every service target is the report.\n findings.push(...(await fleetLinkFindings({ docsDir, fleet })));\n // The glossary is graded on who cites it, which is a question only the whole\n // repository answers — so it belongs here, beside the two vocabularies, and\n // nowhere else.\n findings.push(...(await glossaryFindings(docsDir, fleet)));\n // The architectural obligation vocabulary, read ONCE here and handed to the\n // map half below: its own two verdicts hold whether or not the landscape\n // exists or parses, and a run where somebody is fixing the map must still be\n // told that this file does not read.\n const obligations = await readObligations(obligationsPath(docsDir));\n findings.push(...obligationVocabularyFindings(docsDir, obligations));\n\n if (!existsSync(path)) {\n const count = entries.length;\n findings.push({\n severity: count > 0 ? \"error\" : \"warn\",\n code: \"landscape.missing\",\n message:\n `landscape: architecture/landscape.likec4 does not exist — ` +\n (count > 0\n ? `${count} service(s) are adopted and nothing draws the fleet. `\n : \"nothing draws the fleet. \") +\n \"It is the one map every derived view and the C4↔API spine are computed from: \" +\n \"write a `specification { element softwareSystem }` + `model { … }` document there \" +\n \"with one element per services/<id>/, bound with `metadata { service '<id>' }`.\",\n });\n return report;\n }\n\n // Conflict markers before the parse — `loam doctor`'s order, and for its\n // reason: the markers are the cause and the parse errors are the cascade.\n // Nothing may be concluded from a file that is two halves of two different\n // maps, least of all that a service nobody drew is unmodelled, so this\n // returns the way `landscape.invalid` does. An error, gating by the default\n // rule and deliberately not carrying `gates` — that field is coherence's,\n // and the archive gate has to ask this question itself (it does not yet).\n // Read plainly rather than through FleetContext: this target runs outside\n // `guarded`, and a document refused for its encoding would surface here as\n // the whole run's `repository-unavailable` instead of one finding.\n //\n // Both reads are contained for that same reason — see `unreadableLandscape`.\n // The conflict-marker read is the FIRST touch of the file, so it is the one\n // that fails when the file cannot be opened at all, and it runs before\n // `preloaded ??` can spare it.\n let land: LoadedDoc;\n try {\n const conflict = landscapeConflictFinding(\n \"architecture/landscape.likec4\",\n await readFile(path, \"utf8\"),\n );\n if (conflict !== null) {\n findings.push(conflict);\n return report;\n }\n land = preloaded ?? (await fleet.loadLikeC4(path));\n } catch (err) {\n land = unreadableLandscape(err);\n }\n if (land.errors.length > 0) {\n // Nothing may be concluded from a document that did not parse — in particular\n // not that every service is unmodelled.\n //\n // The fleet map is a PROJECT now, not a file: `architecture/landscape.likec4`\n // plus every `architecture/usecases/*.likec4`, merged the way the renderer\n // merges them. So the message names the FILES that broke rather than the\n // landscape by default — a use case with a typo'd element used to be\n // reported as the landscape having errors, which sent the author to the\n // wrong file with a line number that pointed at somebody else's text.\n const broken = brokenDocumentPaths(docsDir, land.errors);\n const named = broken.length === 0 ? \"architecture/landscape.likec4\" : broken.join(\", \");\n // The verb agrees with the LIST, not with the count after it: `named` is a\n // comma-joined series once two documents broke, and \"a, b has 6 error(s)\"\n // is a sentence a reader trips over. The service arm (`service/spine.ts`)\n // picks the verb the same way off the same list, and these two messages are\n // read side by side in one report — a run where the fleet line says \"has\"\n // and the service line says \"have\" about the same two files reads as two\n // different findings.\n const verb = broken.length > 1 ? \"have\" : \"has\";\n findings.push({\n severity: \"error\",\n code: \"landscape.invalid\",\n // The tail is general on purpose. It used to speak about use-case flows\n // alone, so an author whose MODEL EDGE named a container was told to move\n // a flow that does not exist (#01). Both shapes are the same defect: loam\n // grades the `architecture/` project, the renderer loads that project plus\n // every extending model, and a reference to a container only the model\n // declares therefore resolves there and not here.\n message:\n `landscape: ${named} ${verb} ${land.errors.length} error(s) — cross-check with services/ impossible. ` +\n \"An unresolved name that a service's extending model declares — a use-case hop or an edge \" +\n \"naming `<service-fqn>.<container>` — renders for the renderer and resolves for nobody here: \" +\n \"name the SERVICE on the map, and the container in that service's own model (a container-level \" +\n \"flow lives beside the model that declares it)\",\n // Every line carries its own file, because one project's errors can come\n // from more than one document and a bare `L8:` is unactionable then. The\n // prefix is `brokenDocumentPaths`'s spelling of that one error's document,\n // so the message's file list and each line's prefix are one rule.\n details: land.errors.map((e) => {\n const [file] = broken.length < 2 ? [] : brokenDocumentPaths(docsDir, [e]);\n return file === undefined ? errorText(e) : `${file} ${errorText(e)}`;\n }),\n });\n return report;\n }\n\n // The generated views files, graded only now that the landscape has parsed:\n // the expected bytes are a function of (tree, landscape elements, the global\n // style ids the map declares) — the whole doc goes across so the grader and\n // `sync` read one record. There are TWO generated files now\n // (`subsystems.likec4` and `services.likec4`) and this pushes ONE error PER\n // STALE FILE, each naming its own file; `views/stale.ts` says why a content\n // compare, and why two files share one code but never one finding.\n findings.push(...(await viewsStaleFindings(docsDir, tree, land)));\n // The renderer's own reading of the tree: the map, every extending model and\n // every `.likec4` beside one, merged into ONE project. It answers two\n // questions at once and only one of them can be true at a time — either that\n // project does not parse (`c4.fleet-project-invalid`), or it parsed and its\n // view-id census is the real one.\n const merged = await fleetProjectFindings({\n docsDir, entries, shapes, fleet, tree,\n architecture: land,\n mapExcluded: projects.mapExcluded,\n known: new Set(entries.map((s) => s.id)),\n });\n if (merged.kind === \"invalid\") findings.push(...merged.findings);\n // Beside staleness, and for the same file: an authored view id that collides\n // with one loam mints into it takes the whole root project down in the\n // renderer while every check here stays green — see views/ids.ts. The census\n // is the merged project's when there is one; otherwise the `architecture/`\n // project's alone, whose claims are spelled relative to that directory and are\n // made docs-relative here.\n // `land` goes across for the SERVICE half of the reservation: an id is minted\n // per service the map DRAWS, so the census needs the render's own element join.\n const claims =\n merged.kind === \"clean\"\n ? merged.viewIds\n : land.viewIds?.map((claim) => ({ ...claim, sourcePath: `architecture/${claim.sourcePath}` }));\n findings.push(...viewIdFindings(claims, tree, land));\n // The three obligation questions that need the map — where each declared rule\n // is applied, which tags resolve to nothing, and which applications no living\n // arch requirement covers. Here rather than beside the vocabulary above\n // because all three are about the parsed landscape, and `land` is only\n // trustworthy past this point.\n findings.push(...(await obligationFindings({ docsDir, vocabulary: obligations, land, services: entries, fleet })));\n\n const services: ReadonlySet<string> = new Set(entries.map((s) => s.id));\n // Where each service actually sits, for every finding below that names a\n // directory a reader is meant to open. `services/<id>/` is right only for an\n // unfiled fleet; a filed service lives at `services/<subsystem>/…/<id>/`, and\n // a finding pointing at the root form sends the fix to a path that does not\n // exist. Built once here because three checks below need the same answer.\n const pathOf = (id: string): string => {\n const entry = entries.find((s) => s.id === id);\n return entry === undefined ? `services/${id}` : serviceTreePath(entry);\n };\n // Ahead of every exemption below, because it is the one defect that can make\n // all of them lie at once: a tag loam grades on, declared on a KIND, landing\n // on an element that stands for one of our own directories — see kind-tags.ts.\n findings.push(...kindTagFindings({ specification: land.specification, elements: land.elements, services }));\n const drawn = serviceLevelElements(land.elements, services);\n // Which services the landscape models, answered by the same resolver every\n // edge join uses — so \"modelled\" here and \"inbound edge\" in the spine check\n // can never disagree about what an element stands for.\n const landSvcOf = serviceResolver(land.elements, services);\n const modelled: ReadonlySet<string> = new Set(land.elements.map((e) => landSvcOf(e.id)));\n // The same set with `#external` removed — the isolation check's input, and\n // NOT `service-unmodelled`'s: a foreign box bound to one of our directories\n // still means the directory is drawn, but \"deliberately not ours\" must not\n // make it a subject of an advisory about our own map (R4/W12). The two\n // binding passes have always skipped the tag; this is the third.\n const external: ReadonlySet<string> = new Set(\n land.elements.filter((e) => e.tags.includes(EXTERNAL_TAG)).map((e) => e.id),\n );\n const ours: ReadonlySet<string> = new Set(\n land.elements.filter((e) => !external.has(e.id)).map((e) => landSvcOf(e.id)),\n );\n\n // The element↔directory passes: two boxes for one directory, a directory\n // nobody drew, a binding naming nothing, and an element nobody owns.\n const systems = drawnSystems(land.elements, services);\n findings.push(...bindingFindings({ elements: land.elements, drawn, systems, services, modelled, pathOf }));\n\n // What the fleet's own models say, read once for the two checks below that\n // need it: a map edge is not the only evidence that a service consumes\n // something, nor the only evidence that it calls out (map/attest.ts).\n const drawnIds: ReadonlySet<string> = new Set(drawn.map((e) => e.id));\n // `census.ts`'s predicate, handed down rather than respelled: a `fleet/map/`\n // module may not import `fleet/`, and the store grades were skipping a\n // datastore that IS a service in one of their two halves only.\n const isService = (e: Elem): boolean => standsForService(e, services);\n const attestation = await mapAttestation({\n docsDir,\n entries,\n services,\n resolve: landSvcOf,\n standsForService: isService,\n drawnIds,\n fleet,\n });\n const attested = attestation.models;\n const mapFacts = { relationships: land.relationships, elements: land.elements, services, resolve: landSvcOf };\n const consumers = consumerCensus({ ...mapFacts, standsForService: isService, attested });\n // The shape advisories run LAST, over the same drawn set and resolver the\n // structural checks used. Any one of them suppresses `landscape.matched`\n // below on purpose: a map with a shape warning did not fully \"agree\".\n findings.push(...fleetShapeFindings({ drawn, services, consumers }));\n const { nestedStores } = attestation;\n findings.push(\n ...datastoreFindings({\n drawn,\n elements: land.elements,\n nestedStores,\n services,\n resolve: landSvcOf,\n standsForService: isService,\n consumers,\n }),\n );\n // A drawn service nothing reaches, graded only where its own model attests\n // a call across its boundary — map/isolation.ts says why the evidence gate.\n findings.push(...isolationFindings({ land, modelled: ours, external, attested, resolve: landSvcOf, pathOf }));\n\n // The use cases the SAME `architecture/` project declares — every\n // `dynamic view` in the landscape and in every `architecture/usecases/*.likec4`\n // — graded against the model above (`map/usecases.ts` holds the call and the\n // two vocabulary reads it needs; `core/usecases/grade/usecases.ts` owns the opt-in and\n // the grades). They ride this target for `viewsStaleFindings`' reason: a view\n // belongs to no service, and only the fleet run has both the whole model and\n // the enumerated `services/` in view at once.\n findings.push(\n ...(await fleetUseCaseFindings({\n docsDir,\n views: preloaded?.views ?? [],\n elements: land.elements,\n relationships: land.relationships,\n services,\n resolve: landSvcOf,\n fleet,\n })),\n );\n\n if (findings.length === 0) {\n findings.push({\n severity: \"ok\",\n code: \"landscape.matched\",\n message: `landscape: ${services.size} service(s) modelled — architecture/landscape.likec4 and services/ agree`,\n });\n }\n return report;\n}\n"]}
|
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The landscape's contained load path — the one phase of the fleet target that
|
|
3
|
+
* touches the filesystem before anything can be graded. Split from
|
|
4
|
+
* `./landscape.ts` when the fleet target grew past the line limit; the
|
|
5
|
+
* containment DOCTRINE below travelled with the functions it explains.
|
|
6
|
+
*
|
|
7
|
+
* The load ITSELF is no longer here. `loadArchitecture` moved to
|
|
8
|
+
* `core/c4/project/architecture.ts` when the use-case axis grew a second reader
|
|
9
|
+
* of it, and that module's banner records why; what stayed is the containment,
|
|
10
|
+
* which is command-layer business because it is about which validate TARGET a
|
|
11
|
+
* failed read is filed against.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { resolve } from "node:path";
|
|
15
|
+
import { FleetContext } from "../../../core/fleet-context.js";
|
|
16
|
+
import { featurePaths, landscapePath, servicePathsAt } from "../../../core/repo/paths.js";
|
|
1
17
|
/**
|
|
2
18
|
* A landscape that could not be READ, shaped as one that did not PARSE.
|
|
3
19
|
*
|
|
@@ -49,4 +65,54 @@ export async function readLandscape(load) {
|
|
|
49
65
|
return unreadableLandscape(err);
|
|
50
66
|
}
|
|
51
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* ONE workspace per document KIND for the whole `--all` run.
|
|
70
|
+
*
|
|
71
|
+
* The per-path load pays a fresh Langium workspace per document (~100 ms each
|
|
72
|
+
* even warm), which made the fleet's main CI command O(documents) workspace
|
|
73
|
+
* spins — 13.7 s median over the 120-service benchmark (docs/BENCHMARKS.md). So
|
|
74
|
+
* `--all` enumerates its documents up front and batch-parses them into the
|
|
75
|
+
* fleet context's memo; every load below, the landscape read included, is then a
|
|
76
|
+
* seeded hit. The enumerations are the same memoised promises the target loops
|
|
77
|
+
* reuse.
|
|
78
|
+
*
|
|
79
|
+
* TWO WORKSPACES, because the fleet's models no longer parse the same way as
|
|
80
|
+
* each other: a model that EXTENDS the map is a PROJECT (the map plus that
|
|
81
|
+
* file) and a model that stands alone is a document. So the shapes are read
|
|
82
|
+
* first, the DOCUMENT batch is asked for everything that is one — the landscape,
|
|
83
|
+
* every feature delta, every standalone model — and `prefetchServiceModels`
|
|
84
|
+
* then batches the extending half as projects, finding its own standalone list
|
|
85
|
+
* already memoised and asking for nothing.
|
|
86
|
+
*
|
|
87
|
+
* The order is load-bearing rather than tidy. `prefetchLikeC4` returns without a
|
|
88
|
+
* workspace when fewer than two documents are missing (one document gains
|
|
89
|
+
* nothing from batch isolation it already has), so splitting the documents
|
|
90
|
+
* across two calls is how a fleet of one service and one feature ends up
|
|
91
|
+
* batching the feature and parsing the model in a workspace of its own — the
|
|
92
|
+
* exact per-document spin this function exists to remove, and what
|
|
93
|
+
* `test/validate-batch-fallback.test.ts` counts.
|
|
94
|
+
*
|
|
95
|
+
* If a batch CANNOT run — a sandbox denying tmpdir writes — the prefetch seeds
|
|
96
|
+
* nothing and every load falls back to today's per-path parse: identical
|
|
97
|
+
* findings, the old speed. Single-service `validate` and `list` keep their
|
|
98
|
+
* untouched code paths on purpose, so the ≤10% regression bound in
|
|
99
|
+
* docs/BENCHMARKS.md holds by construction.
|
|
100
|
+
*
|
|
101
|
+
* It lives HERE rather than in `../validate.ts` because it is fleet-loading
|
|
102
|
+
* business and that module is the argument grammar and the target dispatch; the
|
|
103
|
+
* block also took that file to its line limit, which is the ceiling asking the
|
|
104
|
+
* question it exists to ask.
|
|
105
|
+
*/
|
|
106
|
+
export async function prefetchFleetDocuments(input) {
|
|
107
|
+
const { docsDir, fleet } = input;
|
|
108
|
+
const paths = input.services.filter((svc) => svc.has.model).map((svc) => servicePathsAt(svc.dir));
|
|
109
|
+
const shapes = await fleet.modelShapes(paths.map((p) => p.model));
|
|
110
|
+
const landscape = landscapePath(docsDir);
|
|
111
|
+
await fleet.prefetchLikeC4([
|
|
112
|
+
...(existsSync(landscape) ? [landscape] : []),
|
|
113
|
+
...input.features.filter((feat) => feat.has.delta).map((feat) => featurePaths(feat.dir).delta),
|
|
114
|
+
...paths.filter((p) => shapes.get(resolve(p.model)) !== "extending").map((p) => p.model),
|
|
115
|
+
]);
|
|
116
|
+
await fleet.prefetchServiceModels(docsDir, paths);
|
|
117
|
+
}
|
|
52
118
|
//# sourceMappingURL=load.js.map
|