@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5992 -82
- package/COMPARISON.md +168 -63
- package/CONTRIBUTING.md +121 -0
- package/MIGRATING-from-OpenSpec.md +238 -55
- package/QUICKSTART.md +302 -0
- package/README.md +653 -144
- package/ROADMAP.md +1035 -0
- package/SCHEMA.md +3916 -263
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +927 -0
- package/dist/cli.js +133 -21
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +204 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +309 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +74 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/closing.js +42 -0
- package/dist/commands/archive/closing.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/consumers.js +56 -0
- package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +193 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/document/head.js +151 -0
- package/dist/commands/archive/plan/document/head.js.map +1 -0
- package/dist/commands/archive/plan/document/links.js +284 -0
- package/dist/commands/archive/plan/document/links.js.map +1 -0
- package/dist/commands/archive/plan/document/run.js +136 -0
- package/dist/commands/archive/plan/document/run.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +319 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +298 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/model/extending.js +85 -0
- package/dist/commands/archive/plan/model/extending.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +106 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +318 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +30 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +355 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/archive/shipped.js +49 -0
- package/dist/commands/archive/shipped.js.map +1 -0
- package/dist/commands/context/context.js +166 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +305 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +367 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +221 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +6 -8
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +86 -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 +65 -5
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +227 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +39 -28
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +152 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +66 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +105 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +262 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +146 -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 +72 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +142 -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 +63 -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 +155 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +358 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +344 -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/suites/suites.js +140 -0
- package/dist/commands/list/suites/suites.js.map +1 -0
- package/dist/commands/list/views.js +108 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +238 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +75 -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 +175 -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 +143 -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 +86 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +18 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +40 -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/capability-template.js +118 -0
- package/dist/commands/new/capability-template.js.map +1 -0
- package/dist/commands/new/commit.js +62 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/modifies.js +206 -0
- package/dist/commands/new/modifies.js.map +1 -0
- package/dist/commands/new/new.js +328 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +279 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +199 -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} +38 -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 +300 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +221 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +278 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +174 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +182 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/introduced.js +157 -0
- package/dist/commands/show/introduced.js.map +1 -0
- package/dist/commands/show/marks.js +53 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/show/service.js +239 -0
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +87 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/fleet-next.js +90 -0
- package/dist/commands/status/fleet-next.js.map +1 -0
- package/dist/commands/status/json.js +47 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +209 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +115 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +269 -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 +325 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +113 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +98 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +318 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/exclude.js +132 -0
- package/dist/commands/subsystem/txn/exclude.js.map +1 -0
- package/dist/commands/subsystem/txn/links.js +128 -0
- package/dist/commands/subsystem/txn/links.js.map +1 -0
- package/dist/commands/subsystem/txn/report.js +174 -0
- package/dist/commands/subsystem/txn/report.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +196 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +249 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/tasks/actions.js +107 -0
- package/dist/commands/tasks/actions.js.map +1 -0
- package/dist/commands/tasks/render.js +253 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +119 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +176 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/unarchive/restore.js +254 -0
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +59 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +245 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +204 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +58 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/introduced.js +102 -0
- package/dist/commands/validate/checks/introduced.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +264 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +85 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/coverage/covers-after.js +105 -0
- package/dist/commands/validate/coverage/covers-after.js.map +1 -0
- package/dist/commands/validate/feature.js +222 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +93 -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 +371 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +118 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/map/attest.js +98 -0
- package/dist/commands/validate/fleet/map/attest.js.map +1 -0
- package/dist/commands/validate/fleet/map/bindings.js +107 -0
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
- package/dist/commands/validate/fleet/map/consumers.js +244 -0
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
- package/dist/commands/validate/fleet/map/isolation.js +116 -0
- package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
- package/dist/commands/validate/fleet/map/usecases.js +54 -0
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +266 -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 +71 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.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/views/fleet-project.js +217 -0
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +75 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/projects.js +278 -0
- package/dist/commands/validate/fleet/views/projects.js.map +1 -0
- package/dist/commands/validate/fleet/views/root-documents.js +83 -0
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +52 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +89 -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/render/repeats.js +63 -0
- package/dist/commands/validate/render/repeats.js.map +1 -0
- package/dist/commands/validate/render/rollups.js +115 -0
- package/dist/commands/validate/render/rollups.js.map +1 -0
- package/dist/commands/validate/render/text.js +199 -0
- package/dist/commands/validate/render/text.js.map +1 -0
- package/dist/commands/validate/report.js +145 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/scope.js +113 -0
- package/dist/commands/validate/scope.js.map +1 -0
- package/dist/commands/validate/service/api.js +252 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/contracts/generated.js +134 -0
- package/dist/commands/validate/service/contracts/generated.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +241 -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 +177 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/model/diverged.js +226 -0
- package/dist/commands/validate/service/model/diverged.js.map +1 -0
- package/dist/commands/validate/service/model/grade.js +163 -0
- package/dist/commands/validate/service/model/grade.js.map +1 -0
- package/dist/commands/validate/service/service.js +310 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +279 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +148 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/service/usecases/tags.js +113 -0
- package/dist/commands/validate/service/usecases/tags.js.map +1 -0
- package/dist/commands/validate/service/usecases/usecases.js +209 -0
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/validate.js +363 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +178 -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 +81 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +263 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +278 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +206 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +328 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +220 -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 +266 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +141 -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 +230 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +111 -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 +155 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +169 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +299 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +46 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +44 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +78 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +104 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +138 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +273 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md.js +203 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -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 +254 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +144 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +151 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +193 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +280 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +373 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +323 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +220 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +188 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +311 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +67 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +210 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +19 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +338 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +43 -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 +146 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +92 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +38 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +290 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +195 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +83 -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/read.js +263 -0
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +285 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +385 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +273 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/map/extend.js +84 -0
- package/dist/core/brief/map/extend.js.map +1 -0
- package/dist/core/brief/map/owed.js +266 -0
- package/dist/core/brief/map/owed.js.map +1 -0
- package/dist/core/brief/targets.js +304 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +58 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +190 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/direction/direction.js +114 -0
- package/dist/core/c4/direction/direction.js.map +1 -0
- package/dist/core/c4/likec4.js +243 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/locate/unlocated.js +150 -0
- package/dist/core/c4/locate/unlocated.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +160 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +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 +110 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +113 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/prefetch/fleet.js +134 -0
- package/dist/core/c4/prefetch/fleet.js.map +1 -0
- package/dist/core/c4/project/architecture.js +161 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/batch.js +140 -0
- package/dist/core/c4/project/batch.js.map +1 -0
- package/dist/core/c4/project/documents.js +89 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +219 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/project/staged.js +277 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/attested.js +0 -0
- package/dist/core/c4/resolve/attested.js.map +1 -0
- package/dist/core/c4/resolve/external.js +51 -0
- package/dist/core/c4/resolve/external.js.map +1 -0
- package/dist/core/c4/resolve/service.js +174 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/resolve/steps.js +290 -0
- package/dist/core/c4/resolve/steps.js.map +1 -0
- package/dist/core/c4/resolve/systems.js +154 -0
- package/dist/core/c4/resolve/systems.js.map +1 -0
- package/dist/core/c4/root-project/exclude.js +352 -0
- package/dist/core/c4/root-project/exclude.js.map +1 -0
- package/dist/core/c4/seed/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 +173 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/service-model/created/models.js +96 -0
- package/dist/core/c4/service-model/created/models.js.map +1 -0
- package/dist/core/c4/service-model/documents.js +47 -0
- package/dist/core/c4/service-model/documents.js.map +1 -0
- package/dist/core/c4/service-model/fleet/extending.js +82 -0
- package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
- package/dist/core/c4/service-model/load.js +165 -0
- package/dist/core/c4/service-model/load.js.map +1 -0
- package/dist/core/c4/service-model/renderer.js +128 -0
- package/dist/core/c4/service-model/renderer.js.map +1 -0
- package/dist/core/c4/service-model/shape.js +106 -0
- package/dist/core/c4/service-model/shape.js.map +1 -0
- package/dist/core/c4/service-model/slice.js +188 -0
- package/dist/core/c4/service-model/slice.js.map +1 -0
- package/dist/core/c4/source-mask.js +369 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +308 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +167 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +30 -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/declared.js +87 -0
- package/dist/core/c4/splice/identity/declared.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +73 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/identity/existing.js +80 -0
- package/dist/core/c4/splice/identity/existing.js.map +1 -0
- package/dist/core/c4/splice/identity/interior.js +80 -0
- package/dist/core/c4/splice/identity/interior.js.map +1 -0
- package/dist/core/c4/splice/identity/owner.js +50 -0
- package/dist/core/c4/splice/identity/owner.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +337 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/model/merge.js +151 -0
- package/dist/core/c4/splice/model/merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +298 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/splice/text/spot.js +131 -0
- package/dist/core/c4/splice/text/spot.js.map +1 -0
- package/dist/core/c4/workspace.js +166 -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 +47 -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 +338 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +174 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +123 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +205 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +104 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +267 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +185 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +75 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/calls/called.js +52 -0
- package/dist/core/coherence/calls/called.js.map +1 -0
- package/dist/core/coherence/coherence.js +332 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/consumed/operations.js +70 -0
- package/dist/core/coherence/consumed/operations.js.map +1 -0
- package/dist/core/coherence/consumed/refusal.js +38 -0
- package/dist/core/coherence/consumed/refusal.js.map +1 -0
- package/dist/core/coherence/covers/health.js +85 -0
- package/dist/core/coherence/covers/health.js.map +1 -0
- package/dist/core/coherence/declared.js +295 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +191 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +335 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +189 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +63 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/produced.js +100 -0
- package/dist/core/coherence/events/produced.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 +95 -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/coherence/retired/archived.js +285 -0
- package/dist/core/coherence/retired/archived.js.map +1 -0
- package/dist/core/coherence/retired/event-pair.js +62 -0
- package/dist/core/coherence/retired/event-pair.js.map +1 -0
- package/dist/core/coherence/retired/merged.js +79 -0
- package/dist/core/coherence/retired/merged.js.map +1 -0
- package/dist/core/coherence/retired/retirement.js +49 -0
- package/dist/core/coherence/retired/retirement.js.map +1 -0
- package/dist/core/coherence/retired/revival/arrivals.js +131 -0
- package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
- package/dist/core/coherence/retired/revival/revived.js +297 -0
- package/dist/core/coherence/retired/revival/revived.js.map +1 -0
- package/dist/core/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.js.map +1 -0
- package/dist/core/consumers/after.js +113 -0
- package/dist/core/consumers/after.js.map +1 -0
- package/dist/core/consumers/consumers.js +296 -0
- package/dist/core/consumers/consumers.js.map +1 -0
- package/dist/core/consumers/current.js +211 -0
- package/dist/core/consumers/current.js.map +1 -0
- package/dist/core/consumers/scan.js +46 -0
- package/dist/core/consumers/scan.js.map +1 -0
- package/dist/core/consumers/state.js +27 -0
- package/dist/core/consumers/state.js.map +1 -0
- package/dist/core/delta/claims.js +73 -0
- package/dist/core/delta/claims.js.map +1 -0
- package/dist/core/delta/delta.js +341 -0
- package/dist/core/delta/delta.js.map +1 -0
- package/dist/core/delta/document.js +177 -0
- package/dist/core/delta/document.js.map +1 -0
- package/dist/core/delta/scope.js +48 -0
- package/dist/core/delta/scope.js.map +1 -0
- package/dist/core/delta/select.js +237 -0
- package/dist/core/delta/select.js.map +1 -0
- package/dist/core/dependencies/dependencies.js +141 -0
- package/dist/core/dependencies/dependencies.js.map +1 -0
- package/dist/core/dependencies/facts.js +165 -0
- package/dist/core/dependencies/facts.js.map +1 -0
- package/dist/core/dependencies/fanin.js +88 -0
- package/dist/core/dependencies/fanin.js.map +1 -0
- package/dist/core/dependencies/graph.js +106 -0
- package/dist/core/dependencies/graph.js.map +1 -0
- package/dist/core/deployment/delta.js +191 -0
- package/dist/core/deployment/delta.js.map +1 -0
- package/dist/core/deployment/objects.js +145 -0
- package/dist/core/deployment/objects.js.map +1 -0
- package/dist/core/diff/base-git.js +230 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +237 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/joins.js +136 -0
- package/dist/core/diff/joins.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +204 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/scope/edges.js +82 -0
- package/dist/core/diff/scope/edges.js.map +1 -0
- package/dist/core/diff/semantic.js +312 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/docs.js +37 -85
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +238 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +139 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +355 -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/reports/scan.js +242 -0
- package/dist/core/doctor/reports/scan.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 +224 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -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 +286 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +238 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +234 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +89 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +209 -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 +180 -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 +194 -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/documents.js +227 -0
- package/dist/core/explain/terms/documents.js.map +1 -0
- package/dist/core/explain/terms/done-check.js +144 -0
- package/dist/core/explain/terms/done-check.js.map +1 -0
- package/dist/core/explain/terms/entry.js +14 -0
- package/dist/core/explain/terms/entry.js.map +1 -0
- package/dist/core/explain/terms/stages.js +71 -0
- package/dist/core/explain/terms/stages.js.map +1 -0
- package/dist/core/explain/terms/tasks.js +97 -0
- package/dist/core/explain/terms/tasks.js.map +1 -0
- package/dist/core/explain/terms.js +103 -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/explore.js +204 -0
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +174 -146
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +208 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +246 -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 +176 -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 +210 -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 +109 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +73 -0
- package/dist/core/glossary/tree.js.map +1 -0
- package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -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/fqn/ancestors.js +65 -0
- package/dist/core/kernel/ids/fqn/ancestors.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} +56 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/{records.js → kernel/records.js} +11 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +66 -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 +118 -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 +265 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +212 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +73 -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 +324 -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 +207 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +142 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +174 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/contract-text.js +33 -0
- package/dist/core/openapi/contract-text.js.map +1 -0
- package/dist/core/openapi/contract-tree.js +301 -0
- package/dist/core/openapi/contract-tree.js.map +1 -0
- package/dist/core/openapi/depth.js +136 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +239 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +54 -108
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +199 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +16 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +204 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +232 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +110 -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 +220 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +78 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +70 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +241 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +191 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +304 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +116 -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 +157 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +120 -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/projection/introduced.js +14 -0
- package/dist/core/projection/introduced.js.map +1 -0
- package/dist/core/provenance/findings.js +244 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +201 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +139 -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 +280 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +220 -0
- package/dist/core/provenance/stamp.js.map +1 -0
- package/dist/core/provenance/walk.js +157 -0
- package/dist/core/provenance/walk.js.map +1 -0
- package/dist/core/repo/authored/paths.js +210 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +322 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +308 -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 +61 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +90 -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/render/body.js +258 -0
- package/dist/core/repo/tree/render/body.js.map +1 -0
- package/dist/core/repo/tree/render/projects.js +182 -0
- package/dist/core/repo/tree/render/projects.js.map +1 -0
- package/dist/core/repo/tree/render/service/header.js +125 -0
- package/dist/core/repo/tree/render/service/header.js.map +1 -0
- package/dist/core/repo/tree/render/service/peers.js +28 -0
- package/dist/core/repo/tree/render/service/peers.js.map +1 -0
- package/dist/core/repo/tree/render/service/view-id.js +67 -0
- package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
- package/dist/core/repo/tree/render/service/views.js +78 -0
- package/dist/core/repo/tree/render/service/views.js.map +1 -0
- package/dist/core/repo/tree/render/stale.js +42 -0
- package/dist/core/repo/tree/render/stale.js.map +1 -0
- package/dist/core/repo/tree/render/text.js +84 -0
- package/dist/core/repo/tree/render/text.js.map +1 -0
- package/dist/core/repo/tree/render/views.js +293 -0
- package/dist/core/repo/tree/render/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +255 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +146 -14
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +239 -0
- package/dist/core/scaffold/landscape.js.map +1 -0
- package/dist/core/scaffold/legacy.js +271 -0
- package/dist/core/scaffold/legacy.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 +252 -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 +268 -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 +95 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +204 -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/manifest.js +188 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/snapshot/snapshot.js +196 -0
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +181 -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 +60 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +126 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +196 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +214 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +163 -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/feature/words.js +96 -0
- package/dist/core/status/feature/words.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +216 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +302 -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 +216 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/tasks/packet.js +199 -0
- package/dist/core/tasks/packet.js.map +1 -0
- package/dist/core/tasks/record.js +43 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/sources.js +181 -0
- package/dist/core/tasks/sources.js.map +1 -0
- package/dist/core/tasks/stamps.js +76 -0
- package/dist/core/tasks/stamps.js.map +1 -0
- package/dist/core/tasks/unit.js +0 -0
- package/dist/core/tasks/unit.js.map +1 -0
- package/dist/core/usecases/capability.js +166 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +140 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +101 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/modified.js +315 -0
- package/dist/core/usecases/delta/modified.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +76 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +296 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/grade/capability-tag.js +93 -0
- package/dist/core/usecases/grade/capability-tag.js.map +1 -0
- package/dist/core/usecases/grade/feature.js +88 -0
- package/dist/core/usecases/grade/feature.js.map +1 -0
- package/dist/core/usecases/grade/requirement-tag.js +94 -0
- package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
- package/dist/core/usecases/grade/steps.js +266 -0
- package/dist/core/usecases/grade/steps.js.map +1 -0
- package/dist/core/usecases/grade/usecases.js +112 -0
- package/dist/core/usecases/grade/usecases.js.map +1 -0
- package/dist/core/usecases/operations.js +123 -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/service/exclude.js +119 -0
- package/dist/core/usecases/service/exclude.js.map +1 -0
- package/dist/core/usecases/service/flows.js +164 -0
- package/dist/core/usecases/service/flows.js.map +1 -0
- package/dist/core/usecases/suites/participants.js +83 -0
- package/dist/core/usecases/suites/participants.js.map +1 -0
- package/dist/core/usecases/suites/suites.js +45 -0
- package/dist/core/usecases/suites/suites.js.map +1 -0
- package/dist/core/usecases/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +180 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +170 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +259 -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/location.js +67 -0
- package/dist/core/verify/location.js.map +1 -0
- package/dist/core/verify/pins/lint.js +158 -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/read/file.js +224 -0
- package/dist/core/verify/read/file.js.map +1 -0
- package/dist/core/verify/read/shape.js +169 -0
- package/dist/core/verify/read/shape.js.map +1 -0
- package/dist/core/verify/read/union.js +105 -0
- package/dist/core/verify/read/union.js.map +1 -0
- package/dist/core/verify/record.js +165 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +99 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +61 -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 +59 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +216 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/vocabulary/report.js +90 -0
- 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 +232 -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 +336 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/services.likec4 +70 -0
- package/examples/docs/architecture/subsystems.likec4 +18 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +74 -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 +132 -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 +31 -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 +73 -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 +8 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +92 -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 +134 -0
- package/examples/docs/services/order-service/asyncapi.yaml +109 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +126 -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 +76 -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 +68 -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 +120 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +81 -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 +200 -0
- package/examples/docs/services/platform/notification-service/health.yaml +40 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +97 -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 +0 -320
- 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 +0 -317
- 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 +0 -253
- 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 +0 -225
- 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 +0 -47
- 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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The services a feature's delta CALLS an operation on — the target of every
|
|
3
|
+
* tagged edge carrying `metadata { op }`, resolved the way coherence's own
|
|
4
|
+
* edge checks resolve it.
|
|
5
|
+
*
|
|
6
|
+
* Read for `loam status` (`core/status/contracts.ts`), which has to know
|
|
7
|
+
* whether a service is owed an `openapi.yaml` and used to answer "always" for a
|
|
8
|
+
* service the living docs had never heard of. An op-linked edge into a service
|
|
9
|
+
* is one of the two things that make its contract owed: `c4-api.op-undefined`
|
|
10
|
+
* grades exactly these edges against that file, so a service called this way
|
|
11
|
+
* with no contract is a gate error, and a status that said "none owed" beside
|
|
12
|
+
* it would contradict its own payload.
|
|
13
|
+
*
|
|
14
|
+
* A second reading of the join `../coherence.ts`'s edge loop makes, not that
|
|
15
|
+
* loop itself: the loop grades each edge as it goes and keeps no list. It lives
|
|
16
|
+
* beside it so the two are read together — the same tagged edges, the same
|
|
17
|
+
* fleet set handed to the same resolver — and a change to which edges the gate
|
|
18
|
+
* grades has to be made in both.
|
|
19
|
+
*
|
|
20
|
+
* Through the context's memo: both status forms have already parsed the delta
|
|
21
|
+
* by the time they ask (the coherence pass, the dependency graph), so this is
|
|
22
|
+
* a lookup, never a second LikeC4 workspace.
|
|
23
|
+
*/
|
|
24
|
+
import { existsSync } from "node:fs";
|
|
25
|
+
import { serviceResolver } from "../../c4/resolve/service.js";
|
|
26
|
+
import { featurePaths } from "../../repo/paths.js";
|
|
27
|
+
import { featureSpecServices } from "../../repo/repo.js";
|
|
28
|
+
import { enumeratedServiceIds } from "../../repo/service-target.js";
|
|
29
|
+
/**
|
|
30
|
+
* The called services, or `unreadable` when the delta does not parse — which
|
|
31
|
+
* is not "nobody is called": loam could not look, and `delta.invalid` already
|
|
32
|
+
* gates. A feature with no delta calls nobody.
|
|
33
|
+
*/
|
|
34
|
+
export async function calledServices(scope, context) {
|
|
35
|
+
const { docsDir, featureDir, featureId } = scope;
|
|
36
|
+
const deltaPath = featurePaths(featureDir).delta;
|
|
37
|
+
if (!existsSync(deltaPath))
|
|
38
|
+
return new Set();
|
|
39
|
+
const doc = await context.loadLikeC4(deltaPath);
|
|
40
|
+
if (doc.errors.length > 0)
|
|
41
|
+
return "unreadable";
|
|
42
|
+
// The same fleet set coherence hands its resolver — `services/` plus this
|
|
43
|
+
// feature's own `specs/` — so an edge into a modelled container names the
|
|
44
|
+
// service that owns it, never a service called after the container.
|
|
45
|
+
const known = new Set([
|
|
46
|
+
...(await enumeratedServiceIds(docsDir, context)),
|
|
47
|
+
...(await featureSpecServices(featureDir, context)),
|
|
48
|
+
]);
|
|
49
|
+
const svcOf = serviceResolver(doc.elements, known);
|
|
50
|
+
return new Set(doc.relationships.filter((r) => r.op !== undefined && r.tags.includes(featureId)).map((r) => svcOf(r.target)));
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=called.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"called.js","sourceRoot":"","sources":["../../../../src/core/coherence/calls/called.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAGpE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAiB,EAAE,OAAqB;IAC3E,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IACjD,MAAM,SAAS,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC;IACjD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,GAAG,EAAE,CAAC;IAC7C,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IAChD,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,YAAY,CAAC;IAC/C,0EAA0E;IAC1E,0EAA0E;IAC1E,oEAAoE;IACpE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS;QAC5B,GAAG,CAAC,MAAM,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACjD,GAAG,CAAC,MAAM,mBAAmB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;KACpD,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACnD,OAAO,IAAI,GAAG,CACZ,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAC9G,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The services a feature's delta CALLS an operation on — the target of every\n * tagged edge carrying `metadata { op }`, resolved the way coherence's own\n * edge checks resolve it.\n *\n * Read for `loam status` (`core/status/contracts.ts`), which has to know\n * whether a service is owed an `openapi.yaml` and used to answer \"always\" for a\n * service the living docs had never heard of. An op-linked edge into a service\n * is one of the two things that make its contract owed: `c4-api.op-undefined`\n * grades exactly these edges against that file, so a service called this way\n * with no contract is a gate error, and a status that said \"none owed\" beside\n * it would contradict its own payload.\n *\n * A second reading of the join `../coherence.ts`'s edge loop makes, not that\n * loop itself: the loop grades each edge as it goes and keeps no list. It lives\n * beside it so the two are read together — the same tagged edges, the same\n * fleet set handed to the same resolver — and a change to which edges the gate\n * grades has to be made in both.\n *\n * Through the context's memo: both status forms have already parsed the delta\n * by the time they ask (the coherence pass, the dependency graph), so this is\n * a lookup, never a second LikeC4 workspace.\n */\nimport { existsSync } from \"node:fs\";\nimport { serviceResolver } from \"../../c4/resolve/service.js\";\nimport type { FleetContext } from \"../../fleet-context.js\";\nimport { featurePaths } from \"../../repo/paths.js\";\nimport { featureSpecServices } from \"../../repo/repo.js\";\nimport { enumeratedServiceIds } from \"../../repo/service-target.js\";\nimport type { DeltaScope } from \"../declared.js\";\n\n/**\n * The called services, or `unreadable` when the delta does not parse — which\n * is not \"nobody is called\": loam could not look, and `delta.invalid` already\n * gates. A feature with no delta calls nobody.\n */\nexport async function calledServices(scope: DeltaScope, context: FleetContext): Promise<ReadonlySet<string> | \"unreadable\"> {\n const { docsDir, featureDir, featureId } = scope;\n const deltaPath = featurePaths(featureDir).delta;\n if (!existsSync(deltaPath)) return new Set();\n const doc = await context.loadLikeC4(deltaPath);\n if (doc.errors.length > 0) return \"unreadable\";\n // The same fleet set coherence hands its resolver — `services/` plus this\n // feature's own `specs/` — so an edge into a modelled container names the\n // service that owns it, never a service called after the container.\n const known = new Set<string>([\n ...(await enumeratedServiceIds(docsDir, context)),\n ...(await featureSpecServices(featureDir, context)),\n ]);\n const svcOf = serviceResolver(doc.elements, known);\n return new Set(\n doc.relationships.filter((r) => r.op !== undefined && r.tags.includes(featureId)).map((r) => svcOf(r.target)),\n );\n}\n"]}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { loadFile } from "../c4/likec4.js";
|
|
3
|
+
import { elementService, serviceResolver } from "../c4/resolve/service.js";
|
|
4
|
+
import { infrastructureKind } from "../c4/direction/direction.js";
|
|
5
|
+
import { livingMapOf, readDeltaSystem } from "../c4/resolve/systems.js";
|
|
6
|
+
import { extendingModels } from "../c4/service-model/fleet/extending.js";
|
|
7
|
+
import { serviceIdProblem } from "../kernel/ids/service.js";
|
|
8
|
+
import { deltaShapeIssues } from "../delta/delta.js";
|
|
9
|
+
import { featurePaths, landscapePath } from "../repo/paths.js";
|
|
10
|
+
import { featureSpecServices } from "../repo/repo.js";
|
|
11
|
+
import { enumeratedServiceIds, enumeratedServiceIndex } from "../repo/service-target.js";
|
|
12
|
+
import { serviceOperationIds } from "../openapi/doc.js";
|
|
13
|
+
import { declaredByService } from "./declared.js";
|
|
14
|
+
import { retiredLookup } from "./retired/archived.js";
|
|
15
|
+
import { revivedOperations } from "./retired/revival/revived.js";
|
|
16
|
+
import { coherenceLookups } from "./lookups.js";
|
|
17
|
+
import { consumerIndex } from "../consumers/consumers.js";
|
|
18
|
+
import { consumedOperationIssues } from "./consumed/operations.js";
|
|
19
|
+
import { eventCoherence } from "./events/events.js";
|
|
20
|
+
import { authoringIssues } from "./authoring/scaffold.js";
|
|
21
|
+
import { droppedHealthCoverage } from "./covers/health.js";
|
|
22
|
+
import { glossaryDeltaIssues } from "../glossary/delta.js";
|
|
23
|
+
import { flowDeltaIssues } from "../usecases/delta/flows.js";
|
|
24
|
+
import { deploymentDeltaIssues, readFeatureDeployments } from "../deployment/delta.js";
|
|
25
|
+
export async function featureCoherence(request) {
|
|
26
|
+
const { docsDir, featureDir, featureId, preloadedDelta, context } = request;
|
|
27
|
+
const scope = { docsDir, featureDir, featureId };
|
|
28
|
+
// Delta shape first: a diff that does not apply to the living spec explains
|
|
29
|
+
// everything downstream, and it is the one breach that is silent without a check.
|
|
30
|
+
const issues = await deltaShapeIssues(docsDir, featureDir, featureId, context);
|
|
31
|
+
// The vocabulary axis, and it is asked first because it is cheap and
|
|
32
|
+
// independent: one `existsSync` for a feature with no glossary/, and nothing
|
|
33
|
+
// downstream reads its answer. A term this feature introduces that the living
|
|
34
|
+
// glossary already defines is the one thing that can go wrong on a create-only
|
|
35
|
+
// merge, and it must be caught before the copy, not after.
|
|
36
|
+
issues.push(...(await glossaryDeltaIssues(docsDir, featureDir)));
|
|
37
|
+
// The use-case axis, and it is asked here for the vocabulary axis's reasons
|
|
38
|
+
// exactly: one walk over a directory that is usually absent, nothing
|
|
39
|
+
// downstream reads its answer, and a create-only merge has one thing that can
|
|
40
|
+
// go wrong. A flow this feature introduces that the living `architecture/`
|
|
41
|
+
// already holds must be caught before the copy, not after it has replaced an
|
|
42
|
+
// authored hop sequence.
|
|
43
|
+
issues.push(...(await flowDeltaIssues(docsDir, featureDir)));
|
|
44
|
+
issues.push(...(await deploymentDeltaIssues(docsDir, featureDir)));
|
|
45
|
+
// And the topology's second question, which the collision check above cannot
|
|
46
|
+
// ask: does the document READ against the map this feature's own merge would
|
|
47
|
+
// leave behind. It matters more literally here than one axis over — a feature
|
|
48
|
+
// that stands a service up in a new cluster declares that service in its
|
|
49
|
+
// `delta.likec4` and instances it in the topology, so the element the document
|
|
50
|
+
// names exists only post-merge — and without it the archive copies an
|
|
51
|
+
// unreadable document into `architecture/` for the next reader's
|
|
52
|
+
// `loam validate --all` to fail on, against a file they did not write.
|
|
53
|
+
const topology = await readFeatureDeployments({
|
|
54
|
+
docsDir,
|
|
55
|
+
featureDir,
|
|
56
|
+
featureId,
|
|
57
|
+
// A function rather than the context itself, for the reason the use-case
|
|
58
|
+
// overlay states: one memoised read does not justify an edge from
|
|
59
|
+
// `core/deployment/` to `fleet-context`.
|
|
60
|
+
...(context === undefined ? {} : { load: (path) => context.loadLikeC4(path) }),
|
|
61
|
+
// The fleet's extending models, so the preview is the map the archive would
|
|
62
|
+
// really leave: a nested addition is routed into the service's own model,
|
|
63
|
+
// never onto the map. Read here for the same reason `load` is passed here —
|
|
64
|
+
// this module holds the context and `core/deployment/` does not — and as a
|
|
65
|
+
// thunk, so a feature with no `deployment/` directory pays nothing for it.
|
|
66
|
+
models: () => extendingModels(docsDir, context),
|
|
67
|
+
});
|
|
68
|
+
if (topology.kind === "unreadable") {
|
|
69
|
+
issues.push({
|
|
70
|
+
severity: "error",
|
|
71
|
+
code: "deployment.doc-invalid",
|
|
72
|
+
subject: featureId,
|
|
73
|
+
// The opening sentence does not say whose file is at fault, on the
|
|
74
|
+
// `usecase.flow-invalid` message's reasoning: the corpus is the feature's
|
|
75
|
+
// `deployment/` PLUS the living `architecture/` documents it extends, so
|
|
76
|
+
// the failing path can be a living one — a landscape that no longer
|
|
77
|
+
// parses, a topology somebody else wrote. Every message carries its own
|
|
78
|
+
// path, so a reader can place it.
|
|
79
|
+
message: `this feature's deployment document(s) could not be read against the map its own merge would leave behind, ` +
|
|
80
|
+
`so the archive would land an architecture/ nothing has checked. The corpus is the feature's deployment/ AND ` +
|
|
81
|
+
`the living architecture/ documents it extends, so the fault may be in either — each message names its file. ` +
|
|
82
|
+
`${topology.errors.length} problem(s): ${topology.errors.join("; ")}`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// --- C4 delta ---
|
|
86
|
+
let elements = [];
|
|
87
|
+
let taggedEls = [];
|
|
88
|
+
let taggedRels = [];
|
|
89
|
+
const deltaPath = featurePaths(featureDir).delta;
|
|
90
|
+
if (existsSync(deltaPath)) {
|
|
91
|
+
const res = preloadedDelta ?? (context === undefined ? await loadFile(deltaPath) : await context.loadLikeC4(deltaPath));
|
|
92
|
+
if (res.errors.length > 0) {
|
|
93
|
+
// An unreadable architecture axis can prove nothing — it must never count as coherent.
|
|
94
|
+
issues.push({
|
|
95
|
+
severity: "error",
|
|
96
|
+
code: "delta.invalid",
|
|
97
|
+
message: `delta.likec4 has ${res.errors.length} parse error(s) — architecture axis unreadable (run \`loam validate --feature ${featureId}\`)`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
elements = res.elements;
|
|
102
|
+
taggedEls = res.elements.filter((e) => e.tags.includes(featureId));
|
|
103
|
+
taggedRels = res.relationships.filter((r) => r.tags.includes(featureId));
|
|
104
|
+
// Every rule below filters by the feature tag, so a delta whose author
|
|
105
|
+
// forgot the tags entirely passes every check and archives while merging
|
|
106
|
+
// nothing. Whole-file only: once ANYTHING is tagged, deciding that an
|
|
107
|
+
// untagged edge "looks intended" would be guessing.
|
|
108
|
+
if ((res.elements.length > 0 || res.relationships.length > 0) &&
|
|
109
|
+
taggedEls.length === 0 &&
|
|
110
|
+
taggedRels.length === 0) {
|
|
111
|
+
issues.push({
|
|
112
|
+
severity: "error",
|
|
113
|
+
code: "delta.nothing-tagged",
|
|
114
|
+
message: `delta.likec4 declares elements/relationships but none are tagged #${featureId}; loam cannot see untagged changes`,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// --- per-service specs (requirement operations) + openapi deltas ---
|
|
120
|
+
const svcNames = await featureSpecServices(featureDir, context);
|
|
121
|
+
// Every axis below joins on the service id, so endpoints resolve through the
|
|
122
|
+
// element's `metadata { service }` binding — never through what the box is
|
|
123
|
+
// called. The enumerated fleet — `services/` plus this feature's own
|
|
124
|
+
// `specs/` directories, the same union `enumeratedTarget` probes below —
|
|
125
|
+
// rides into the resolver so a delta that models CONTAINERS joins correctly:
|
|
126
|
+
// without it, an edge into `payment.api` resolves to a service called "api"
|
|
127
|
+
// that has never existed, and every check below grades the edge against an
|
|
128
|
+
// absent service instead of the one that owns the container. An unenumerable
|
|
129
|
+
// services/ falls back to the feature's own names — every living probe would
|
|
130
|
+
// have found nothing there anyway.
|
|
131
|
+
const fleetIds = await enumeratedServiceIds(docsDir, context);
|
|
132
|
+
const known = new Set([...fleetIds, ...svcNames]);
|
|
133
|
+
const svcOf = serviceResolver(elements, known);
|
|
134
|
+
// Which elements the landscape merge would SPLICE: the tagged ones and
|
|
135
|
+
// everything nested inside their blocks. Defined here because two checks
|
|
136
|
+
// share it — the scaffold gate just below, and the binding-grammar check
|
|
137
|
+
// near the end of this function — and the merge carries a tagged element's
|
|
138
|
+
// authored block over byte for byte, children included, so a scope narrower
|
|
139
|
+
// than the splice lets a nested child's text ride through unread.
|
|
140
|
+
const taggedIds = taggedEls.map((el) => el.id);
|
|
141
|
+
const ridesWithTag = (el) => el.tags.includes(featureId) || taggedIds.some((id) => el.id.startsWith(`${id}.`));
|
|
142
|
+
// The scaffold gate: placeholder text and an unwritten intent are legal
|
|
143
|
+
// documents whose merge would publish content nobody authored — the exact
|
|
144
|
+
// template strings `loam new` wrote (authoring/scaffold.ts owns the list).
|
|
145
|
+
issues.push(...(await authoringIssues({ featureDir, featureId, splicedEls: elements.filter(ridesWithTag), svcNames, context })));
|
|
146
|
+
const { reqOps, removingOps, featureApiOps, unreadableApis, revivalCandidates, displacedOps, } = await declaredByService(scope, svcNames, issues, context);
|
|
147
|
+
// A revival: an operation the merged contract would answer that the living
|
|
148
|
+
// contract no longer has because an ARCHIVED feature retired it — or would
|
|
149
|
+
// answer again at an address an archived feature took it out of, beside
|
|
150
|
+
// where it lives now — and the merge would read it as an addition and put
|
|
151
|
+
// it back (./retired/ says why the gate could not see this before). One
|
|
152
|
+
// lazy handle for both contract axes, so the walk of features/archive/ is
|
|
153
|
+
// paid once per call at most, and only when the merged contract answers
|
|
154
|
+
// something at an address the living one does not.
|
|
155
|
+
const retired = retiredLookup(docsDir, context);
|
|
156
|
+
for (const [svc, arrived] of revivalCandidates) {
|
|
157
|
+
if (arrived.length === 0)
|
|
158
|
+
continue;
|
|
159
|
+
issues.push(...revivedOperations(svc, arrived, await retired()));
|
|
160
|
+
}
|
|
161
|
+
const { governedByLivingSpec, definedElsewhere, deprecatedInLiving, undeprecatedByFeature } = coherenceLookups(scope, context);
|
|
162
|
+
// --- taking an operation out of the contract while the fleet still calls it ---
|
|
163
|
+
// ./consumed/operations.ts owns the gate; the index is built here because
|
|
164
|
+
// the event axis below asks the same one, so the fleet is read once.
|
|
165
|
+
const consumers = consumerIndex({ docsDir, context, afterFeature: featureDir });
|
|
166
|
+
issues.push(...(await consumedOperationIssues({ consumers, removingOps, displacedOps })));
|
|
167
|
+
// E1: Spec -> API — every operation a requirement governs must exist in that service's OpenAPI.
|
|
168
|
+
for (const [svc, ops] of reqOps) {
|
|
169
|
+
// The union below reads the feature's own contract; unreadable means the
|
|
170
|
+
// op may well be defined in the file nobody could open, and `op-undefined`
|
|
171
|
+
// would point the author at the requirement when the truth is the YAML.
|
|
172
|
+
// `openapi.invalid` (declared.ts) already gates; one breach, one finding.
|
|
173
|
+
if (unreadableApis.has(svc))
|
|
174
|
+
continue;
|
|
175
|
+
const available = await serviceOperationIds(docsDir, svc, featureDir, context);
|
|
176
|
+
for (const op of ops) {
|
|
177
|
+
if (available.includes(op))
|
|
178
|
+
continue;
|
|
179
|
+
const other = await definedElsewhere(svc, op);
|
|
180
|
+
if (other !== undefined) {
|
|
181
|
+
issues.push({ severity: "warn", code: "spec-api.op-pending", message: `requirement in ${svc} governs '${op}', defined by in-flight ${other} — archive it first` });
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
issues.push({ severity: "error", code: "spec-api.op-undefined", message: `requirement in ${svc} governs '${op}', not defined in ${svc}'s OpenAPI` });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// The declared→enumerated bridge for edge TARGETS. `svcOf` answers with
|
|
188
|
+
// whatever the document wrote — `metadata { service '../../x' }` parses in
|
|
189
|
+
// LikeC4 without one error — and every living lookup below joins its answer
|
|
190
|
+
// into `services/<target>/` or `specs/<target>/`. So a target resolves
|
|
191
|
+
// through the enumerations first (the fleet's `services/` plus this
|
|
192
|
+
// feature's own `specs/`, where a service it introduces lives), and a name
|
|
193
|
+
// neither knows skips the lookups — no ops, not governed, not deprecated —
|
|
194
|
+
// grading exactly as an absent service, spelled with the declared name.
|
|
195
|
+
const enumeratedTarget = enumeratedServiceIndex(docsDir, svcNames, context);
|
|
196
|
+
// E2 / W1 / W4: C4 edges vs API + requirements.
|
|
197
|
+
for (const r of taggedRels) {
|
|
198
|
+
if (r.op === undefined) {
|
|
199
|
+
if ((r.title ?? "").toLowerCase().startsWith("call")) {
|
|
200
|
+
issues.push({ severity: "warn", code: "c4.op-link-missing", message: `edge ${svcOf(r.source)} → ${svcOf(r.target)} ("${r.title}") has no operation link (metadata { op })` });
|
|
201
|
+
}
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const target = svcOf(r.target);
|
|
205
|
+
const pathable = await enumeratedTarget(target);
|
|
206
|
+
// Same suspension as E1, but only for the verdicts that READ a contract:
|
|
207
|
+
// does the op exist, is it being removed, is it deprecated (whose
|
|
208
|
+
// un-deprecation escape reads the feature contract too). Each of those
|
|
209
|
+
// would be an opinion about a file nobody could open. The governance
|
|
210
|
+
// question below is deliberately NOT suspended — it joins the edge against
|
|
211
|
+
// requirement documents alone, so the broken YAML could never change its
|
|
212
|
+
// answer, and silencing it deferred a real warning for no reason.
|
|
213
|
+
const contractUnreadable = pathable !== undefined && unreadableApis.has(pathable);
|
|
214
|
+
const available = pathable === undefined || contractUnreadable
|
|
215
|
+
? []
|
|
216
|
+
: await serviceOperationIds(docsDir, pathable, featureDir, context);
|
|
217
|
+
if (contractUnreadable) {
|
|
218
|
+
// openapi.invalid (declared.ts) already gates; one breach, one finding.
|
|
219
|
+
}
|
|
220
|
+
else if (pathable !== undefined &&
|
|
221
|
+
// An operation replaced at its address leaves as surely as a retired
|
|
222
|
+
// one; `available` below still lists it, because serviceOperationIds
|
|
223
|
+
// subtracts markers only, so without this a new edge onto it passed.
|
|
224
|
+
(removingOps.get(pathable)?.has(r.op) === true || displacedOps.get(pathable)?.some((d) => d.id === r.op) === true)) {
|
|
225
|
+
issues.push({ severity: "error", code: "c4-api.op-removing", message: `${svcOf(r.source)} builds new consumption on '${r.op}', which this feature removes from ${target}` });
|
|
226
|
+
}
|
|
227
|
+
else if (!available.includes(r.op)) {
|
|
228
|
+
const other = await definedElsewhere(target, r.op);
|
|
229
|
+
if (other !== undefined) {
|
|
230
|
+
issues.push({ severity: "warn", code: "c4-api.op-pending", message: `${svcOf(r.source)} calls '${r.op}' on ${target}, defined by in-flight ${other} — archive it first` });
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
issues.push({ severity: "error", code: "c4-api.op-undefined", message: `${svcOf(r.source)} calls '${r.op}' on ${target}, but ${target}'s OpenAPI does not define it (contract broken)` });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Governed by THIS target's requirements, not by anybody's. An operationId
|
|
237
|
+
// is unique only inside one contract, so the fleet-wide set this used to
|
|
238
|
+
// ask meant a `getStatus` governed in service A silenced the question for
|
|
239
|
+
// service B's entirely unrelated `getStatus` — the warning went quiet for
|
|
240
|
+
// the edge that needed it, and only in repos where some other service
|
|
241
|
+
// happened to reuse the name. The living half on the same line has always
|
|
242
|
+
// joined per service (`governedByLivingSpec(target, …)`); this is the delta
|
|
243
|
+
// half asking it the same way.
|
|
244
|
+
if (pathable === undefined || (!(reqOps.get(pathable) ?? []).includes(r.op) && !(await governedByLivingSpec(pathable, r.op)))) {
|
|
245
|
+
issues.push({ severity: "warn", code: "c4.op-ungoverned", message: `'${r.op}' is called by ${svcOf(r.source)} but no requirement governs it` });
|
|
246
|
+
}
|
|
247
|
+
// Lifecycle: this NEW tagged edge builds consumption on an operation the
|
|
248
|
+
// living provider contract already marks deprecated. Advisory, never an
|
|
249
|
+
// archive gate — the edge is legal and the contract holds — but new
|
|
250
|
+
// consumption of a dying op deserves an eye before it ships. Quiet when
|
|
251
|
+
// the feature's own openapi delta drops the flag: that state is the fix
|
|
252
|
+
// in progress, not new consumption of a dying op.
|
|
253
|
+
if (!contractUnreadable && pathable !== undefined && (await deprecatedInLiving(pathable, r.op)) && !(await undeprecatedByFeature(pathable, r.op))) {
|
|
254
|
+
issues.push({ severity: "warn", code: "c4-api.op-deprecated", message: `${svcOf(r.source)} builds new consumption on '${r.op}', which ${target}'s living OpenAPI marks deprecated — prefer the replacement operation` });
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// W2: API -> C4 — every operation the feature adds should be consumed by some edge.
|
|
258
|
+
const consumed = new Set(taggedRels.map((r) => r.op).filter((o) => o !== undefined));
|
|
259
|
+
for (const op of featureApiOps) {
|
|
260
|
+
if (!consumed.has(op)) {
|
|
261
|
+
issues.push({ severity: "warn", code: "api.op-unconsumed", message: `operation '${op}' is added but no architecture edge consumes it (provider-only or unmodeled)` });
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// W3: a new service should carry a requirement delta. "New service" is the
|
|
265
|
+
// fleet census's reading of the map this merge leaves (../c4/resolve/systems.ts):
|
|
266
|
+
// a tagged `#external` producer, a grouping and a container are no service of
|
|
267
|
+
// ours, and asking each for a `specs/` delta put a unit of work nobody owes
|
|
268
|
+
// on the board and a warning the archived fleet never repeats. Nor is a
|
|
269
|
+
// service the fleet already holds new — its own directory, or a box the
|
|
270
|
+
// living map draws — whatever the delta's tag says: re-declaring is not
|
|
271
|
+
// introducing.
|
|
272
|
+
// The living map is parsed only for a candidate no directory answers for.
|
|
273
|
+
const systems = {
|
|
274
|
+
elements,
|
|
275
|
+
known,
|
|
276
|
+
living: new Set(fleetIds),
|
|
277
|
+
livingMap: livingMapOf(landscapePath(docsDir), (path) => (context === undefined ? loadFile(path) : context.loadLikeC4(path))),
|
|
278
|
+
};
|
|
279
|
+
for (const e of taggedEls) {
|
|
280
|
+
const svc = elementService(e);
|
|
281
|
+
if (e.kind !== "softwareSystem" || svcNames.some((n) => n === svc))
|
|
282
|
+
continue;
|
|
283
|
+
if ((await readDeltaSystem(e, systems)) !== "service")
|
|
284
|
+
continue;
|
|
285
|
+
issues.push({ severity: "warn", code: "service.no-requirement-delta", message: `new service ${svc} has no requirement delta under specs/` });
|
|
286
|
+
}
|
|
287
|
+
// An explicit `metadata { service '<id>' }` binding, held to the same grammar
|
|
288
|
+
// every `--service` flag is — on the tagged elements AND everything nested
|
|
289
|
+
// inside their blocks. The scope is the splice's, not the tag's: the
|
|
290
|
+
// landscape merge carries a tagged element's authored block over byte for
|
|
291
|
+
// byte, children included (landscape-merge.ts's rides() exists exactly so a
|
|
292
|
+
// child travels inside its parent's text), so an untagged container's
|
|
293
|
+
// binding reaches the living map as surely as its tagged parent's — and
|
|
294
|
+
// checking only the tagged elements themselves let it ride through unread.
|
|
295
|
+
// The binding is the one name the archive TRUSTS: the merge splices it into
|
|
296
|
+
// the living map verbatim, and the new-service scan probes
|
|
297
|
+
// `services/<binding>/` with it — where `metadata { service '../outside-svc' }`,
|
|
298
|
+
// which LikeC4 parses without a murmur, collapses the probe right out of
|
|
299
|
+
// services/, and the spliced map fails the very next `validate --all`
|
|
300
|
+
// (`landscape.binding-unknown`). Explicit bindings only, on purpose: a prose
|
|
301
|
+
// title with no binding is legal C4, and a title becomes a path only through
|
|
302
|
+
// `specs/<svc>/`, whose own grammar check (`delta.service-id-invalid`)
|
|
303
|
+
// guards that route. `ridesWithTag` itself is defined up beside the scaffold
|
|
304
|
+
// gate, which shares the splice's scope for the same reason.
|
|
305
|
+
for (const e of elements.filter(ridesWithTag)) {
|
|
306
|
+
if (e.service === undefined)
|
|
307
|
+
continue;
|
|
308
|
+
const problem = serviceIdProblem(e.service, "metadata { service } binding");
|
|
309
|
+
if (problem === null)
|
|
310
|
+
continue;
|
|
311
|
+
issues.push({
|
|
312
|
+
severity: "error",
|
|
313
|
+
code: "c4.service-binding-invalid",
|
|
314
|
+
subject: e.service,
|
|
315
|
+
message: `'${e.title}' (${e.id}) — ${problem} ` +
|
|
316
|
+
`\`loam archive\` would splice '${e.service}' into the living landscape.likec4 exactly as written, ` +
|
|
317
|
+
`and probe services/${e.service}/ with it. Bind the element to the services/<id>/ directory it means.`,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
// The event axis — the same three-way agreement the operation checks above
|
|
321
|
+
// grade, joined on the message name instead of the operationId: the
|
|
322
|
+
// feature's asyncapi deltas (pins, markers, justification), the tagged
|
|
323
|
+
// edges' publishes/consumes metadata, and the requirement deltas'
|
|
324
|
+
// Publishes:/Consumes: lines (./events/events.ts owns the walk).
|
|
325
|
+
const infraKindOf = infrastructureKind(elements);
|
|
326
|
+
issues.push(...(await eventCoherence({ scope, svcNames, taggedRels, svcOf, infraKindOf, context, retired, consumers, known })));
|
|
327
|
+
// The health axis's one merge question: an alert or SLI the living
|
|
328
|
+
// arch.spec.md covers that this delta would leave covered by nothing.
|
|
329
|
+
issues.push(...(await droppedHealthCoverage({ docsDir, featureDir, services: svcNames, ...(context === undefined ? {} : { context }) })));
|
|
330
|
+
return issues;
|
|
331
|
+
}
|
|
332
|
+
//# sourceMappingURL=coherence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coherence.js","sourceRoot":"","sources":["../../../src/core/coherence/coherence.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { loadFile, type Elem, type LoadedDoc, type Rel } from \"../c4/likec4.js\";\nimport { elementService, serviceResolver } from \"../c4/resolve/service.js\";\nimport { infrastructureKind } from \"../c4/direction/direction.js\";\nimport { livingMapOf, readDeltaSystem } from \"../c4/resolve/systems.js\";\nimport { extendingModels } from \"../c4/service-model/fleet/extending.js\";\nimport { serviceIdProblem } from \"../kernel/ids/service.js\";\nimport { deltaShapeIssues } from \"../delta/delta.js\";\nimport type { Issue } from \"../vocabulary/issue.js\";\nimport { featurePaths, landscapePath } from \"../repo/paths.js\";\nimport { featureSpecServices } from \"../repo/repo.js\";\nimport { enumeratedServiceIds, enumeratedServiceIndex } from \"../repo/service-target.js\";\nimport { serviceOperationIds } from \"../openapi/doc.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport { declaredByService, type DeltaScope } from \"./declared.js\";\nimport { retiredLookup } from \"./retired/archived.js\";\nimport { revivedOperations } from \"./retired/revival/revived.js\";\nimport { coherenceLookups } from \"./lookups.js\";\nimport { consumerIndex } from \"../consumers/consumers.js\";\nimport { consumedOperationIssues } from \"./consumed/operations.js\";\nimport { eventCoherence } from \"./events/events.js\";\nimport { authoringIssues } from \"./authoring/scaffold.js\";\nimport { droppedHealthCoverage } from \"./covers/health.js\";\nimport { glossaryDeltaIssues } from \"../glossary/delta.js\";\nimport { flowDeltaIssues } from \"../usecases/delta/flows.js\";\nimport { deploymentDeltaIssues, readFeatureDeployments } from \"../deployment/delta.js\";\nimport type { DocsDir, FeatureDir } from \"../kernel/ids/dirs.js\";\n\n/**\n * Cross-axis consistency for a feature: do C4 (architecture), requirements (behaviour),\n * and OpenAPI (contract) agree? Errors are hard (would corrupt the living docs on archive);\n * warnings surface softer misalignments.\n *\n * `preloadedDelta` is the feature's already-parsed delta.likec4, when the caller\n * has it — loading a LikeC4 document spins up a fresh Langium workspace, the\n * dominant per-feature cost, and validate/archive have both parsed the same file\n * moments earlier. Standalone calls omit it and nothing changes: the file is\n * loaded here, exactly as before.\n */\n\n/** How a caller names the feature being graded, and what it already has in hand. */\nexport interface CoherenceRequest {\n docsDir: DocsDir;\n featureDir: FeatureDir;\n featureId: string;\n /** The delta LikeC4 document, when the caller already parsed it. */\n preloadedDelta?: LoadedDoc;\n context?: FleetContext;\n}\n\nexport async function featureCoherence(request: CoherenceRequest): Promise<Issue[]> {\n const { docsDir, featureDir, featureId, preloadedDelta, context } = request;\n const scope: DeltaScope = { docsDir, featureDir, featureId };\n // Delta shape first: a diff that does not apply to the living spec explains\n // everything downstream, and it is the one breach that is silent without a check.\n const issues: Issue[] = await deltaShapeIssues(docsDir, featureDir, featureId, context);\n\n // The vocabulary axis, and it is asked first because it is cheap and\n // independent: one `existsSync` for a feature with no glossary/, and nothing\n // downstream reads its answer. A term this feature introduces that the living\n // glossary already defines is the one thing that can go wrong on a create-only\n // merge, and it must be caught before the copy, not after.\n issues.push(...(await glossaryDeltaIssues(docsDir, featureDir)));\n\n // The use-case axis, and it is asked here for the vocabulary axis's reasons\n // exactly: one walk over a directory that is usually absent, nothing\n // downstream reads its answer, and a create-only merge has one thing that can\n // go wrong. A flow this feature introduces that the living `architecture/`\n // already holds must be caught before the copy, not after it has replaced an\n // authored hop sequence.\n issues.push(...(await flowDeltaIssues(docsDir, featureDir)));\n issues.push(...(await deploymentDeltaIssues(docsDir, featureDir)));\n\n // And the topology's second question, which the collision check above cannot\n // ask: does the document READ against the map this feature's own merge would\n // leave behind. It matters more literally here than one axis over — a feature\n // that stands a service up in a new cluster declares that service in its\n // `delta.likec4` and instances it in the topology, so the element the document\n // names exists only post-merge — and without it the archive copies an\n // unreadable document into `architecture/` for the next reader's\n // `loam validate --all` to fail on, against a file they did not write.\n const topology = await readFeatureDeployments({\n docsDir,\n featureDir,\n featureId,\n // A function rather than the context itself, for the reason the use-case\n // overlay states: one memoised read does not justify an edge from\n // `core/deployment/` to `fleet-context`.\n ...(context === undefined ? {} : { load: (path: string) => context.loadLikeC4(path) }),\n // The fleet's extending models, so the preview is the map the archive would\n // really leave: a nested addition is routed into the service's own model,\n // never onto the map. Read here for the same reason `load` is passed here —\n // this module holds the context and `core/deployment/` does not — and as a\n // thunk, so a feature with no `deployment/` directory pays nothing for it.\n models: () => extendingModels(docsDir, context),\n });\n if (topology.kind === \"unreadable\") {\n issues.push({\n severity: \"error\",\n code: \"deployment.doc-invalid\",\n subject: featureId,\n // The opening sentence does not say whose file is at fault, on the\n // `usecase.flow-invalid` message's reasoning: the corpus is the feature's\n // `deployment/` PLUS the living `architecture/` documents it extends, so\n // the failing path can be a living one — a landscape that no longer\n // parses, a topology somebody else wrote. Every message carries its own\n // path, so a reader can place it.\n message:\n `this feature's deployment document(s) could not be read against the map its own merge would leave behind, ` +\n `so the archive would land an architecture/ nothing has checked. The corpus is the feature's deployment/ AND ` +\n `the living architecture/ documents it extends, so the fault may be in either — each message names its file. ` +\n `${topology.errors.length} problem(s): ${topology.errors.join(\"; \")}`,\n });\n }\n\n // --- C4 delta ---\n let elements: Elem[] = [];\n let taggedEls: Elem[] = [];\n let taggedRels: Rel[] = [];\n const deltaPath = featurePaths(featureDir).delta;\n if (existsSync(deltaPath)) {\n const res = preloadedDelta ?? (context === undefined ? await loadFile(deltaPath) : await context.loadLikeC4(deltaPath));\n if (res.errors.length > 0) {\n // An unreadable architecture axis can prove nothing — it must never count as coherent.\n issues.push({\n severity: \"error\",\n code: \"delta.invalid\",\n message: `delta.likec4 has ${res.errors.length} parse error(s) — architecture axis unreadable (run \\`loam validate --feature ${featureId}\\`)`,\n });\n } else {\n elements = res.elements;\n taggedEls = res.elements.filter((e) => e.tags.includes(featureId));\n taggedRels = res.relationships.filter((r) => r.tags.includes(featureId));\n // Every rule below filters by the feature tag, so a delta whose author\n // forgot the tags entirely passes every check and archives while merging\n // nothing. Whole-file only: once ANYTHING is tagged, deciding that an\n // untagged edge \"looks intended\" would be guessing.\n if (\n (res.elements.length > 0 || res.relationships.length > 0) &&\n taggedEls.length === 0 &&\n taggedRels.length === 0\n ) {\n issues.push({\n severity: \"error\",\n code: \"delta.nothing-tagged\",\n message: `delta.likec4 declares elements/relationships but none are tagged #${featureId}; loam cannot see untagged changes`,\n });\n }\n }\n }\n // --- per-service specs (requirement operations) + openapi deltas ---\n const svcNames = await featureSpecServices(featureDir, context);\n\n // Every axis below joins on the service id, so endpoints resolve through the\n // element's `metadata { service }` binding — never through what the box is\n // called. The enumerated fleet — `services/` plus this feature's own\n // `specs/` directories, the same union `enumeratedTarget` probes below —\n // rides into the resolver so a delta that models CONTAINERS joins correctly:\n // without it, an edge into `payment.api` resolves to a service called \"api\"\n // that has never existed, and every check below grades the edge against an\n // absent service instead of the one that owns the container. An unenumerable\n // services/ falls back to the feature's own names — every living probe would\n // have found nothing there anyway.\n const fleetIds = await enumeratedServiceIds(docsDir, context);\n const known = new Set([...fleetIds, ...svcNames]);\n const svcOf = serviceResolver(elements, known);\n\n // Which elements the landscape merge would SPLICE: the tagged ones and\n // everything nested inside their blocks. Defined here because two checks\n // share it — the scaffold gate just below, and the binding-grammar check\n // near the end of this function — and the merge carries a tagged element's\n // authored block over byte for byte, children included, so a scope narrower\n // than the splice lets a nested child's text ride through unread.\n const taggedIds = taggedEls.map((el) => el.id);\n const ridesWithTag = (el: Elem): boolean =>\n el.tags.includes(featureId) || taggedIds.some((id) => el.id.startsWith(`${id}.`));\n\n // The scaffold gate: placeholder text and an unwritten intent are legal\n // documents whose merge would publish content nobody authored — the exact\n // template strings `loam new` wrote (authoring/scaffold.ts owns the list).\n issues.push(\n ...(await authoringIssues({ featureDir, featureId, splicedEls: elements.filter(ridesWithTag), svcNames, context })),\n );\n const {\n reqOps, removingOps, featureApiOps, unreadableApis, revivalCandidates, displacedOps,\n } = await declaredByService(scope, svcNames, issues, context);\n\n // A revival: an operation the merged contract would answer that the living\n // contract no longer has because an ARCHIVED feature retired it — or would\n // answer again at an address an archived feature took it out of, beside\n // where it lives now — and the merge would read it as an addition and put\n // it back (./retired/ says why the gate could not see this before). One\n // lazy handle for both contract axes, so the walk of features/archive/ is\n // paid once per call at most, and only when the merged contract answers\n // something at an address the living one does not.\n const retired = retiredLookup(docsDir, context);\n for (const [svc, arrived] of revivalCandidates) {\n if (arrived.length === 0) continue;\n issues.push(...revivedOperations(svc, arrived, await retired()));\n }\n const { governedByLivingSpec, definedElsewhere, deprecatedInLiving, undeprecatedByFeature } = coherenceLookups(scope, context);\n\n // --- taking an operation out of the contract while the fleet still calls it ---\n // ./consumed/operations.ts owns the gate; the index is built here because\n // the event axis below asks the same one, so the fleet is read once.\n const consumers = consumerIndex({ docsDir, context, afterFeature: featureDir });\n issues.push(...(await consumedOperationIssues({ consumers, removingOps, displacedOps })));\n\n // E1: Spec -> API — every operation a requirement governs must exist in that service's OpenAPI.\n for (const [svc, ops] of reqOps) {\n // The union below reads the feature's own contract; unreadable means the\n // op may well be defined in the file nobody could open, and `op-undefined`\n // would point the author at the requirement when the truth is the YAML.\n // `openapi.invalid` (declared.ts) already gates; one breach, one finding.\n if (unreadableApis.has(svc)) continue;\n const available = await serviceOperationIds(docsDir, svc, featureDir, context);\n for (const op of ops) {\n if (available.includes(op)) continue;\n const other = await definedElsewhere(svc, op);\n if (other !== undefined) {\n issues.push({ severity: \"warn\", code: \"spec-api.op-pending\", message: `requirement in ${svc} governs '${op}', defined by in-flight ${other} — archive it first` });\n continue;\n }\n issues.push({ severity: \"error\", code: \"spec-api.op-undefined\", message: `requirement in ${svc} governs '${op}', not defined in ${svc}'s OpenAPI` });\n }\n }\n\n // The declared→enumerated bridge for edge TARGETS. `svcOf` answers with\n // whatever the document wrote — `metadata { service '../../x' }` parses in\n // LikeC4 without one error — and every living lookup below joins its answer\n // into `services/<target>/` or `specs/<target>/`. So a target resolves\n // through the enumerations first (the fleet's `services/` plus this\n // feature's own `specs/`, where a service it introduces lives), and a name\n // neither knows skips the lookups — no ops, not governed, not deprecated —\n // grading exactly as an absent service, spelled with the declared name.\n const enumeratedTarget = enumeratedServiceIndex(docsDir, svcNames, context);\n\n // E2 / W1 / W4: C4 edges vs API + requirements.\n for (const r of taggedRels) {\n if (r.op === undefined) {\n if ((r.title ?? \"\").toLowerCase().startsWith(\"call\")) {\n issues.push({ severity: \"warn\", code: \"c4.op-link-missing\", message: `edge ${svcOf(r.source)} → ${svcOf(r.target)} (\"${r.title}\") has no operation link (metadata { op })` });\n }\n continue;\n }\n const target = svcOf(r.target);\n const pathable = await enumeratedTarget(target);\n // Same suspension as E1, but only for the verdicts that READ a contract:\n // does the op exist, is it being removed, is it deprecated (whose\n // un-deprecation escape reads the feature contract too). Each of those\n // would be an opinion about a file nobody could open. The governance\n // question below is deliberately NOT suspended — it joins the edge against\n // requirement documents alone, so the broken YAML could never change its\n // answer, and silencing it deferred a real warning for no reason.\n const contractUnreadable = pathable !== undefined && unreadableApis.has(pathable);\n const available =\n pathable === undefined || contractUnreadable\n ? []\n : await serviceOperationIds(docsDir, pathable, featureDir, context);\n if (contractUnreadable) {\n // openapi.invalid (declared.ts) already gates; one breach, one finding.\n } else if (\n pathable !== undefined &&\n // An operation replaced at its address leaves as surely as a retired\n // one; `available` below still lists it, because serviceOperationIds\n // subtracts markers only, so without this a new edge onto it passed.\n (removingOps.get(pathable)?.has(r.op) === true || displacedOps.get(pathable)?.some((d) => d.id === r.op) === true)\n ) {\n issues.push({ severity: \"error\", code: \"c4-api.op-removing\", message: `${svcOf(r.source)} builds new consumption on '${r.op}', which this feature removes from ${target}` });\n } else if (!available.includes(r.op)) {\n const other = await definedElsewhere(target, r.op);\n if (other !== undefined) {\n issues.push({ severity: \"warn\", code: \"c4-api.op-pending\", message: `${svcOf(r.source)} calls '${r.op}' on ${target}, defined by in-flight ${other} — archive it first` });\n } else {\n issues.push({ severity: \"error\", code: \"c4-api.op-undefined\", message: `${svcOf(r.source)} calls '${r.op}' on ${target}, but ${target}'s OpenAPI does not define it (contract broken)` });\n }\n }\n // Governed by THIS target's requirements, not by anybody's. An operationId\n // is unique only inside one contract, so the fleet-wide set this used to\n // ask meant a `getStatus` governed in service A silenced the question for\n // service B's entirely unrelated `getStatus` — the warning went quiet for\n // the edge that needed it, and only in repos where some other service\n // happened to reuse the name. The living half on the same line has always\n // joined per service (`governedByLivingSpec(target, …)`); this is the delta\n // half asking it the same way.\n if (pathable === undefined || (!(reqOps.get(pathable) ?? []).includes(r.op) && !(await governedByLivingSpec(pathable, r.op)))) {\n issues.push({ severity: \"warn\", code: \"c4.op-ungoverned\", message: `'${r.op}' is called by ${svcOf(r.source)} but no requirement governs it` });\n }\n // Lifecycle: this NEW tagged edge builds consumption on an operation the\n // living provider contract already marks deprecated. Advisory, never an\n // archive gate — the edge is legal and the contract holds — but new\n // consumption of a dying op deserves an eye before it ships. Quiet when\n // the feature's own openapi delta drops the flag: that state is the fix\n // in progress, not new consumption of a dying op.\n if (!contractUnreadable && pathable !== undefined && (await deprecatedInLiving(pathable, r.op)) && !(await undeprecatedByFeature(pathable, r.op))) {\n issues.push({ severity: \"warn\", code: \"c4-api.op-deprecated\", message: `${svcOf(r.source)} builds new consumption on '${r.op}', which ${target}'s living OpenAPI marks deprecated — prefer the replacement operation` });\n }\n }\n\n // W2: API -> C4 — every operation the feature adds should be consumed by some edge.\n const consumed = new Set(taggedRels.map((r) => r.op).filter((o): o is string => o !== undefined));\n for (const op of featureApiOps) {\n if (!consumed.has(op)) {\n issues.push({ severity: \"warn\", code: \"api.op-unconsumed\", message: `operation '${op}' is added but no architecture edge consumes it (provider-only or unmodeled)` });\n }\n }\n\n // W3: a new service should carry a requirement delta. \"New service\" is the\n // fleet census's reading of the map this merge leaves (../c4/resolve/systems.ts):\n // a tagged `#external` producer, a grouping and a container are no service of\n // ours, and asking each for a `specs/` delta put a unit of work nobody owes\n // on the board and a warning the archived fleet never repeats. Nor is a\n // service the fleet already holds new — its own directory, or a box the\n // living map draws — whatever the delta's tag says: re-declaring is not\n // introducing.\n // The living map is parsed only for a candidate no directory answers for.\n const systems = {\n elements,\n known,\n living: new Set<string>(fleetIds),\n livingMap: livingMapOf(landscapePath(docsDir), (path) => (context === undefined ? loadFile(path) : context.loadLikeC4(path))),\n };\n for (const e of taggedEls) {\n const svc: string = elementService(e);\n if (e.kind !== \"softwareSystem\" || svcNames.some((n) => n === svc)) continue;\n if ((await readDeltaSystem(e, systems)) !== \"service\") continue;\n issues.push({ severity: \"warn\", code: \"service.no-requirement-delta\", message: `new service ${svc} has no requirement delta under specs/` });\n }\n\n // An explicit `metadata { service '<id>' }` binding, held to the same grammar\n // every `--service` flag is — on the tagged elements AND everything nested\n // inside their blocks. The scope is the splice's, not the tag's: the\n // landscape merge carries a tagged element's authored block over byte for\n // byte, children included (landscape-merge.ts's rides() exists exactly so a\n // child travels inside its parent's text), so an untagged container's\n // binding reaches the living map as surely as its tagged parent's — and\n // checking only the tagged elements themselves let it ride through unread.\n // The binding is the one name the archive TRUSTS: the merge splices it into\n // the living map verbatim, and the new-service scan probes\n // `services/<binding>/` with it — where `metadata { service '../outside-svc' }`,\n // which LikeC4 parses without a murmur, collapses the probe right out of\n // services/, and the spliced map fails the very next `validate --all`\n // (`landscape.binding-unknown`). Explicit bindings only, on purpose: a prose\n // title with no binding is legal C4, and a title becomes a path only through\n // `specs/<svc>/`, whose own grammar check (`delta.service-id-invalid`)\n // guards that route. `ridesWithTag` itself is defined up beside the scaffold\n // gate, which shares the splice's scope for the same reason.\n for (const e of elements.filter(ridesWithTag)) {\n if (e.service === undefined) continue;\n const problem = serviceIdProblem(e.service, \"metadata { service } binding\");\n if (problem === null) continue;\n issues.push({\n severity: \"error\",\n code: \"c4.service-binding-invalid\",\n subject: e.service,\n message:\n `'${e.title}' (${e.id}) — ${problem} ` +\n `\\`loam archive\\` would splice '${e.service}' into the living landscape.likec4 exactly as written, ` +\n `and probe services/${e.service}/ with it. Bind the element to the services/<id>/ directory it means.`,\n });\n }\n\n // The event axis — the same three-way agreement the operation checks above\n // grade, joined on the message name instead of the operationId: the\n // feature's asyncapi deltas (pins, markers, justification), the tagged\n // edges' publishes/consumes metadata, and the requirement deltas'\n // Publishes:/Consumes: lines (./events/events.ts owns the walk).\n const infraKindOf = infrastructureKind(elements);\n issues.push(...(await eventCoherence({ scope, svcNames, taggedRels, svcOf, infraKindOf, context, retired, consumers, known })));\n\n // The health axis's one merge question: an alert or SLI the living\n // arch.spec.md covers that this delta would leave covered by nothing.\n issues.push(...(await droppedHealthCoverage({ docsDir, featureDir, services: svcNames, ...(context === undefined ? {} : { context }) })));\n\n return issues;\n}\n"]}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { nothingStill, refusalDetails, refusalMessage, stillNamed } from "./refusal.js";
|
|
2
|
+
export async function consumedOperationIssues(request) {
|
|
3
|
+
const { consumers, removingOps, displacedOps } = request;
|
|
4
|
+
const issues = [];
|
|
5
|
+
// --- taking an operation out of the contract while the fleet still calls it ---
|
|
6
|
+
// Exactness and justification never ask what matters to the other
|
|
7
|
+
// ninety-nine repos: is anybody still calling it? The merge deletes the
|
|
8
|
+
// operation while the edge, the requirement and the use-case hop naming it
|
|
9
|
+
// stay, so the next `validate --all` breaks a repository whose author was
|
|
10
|
+
// never in this feature. Asked of the ONE consumer index, read after this
|
|
11
|
+
// feature's merge (core/consumers/ says what it reads and what a feature can
|
|
12
|
+
// retire). `own` counts too: for a marker the REMOVED requirement leaves with
|
|
13
|
+
// the merge, so what remains is a second one, or an internal edge. One index
|
|
14
|
+
// for both shapes and the event axis, so the fleet is read once. A consumer
|
|
15
|
+
// document the index could not read or place refuses too (./refusal.ts):
|
|
16
|
+
// "nobody could look" never let a removal through before the one index.
|
|
17
|
+
const still = async (svc, op) => stillNamed(await consumers.opConsumers(svc, op));
|
|
18
|
+
// The landscape merge only ADDS edges, so an edge is dropped or redrawn in the living map itself.
|
|
19
|
+
const route = `drop or redraw its edge in the architecture/ project, MODIFY or REMOVE the requirement that names it in this feature's specs/<service>/ delta`;
|
|
20
|
+
for (const [svc, retiring] of removingOps) {
|
|
21
|
+
for (const op of retiring) {
|
|
22
|
+
const found = await still(svc, op);
|
|
23
|
+
if (nothingStill(found))
|
|
24
|
+
continue;
|
|
25
|
+
issues.push({
|
|
26
|
+
severity: "error",
|
|
27
|
+
code: "openapi.remove-op-consumed",
|
|
28
|
+
subject: svc,
|
|
29
|
+
details: refusalDetails(found),
|
|
30
|
+
message: refusalMessage(found, {
|
|
31
|
+
subject: svc,
|
|
32
|
+
lost: `this feature retires '${op}'`,
|
|
33
|
+
verb: "consume",
|
|
34
|
+
named: (list) => `${svc}: this feature retires '${op}', but the fleet would still consume it after this merge — ${list}. Retire each consumer in the same change (${route}), or archive with --approve to break it deliberately.`,
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// The same loss with no marker to read: another operation defined where a
|
|
40
|
+
// consumed one lives replaces it there, and once the contract the merge
|
|
41
|
+
// would write defines it nowhere it has left the contract exactly as a
|
|
42
|
+
// retirement does. One code, because the breach and its override are the
|
|
43
|
+
// removal's — only `api.op-unconsumed` (advisory) said anything before, and
|
|
44
|
+
// the archive passed without `--approve`. With no marker there is no REMOVED
|
|
45
|
+
// requirement either, so the provider's own requirement naming the old id
|
|
46
|
+
// stays unless this feature restates it — `own` is what catches it.
|
|
47
|
+
for (const [svc, displaced] of displacedOps) {
|
|
48
|
+
for (const { id: op, at } of displaced) {
|
|
49
|
+
const found = await still(svc, op);
|
|
50
|
+
if (nothingStill(found))
|
|
51
|
+
continue;
|
|
52
|
+
const by = at.map(({ address, by: id }) => `${id === undefined ? "an operation with no operationId" : `'${id}'`} at ${address}`).join(" and ");
|
|
53
|
+
const lost = `this feature's openapi.yaml defines ${by}, where '${op}' lives now — the merge replaces it there and would leave '${op}' defined nowhere`;
|
|
54
|
+
issues.push({
|
|
55
|
+
severity: "error",
|
|
56
|
+
code: "openapi.remove-op-consumed",
|
|
57
|
+
subject: svc,
|
|
58
|
+
details: refusalDetails(found),
|
|
59
|
+
message: refusalMessage(found, {
|
|
60
|
+
subject: svc,
|
|
61
|
+
lost,
|
|
62
|
+
verb: "consume",
|
|
63
|
+
named: (list) => `${svc}: ${lost}, but it is still consumed — ${list}. Define '${op}' at another address in this delta if it is to stay. To take it out on purpose, update every consumer in the same change — ${route} (${svc}'s own restated to name the new operation, for a rename; a REMOVED one owes no x-loam-remove marker, since the overwrite already takes '${op}' out) — or archive with --approve to break it deliberately.`,
|
|
64
|
+
}),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return issues;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=operations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations.js","sourceRoot":"","sources":["../../../../src/core/coherence/consumed/operations.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The contract axis's removal gate, `openapi.remove-op-consumed`: does the\n * fleet still consume an operation this feature takes out of the contract —\n * by a removal marker, or by defining another operation where it lives?\n *\n * Moved out of `../coherence.ts`, which ran at its 400-line limit, along the\n * seam the gate already had there: everything below asks the consumer index\n * (core/consumers/) one question per operation the merge loses and phrases\n * the refusal, and nothing else in featureCoherence reads its answer. The\n * index itself is built there and handed in, because the event axis's twin\n * (`asyncapi.remove-message-consumed`, ../events/events.ts) asks the same one.\n */\nimport type { Issue } from \"../../vocabulary/issue.js\";\nimport type { ConsumerIndex } from \"../../consumers/consumers.js\";\nimport type { Declared } from \"../declared.js\";\nimport { nothingStill, refusalDetails, refusalMessage, stillNamed, type StillNamed } from \"./refusal.js\";\n\n/** What the gate is asked over: the shared index, and the two ways this feature's merge loses an operation. */\nexport interface ConsumedOperationsRequest {\n /** The consumer index, read after this feature's merge — shared with the event axis so the fleet is read once. */\n consumers: ConsumerIndex;\n removingOps: Declared[\"removingOps\"];\n displacedOps: Declared[\"displacedOps\"];\n}\n\nexport async function consumedOperationIssues(request: ConsumedOperationsRequest): Promise<Issue[]> {\n const { consumers, removingOps, displacedOps } = request;\n const issues: Issue[] = [];\n // --- taking an operation out of the contract while the fleet still calls it ---\n // Exactness and justification never ask what matters to the other\n // ninety-nine repos: is anybody still calling it? The merge deletes the\n // operation while the edge, the requirement and the use-case hop naming it\n // stay, so the next `validate --all` breaks a repository whose author was\n // never in this feature. Asked of the ONE consumer index, read after this\n // feature's merge (core/consumers/ says what it reads and what a feature can\n // retire). `own` counts too: for a marker the REMOVED requirement leaves with\n // the merge, so what remains is a second one, or an internal edge. One index\n // for both shapes and the event axis, so the fleet is read once. A consumer\n // document the index could not read or place refuses too (./refusal.ts):\n // \"nobody could look\" never let a removal through before the one index.\n const still = async (svc: string, op: string): Promise<StillNamed> => stillNamed(await consumers.opConsumers(svc, op));\n // The landscape merge only ADDS edges, so an edge is dropped or redrawn in the living map itself.\n const route = `drop or redraw its edge in the architecture/ project, MODIFY or REMOVE the requirement that names it in this feature's specs/<service>/ delta`;\n for (const [svc, retiring] of removingOps) {\n for (const op of retiring) {\n const found = await still(svc, op);\n if (nothingStill(found)) continue;\n issues.push({\n severity: \"error\",\n code: \"openapi.remove-op-consumed\",\n subject: svc,\n details: refusalDetails(found),\n message: refusalMessage(found, {\n subject: svc,\n lost: `this feature retires '${op}'`,\n verb: \"consume\",\n named: (list) => `${svc}: this feature retires '${op}', but the fleet would still consume it after this merge — ${list}. Retire each consumer in the same change (${route}), or archive with --approve to break it deliberately.`,\n }),\n });\n }\n }\n\n // The same loss with no marker to read: another operation defined where a\n // consumed one lives replaces it there, and once the contract the merge\n // would write defines it nowhere it has left the contract exactly as a\n // retirement does. One code, because the breach and its override are the\n // removal's — only `api.op-unconsumed` (advisory) said anything before, and\n // the archive passed without `--approve`. With no marker there is no REMOVED\n // requirement either, so the provider's own requirement naming the old id\n // stays unless this feature restates it — `own` is what catches it.\n for (const [svc, displaced] of displacedOps) {\n for (const { id: op, at } of displaced) {\n const found = await still(svc, op);\n if (nothingStill(found)) continue;\n const by = at.map(({ address, by: id }) => `${id === undefined ? \"an operation with no operationId\" : `'${id}'`} at ${address}`).join(\" and \");\n const lost = `this feature's openapi.yaml defines ${by}, where '${op}' lives now — the merge replaces it there and would leave '${op}' defined nowhere`;\n issues.push({\n severity: \"error\",\n code: \"openapi.remove-op-consumed\",\n subject: svc,\n details: refusalDetails(found),\n message: refusalMessage(found, {\n subject: svc,\n lost,\n verb: \"consume\",\n named: (list) => `${svc}: ${lost}, but it is still consumed — ${list}. Define '${op}' at another address in this delta if it is to stay. To take it out on purpose, update every consumer in the same change — ${route} (${svc}'s own restated to name the new operation, for a rename; a REMOVED one owes no x-loam-remove marker, since the overwrite already takes '${op}' out) — or archive with --approve to break it deliberately.`,\n }),\n });\n }\n }\n return issues;\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { documentDoubt } from "../../consumers/scan.js";
|
|
2
|
+
/**
|
|
3
|
+
* The gate's reading of one answer: `victims` and `own` as evidence, and of the
|
|
4
|
+
* suspensions only the document doubts. A caller drawn with no op and a
|
|
5
|
+
* contested hop stay out — `documentDoubt` (core/consumers/scan.ts) says why
|
|
6
|
+
* they are a warning's worth in `loam diff` and nothing here.
|
|
7
|
+
*/
|
|
8
|
+
export function stillNamed(found) {
|
|
9
|
+
return {
|
|
10
|
+
named: [...found.victims, ...found.own],
|
|
11
|
+
unchecked: [...found.suspended, ...found.ownSuspended].filter(documentDoubt).map((s) => s.text),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** Nothing named and nothing unchecked: the removal is the gate's to let through. */
|
|
15
|
+
export function nothingStill(still) {
|
|
16
|
+
return still.named.length === 0 && still.unchecked.length === 0;
|
|
17
|
+
}
|
|
18
|
+
/** The one remedy every unchecked document shares, after "make". */
|
|
19
|
+
const READABLE = "each document listed readable (re-save it as UTF-8, or leave one directory per service id) so the gate can answer";
|
|
20
|
+
/**
|
|
21
|
+
* The message for one refusal. With named consumers it is the gate's own
|
|
22
|
+
* sentence, plus one more when documents went unchecked too; with only
|
|
23
|
+
* unchecked documents it never claims a consumer — "nobody could look" is not
|
|
24
|
+
* "somebody still calls it", any more than it is "nobody does".
|
|
25
|
+
*/
|
|
26
|
+
export function refusalMessage(still, wording) {
|
|
27
|
+
const unchecked = still.unchecked.join("; ");
|
|
28
|
+
if (still.named.length === 0) {
|
|
29
|
+
return `${wording.subject}: ${wording.lost}, but whether the fleet would still ${wording.verb} it after this merge could not be checked — ${unchecked}. Make ${READABLE}, or archive with --approve to break it deliberately.`;
|
|
30
|
+
}
|
|
31
|
+
const named = wording.named(still.named.join("; "));
|
|
32
|
+
return still.unchecked.length === 0 ? named : `${named} Whether anything else would still ${wording.verb} it could not be checked either — ${unchecked}: make ${READABLE}.`;
|
|
33
|
+
}
|
|
34
|
+
/** What a refusal's `details[]` lists: the named consumers, then the documents nobody could check. */
|
|
35
|
+
export function refusalDetails(still) {
|
|
36
|
+
return [...still.named, ...still.unchecked];
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=refusal.js.map
|