@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.1
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 +2548 -86
- package/COMPARISON.md +80 -63
- package/CONTRIBUTING.md +84 -0
- package/MIGRATING-from-OpenSpec.md +213 -54
- package/QUICKSTART.md +125 -0
- package/README.md +450 -150
- package/ROADMAP.md +494 -0
- package/SCHEMA.md +2355 -256
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +701 -0
- package/dist/cli.js +113 -19
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +209 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +268 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +77 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +159 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +317 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +161 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +111 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +237 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +27 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +251 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/context/context.js +99 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +283 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +279 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +205 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +9 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +93 -0
- package/dist/commands/diff/diff.js.map +1 -0
- package/dist/commands/diff/print.js +38 -0
- package/dist/commands/diff/print.js.map +1 -0
- package/dist/commands/doctor.js +5 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +151 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +29 -24
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +115 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +54 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +146 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +246 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +149 -0
- package/dist/commands/gherkin/reconcile.js.map +1 -0
- package/dist/commands/gherkin/render.js +77 -0
- package/dist/commands/gherkin/render.js.map +1 -0
- package/dist/commands/init/example.js +204 -0
- package/dist/commands/init/example.js.map +1 -0
- package/dist/commands/init/first-hour.js +28 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +146 -71
- package/dist/commands/init/init.js.map +1 -0
- package/dist/commands/init/mcp.js +131 -0
- package/dist/commands/init/mcp.js.map +1 -0
- package/dist/commands/init/options.js +78 -0
- package/dist/commands/init/options.js.map +1 -0
- package/dist/commands/instructions.js +72 -14
- package/dist/commands/instructions.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +65 -0
- package/dist/commands/list/campaign/campaign.js.map +1 -0
- package/dist/commands/list/campaign/owners.js +65 -0
- package/dist/commands/list/campaign/owners.js.map +1 -0
- package/dist/commands/list/json.js +157 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +343 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +301 -0
- package/dist/commands/list/print.js.map +1 -0
- package/dist/commands/list/review.js +120 -0
- package/dist/commands/list/review.js.map +1 -0
- package/dist/commands/list/views.js +105 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +183 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +34 -0
- package/dist/commands/mcp/mcp.js.map +1 -0
- package/dist/commands/mcp/serve.js +55 -0
- package/dist/commands/mcp/serve.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/active.js +170 -0
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
- package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/living.js +62 -0
- package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/target.js +219 -0
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +19 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/read.js +49 -0
- package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
- package/dist/commands/migrate-openspec/print.js +89 -0
- package/dist/commands/migrate-openspec/print.js.map +1 -0
- package/dist/commands/new/commit.js +76 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/new.js +283 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +355 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +203 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/policy/format.js +152 -0
- package/dist/commands/policy/format.js.map +1 -0
- package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
- package/dist/commands/policy/gate.js.map +1 -0
- package/dist/commands/rebase/edit.js +106 -0
- package/dist/commands/rebase/edit.js.map +1 -0
- package/dist/commands/rebase/living.js +185 -0
- package/dist/commands/rebase/living.js.map +1 -0
- package/dist/commands/rebase/plan.js +245 -0
- package/dist/commands/rebase/plan.js.map +1 -0
- package/dist/commands/rebase/rebase.js +275 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +192 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +133 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +172 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +178 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/marks.js +24 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/{show.js → show/service.js} +63 -152
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +77 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/json.js +45 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +157 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +119 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +189 -0
- package/dist/commands/steps/steps.js.map +1 -0
- package/dist/commands/subsystem/edit.js +192 -0
- package/dist/commands/subsystem/edit.js.map +1 -0
- package/dist/commands/subsystem/move.js +265 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +115 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +101 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +103 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +94 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +70 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +160 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +67 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +194 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +296 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +55 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +254 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +76 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/checks/vocabulary.js +31 -0
- package/dist/commands/validate/checks/vocabulary.js.map +1 -0
- package/dist/commands/validate/feature.js +216 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +69 -0
- package/dist/commands/validate/fleet/census.js.map +1 -0
- package/dist/commands/validate/fleet/kind-tags.js +39 -0
- package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
- package/dist/commands/validate/fleet/landscape.js +353 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +52 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +236 -0
- package/dist/commands/validate/fleet/obligations.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/print.js +63 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/place.js +13 -0
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/steps.js +197 -0
- package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
- package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +40 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +59 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +92 -0
- package/dist/commands/validate/links/corpus.js.map +1 -0
- package/dist/commands/validate/links/glossary.js +75 -0
- package/dist/commands/validate/links/glossary.js.map +1 -0
- package/dist/commands/validate/report.js +269 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/service/api.js +338 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +219 -0
- package/dist/commands/validate/service/events/events.js.map +1 -0
- package/dist/commands/validate/service/events/message-producers.js +77 -0
- package/dist/commands/validate/service/events/message-producers.js.map +1 -0
- package/dist/commands/validate/service/evidence-pins.js +131 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/service.js +250 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +219 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +113 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/validate.js +338 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +182 -0
- package/dist/commands/verify/cross/diff.js.map +1 -0
- package/dist/commands/verify/evidence/contract.js +32 -0
- package/dist/commands/verify/evidence/contract.js.map +1 -0
- package/dist/commands/verify/evidence/pins.js +52 -0
- package/dist/commands/verify/evidence/pins.js.map +1 -0
- package/dist/commands/verify/evidence/read.js +72 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +241 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +226 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +223 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +246 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +217 -0
- package/dist/commands/verify/verify.js.map +1 -0
- package/dist/commands/vouch/contract.js +11 -0
- package/dist/commands/vouch/contract.js.map +1 -0
- package/dist/commands/vouch/pack/contract.js +2 -0
- package/dist/commands/vouch/pack/contract.js.map +1 -0
- package/dist/commands/vouch/pack/pack.js +266 -0
- package/dist/commands/vouch/pack/pack.js.map +1 -0
- package/dist/commands/vouch/pack/print.js +271 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +142 -0
- package/dist/commands/vouch/pack/sections.js.map +1 -0
- package/dist/commands/vouch/prompt/confirm.js +46 -0
- package/dist/commands/vouch/prompt/confirm.js.map +1 -0
- package/dist/commands/vouch/report.js +101 -0
- package/dist/commands/vouch/report.js.map +1 -0
- package/dist/commands/vouch/run.js +285 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +125 -0
- package/dist/commands/vouch/sample/plan.js.map +1 -0
- package/dist/commands/vouch/sample/print.js +109 -0
- package/dist/commands/vouch/sample/print.js.map +1 -0
- package/dist/commands/vouch/vet/verify.js +123 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +176 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/artifacts.js +220 -0
- package/dist/core/agent/agents-md/artifacts.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +324 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/cycle.js +165 -0
- package/dist/core/agent/agents-md/cycle.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +34 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +41 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +62 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +32 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +60 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +246 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
- package/dist/core/agent/agents-md/spine.js +40 -0
- package/dist/core/agent/agents-md/spine.js.map +1 -0
- package/dist/core/agent/agents-md.js +170 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +50 -0
- package/dist/core/agent/agents-stamp.js.map +1 -0
- package/dist/core/agent/contract.js +2 -0
- package/dist/core/agent/contract.js.map +1 -0
- package/dist/core/agent/protocol.js +193 -0
- package/dist/core/agent/protocol.js.map +1 -0
- package/dist/core/agent/scaffold.js +259 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +103 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +150 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +228 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +133 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +334 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +262 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +105 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +105 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +209 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +65 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +188 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +16 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +297 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +110 -0
- package/dist/core/asyncapi/baseline/plan.js.map +1 -0
- package/dist/core/asyncapi/baseline/surfaces.js +54 -0
- package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
- package/dist/core/asyncapi/depth.js +164 -0
- package/dist/core/asyncapi/depth.js.map +1 -0
- package/dist/core/asyncapi/digest.js +141 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +91 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +33 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +308 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +215 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +107 -0
- package/dist/core/asyncapi/merge/pin.js.map +1 -0
- package/dist/core/asyncapi/model.js +11 -0
- package/dist/core/asyncapi/model.js.map +1 -0
- package/dist/core/asyncapi/producers.js +50 -0
- package/dist/core/asyncapi/producers.js.map +1 -0
- package/dist/core/{asyncapi.js → asyncapi/read.js} +95 -109
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +225 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +250 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +194 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/targets.js +226 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +47 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +282 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/likec4.js +88 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +57 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +75 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/project/architecture.js +45 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/documents.js +58 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +183 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/resolve/service.js +113 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/seed/fleet-file.js +201 -0
- package/dist/core/c4/seed/fleet-file.js.map +1 -0
- package/dist/core/c4/seed/items.js +91 -0
- package/dist/core/c4/seed/items.js.map +1 -0
- package/dist/core/c4/seed/stamp.js +48 -0
- package/dist/core/c4/seed/stamp.js.map +1 -0
- package/dist/core/c4/seed/template.js +109 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/source-mask.js +82 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +227 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +101 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +10 -0
- package/dist/core/c4/splice/contract.js.map +1 -0
- package/dist/core/c4/splice/delta-blocks.js +126 -0
- package/dist/core/c4/splice/delta-blocks.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +36 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +269 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +194 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/workspace.js +172 -0
- package/dist/core/c4/workspace.js.map +1 -0
- package/dist/core/capabilities/authoring/notes.js +141 -0
- package/dist/core/capabilities/authoring/notes.js.map +1 -0
- package/dist/core/capabilities/capabilities.js +124 -0
- package/dist/core/capabilities/capabilities.js.map +1 -0
- package/dist/core/capabilities/delta/doc.js +50 -0
- package/dist/core/capabilities/delta/doc.js.map +1 -0
- package/dist/core/capabilities/delta/overlay.js +129 -0
- package/dist/core/capabilities/delta/overlay.js.map +1 -0
- package/dist/core/capabilities/delta/summary.js +57 -0
- package/dist/core/capabilities/delta/summary.js.map +1 -0
- package/dist/core/capabilities/delta/tree.js +43 -0
- package/dist/core/capabilities/delta/tree.js.map +1 -0
- package/dist/core/capabilities/delta/uncovered.js +222 -0
- package/dist/core/capabilities/delta/uncovered.js.map +1 -0
- package/dist/core/capabilities/findings.js +342 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +181 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +143 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +199 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +126 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +277 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +177 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +74 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/coherence.js +251 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/declared.js +269 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +206 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +204 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +166 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +122 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/merged.js +40 -0
- package/dist/core/coherence/events/merged.js.map +1 -0
- package/dist/core/coherence/living.js +198 -0
- package/dist/core/coherence/living.js.map +1 -0
- package/dist/core/coherence/lookups.js +155 -0
- package/dist/core/coherence/lookups.js.map +1 -0
- package/dist/core/coherence/pending.js +39 -0
- package/dist/core/coherence/pending.js.map +1 -0
- package/dist/core/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.js.map +1 -0
- package/dist/core/delta/claims.js +73 -0
- package/dist/core/delta/claims.js.map +1 -0
- package/dist/core/delta/delta.js +296 -0
- package/dist/core/delta/delta.js.map +1 -0
- package/dist/core/delta/document.js +177 -0
- package/dist/core/delta/document.js.map +1 -0
- package/dist/core/delta/scope.js +48 -0
- package/dist/core/delta/scope.js.map +1 -0
- package/dist/core/delta/select.js +237 -0
- package/dist/core/delta/select.js.map +1 -0
- package/dist/core/dependencies/dependencies.js +141 -0
- package/dist/core/dependencies/dependencies.js.map +1 -0
- package/dist/core/dependencies/facts.js +165 -0
- package/dist/core/dependencies/facts.js.map +1 -0
- package/dist/core/dependencies/fanin.js +88 -0
- package/dist/core/dependencies/fanin.js.map +1 -0
- package/dist/core/dependencies/graph.js +106 -0
- package/dist/core/dependencies/graph.js.map +1 -0
- package/dist/core/diff/base-git.js +148 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +209 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/current-state.js +96 -0
- package/dist/core/diff/current-state.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +188 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/semantic.js +243 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/diff/victims.js +247 -0
- package/dist/core/diff/victims.js.map +1 -0
- package/dist/core/docs.js +7 -64
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +222 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +135 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +275 -0
- package/dist/core/doctor/doctor.js.map +1 -0
- package/dist/core/doctor/report.js +13 -0
- package/dist/core/doctor/report.js.map +1 -0
- package/dist/core/doctor/residue.js +110 -0
- package/dist/core/doctor/residue.js.map +1 -0
- package/dist/core/document/apply.js +77 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
- package/dist/core/document/frontmatter.js.map +1 -0
- package/dist/core/document/grammar/directives.js +143 -0
- package/dist/core/document/grammar/directives.js.map +1 -0
- package/dist/core/document/parse.js +263 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +221 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +241 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +79 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +175 -0
- package/dist/core/envelope/json.js.map +1 -0
- package/dist/core/{version.js → envelope/version.js} +3 -3
- package/dist/core/envelope/version.js.map +1 -0
- package/dist/core/explain/families.js +175 -0
- package/dist/core/explain/families.js.map +1 -0
- package/dist/core/explain/fix-tables.js +178 -0
- package/dist/core/explain/fix-tables.js.map +1 -0
- package/dist/core/explain/lookup.js +181 -0
- package/dist/core/explain/lookup.js.map +1 -0
- package/dist/core/explain/refusals.js +49 -0
- package/dist/core/explain/refusals.js.map +1 -0
- package/dist/core/explain/terms.js +144 -0
- package/dist/core/explain/terms.js.map +1 -0
- package/dist/core/explore/describe.js +105 -0
- package/dist/core/explore/describe.js.map +1 -0
- package/dist/core/{explore.js → explore/explore.js} +50 -101
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +120 -78
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +201 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +205 -0
- package/dist/core/gate/partners.js.map +1 -0
- package/dist/core/gate/report.js +47 -0
- package/dist/core/gate/report.js.map +1 -0
- package/dist/core/gate/verification.js +113 -0
- package/dist/core/gate/verification.js.map +1 -0
- package/dist/core/gherkin/digest.js +60 -0
- package/dist/core/gherkin/digest.js.map +1 -0
- package/dist/core/gherkin/emit.js +177 -0
- package/dist/core/gherkin/emit.js.map +1 -0
- package/dist/core/gherkin/read.js +76 -0
- package/dist/core/gherkin/read.js.map +1 -0
- package/dist/core/gherkin/stale.js +234 -0
- package/dist/core/gherkin/stale.js.map +1 -0
- package/dist/core/gherkin/stamp.js +77 -0
- package/dist/core/gherkin/stamp.js.map +1 -0
- package/dist/core/gherkin/steps/catalogue.js +154 -0
- package/dist/core/gherkin/steps/catalogue.js.map +1 -0
- package/dist/core/gherkin/steps/inventory.js +98 -0
- package/dist/core/gherkin/steps/inventory.js.map +1 -0
- package/dist/core/gherkin/steps/phrase.js +72 -0
- package/dist/core/gherkin/steps/phrase.js.map +1 -0
- package/dist/core/glossary/delta.js +106 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +86 -0
- package/dist/core/glossary/tree.js.map +1 -0
- package/dist/core/kernel/concurrency.js.map +1 -0
- package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
- package/dist/core/kernel/document-bytes.js.map +1 -0
- package/dist/core/kernel/fences.js +42 -0
- package/dist/core/kernel/fences.js.map +1 -0
- package/dist/core/kernel/ids/capability.js +72 -0
- package/dist/core/kernel/ids/capability.js.map +1 -0
- package/dist/core/kernel/ids/dirs.js +33 -0
- package/dist/core/kernel/ids/dirs.js.map +1 -0
- package/dist/core/kernel/ids/feature.js +75 -0
- package/dist/core/kernel/ids/feature.js.map +1 -0
- package/dist/core/kernel/ids/service.js +156 -0
- package/dist/core/kernel/ids/service.js.map +1 -0
- package/dist/core/kernel/ids/subsystem.js +63 -0
- package/dist/core/kernel/ids/subsystem.js.map +1 -0
- package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +68 -0
- package/dist/core/links/backlinks.js.map +1 -0
- package/dist/core/links/case.js +74 -0
- package/dist/core/links/case.js.map +1 -0
- package/dist/core/links/corpus.js +104 -0
- package/dist/core/links/corpus.js.map +1 -0
- package/dist/core/links/findings.js +110 -0
- package/dist/core/links/findings.js.map +1 -0
- package/dist/core/links/parse.js +236 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +111 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +72 -0
- package/dist/core/mcp/author-tools.js.map +1 -0
- package/dist/core/mcp/framing.js +46 -0
- package/dist/core/mcp/framing.js.map +1 -0
- package/dist/core/mcp/protocol.js +280 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/tools.js +314 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/obligations/obligations.js +106 -0
- package/dist/core/obligations/obligations.js.map +1 -0
- package/dist/core/openapi/baseline/gate.js +166 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +112 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +175 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/depth.js +122 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +189 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +44 -106
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +234 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +26 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +208 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +256 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +128 -0
- package/dist/core/openapi/merge/pin.js.map +1 -0
- package/dist/core/openspec/decide/capabilities.js +244 -0
- package/dist/core/openspec/decide/capabilities.js.map +1 -0
- package/dist/core/openspec/decide/dispositions.js +63 -0
- package/dist/core/openspec/decide/dispositions.js.map +1 -0
- package/dist/core/openspec/decide/renames.js +179 -0
- package/dist/core/openspec/decide/renames.js.map +1 -0
- package/dist/core/openspec/decide/verdict.js +84 -0
- package/dist/core/openspec/decide/verdict.js.map +1 -0
- package/dist/core/openspec/inventory.js +221 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +76 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +65 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +235 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +200 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +260 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +133 -0
- package/dist/core/openspec/scan/walk.js.map +1 -0
- package/dist/core/openspec/scan/workspace.js +71 -0
- package/dist/core/openspec/scan/workspace.js.map +1 -0
- package/dist/core/owners/codeowners.js +141 -0
- package/dist/core/owners/codeowners.js.map +1 -0
- package/dist/core/pack/features.js +120 -0
- package/dist/core/pack/features.js.map +1 -0
- package/dist/core/pack/joins.js +112 -0
- package/dist/core/pack/joins.js.map +1 -0
- package/dist/core/pack/living.js +118 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +76 -0
- package/dist/core/pack/pack.js.map +1 -0
- package/dist/core/permissions/permissions.js +87 -0
- package/dist/core/permissions/permissions.js.map +1 -0
- package/dist/core/projection/api.js +84 -0
- package/dist/core/projection/api.js.map +1 -0
- package/dist/core/projection/arch-slice.js +63 -0
- package/dist/core/projection/arch-slice.js.map +1 -0
- package/dist/core/projection/events.js +34 -0
- package/dist/core/projection/events.js.map +1 -0
- package/dist/core/provenance/findings.js +208 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +225 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +182 -0
- package/dist/core/provenance/gitq/moves.js.map +1 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
- package/dist/core/provenance/sample/scope.js +238 -0
- package/dist/core/provenance/sample/scope.js.map +1 -0
- package/dist/core/provenance/sample/sections.js +61 -0
- package/dist/core/provenance/sample/sections.js.map +1 -0
- package/dist/core/provenance/sources.js +263 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +232 -0
- package/dist/core/provenance/stamp.js.map +1 -0
- package/dist/core/provenance/walk.js +157 -0
- package/dist/core/provenance/walk.js.map +1 -0
- package/dist/core/repo/authored/paths.js +192 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +236 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +248 -0
- package/dist/core/repo/repo.js.map +1 -0
- package/dist/core/repo/service-target.js +153 -0
- package/dist/core/repo/service-target.js.map +1 -0
- package/dist/core/repo/state.js +58 -0
- package/dist/core/repo/state.js.map +1 -0
- package/dist/core/repo/tree/find.js +52 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +64 -0
- package/dist/core/repo/tree/fs.js.map +1 -0
- package/dist/core/repo/tree/marker.js +61 -0
- package/dist/core/repo/tree/marker.js.map +1 -0
- package/dist/core/repo/tree/views.js +172 -0
- package/dist/core/repo/tree/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +234 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +99 -2
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +131 -0
- package/dist/core/scaffold/landscape.js.map +1 -0
- package/dist/core/scaffold/readme.js +84 -0
- package/dist/core/scaffold/readme.js.map +1 -0
- package/dist/core/staging/commit.js +241 -0
- package/dist/core/staging/commit.js.map +1 -0
- package/dist/core/staging/interrupted.js +96 -0
- package/dist/core/staging/interrupted.js.map +1 -0
- package/dist/core/staging/lock.js +206 -0
- package/dist/core/staging/lock.js.map +1 -0
- package/dist/core/staging/recovery/finding.js +35 -0
- package/dist/core/staging/recovery/finding.js.map +1 -0
- package/dist/core/staging/recovery/intent.js +98 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +126 -0
- package/dist/core/staging/recovery/recover.js.map +1 -0
- package/dist/core/staging/recovery/residue.js +62 -0
- package/dist/core/staging/recovery/residue.js.map +1 -0
- package/dist/core/staging/snapshot.js +202 -0
- package/dist/core/staging/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +171 -0
- package/dist/core/staging/txn/forward.js.map +1 -0
- package/dist/core/staging/txn/journal.js +139 -0
- package/dist/core/staging/txn/journal.js.map +1 -0
- package/dist/core/staging/txn/transaction.js +75 -0
- package/dist/core/staging/txn/transaction.js.map +1 -0
- package/dist/core/staging/writes.js +113 -0
- package/dist/core/staging/writes.js.map +1 -0
- package/dist/core/status/actions/execution.js +49 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +102 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +171 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +207 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +150 -0
- package/dist/core/status/feature/next.js.map +1 -0
- package/dist/core/status/feature/state.js +21 -0
- package/dist/core/status/feature/state.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +187 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +207 -0
- package/dist/core/status/fleet/next.js.map +1 -0
- package/dist/core/status/interrupted.js +97 -0
- package/dist/core/status/interrupted.js.map +1 -0
- package/dist/core/status/report.js +31 -0
- package/dist/core/status/report.js.map +1 -0
- package/dist/core/status/scan.js +41 -0
- package/dist/core/status/scan.js.map +1 -0
- package/dist/core/status/verification.js +201 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/usecases/capability.js +169 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +116 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +103 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +235 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +137 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/operations.js +111 -0
- package/dist/core/usecases/operations.js.map +1 -0
- package/dist/core/usecases/place.js +44 -0
- package/dist/core/usecases/place.js.map +1 -0
- package/dist/core/usecases/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +173 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +150 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +201 -0
- package/dist/core/verify/checklist.js.map +1 -0
- package/dist/core/verify/claims/identity.js +61 -0
- package/dist/core/verify/claims/identity.js.map +1 -0
- package/dist/core/verify/cross/diff.js +97 -0
- package/dist/core/verify/cross/diff.js.map +1 -0
- package/dist/core/verify/evidence/contract.js +169 -0
- package/dist/core/verify/evidence/contract.js.map +1 -0
- package/dist/core/verify/file.js +257 -0
- package/dist/core/verify/file.js.map +1 -0
- package/dist/core/verify/pins/lint.js +157 -0
- package/dist/core/verify/pins/lint.js.map +1 -0
- package/dist/core/verify/pins/pin.js +95 -0
- package/dist/core/verify/pins/pin.js.map +1 -0
- package/dist/core/verify/record.js +142 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +89 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +57 -0
- package/dist/core/verify/store/render.js.map +1 -0
- package/dist/core/vocabulary/health.js +91 -0
- package/dist/core/vocabulary/health.js.map +1 -0
- package/dist/core/vocabulary/issue.js +55 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +145 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/{report.js → vocabulary/report.js} +30 -2
- package/dist/core/vocabulary/report.js.map +1 -0
- package/dist/core/vocabulary/steps.js +266 -0
- package/dist/core/vocabulary/steps.js.map +1 -0
- package/dist/core/workspace/discover.js +239 -0
- package/dist/core/workspace/discover.js.map +1 -0
- package/dist/core/workspace/render.js +52 -0
- package/dist/core/workspace/render.js.map +1 -0
- package/examples/README.md +189 -0
- package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
- package/examples/docs/architecture/capabilities.yaml +31 -0
- package/examples/docs/architecture/landscape.likec4 +280 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/subsystems.likec4 +11 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
- package/examples/docs/capabilities/checkout/spec.md +55 -0
- package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
- package/examples/docs/capabilities/order-notifications/spec.md +43 -0
- package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
- package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
- package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
- package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
- package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
- package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
- package/examples/docs/glossary/order.md +15 -0
- package/examples/docs/glossary/payments/authorization.md +14 -0
- package/examples/docs/likec4.config.json +9 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +109 -0
- package/examples/docs/services/checkout-web/spec.md +91 -0
- package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
- package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
- package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
- package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
- package/examples/docs/services/order-service/arch.spec.md +127 -0
- package/examples/docs/services/order-service/asyncapi.yaml +108 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +138 -0
- package/examples/docs/services/order-service/openapi.yaml +257 -0
- package/examples/docs/services/order-service/runbook.md +62 -0
- package/examples/docs/services/order-service/spec.md +134 -0
- package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
- package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
- package/examples/docs/services/payment-service/arch.spec.md +73 -0
- package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
- package/examples/docs/services/payment-service/health.yaml +39 -0
- package/examples/docs/services/payment-service/model.likec4 +67 -0
- package/examples/docs/services/payment-service/openapi.yaml +151 -0
- package/examples/docs/services/payment-service/runbook.md +37 -0
- package/examples/docs/services/payment-service/spec.md +88 -0
- package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
- package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
- package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
- package/examples/docs/services/platform/identity-service/runbook.md +95 -0
- package/examples/docs/services/platform/identity-service/spec.md +119 -0
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
- package/examples/docs/services/platform/notification-service/health.yaml +35 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
- package/examples/docs/services/platform/notification-service/runbook.md +48 -0
- package/examples/docs/services/platform/notification-service/spec.md +112 -0
- package/examples/docs/services/platform/subsystem.yaml +2 -0
- package/examples/fleet.yaml +57 -0
- package/package.json +19 -6
- package/dist/commands/adopt.js +0 -240
- package/dist/commands/adopt.js.map +0 -1
- package/dist/commands/archive.js +0 -1313
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/delta.js +0 -388
- package/dist/commands/delta.js.map +0 -1
- package/dist/commands/docs-repo-gate.js.map +0 -1
- package/dist/commands/format.js +0 -17
- package/dist/commands/format.js.map +0 -1
- package/dist/commands/gherkin.js +0 -309
- package/dist/commands/gherkin.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/list.js +0 -295
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/migrate-openspec.js +0 -950
- package/dist/commands/migrate-openspec.js.map +0 -1
- package/dist/commands/new.js +0 -413
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/rebase.js +0 -356
- package/dist/commands/rebase.js.map +0 -1
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/status.js +0 -262
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unarchive.js.map +0 -1
- package/dist/commands/validate.js +0 -1773
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/verify.js +0 -775
- package/dist/commands/verify.js.map +0 -1
- package/dist/commands/vouch.js +0 -421
- package/dist/commands/vouch.js.map +0 -1
- package/dist/core/agent.js +0 -2173
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agents-stamp.js.map +0 -1
- package/dist/core/arch.js +0 -130
- package/dist/core/arch.js.map +0 -1
- package/dist/core/asyncapi.js.map +0 -1
- package/dist/core/brief.js +0 -755
- package/dist/core/brief.js.map +0 -1
- package/dist/core/coherence.js +0 -577
- package/dist/core/coherence.js.map +0 -1
- package/dist/core/concurrency.js.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/delta.js +0 -476
- package/dist/core/delta.js.map +0 -1
- package/dist/core/dependencies.js +0 -356
- package/dist/core/dependencies.js.map +0 -1
- package/dist/core/doctor.js +0 -596
- package/dist/core/doctor.js.map +0 -1
- package/dist/core/document-bytes.js.map +0 -1
- package/dist/core/explore.js.map +0 -1
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/gherkin.js +0 -463
- package/dist/core/gherkin.js.map +0 -1
- package/dist/core/health.js +0 -67
- package/dist/core/health.js.map +0 -1
- package/dist/core/ids.js +0 -122
- package/dist/core/ids.js.map +0 -1
- package/dist/core/issue.js +0 -9
- package/dist/core/issue.js.map +0 -1
- package/dist/core/json.js +0 -74
- package/dist/core/json.js.map +0 -1
- package/dist/core/likec4.js +0 -489
- package/dist/core/likec4.js.map +0 -1
- package/dist/core/maturity.js +0 -66
- package/dist/core/maturity.js.map +0 -1
- package/dist/core/openapi-merge.js +0 -552
- package/dist/core/openapi-merge.js.map +0 -1
- package/dist/core/openapi.js.map +0 -1
- package/dist/core/openspec-inventory.js +0 -1440
- package/dist/core/openspec-inventory.js.map +0 -1
- package/dist/core/path-safety.js.map +0 -1
- package/dist/core/provenance.js +0 -787
- package/dist/core/provenance.js.map +0 -1
- package/dist/core/records.js.map +0 -1
- package/dist/core/repo.js +0 -438
- package/dist/core/repo.js.map +0 -1
- package/dist/core/report.js.map +0 -1
- package/dist/core/spec.js +0 -505
- package/dist/core/spec.js.map +0 -1
- package/dist/core/staging.js +0 -890
- package/dist/core/staging.js.map +0 -1
- package/dist/core/status.js +0 -1132
- package/dist/core/status.js.map +0 -1
- package/dist/core/steps.js +0 -72
- package/dist/core/steps.js.map +0 -1
- package/dist/core/verify.js +0 -807
- package/dist/core/verify.js.map +0 -1
- package/dist/core/version.js.map +0 -1
- /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
- /package/dist/core/{records.js → kernel/records.js} +0 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fleet target: `services/` and architecture/landscape.likec4 graded
|
|
3
|
+
* against each other, plus the two exemptions that decide which drawn element
|
|
4
|
+
* answers for a service directory at all.
|
|
5
|
+
*
|
|
6
|
+
* The landscape is the one artifact no service owns — parsed once for the whole
|
|
7
|
+
* run and graded on a target of its own, outside the dispatcher's `guarded`.
|
|
8
|
+
* That is why its IO containment lives in this package instead: see
|
|
9
|
+
* `unreadableLandscape` in `./load.ts`.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
import { relative } from "node:path";
|
|
13
|
+
import { readFile } from "node:fs/promises";
|
|
14
|
+
import { loadFile } from "../../../core/c4/likec4.js";
|
|
15
|
+
import { elementService, serviceResolver } from "../../../core/c4/resolve/service.js";
|
|
16
|
+
import { landscapePath as landscapeFile } from "../../../core/repo/paths.js";
|
|
17
|
+
import { serviceIdFindings } from "../../../core/repo/entries.js";
|
|
18
|
+
import { listFleetTree, listServices } from "../../../core/repo/repo.js";
|
|
19
|
+
import {} from "../../../core/vocabulary/report.js";
|
|
20
|
+
import { landscapeConflictFinding } from "../../../core/conflict-markers.js";
|
|
21
|
+
import { FleetContext } from "../../../core/fleet-context.js";
|
|
22
|
+
import { capabilityFleetFindings, fleetShapeFindings, permissionFindings } from "../checks/fleet-shape.js";
|
|
23
|
+
import { fleetLinkFindings } from "../links/corpus.js";
|
|
24
|
+
import { glossaryFindings } from "../links/glossary.js";
|
|
25
|
+
import { obligationFindings, obligationVocabularyFindings } from "./obligations.js";
|
|
26
|
+
import { readObligations } from "../../../core/obligations/obligations.js";
|
|
27
|
+
import { obligationsPath } from "../../../core/repo/paths.js";
|
|
28
|
+
import { EXTERNAL_TAG } from "../../../core/vocabulary/maturity.js";
|
|
29
|
+
import { errorText } from "../checks/vocabulary.js";
|
|
30
|
+
import { serviceTreePath } from "../../../core/kernel/ids/dirs.js";
|
|
31
|
+
import { drawnSystems, serviceLevelElements } from "./census.js";
|
|
32
|
+
import { unreadableLandscape } from "./load.js";
|
|
33
|
+
import { kindTagFindings } from "./kind-tags.js";
|
|
34
|
+
import { useCaseFindings } from "./usecases/usecases.js";
|
|
35
|
+
import { viewIdFindings } from "./views/ids.js";
|
|
36
|
+
import { viewsStaleFindings } from "./views/stale.js";
|
|
37
|
+
import { readCapabilityVocabulary } from "../../../core/capabilities/capabilities.js";
|
|
38
|
+
import { capabilityRequirementIndex, gradableCapabilityIds } from "../../../core/capabilities/findings.js";
|
|
39
|
+
import { parseRequirements, readRequirementsDocument } from "../../../core/document/parse.js";
|
|
40
|
+
import { isUseCase } from "../../../core/usecases/fleet.js";
|
|
41
|
+
/**
|
|
42
|
+
* The fleet's flows as a grade may read them, or `null` when loam cannot see
|
|
43
|
+
* them at all — the same `null`-suspends idiom `gradableCapabilityIds` uses,
|
|
44
|
+
* and here it guards one specific wrong answer.
|
|
45
|
+
*
|
|
46
|
+
* `capability.requirement-unrealized` says a business promise is kept by
|
|
47
|
+
* 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 preload (a single-target
|
|
49
|
+
* run) and a project that did not parse are both "loam did not look", never
|
|
50
|
+
* "there is nothing there". A preload that DID parse and declares no views is a
|
|
51
|
+
* real, empty answer and grades normally.
|
|
52
|
+
*
|
|
53
|
+
* Filtered through `isUseCase` — the same opt-in `readUseCases` applies before
|
|
54
|
+
* `loam list capabilities` asks this question — because the two surfaces must
|
|
55
|
+
* never disagree about `keptBy`. Handing the unfiltered preload over was
|
|
56
|
+
* harmless only by luck: an untagged view yields no claims, so the answers
|
|
57
|
+
* matched for want of an input that could tell them apart. A `#req-`-only view
|
|
58
|
+
* is exactly that input.
|
|
59
|
+
*/
|
|
60
|
+
function gradableFlows(preloaded) {
|
|
61
|
+
if (preloaded === null || preloaded === undefined || preloaded.errors.length > 0)
|
|
62
|
+
return null;
|
|
63
|
+
return (preloaded.views ?? []).filter(isUseCase);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The fleet cross-check: `services/` and the landscape both claim to name the
|
|
67
|
+
* fleet, and nothing used to compare them. A directory nobody drew and an element
|
|
68
|
+
* with nothing behind it were equally invisible.
|
|
69
|
+
*
|
|
70
|
+
* The two directions are graded differently because the evidence differs. A
|
|
71
|
+
* directory that exists is a fact, so a landscape missing it is an error — every
|
|
72
|
+
* view derived from that landscape is then incomplete. An element with no
|
|
73
|
+
* directory may legitimately be someone else's system, so it warns, and
|
|
74
|
+
* `#external` says "deliberately not ours" and silences it. An explicit
|
|
75
|
+
* `metadata { service '<id>' }` naming nothing is an error either way: a binding
|
|
76
|
+
* is a claim about this repo, not a guess at one.
|
|
77
|
+
*
|
|
78
|
+
* An ABSENT landscape is a finding, not a skipped check. It used to return null
|
|
79
|
+
* — no target, no findings, and a fleet gate that went green over a docs repo
|
|
80
|
+
* with no fleet map at all, which is the single artifact every derived view and
|
|
81
|
+
* every spine check is computed from. It is graded by what its absence proves:
|
|
82
|
+
* with services in `services/` it is an ERROR (a fleet that exists is undrawn),
|
|
83
|
+
* with none it is a WARNING (a docs repo before its first adopt legitimately
|
|
84
|
+
* has nothing to draw, but the file still belongs there — `loam init` scaffolds
|
|
85
|
+
* it, and a repo missing it will silently accept never getting one).
|
|
86
|
+
*
|
|
87
|
+
* `preloaded` is the already-parsed landscape under --all — the same doc every
|
|
88
|
+
* service check gets.
|
|
89
|
+
*/
|
|
90
|
+
export async function validateLandscape(docsDir, preloaded, fleet) {
|
|
91
|
+
const path = landscapeFile(docsDir);
|
|
92
|
+
const findings = [];
|
|
93
|
+
const report = {
|
|
94
|
+
kind: "landscape",
|
|
95
|
+
id: "landscape",
|
|
96
|
+
path: "architecture/landscape.likec4",
|
|
97
|
+
findings,
|
|
98
|
+
};
|
|
99
|
+
// The SET of service directories is this target's other subject, so it is
|
|
100
|
+
// graded before the map is even opened: `service.id-invalid` is a fact about
|
|
101
|
+
// `services/` that holds whether or not a landscape exists or parses, and
|
|
102
|
+
// both of those return early below. Emitted here and nowhere else — the
|
|
103
|
+
// enumeration is what makes the id a question, and one finding per fleet is
|
|
104
|
+
// what the rename fixes.
|
|
105
|
+
const entries = await listServices(docsDir, fleet);
|
|
106
|
+
findings.push(...serviceIdFindings(entries));
|
|
107
|
+
// The tree walk's own findings ride the same fleet target, before the map's
|
|
108
|
+
// early returns for the same reason `service.id-invalid` does: a stranded,
|
|
109
|
+
// colliding or mismarked directory is a fact about `services/` that holds
|
|
110
|
+
// whether or not a landscape exists or parses — and a broken tree must make
|
|
111
|
+
// the fleet gate refuse while still naming every service it found.
|
|
112
|
+
const tree = await listFleetTree(docsDir, fleet);
|
|
113
|
+
findings.push(...tree.findings);
|
|
114
|
+
// Before the landscape's own early returns: the authorization and capability
|
|
115
|
+
// vocabularies are fleet facts that do not depend on the map existing or parsing.
|
|
116
|
+
findings.push(...(await permissionFindings(docsDir, entries, fleet)));
|
|
117
|
+
findings.push(...(await capabilityFleetFindings(docsDir, entries, fleet, gradableFlows(preloaded))));
|
|
118
|
+
// The documents that belong to no service and no feature — the fleet's ADRs
|
|
119
|
+
// and the living capability tree — are graded for their links here, once,
|
|
120
|
+
// for the same reason the two vocabularies above are: a fleet fact repeated
|
|
121
|
+
// on every service target is the report.
|
|
122
|
+
findings.push(...(await fleetLinkFindings({ docsDir, fleet })));
|
|
123
|
+
// The glossary is graded on who cites it, which is a question only the whole
|
|
124
|
+
// repository answers — so it belongs here, beside the two vocabularies, and
|
|
125
|
+
// nowhere else.
|
|
126
|
+
findings.push(...(await glossaryFindings(docsDir, fleet)));
|
|
127
|
+
// The architectural obligation vocabulary, read ONCE here and handed to the
|
|
128
|
+
// map half below: its own two verdicts hold whether or not the landscape
|
|
129
|
+
// exists or parses, and a run where somebody is fixing the map must still be
|
|
130
|
+
// told that this file does not read.
|
|
131
|
+
const obligations = await readObligations(obligationsPath(docsDir));
|
|
132
|
+
findings.push(...obligationVocabularyFindings(docsDir, obligations));
|
|
133
|
+
if (!existsSync(path)) {
|
|
134
|
+
const count = entries.length;
|
|
135
|
+
findings.push({
|
|
136
|
+
severity: count > 0 ? "error" : "warn",
|
|
137
|
+
code: "landscape.missing",
|
|
138
|
+
message: `landscape: architecture/landscape.likec4 does not exist — ` +
|
|
139
|
+
(count > 0
|
|
140
|
+
? `${count} service(s) are adopted and nothing draws the fleet. `
|
|
141
|
+
: "nothing draws the fleet. ") +
|
|
142
|
+
"It is the one map every derived view and the C4↔API spine are computed from: " +
|
|
143
|
+
"write a `specification { element softwareSystem }` + `model { … }` document there " +
|
|
144
|
+
"with one element per services/<id>/, bound with `metadata { service '<id>' }`.",
|
|
145
|
+
});
|
|
146
|
+
return report;
|
|
147
|
+
}
|
|
148
|
+
// Conflict markers before the parse — `loam doctor`'s order, and for its
|
|
149
|
+
// reason: the markers are the cause and the parse errors are the cascade.
|
|
150
|
+
// Nothing may be concluded from a file that is two halves of two different
|
|
151
|
+
// maps, least of all that a service nobody drew is unmodelled, so this
|
|
152
|
+
// returns the way `landscape.invalid` does. An error, gating by the default
|
|
153
|
+
// rule and deliberately not carrying `gates` — that field is coherence's,
|
|
154
|
+
// and the archive gate has to ask this question itself (it does not yet).
|
|
155
|
+
// Read plainly rather than through FleetContext: this target runs outside
|
|
156
|
+
// `guarded`, and a document refused for its encoding would surface here as
|
|
157
|
+
// the whole run's `repository-unavailable` instead of one finding.
|
|
158
|
+
//
|
|
159
|
+
// Both reads are contained for that same reason — see `unreadableLandscape`.
|
|
160
|
+
// The conflict-marker read is the FIRST touch of the file, so it is the one
|
|
161
|
+
// that fails when the file cannot be opened at all, and it runs before
|
|
162
|
+
// `preloaded ??` can spare it.
|
|
163
|
+
let land;
|
|
164
|
+
try {
|
|
165
|
+
const conflict = landscapeConflictFinding("architecture/landscape.likec4", await readFile(path, "utf8"));
|
|
166
|
+
if (conflict !== null) {
|
|
167
|
+
findings.push(conflict);
|
|
168
|
+
return report;
|
|
169
|
+
}
|
|
170
|
+
land = preloaded ?? (fleet === undefined ? await loadFile(path) : await fleet.loadLikeC4(path));
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
land = unreadableLandscape(err);
|
|
174
|
+
}
|
|
175
|
+
if (land.errors.length > 0) {
|
|
176
|
+
// Nothing may be concluded from a document that did not parse — in particular
|
|
177
|
+
// not that every service is unmodelled.
|
|
178
|
+
//
|
|
179
|
+
// The fleet map is a PROJECT now, not a file: `architecture/landscape.likec4`
|
|
180
|
+
// plus every `architecture/usecases/*.likec4`, merged the way the renderer
|
|
181
|
+
// merges them. So the message names the FILES that broke rather than the
|
|
182
|
+
// landscape by default — a use case with a typo'd element used to be
|
|
183
|
+
// reported as the landscape having errors, which sent the author to the
|
|
184
|
+
// wrong file with a line number that pointed at somebody else's text.
|
|
185
|
+
const broken = [...new Set(land.errors.map((e) => e.sourceFsPath).filter((p) => p !== undefined))];
|
|
186
|
+
const spell = (abs) => relative(docsDir, abs).split(/[\\/]/).join("/");
|
|
187
|
+
const named = broken.length === 0 ? "architecture/landscape.likec4" : broken.map(spell).sort().join(", ");
|
|
188
|
+
findings.push({
|
|
189
|
+
severity: "error",
|
|
190
|
+
code: "landscape.invalid",
|
|
191
|
+
message: `landscape: ${named} has ${land.errors.length} error(s) — cross-check with services/ impossible`,
|
|
192
|
+
// 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
|
+
details: land.errors.map((e) => e.sourceFsPath === undefined || broken.length < 2 ? errorText(e) : `${spell(e.sourceFsPath)} ${errorText(e)}`),
|
|
195
|
+
});
|
|
196
|
+
return report;
|
|
197
|
+
}
|
|
198
|
+
// The generated subsystem views, graded only now that the landscape has
|
|
199
|
+
// parsed: the expected bytes are a function of (tree, landscape elements) —
|
|
200
|
+
// `views/stale.ts` says why a byte compare and why exactly one finding.
|
|
201
|
+
findings.push(...(await viewsStaleFindings(docsDir, tree, land.elements)));
|
|
202
|
+
// Beside staleness, and for the same file: an authored view id that collides
|
|
203
|
+
// with one loam mints into it takes the whole architecture/ project down in
|
|
204
|
+
// the renderer while every check here stays green — see views/ids.ts.
|
|
205
|
+
findings.push(...viewIdFindings(land.viewIds, tree));
|
|
206
|
+
// The three obligation questions that need the map — where each declared rule
|
|
207
|
+
// is applied, which tags resolve to nothing, and which applications no living
|
|
208
|
+
// arch requirement covers. Here rather than beside the vocabulary above
|
|
209
|
+
// because all three are about the parsed landscape, and `land` is only
|
|
210
|
+
// trustworthy past this point.
|
|
211
|
+
findings.push(...(await obligationFindings({ docsDir, vocabulary: obligations, land, services: entries, fleet })));
|
|
212
|
+
const services = new Set(entries.map((s) => s.id));
|
|
213
|
+
// Where each service actually sits, for every finding below that names a
|
|
214
|
+
// directory a reader is meant to open. `services/<id>/` is right only for an
|
|
215
|
+
// unfiled fleet; a filed service lives at `services/<subsystem>/…/<id>/`, and
|
|
216
|
+
// a finding pointing at the root form sends the fix to a path that does not
|
|
217
|
+
// exist. Built once here because three checks below need the same answer.
|
|
218
|
+
const pathOf = (id) => {
|
|
219
|
+
const entry = entries.find((s) => s.id === id);
|
|
220
|
+
return entry === undefined ? `services/${id}` : serviceTreePath(entry);
|
|
221
|
+
};
|
|
222
|
+
// Ahead of every exemption below, because it is the one defect that can make
|
|
223
|
+
// all of them lie at once: a tag loam grades on, declared on a KIND, landing
|
|
224
|
+
// on an element that stands for one of our own directories — see kind-tags.ts.
|
|
225
|
+
findings.push(...kindTagFindings({ specification: land.specification, elements: land.elements, services }));
|
|
226
|
+
const drawn = serviceLevelElements(land.elements, services);
|
|
227
|
+
// Which services the landscape models, answered by the same resolver every
|
|
228
|
+
// edge join uses — so "modelled" here and "inbound edge" in the spine check
|
|
229
|
+
// can never disagree about what an element stands for.
|
|
230
|
+
const landSvcOf = serviceResolver(land.elements, services);
|
|
231
|
+
const modelled = new Set(land.elements.map((e) => landSvcOf(e.id)));
|
|
232
|
+
// Two boxes standing for one service directory. Every join in loam is
|
|
233
|
+
// `element -> service`, computed by picking the FIRST element that resolves —
|
|
234
|
+
// so with two of them, which one wins is readdir order, and the edges of the
|
|
235
|
+
// loser are attributed to a service they do not belong to. Silent until now,
|
|
236
|
+
// and unfixable by staring at either element on its own.
|
|
237
|
+
const perService = new Map();
|
|
238
|
+
for (const e of drawn) {
|
|
239
|
+
if (e.tags.includes(EXTERNAL_TAG))
|
|
240
|
+
continue;
|
|
241
|
+
const id = elementService(e);
|
|
242
|
+
perService.set(id, [...(perService.get(id) ?? []), e]);
|
|
243
|
+
}
|
|
244
|
+
for (const [id, elems] of perService) {
|
|
245
|
+
if (elems.length < 2)
|
|
246
|
+
continue;
|
|
247
|
+
// A collision only matters where it decides something: a real directory to
|
|
248
|
+
// attribute to, or a binding somebody wrote down on purpose.
|
|
249
|
+
if (!services.has(id) && !elems.some((e) => e.service !== undefined))
|
|
250
|
+
continue;
|
|
251
|
+
findings.push({
|
|
252
|
+
severity: "warn",
|
|
253
|
+
code: "landscape.binding-duplicate",
|
|
254
|
+
subject: id,
|
|
255
|
+
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>/`,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
for (const id of services) {
|
|
259
|
+
if (modelled.has(id))
|
|
260
|
+
continue;
|
|
261
|
+
findings.push({
|
|
262
|
+
severity: "error",
|
|
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
|
+
}
|
|
300
|
+
// The shape advisories run LAST, over the same drawn set and resolver the
|
|
301
|
+
// structural checks used. Any one of them suppresses `landscape.matched`
|
|
302
|
+
// below on purpose: a map with a shape warning did not fully "agree".
|
|
303
|
+
findings.push(...fleetShapeFindings({ drawn, relationships: land.relationships, services, resolve: landSvcOf, pathOf }));
|
|
304
|
+
// The use cases the SAME `architecture/` project declares — every
|
|
305
|
+
// `dynamic view` in the landscape and in every `architecture/usecases/*.likec4`
|
|
306
|
+
// — graded against the model above (usecases/usecases.ts owns the opt-in and
|
|
307
|
+
// the grades). They ride this target for `viewsStaleFindings`' reason: a view
|
|
308
|
+
// belongs to no service, and only the fleet run has both the whole model and
|
|
309
|
+
// the enumerated `services/` in view at once.
|
|
310
|
+
//
|
|
311
|
+
// The views come from `preloaded` rather than from `land`, and that is the
|
|
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({
|
|
336
|
+
views: preloaded?.views ?? [],
|
|
337
|
+
elements: land.elements,
|
|
338
|
+
relationships: land.relationships,
|
|
339
|
+
services,
|
|
340
|
+
resolve: landSvcOf,
|
|
341
|
+
capabilities: gradableCapabilityIds(vocabulary),
|
|
342
|
+
requirementsOf: (capability) => capabilityReqs.byCapability.get(capability),
|
|
343
|
+
}));
|
|
344
|
+
if (findings.length === 0) {
|
|
345
|
+
findings.push({
|
|
346
|
+
severity: "ok",
|
|
347
|
+
code: "landscape.matched",
|
|
348
|
+
message: `landscape: ${services.size} service(s) modelled — architecture/landscape.likec4 and services/ agree`,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
return report;
|
|
352
|
+
}
|
|
353
|
+
//# sourceMappingURL=landscape.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A landscape that could not be READ, shaped as one that did not PARSE.
|
|
3
|
+
*
|
|
4
|
+
* The landscape is the one artifact no target owns: it is read once for the
|
|
5
|
+
* whole run and it is graded on a target of its own, which runs OUTSIDE
|
|
6
|
+
* `guarded`. So a landscape.likec4 that is a directory, or that carries a
|
|
7
|
+
* permission bit this process cannot open, escaped every per-target catch and
|
|
8
|
+
* became the whole run's `repository-unavailable` — one file, and a fleet gate
|
|
9
|
+
* that said nothing about the ninety-nine services that are fine. A DANGLING
|
|
10
|
+
* symlink is not one of those shapes and never was: every read of the file is
|
|
11
|
+
* gated on an `existsSync` that follows the link, so a broken one resolves as
|
|
12
|
+
* `landscape.missing` long before anything opens it.
|
|
13
|
+
*
|
|
14
|
+
* What this contains is the FLEET-level reads, and only those: the `--all`
|
|
15
|
+
* preload, and both reads inside `validateLandscape` — the conflict-marker
|
|
16
|
+
* `readFile` and the parse. `loam validate --service <id>` and
|
|
17
|
+
* `loam validate --feature <id>` hand in no preloaded doc, so `validateService`
|
|
18
|
+
* and `validateFeature` open the same file again on demand, unwrapped and
|
|
19
|
+
* INSIDE `guarded`: an EISDIR there is still reported as `service.unreadable`
|
|
20
|
+
* or `feature.unreadable`, which files the fleet map's failure against the one
|
|
21
|
+
* target the caller happened to name. That is the wrong subject on a finding
|
|
22
|
+
* that does at least carry the offending path, and it costs those runs nothing
|
|
23
|
+
* further — they grade a single target either way, so there is no report left
|
|
24
|
+
* unwritten — which is why the remainder was left for the change that gives the
|
|
25
|
+
* landscape one load path instead of three.
|
|
26
|
+
*
|
|
27
|
+
* `guarded` is deliberately NOT widened to cover the landscape target instead.
|
|
28
|
+
* Its code ternary knows only services and features, so it would file the fleet
|
|
29
|
+
* map's failure as `feature.unreadable`; and a guarded failure yields no
|
|
30
|
+
* document, so all N services would go on to re-open the same broken file
|
|
31
|
+
* inside their own guards and emit N copies of it. Containing the IO here needs
|
|
32
|
+
* no new code and no new sentence: "could not be read" and "did not parse" have
|
|
33
|
+
* the same consequence — nothing may be concluded from this file — and
|
|
34
|
+
* `landscape.invalid` is already how that is said.
|
|
35
|
+
*/
|
|
36
|
+
export function unreadableLandscape(err) {
|
|
37
|
+
return {
|
|
38
|
+
errors: [{ message: err instanceof Error ? err.message : String(err) }],
|
|
39
|
+
elements: [],
|
|
40
|
+
relationships: [],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** One landscape load, answering with `unreadableLandscape` rather than throwing. */
|
|
44
|
+
export async function readLandscape(load) {
|
|
45
|
+
try {
|
|
46
|
+
return await load();
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
return unreadableLandscape(err);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=load.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../../../src/commands/validate/fleet/load.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,OAAO;QACL,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACvE,QAAQ,EAAE,EAAE;QACZ,aAAa,EAAE,EAAE;KAClB,CAAC;AACJ,CAAC;AAED,qFAAqF;AACrF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAA8B;IAChE,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;AACH,CAAC","sourcesContent":["/**\n * The landscape's contained load path — the one phase of the fleet target that\n * touches the filesystem before anything can be graded. Split from\n * `./landscape.ts` when the fleet target grew past the line limit; the\n * containment DOCTRINE below travelled with the functions it explains.\n *\n * The load ITSELF is no longer here. `loadArchitecture` moved to\n * `core/c4/project/architecture.ts` when the use-case axis grew a second reader\n * of it, and that module's banner records why; what stayed is the containment,\n * which is command-layer business because it is about which validate TARGET a\n * failed read is filed against.\n */\nimport type { LoadedDoc } from \"../../../core/c4/likec4.js\";\n\n/**\n * A landscape that could not be READ, shaped as one that did not PARSE.\n *\n * The landscape is the one artifact no target owns: it is read once for the\n * whole run and it is graded on a target of its own, which runs OUTSIDE\n * `guarded`. So a landscape.likec4 that is a directory, or that carries a\n * permission bit this process cannot open, escaped every per-target catch and\n * became the whole run's `repository-unavailable` — one file, and a fleet gate\n * that said nothing about the ninety-nine services that are fine. A DANGLING\n * symlink is not one of those shapes and never was: every read of the file is\n * gated on an `existsSync` that follows the link, so a broken one resolves as\n * `landscape.missing` long before anything opens it.\n *\n * What this contains is the FLEET-level reads, and only those: the `--all`\n * preload, and both reads inside `validateLandscape` — the conflict-marker\n * `readFile` and the parse. `loam validate --service <id>` and\n * `loam validate --feature <id>` hand in no preloaded doc, so `validateService`\n * and `validateFeature` open the same file again on demand, unwrapped and\n * INSIDE `guarded`: an EISDIR there is still reported as `service.unreadable`\n * or `feature.unreadable`, which files the fleet map's failure against the one\n * target the caller happened to name. That is the wrong subject on a finding\n * that does at least carry the offending path, and it costs those runs nothing\n * further — they grade a single target either way, so there is no report left\n * unwritten — which is why the remainder was left for the change that gives the\n * landscape one load path instead of three.\n *\n * `guarded` is deliberately NOT widened to cover the landscape target instead.\n * Its code ternary knows only services and features, so it would file the fleet\n * map's failure as `feature.unreadable`; and a guarded failure yields no\n * document, so all N services would go on to re-open the same broken file\n * inside their own guards and emit N copies of it. Containing the IO here needs\n * no new code and no new sentence: \"could not be read\" and \"did not parse\" have\n * the same consequence — nothing may be concluded from this file — and\n * `landscape.invalid` is already how that is said.\n */\nexport function unreadableLandscape(err: unknown): LoadedDoc {\n return {\n errors: [{ message: err instanceof Error ? err.message : String(err) }],\n elements: [],\n relationships: [],\n };\n}\n\n/** One landscape load, answering with `unreadableLandscape` rather than throwing. */\nexport async function readLandscape(load: () => Promise<LoadedDoc>): Promise<LoadedDoc> {\n try {\n return await load();\n } catch (err) {\n return unreadableLandscape(err);\n }\n}\n"]}
|