@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 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../../src/core/coherence/events/events.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The event axis of the feature gate: do the C4 delta's tagged edges, the\n * requirement deltas' `Publishes:`/`Consumes:` lines, and the asyncapi\n * contracts agree about what each service puts on the wire?\n *\n * The package's orchestrator, called once from featureCoherence with the\n * delta facts it already holds (tagged relationships and the element\n * resolver): ./declared.ts walks the feature's own contracts and grades\n * what one service's pair of documents can settle; ./lookups.ts answers the\n * in-flight question lazily, and the consumer index (core/consumers/) who\n * still consumes a message; this module joins the three axes — the exact\n * shape coherence.ts gives the operation join, on the message name.\n *\n * A package of its own rather than lines in coherence.ts because that file\n * ran at its 300-line limit before the event axis existed; the seam is\n * real, not cosmetic — everything here joins on a message name, nothing\n * there does.\n */\nimport { type Rel } from \"../../c4/likec4.js\";\nimport { eventKeys, unboundSentence } from \"../../c4/direction/direction.js\";\nimport { type PathableService, type RawServiceId } from \"../../kernel/ids/service.js\";\nimport type { Issue } from \"../../vocabulary/issue.js\";\nimport { locateServicePaths } from \"../../repo/service-target.js\";\nimport { enumeratedServiceIndex } from \"../../repo/service-target.js\";\nimport { readAsyncapi } from \"../../asyncapi/read.js\";\nimport type { AsyncapiDoc } from \"../../asyncapi/model.js\";\nimport type { FleetContext } from \"../../fleet-context.js\";\nimport { declaredEvents, type EventDeltaScope } from \"./declared.js\";\nimport { eventLookups } from \"./lookups.js\";\nimport type { RetiredLookup } from \"../retired/archived.js\";\nimport { revivedEvents } from \"../retired/revival/revived.js\";\nimport type { ConsumerIndex } from \"../../consumers/consumers.js\";\nimport { nothingStill, refusalDetails, refusalMessage, stillNamed, type StillNamed } from \"../consumed/refusal.js\";\nimport { fleetSendersAfter, unproducedIssues, type ConsumeClaim } from \"./produced.js\";\n\n/** What featureCoherence hands the event axis — the delta facts it already computed. */\nexport interface EventCoherenceRequest {\n scope: EventDeltaScope;\n /** The services this feature's specs/ touch — the walk's subjects. */\n svcNames: PathableService[];\n /** The delta's tagged relationships — the edges the landscape merge would splice. */\n taggedRels: Rel[];\n /** The element→service resolver over the delta's elements plus the enumerated fleet. */\n svcOf: (id: string) => string;\n /** The infrastructure kind of a delta element or its ancestor (core/c4/direction/direction.ts) — a key bound there is on the wrong end. */\n infraKindOf: (id: string) => string | undefined;\n context?: FleetContext;\n /** The retired index, shared with the contract axis so one call walks `features/archive/` once at most. */\n retired: RetiredLookup;\n /** The consumer index, read after this feature's merge — shared with the contract axis so the fleet is read once. */\n consumers: ConsumerIndex;\n /** The services the merge leaves a directory for — the enumerated fleet plus this feature's `specs/` (./produced.ts). */\n known: ReadonlySet<RawServiceId>;\n}\n\nexport async function eventCoherence(request: EventCoherenceRequest): Promise<Issue[]> {\n const { scope, svcNames, taggedRels, svcOf, context, consumers } = request;\n const issues: Issue[] = [];\n const declared = await declaredEvents(scope, svcNames, issues, context);\n const lookups = eventLookups({ docsDir: scope.docsDir, featureId: scope.featureId }, context);\n\n // Who would still name a message after this merge: the consumer index's\n // consumers, and its `own` — the provider's own `Publishes:` lines as the\n // merge leaves them. That is the event twin of the overwrite's own-requirement\n // scan: a message re-keyed or no longer sent while the provider's living\n // requirement still says it `Publishes:` it archived at exit 0, and the next\n // `validate --all` reported `spec-event.message-undefined` against the\n // provider (review 2026-10-12, finding 3) — a REMOVED requirement justifies a\n // marker, but nothing asks a re-key or a turned-around operation for one.\n // A consumer document nobody could read or place refuses too, as on the\n // contract axis (../consumed/refusal.ts).\n //\n // But a CONSUMER is stranded only when nothing would send the message after\n // this merge — no service, and no #external element whose edge publishes it.\n // That is the rule `spine.message-unproduced` grades a consumer by — it stays\n // quiet over an outside producer (`externalProducerOf`,\n // core/c4/resolve/external.ts) — and the one `loam diff` asks first\n // (`producers`, then `externalProducer`, core/diff/semantic.ts).\n // Counting every consumer \"whoever its producer is\" refused a retirement from\n // one of two senders over the other sender's own consumes edge, and told the\n // author to drop it, while `loam diff` called the same removal a warning\n // (\"still sent by …\") and the next `validate --all` was clean (the\n // verification of the consumer fixes, N2). Counting the fleet's senders alone\n // then refused a retirement from a message's only fleet sender while an\n // #external element still published it, and `loam diff` called the archived\n // removal `diff.message-removed-consumed`, while the next `validate --all` was\n // clean again (the verification of N1–N3, D1). The provider's OWN documents are\n // another matter: the spine and validate grade them against the provider's\n // own contract, so they strand whoever else sends the message, and `own`\n // still refuses beside a surviving sender.\n //\n // The senders are asked of the MERGE, never of the living fleet alone:\n // `producers` reads the fleet as it stands, so a feature retiring the message\n // from both senders would let each one pass on the other's living contract.\n // A service this feature carries an event delta for sends what the\n // simulation leaves it (`declared.sentAfter`), or vouches for nothing; every\n // other service sends what its living contract does. Positive evidence only,\n // as `producers` is: an unreadable contract, or a merge that stood down,\n // never keeps a message produced. The outside producer is the living map's\n // edge and tag, which the landscape merge cannot take away (it only adds to\n // the map), asked over the directories the merge leaves: each `specs/<svc>/`\n // of this feature becomes a `services/<svc>/`, and a directory the #external\n // element resolves to outranks its tag, so a feature onboarding the outside\n // system as a service takes the producer away. Asked over the directories\n // as they stood, the gate passed that retirement while the next `loam diff`\n // reported `diff.message-removed-consumed` and `validate --all`\n // `spine.message-unproduced` (the verification of D1, X2). One this\n // feature's own C4 delta would draw is not counted, so that shape errs\n // toward refusing — `--approve`, or draw the edge in the living map. The\n // consumer check in ./produced.ts DOES count it, deliberately: there the\n // closed direction is the other one (that module says why), and the fleet\n // half of the senders is the one helper both read.\n const sendersAfter = async (svc: string, message: string): Promise<string[]> => {\n const fleet = (await fleetSendersAfter(declared, consumers, message)).filter((id) => id !== svc);\n const outside = await consumers.externalProducer(message);\n return outside === null ? fleet : [...fleet, `${outside} (#external)`];\n };\n const still = async (svc: string, message: string): Promise<{ found: StillNamed; senders: string[] }> => {\n const answer = await consumers.messageConsumers(svc, message);\n const senders = await sendersAfter(svc, message);\n return { senders, found: stillNamed(senders.length === 0 ? answer : { ...answer, victims: [], suspended: [] }) };\n };\n // The landscape merge only ADDS edges, so an edge is dropped in the living map\n // itself — a consumer's consumes edge, or the provider's own publishes edge,\n // which the spine grades on its source (`own`, core/consumers/consumers.ts).\n const route = `drop its consumes edge, or drop or redraw its publishes edge, in the architecture/ project, MODIFY or REMOVE the requirement whose Consumes:/Publishes: line names it in this feature's specs/<service>/ delta`;\n // With a sender left only the provider's own documents are named, so the\n // remedy is theirs alone — telling the author to drop a consumer's edge\n // there is the false route this gate used to give.\n const ownRoute = (svc: string): string =>\n `drop or redraw its publishes edge in the architecture/ project, or MODIFY or REMOVE the requirement whose Publishes: line names it in this feature's specs/${svc}/ delta`;\n const ownOnly = (svc: string, senders: string[]): string =>\n `${senders.join(\", \")} would still send it after this merge, so its consumers keep a producer, but ${svc}'s own documents would still name it`;\n // The route a consumer's refusal gains: another sender keeps the message\n // produced, and one this feature adds counts (`declared.sentAfter`); so does\n // the #external element that publishes it, drawn in the living map — the one\n // place `sendersAfter` reads an outside producer from — unless this feature\n // makes it a service. The route says so: a feature onboarding the gateway is\n // told no #external element publishes the message while its living map\n // draws one doing exactly that, and the way out is the first route, the new\n // service's own send operation in its specs/<service>/ delta.\n const anotherSender =\n \"keep another service sending it (an action: send operation in its asyncapi.yaml, living or in this feature's specs/<service>/ delta) or an #external element publishing it (a publishes edge from it in the living architecture/ project; one whose element this feature's specs/<service>/ makes a service no longer counts)\";\n\n // Retiring a message the fleet still consumes — openapi.remove-op-consumed's\n // twin, and like it a question neither exactness nor justification asks:\n // the merge deletes the declaration while the consumes edge and the other\n // repo's requirement stay, so the next `validate --all` breaks on a\n // repository whose author was never in this feature.\n for (const [svc, net] of declared.netRemoved) {\n for (const message of net) {\n const { found, senders } = await still(svc, message);\n if (nothingStill(found)) continue;\n const lost = `this feature retires message '${message}'`;\n issues.push({\n severity: \"error\",\n code: \"asyncapi.remove-message-consumed\",\n subject: svc,\n details: refusalDetails(found),\n message: refusalMessage(found, {\n subject: svc,\n lost,\n verb: \"name\",\n named: (list) =>\n senders.length === 0\n ? `${svc}: ${lost}, and no readable contract would still send it after this merge, nor does an #external element publish it, but the fleet would still name it — ${list}. Retire each in the same change (${route}), ${anotherSender}, or archive with --approve to break it deliberately.`\n : `${svc}: ${lost}; ${ownOnly(svc, senders)} — ${list}. Retire each in the same change (${ownRoute(svc)}), or archive with --approve to break it deliberately.`,\n }),\n });\n }\n }\n\n // The WIRE half of the same question: a channel or operation removal (or\n // an edit) can stop the service SENDING a message whose declaration\n // survives — the merge applies cleanly, and the next `validate --all`\n // breaks on the consumer's repository (spine.message-unproduced) exactly\n // as a deleted declaration would. Asked of the simulated merge's sent-set\n // diff; a name the net-removal loop above already asked keeps one finding.\n for (const [svc, stopped] of declared.stoppedSending) {\n const net = declared.netRemoved.get(svc);\n for (const message of stopped) {\n if (net?.has(message) === true) continue;\n const { found, senders } = await still(svc, message);\n if (nothingStill(found)) continue;\n const lost = `after this feature's merge, ${svc}'s asyncapi.yaml would no longer declare an action: send operation for '${message}'`;\n issues.push({\n severity: \"error\",\n code: \"asyncapi.remove-message-consumed\",\n subject: svc,\n details: refusalDetails(found),\n message: refusalMessage(found, {\n subject: svc,\n lost,\n verb: \"name\",\n named: (list) =>\n senders.length === 0\n ? `${svc}: ${lost}, and no other readable contract would send it either, nor does an #external element publish it, but the fleet would still name it — ${list}. Keep an operation sending it, ${anotherSender}, retire each in the same change (${route}), or archive with --approve to break it deliberately.`\n : `${svc}: ${lost}; ${ownOnly(svc, senders)} — ${list}. Keep an operation sending it, retire each in the same change (${ownRoute(svc)}), or archive with --approve to break it deliberately.`,\n }),\n });\n }\n }\n\n // A revival: a slot or message this delta declares that the living\n // contract no longer has because an ARCHIVED feature retired it, or a\n // message name declared again at a key an archived feature took it out of\n // — the contract axis's `openapi.op-revived`, on the slot and the message\n // name (../retired/revival/revived.ts). Asked of the index only when the merged\n // contract declares something the living one does not.\n for (const [svc, arrived] of declared.revivalCandidates) {\n if (arrived.slots.length === 0 && arrived.messages.length === 0) continue;\n issues.push(...revivedEvents(svc, arrived, await request.retired()));\n }\n\n // Two features declaring one (service, message): both deltas apply\n // cleanly, so whichever archives second replaces the other's declaration\n // wholesale — delta.added-conflict's shape on the message join.\n for (const [svc, doc] of declared.featureDocs) {\n for (const m of doc.messages) {\n if (m.remove === true) continue;\n const other = await lookups.messageDefinedElsewhere(svc, m.name);\n if (other === undefined) continue;\n issues.push({\n severity: \"warn\",\n code: \"asyncapi.message-conflict\",\n subject: svc,\n message: `${svc}: this feature declares message '${m.name}', which in-flight ${other} also adds or edits — whichever archives second replaces the other's declaration wholesale; coordinate before either ships`,\n });\n }\n }\n\n // The bound service's contract as the feature would leave it. Where the\n // feature carries a delta over a readable living contract, that is the\n // SIMULATED merge (declared.mergedDocs): a slot the delta retires or edits\n // away stops answering here BEFORE archive — a leftover Publishes: line on\n // a surviving requirement used to pass this gate on living's say-so, then\n // break `validate --all` on the post-archive docs. Everywhere the\n // simulation has no answer — no delta for the service, a side that does\n // not read, a document the merge refuses — the feature ∪ living union\n // stands in, which can only be too lenient, never wrongly red; the living\n // side is read lazily per service, since an edge may bind a service the\n // feature carries no specs/ directory for.\n const livingDocs = new Map<PathableService, AsyncapiDoc>();\n const livingOf = async (svc: PathableService): Promise<AsyncapiDoc> => {\n let doc = livingDocs.get(svc);\n if (doc === undefined) {\n doc = await readAsyncapi((await locateServicePaths(scope.docsDir, svc, context)).asyncapi, context);\n livingDocs.set(svc, doc);\n }\n return doc;\n };\n // undefined = no verdict: an unreadable LIVING contract proves nothing\n // about the message (validate's asyncapi.invalid owns that file), and\n // grading against its empty parse would blame every edge for one broken\n // document.\n const declares = async (\n svc: PathableService,\n direction: \"publishes\" | \"consumes\",\n message: string,\n ): Promise<boolean | undefined> => {\n const merged = declared.mergedDocs.get(svc);\n if (merged !== undefined) {\n return direction === \"publishes\" ? merged.sent.includes(message) : merged.received.includes(message);\n }\n const living = await livingOf(svc);\n if (living.unreadable) return undefined;\n const feat = declared.featureDocs.get(svc);\n return direction === \"publishes\"\n ? living.sent.includes(message) || (feat?.sent.includes(message) ?? false)\n : living.received.includes(message) || (feat?.received.includes(message) ?? false);\n };\n const action = (direction: \"publishes\" | \"consumes\"): string => (direction === \"publishes\" ? \"send\" : \"receive\");\n\n // The declared→enumerated bridge coherence.ts uses for op edges, for the\n // same reason: every lookup below joins into services/<id>/ or the\n // feature's own specs/. A bound element NEITHER knows is skipped rather\n // than graded — an #external producer is the documented shape for a\n // message produced outside the fleet (spine.message-external), so grading\n // its edge against an absent service directory would turn the worked\n // example red.\n const enumeratedTarget = enumeratedServiceIndex(scope.docsDir, svcNames, context);\n\n // Tagged edges: `publishes` binds the edge's SOURCE, `consumes` its\n // TARGET — the same reading validate's event spine takes of the living\n // landscape, applied to the delta, from the one statement of the rule\n // (core/c4/direction/direction.ts).\n // Every consumption this merge would add, collected as the two loops below\n // walk the edges and the lines, and asked for a producer at the end\n // (./produced.ts) — `spine.message-unproduced` at feature scope.\n const claims: ConsumeClaim[] = [];\n for (const r of taggedRels) {\n const edge = `${svcOf(r.source)} → ${svcOf(r.target)}`;\n for (const key of eventKeys(r)) {\n const b = { direction: key.direction, message: key.message, name: svcOf(key.bound), edge };\n const pathable = await enumeratedTarget(b.name);\n if (pathable === undefined) {\n // The skip above, unless the key is bound to infrastructure and a\n // service sits at the OTHER end: then it is on the wrong end of its\n // edge and binds nothing, which the living spine reports under the\n // same code once this delta merges. An `#external` system at the bound\n // end is an outside producer or consumer, and stays skipped.\n const kind = request.infraKindOf(key.bound);\n const drawer = kind === undefined ? undefined : await enumeratedTarget(svcOf(key.other));\n if (kind !== undefined && drawer !== undefined) {\n issues.push({ severity: \"warn\", code: \"spine.message-unbound\", subject: drawer, message: `delta ${unboundSentence(r, key, kind)}` });\n }\n continue;\n }\n // asyncapi.invalid already gates; one breach, one finding.\n if (declared.unreadable.has(pathable)) continue;\n if (b.direction === \"consumes\") claims.push({ service: pathable, message: b.message, source: \"edge\", via: `edge ${b.edge}` });\n const ok = await declares(pathable, b.direction, b.message);\n if (ok !== false) continue;\n const other = await lookups.messageDefinedElsewhere(pathable, b.message);\n if (other !== undefined) {\n issues.push({\n severity: \"warn\",\n code: \"c4-event.message-pending\",\n message: `edge ${b.edge} ${b.direction} '${b.message}', defined by in-flight ${other} — archive it first`,\n });\n } else {\n issues.push({\n severity: \"error\",\n code: \"c4-event.message-undefined\",\n message: `edge ${b.edge} ${b.direction} '${b.message}', but ${b.name}'s asyncapi contract (feature and living alike) declares no operation with action: ${action(b.direction)} for it`,\n });\n }\n }\n }\n\n // The requirement deltas' own lines, graded the same way — the same\n // sentence validate gives the living-side breach, under the same code, so\n // one breach keeps one name across scopes. The lines were read once by\n // ./declared.ts's walk (declared.links); re-reading them here per service\n // was a second parse of both spec files on the context-less archive path.\n for (const svc of svcNames) {\n if (declared.unreadable.has(svc)) continue;\n for (const link of declared.links.get(svc) ?? []) {\n if (link.direction === \"consumes\") {\n claims.push({ service: svc, message: link.message, source: \"requirement\", via: `requirement '${link.requirement}'` });\n }\n const ok = await declares(svc, link.direction, link.message);\n if (ok !== false) continue;\n const other = await lookups.messageDefinedElsewhere(svc, link.message);\n if (other !== undefined) {\n issues.push({\n severity: \"warn\",\n code: \"spec-event.message-pending\",\n subject: svc,\n message: `${svc}: requirement '${link.requirement}' ${link.direction} '${link.message}', defined by in-flight ${other} — archive it first`,\n });\n } else {\n issues.push({\n severity: \"error\",\n code: \"spec-event.message-undefined\",\n subject: svc,\n message: `${svc}: requirement '${link.requirement}' ${link.direction} '${link.message}', but ${svc}'s asyncapi.yaml declares no operation with action: ${action(link.direction)} for it`,\n });\n }\n }\n }\n\n issues.push(...(await unproducedIssues({ scope, declared, consumers, lookups, claims, known: request.known, ...(context === undefined ? {} : { context }) })));\n return issues;\n}\n"]}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { ASYNCAPI_BASELINES_KEY, slotKey } from "../../asyncapi/digest.js";
|
|
2
|
+
import { moveBackRemedy } from "../retired/revival/revived.js";
|
|
3
|
+
import { asyncapiSurfaces } from "../../asyncapi/baseline/surfaces.js";
|
|
4
|
+
import { messageName } from "../../asyncapi/read.js";
|
|
5
|
+
import { entryFor, readBaselineRecord, surfaceIn } from "../../openapi/baseline/record.js";
|
|
6
|
+
import { classifyBaselineDigests, OPERATION_DIGEST_LENGTH, OPERATION_DIGEST_RE, valueDigest, } from "../../openapi/digest.js";
|
|
7
|
+
/**
|
|
8
|
+
* One service's baselines against the living contract — openapi/baseline/gate.ts's
|
|
9
|
+
* verdicts, over BOTH halves of this axis: the slot pins in-value, and the
|
|
10
|
+
* component surfaces the root `x-loam-baselines` record pins. One function
|
|
11
|
+
* because the unpinned count is shared (see below), and because a delta is
|
|
12
|
+
* graded once or the two halves drift into different ideas of what it restates.
|
|
13
|
+
*/
|
|
14
|
+
export function gradeBaselines(input, issues) {
|
|
15
|
+
const { featSlots, livingSlots, livingDoc, svc, featureId } = input;
|
|
16
|
+
let unpinned = 0;
|
|
17
|
+
for (const slot of featSlots) {
|
|
18
|
+
// A removal marker is not a restatement of anything; its own exactness
|
|
19
|
+
// checks guard the slot.
|
|
20
|
+
if (slot.remove)
|
|
21
|
+
continue;
|
|
22
|
+
const label = `${slot.section}.${slot.key}`;
|
|
23
|
+
const living = livingSlots.get(slotKey(slot));
|
|
24
|
+
if (slot.basedOn !== undefined && !OPERATION_DIGEST_RE.test(slot.basedOn)) {
|
|
25
|
+
issues.push({
|
|
26
|
+
severity: "error",
|
|
27
|
+
code: "asyncapi.baseline-invalid",
|
|
28
|
+
subject: svc,
|
|
29
|
+
message: `${svc}: ${label} has invalid x-loam-based-on '${slot.basedOn}' — expected ${OPERATION_DIGEST_LENGTH} lowercase hex characters, as \`loam rebase\` writes them`,
|
|
30
|
+
});
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const verdict = classifyBaselineDigests(slot.basedOn, slot.digest, living?.digest);
|
|
34
|
+
if (verdict === "unfounded") {
|
|
35
|
+
// openapi/baseline/gate.ts's reading, on the slot: a pin is only ever
|
|
36
|
+
// written over a living slot, so one with nothing behind it usually
|
|
37
|
+
// means a parallel feature retired the slot — and "drop the marker",
|
|
38
|
+
// which this used to say, archived the quote as an addition and put the
|
|
39
|
+
// retired slot back. Or MOVED it, on the one slot a move vacates on
|
|
40
|
+
// this axis: a `components.messages` key whose message name the living
|
|
41
|
+
// contract now declares elsewhere. A channel or operation slot's
|
|
42
|
+
// identity is its key, so it is never "moved" — it is retired. The
|
|
43
|
+
// move-back remedy is the revival finding's own (../retired/revival/revived.ts):
|
|
44
|
+
// where the name now stands inline under a channel, a marker there
|
|
45
|
+
// retires nothing, so the remedy names the channel instead. The two
|
|
46
|
+
// places are said as a condition ("while it is still declared there"),
|
|
47
|
+
// not as what this delta does: one that already restates or retires
|
|
48
|
+
// that channel takes the name out of it, and only the pin is left.
|
|
49
|
+
const name = slot.section === "components.messages" ? messageName(slot.node, slot.key) : undefined;
|
|
50
|
+
const movedTo = livingDoc.messages.filter((m) => m.remove !== true && m.name === name).map((m) => m.slot);
|
|
51
|
+
// The channels still pointing at a key the remedy retires are read off
|
|
52
|
+
// the contract the merge would leave; where it refuses (and the archive
|
|
53
|
+
// with it), off the living one, which is what the merge would start from.
|
|
54
|
+
const remedy = () => moveBackRemedy(movedTo, label, input.merged()?.root ?? input.livingPlain);
|
|
55
|
+
issues.push({
|
|
56
|
+
severity: "error",
|
|
57
|
+
code: "asyncapi.baseline-invalid",
|
|
58
|
+
subject: svc,
|
|
59
|
+
message: movedTo.length > 0
|
|
60
|
+
? `${svc}: ${label} carries x-loam-based-on, but the living contract has no slot there — message '${name}' is declared at ${movedTo.join(" and ")} now: a parallel feature moved it there (or retired it here, and another re-declared it there). Re-read it there and delete this slot from the delta, making any change at its new key; archived while it is still declared there, it would declare '${name}' at ${label} as well. To move it back on purpose, drop the pin and ${remedy()} in this delta.`
|
|
61
|
+
: `${svc}: ${label} carries x-loam-based-on, but the living contract has no slot there — the version it was pinned to is gone. If a parallel feature retired it, re-read the living contract and delete this slot from the delta, unless this feature deliberately brings it back (then drop the pin and archive with --approve past \`asyncapi.slot-revived\`). A genuinely new channel, operation or message has no living version to be based on and carries no pin.`,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else if (verdict === "stale") {
|
|
65
|
+
issues.push({
|
|
66
|
+
severity: "error",
|
|
67
|
+
code: "asyncapi.baseline-stale",
|
|
68
|
+
subject: svc,
|
|
69
|
+
message: `${svc}: ${label} was written against living version ${slot.basedOn}, but the living contract now holds ${living.digest} — somebody landed a change to it in between, and merging this would replace theirs outright. Re-read the living slot, fold in what you still mean, then run \`loam rebase ${featureId}\`.`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
else if (verdict === "unpinned" && living !== undefined) {
|
|
73
|
+
// Counted, not listed — a delta quotes most of the contract it
|
|
74
|
+
// restates, and one warning per quote teaches people to filter the
|
|
75
|
+
// code out (openapi.baseline-missing's doctrine, verbatim).
|
|
76
|
+
unpinned += 1;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// The surface half's unpinned count folds into the SAME counter, not a
|
|
80
|
+
// second warning: "counted, not listed" is the doctrine above, and one
|
|
81
|
+
// warning per axis-half would have a delta over a schema-heavy contract
|
|
82
|
+
// print two findings naming the same one command.
|
|
83
|
+
unpinned += gradeSurfaces(input, issues);
|
|
84
|
+
if (unpinned > 0) {
|
|
85
|
+
issues.push({
|
|
86
|
+
severity: "warn",
|
|
87
|
+
gates: true,
|
|
88
|
+
code: "asyncapi.baseline-missing",
|
|
89
|
+
subject: svc,
|
|
90
|
+
message: `${svc}: ${unpinned} slot(s) and component surface(s) in this feature's asyncapi.yaml carry no baseline pin (x-loam-based-on / ${ASYNCAPI_BASELINES_KEY}), so the merge cannot tell which ones this delta EDITS from the ones it merely restates — it will upsert all of them, reverting anything that landed on the restated ones. Run \`loam rebase ${featureId} --service ${svc}\`, or archive with --approve to merge unpinned deliberately.`,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The surface half: every `components/<kind>/<name>` outside `messages`,
|
|
96
|
+
* graded from the root `x-loam-baselines` record by the same classifier the
|
|
97
|
+
* slots go through. Returns the unpinned count so the caller can fold it into
|
|
98
|
+
* the one per-service warning rather than emitting a second.
|
|
99
|
+
*
|
|
100
|
+
* The codes are REUSED rather than multiplied — `asyncapi.baseline-invalid`
|
|
101
|
+
* and `asyncapi.baseline-stale` say exactly the same thing about a surface as
|
|
102
|
+
* about a slot, and a caller that branches on them wants one branch.
|
|
103
|
+
*/
|
|
104
|
+
function gradeSurfaces(input, issues) {
|
|
105
|
+
const { featPlain, livingPlain, svc, featureId } = input;
|
|
106
|
+
const invalid = (message) => {
|
|
107
|
+
issues.push({ severity: "error", code: "asyncapi.baseline-invalid", subject: svc, message: `${svc}: ${message}` });
|
|
108
|
+
};
|
|
109
|
+
const { record, problems } = readBaselineRecord(featPlain);
|
|
110
|
+
for (const problem of problems) {
|
|
111
|
+
invalid(`${problem} — the record is \`loam rebase\`'s bookkeeping and cannot be graded as it stands; re-run \`loam rebase ${featureId}\` to rebuild it`);
|
|
112
|
+
}
|
|
113
|
+
const surfaces = asyncapiSurfaces(featPlain);
|
|
114
|
+
// An entry pinning a surface the delta does not declare is a claim about
|
|
115
|
+
// nothing — usually one the author deleted after rebasing. Distinct from
|
|
116
|
+
// `unfounded` below, where the surface IS declared and the LIVING side is
|
|
117
|
+
// what vanished. A `pathItems` section is the same fault at the axis level:
|
|
118
|
+
// an AsyncAPI document has no path items, so the whole section pins nothing,
|
|
119
|
+
// and rebase's wholesale rebuild would drop it without a word.
|
|
120
|
+
const declared = new Set(surfaces.map((s) => s.id));
|
|
121
|
+
for (const id of Object.keys(record.components)) {
|
|
122
|
+
if (declared.has(id))
|
|
123
|
+
continue;
|
|
124
|
+
invalid(`${ASYNCAPI_BASELINES_KEY} pins component '${id}', but this feature's asyncapi.yaml does not declare it — re-run \`loam rebase ${featureId}\` to rebuild the record`);
|
|
125
|
+
}
|
|
126
|
+
for (const path of Object.keys(record.pathItems)) {
|
|
127
|
+
invalid(`${ASYNCAPI_BASELINES_KEY} pins path item '${path}', but an AsyncAPI document has no path items — the section pins nothing; re-run \`loam rebase ${featureId}\` to rebuild the record`);
|
|
128
|
+
}
|
|
129
|
+
let unpinned = 0;
|
|
130
|
+
for (const s of surfaces) {
|
|
131
|
+
const entry = entryFor(record, s);
|
|
132
|
+
const living = surfaceIn(livingPlain, s);
|
|
133
|
+
const verdict = classifyBaselineDigests(entry, valueDigest(s.value), living.found ? valueDigest(living.value) : undefined);
|
|
134
|
+
if (verdict === "unpinned") {
|
|
135
|
+
// Only a surface the living contract ALREADY has can be reverted by an
|
|
136
|
+
// unpinned merge; a genuinely new schema never trips the counter.
|
|
137
|
+
if (living.found)
|
|
138
|
+
unpinned += 1;
|
|
139
|
+
}
|
|
140
|
+
else if (verdict === "stale") {
|
|
141
|
+
issues.push({
|
|
142
|
+
severity: "error",
|
|
143
|
+
code: "asyncapi.baseline-stale",
|
|
144
|
+
subject: svc,
|
|
145
|
+
message: `${svc}: component '${s.id}' was pinned to living version ${entry}, but the living contract now holds ${valueDigest(living.value)} — somebody landed a change to it in between, and merging this would replace theirs outright. Re-read the living value, fold in what you still mean, then run \`loam rebase ${featureId}\`.`,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
else if (verdict === "unfounded") {
|
|
149
|
+
invalid(`component '${s.id}' is pinned to ${entry}, but the living contract no longer has that surface — the pin is structurally unresolvable; re-read the living contract, then run \`loam rebase ${featureId}\``);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return unpinned;
|
|
153
|
+
}
|
|
154
|
+
/** Marker exactness: the slot must exist, and a message marker must name the living declaration. */
|
|
155
|
+
export function gradeMarkers(pair, svc, issues) {
|
|
156
|
+
const { featDoc, livingDoc, featSlots, livingSlots } = pair;
|
|
157
|
+
for (const slot of featSlots) {
|
|
158
|
+
if (!slot.remove)
|
|
159
|
+
continue;
|
|
160
|
+
const label = `${slot.section}.${slot.key}`;
|
|
161
|
+
const living = livingSlots.get(slotKey(slot));
|
|
162
|
+
if (living === undefined) {
|
|
163
|
+
issues.push({
|
|
164
|
+
severity: "error",
|
|
165
|
+
code: "asyncapi.remove-target-missing",
|
|
166
|
+
subject: svc,
|
|
167
|
+
message: `${svc}: removal marker at ${label} addresses no living slot — the contract has nothing there to retire; update the stale marker to the current key, or drop it if the slot is already gone`,
|
|
168
|
+
});
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (slot.section !== "components.messages")
|
|
172
|
+
continue;
|
|
173
|
+
// Removal is exact for messages the way it is for operations: the
|
|
174
|
+
// marker names both the key and the message identity it expects to
|
|
175
|
+
// delete, so a slot whose NAME moved under the delta is caught here
|
|
176
|
+
// rather than deleting somebody else's message.
|
|
177
|
+
const markerName = featDoc.messages.find((m) => m.remove === true && m.slot === label)?.name ?? slot.key;
|
|
178
|
+
const livingName = livingDoc.messages.find((m) => m.slot === label)?.name ?? slot.key;
|
|
179
|
+
if (markerName !== livingName) {
|
|
180
|
+
issues.push({
|
|
181
|
+
severity: "error",
|
|
182
|
+
code: "asyncapi.remove-target-mismatch",
|
|
183
|
+
subject: svc,
|
|
184
|
+
message: `${svc}: removal marker at ${label} names message '${markerName}', but the living declaration there is '${livingName}' — loam never deletes a different message occupying the slot`,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=grades.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grades.js","sourceRoot":"","sources":["../../../../src/core/coherence/events/grades.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The per-slot grades of one service's pair of event contracts: baseline\n * pins and removal-marker exactness. Split from ./declared.ts along the\n * subject seam — that module owns the WALK (which files, which services,\n * which sets), these functions own the verdict each slot gets once both\n * sides are in hand — when the walk grew past the line limit; the split\n * moved them verbatim.\n */\nimport type { Issue } from \"../../vocabulary/issue.js\";\nimport { ASYNCAPI_BASELINES_KEY, slotKey } from \"../../asyncapi/digest.js\";\nimport type { EventPair, EventPairRead } from \"../retired/event-pair.js\";\nimport { moveBackRemedy } from \"../retired/revival/revived.js\";\nimport { asyncapiSurfaces } from \"../../asyncapi/baseline/surfaces.js\";\nimport { messageName } from \"../../asyncapi/read.js\";\nimport { entryFor, readBaselineRecord, surfaceIn } from \"../../openapi/baseline/record.js\";\nimport {\n classifyBaselineDigests,\n OPERATION_DIGEST_LENGTH,\n OPERATION_DIGEST_RE,\n valueDigest,\n} from \"../../openapi/digest.js\";\n\n/** Everything the two baseline graders need about one service's pair of contracts. */\nexport interface AsyncapiBaselineInput extends EventPair, Pick<EventPairRead, \"merged\"> {\n /** The FEATURE document's resolved parse — where the record and the surfaces are read from. */\n featPlain: unknown;\n /** The LIVING document's resolved parse; `{}` where no living contract exists. */\n livingPlain: unknown;\n svc: string;\n featureId: string;\n}\n\n/**\n * One service's baselines against the living contract — openapi/baseline/gate.ts's\n * verdicts, over BOTH halves of this axis: the slot pins in-value, and the\n * component surfaces the root `x-loam-baselines` record pins. One function\n * because the unpinned count is shared (see below), and because a delta is\n * graded once or the two halves drift into different ideas of what it restates.\n */\nexport function gradeBaselines(input: AsyncapiBaselineInput, issues: Issue[]): void {\n const { featSlots, livingSlots, livingDoc, svc, featureId } = input;\n let unpinned = 0;\n for (const slot of featSlots) {\n // A removal marker is not a restatement of anything; its own exactness\n // checks guard the slot.\n if (slot.remove) continue;\n const label = `${slot.section}.${slot.key}`;\n const living = livingSlots.get(slotKey(slot));\n if (slot.basedOn !== undefined && !OPERATION_DIGEST_RE.test(slot.basedOn)) {\n issues.push({\n severity: \"error\",\n code: \"asyncapi.baseline-invalid\",\n subject: svc,\n message: `${svc}: ${label} has invalid x-loam-based-on '${slot.basedOn}' — expected ${OPERATION_DIGEST_LENGTH} lowercase hex characters, as \\`loam rebase\\` writes them`,\n });\n continue;\n }\n const verdict = classifyBaselineDigests(slot.basedOn, slot.digest, living?.digest);\n if (verdict === \"unfounded\") {\n // openapi/baseline/gate.ts's reading, on the slot: a pin is only ever\n // written over a living slot, so one with nothing behind it usually\n // means a parallel feature retired the slot — and \"drop the marker\",\n // which this used to say, archived the quote as an addition and put the\n // retired slot back. Or MOVED it, on the one slot a move vacates on\n // this axis: a `components.messages` key whose message name the living\n // contract now declares elsewhere. A channel or operation slot's\n // identity is its key, so it is never \"moved\" — it is retired. The\n // move-back remedy is the revival finding's own (../retired/revival/revived.ts):\n // where the name now stands inline under a channel, a marker there\n // retires nothing, so the remedy names the channel instead. The two\n // places are said as a condition (\"while it is still declared there\"),\n // not as what this delta does: one that already restates or retires\n // that channel takes the name out of it, and only the pin is left.\n const name = slot.section === \"components.messages\" ? messageName(slot.node, slot.key) : undefined;\n const movedTo = livingDoc.messages.filter((m) => m.remove !== true && m.name === name).map((m) => m.slot);\n // The channels still pointing at a key the remedy retires are read off\n // the contract the merge would leave; where it refuses (and the archive\n // with it), off the living one, which is what the merge would start from.\n const remedy = (): string => moveBackRemedy(movedTo, label, input.merged()?.root ?? input.livingPlain);\n issues.push({\n severity: \"error\",\n code: \"asyncapi.baseline-invalid\",\n subject: svc,\n message: movedTo.length > 0\n ? `${svc}: ${label} carries x-loam-based-on, but the living contract has no slot there — message '${name}' is declared at ${movedTo.join(\" and \")} now: a parallel feature moved it there (or retired it here, and another re-declared it there). Re-read it there and delete this slot from the delta, making any change at its new key; archived while it is still declared there, it would declare '${name}' at ${label} as well. To move it back on purpose, drop the pin and ${remedy()} in this delta.`\n : `${svc}: ${label} carries x-loam-based-on, but the living contract has no slot there — the version it was pinned to is gone. If a parallel feature retired it, re-read the living contract and delete this slot from the delta, unless this feature deliberately brings it back (then drop the pin and archive with --approve past \\`asyncapi.slot-revived\\`). A genuinely new channel, operation or message has no living version to be based on and carries no pin.`,\n });\n } else if (verdict === \"stale\") {\n issues.push({\n severity: \"error\",\n code: \"asyncapi.baseline-stale\",\n subject: svc,\n message: `${svc}: ${label} was written against living version ${slot.basedOn}, but the living contract now holds ${living!.digest} — somebody landed a change to it in between, and merging this would replace theirs outright. Re-read the living slot, fold in what you still mean, then run \\`loam rebase ${featureId}\\`.`,\n });\n } else if (verdict === \"unpinned\" && living !== undefined) {\n // Counted, not listed — a delta quotes most of the contract it\n // restates, and one warning per quote teaches people to filter the\n // code out (openapi.baseline-missing's doctrine, verbatim).\n unpinned += 1;\n }\n }\n // The surface half's unpinned count folds into the SAME counter, not a\n // second warning: \"counted, not listed\" is the doctrine above, and one\n // warning per axis-half would have a delta over a schema-heavy contract\n // print two findings naming the same one command.\n unpinned += gradeSurfaces(input, issues);\n if (unpinned > 0) {\n issues.push({\n severity: \"warn\",\n gates: true,\n code: \"asyncapi.baseline-missing\",\n subject: svc,\n message: `${svc}: ${unpinned} slot(s) and component surface(s) in this feature's asyncapi.yaml carry no baseline pin (x-loam-based-on / ${ASYNCAPI_BASELINES_KEY}), so the merge cannot tell which ones this delta EDITS from the ones it merely restates — it will upsert all of them, reverting anything that landed on the restated ones. Run \\`loam rebase ${featureId} --service ${svc}\\`, or archive with --approve to merge unpinned deliberately.`,\n });\n }\n}\n\n/**\n * The surface half: every `components/<kind>/<name>` outside `messages`,\n * graded from the root `x-loam-baselines` record by the same classifier the\n * slots go through. Returns the unpinned count so the caller can fold it into\n * the one per-service warning rather than emitting a second.\n *\n * The codes are REUSED rather than multiplied — `asyncapi.baseline-invalid`\n * and `asyncapi.baseline-stale` say exactly the same thing about a surface as\n * about a slot, and a caller that branches on them wants one branch.\n */\nfunction gradeSurfaces(input: AsyncapiBaselineInput, issues: Issue[]): number {\n const { featPlain, livingPlain, svc, featureId } = input;\n const invalid = (message: string): void => {\n issues.push({ severity: \"error\", code: \"asyncapi.baseline-invalid\", subject: svc, message: `${svc}: ${message}` });\n };\n const { record, problems } = readBaselineRecord(featPlain);\n for (const problem of problems) {\n invalid(`${problem} — the record is \\`loam rebase\\`'s bookkeeping and cannot be graded as it stands; re-run \\`loam rebase ${featureId}\\` to rebuild it`);\n }\n const surfaces = asyncapiSurfaces(featPlain);\n // An entry pinning a surface the delta does not declare is a claim about\n // nothing — usually one the author deleted after rebasing. Distinct from\n // `unfounded` below, where the surface IS declared and the LIVING side is\n // what vanished. A `pathItems` section is the same fault at the axis level:\n // an AsyncAPI document has no path items, so the whole section pins nothing,\n // and rebase's wholesale rebuild would drop it without a word.\n const declared = new Set(surfaces.map((s) => s.id));\n for (const id of Object.keys(record.components)) {\n if (declared.has(id)) continue;\n invalid(`${ASYNCAPI_BASELINES_KEY} pins component '${id}', but this feature's asyncapi.yaml does not declare it — re-run \\`loam rebase ${featureId}\\` to rebuild the record`);\n }\n for (const path of Object.keys(record.pathItems)) {\n invalid(`${ASYNCAPI_BASELINES_KEY} pins path item '${path}', but an AsyncAPI document has no path items — the section pins nothing; re-run \\`loam rebase ${featureId}\\` to rebuild the record`);\n }\n\n let unpinned = 0;\n for (const s of surfaces) {\n const entry = entryFor(record, s);\n const living = surfaceIn(livingPlain, s);\n const verdict = classifyBaselineDigests(\n entry,\n valueDigest(s.value),\n living.found ? valueDigest(living.value) : undefined,\n );\n if (verdict === \"unpinned\") {\n // Only a surface the living contract ALREADY has can be reverted by an\n // unpinned merge; a genuinely new schema never trips the counter.\n if (living.found) unpinned += 1;\n } else if (verdict === \"stale\") {\n issues.push({\n severity: \"error\",\n code: \"asyncapi.baseline-stale\",\n subject: svc,\n message: `${svc}: component '${s.id}' was pinned to living version ${entry}, but the living contract now holds ${valueDigest(living.value)} — somebody landed a change to it in between, and merging this would replace theirs outright. Re-read the living value, fold in what you still mean, then run \\`loam rebase ${featureId}\\`.`,\n });\n } else if (verdict === \"unfounded\") {\n invalid(`component '${s.id}' is pinned to ${entry}, but the living contract no longer has that surface — the pin is structurally unresolvable; re-read the living contract, then run \\`loam rebase ${featureId}\\``);\n }\n }\n return unpinned;\n}\n\n/** Marker exactness: the slot must exist, and a message marker must name the living declaration. */\nexport function gradeMarkers(pair: EventPair, svc: string, issues: Issue[]): void {\n const { featDoc, livingDoc, featSlots, livingSlots } = pair;\n for (const slot of featSlots) {\n if (!slot.remove) continue;\n const label = `${slot.section}.${slot.key}`;\n const living = livingSlots.get(slotKey(slot));\n if (living === undefined) {\n issues.push({\n severity: \"error\",\n code: \"asyncapi.remove-target-missing\",\n subject: svc,\n message: `${svc}: removal marker at ${label} addresses no living slot — the contract has nothing there to retire; update the stale marker to the current key, or drop it if the slot is already gone`,\n });\n continue;\n }\n if (slot.section !== \"components.messages\") continue;\n // Removal is exact for messages the way it is for operations: the\n // marker names both the key and the message identity it expects to\n // delete, so a slot whose NAME moved under the delta is caught here\n // rather than deleting somebody else's message.\n const markerName = featDoc.messages.find((m) => m.remove === true && m.slot === label)?.name ?? slot.key;\n const livingName = livingDoc.messages.find((m) => m.slot === label)?.name ?? slot.key;\n if (markerName !== livingName) {\n issues.push({\n severity: \"error\",\n code: \"asyncapi.remove-target-mismatch\",\n subject: svc,\n message: `${svc}: removal marker at ${label} names message '${markerName}', but the living declaration there is '${livingName}' — loam never deletes a different message occupying the slot`,\n });\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The event axis's fleet question, read lazily — ../lookups.ts's pattern on
|
|
3
|
+
* the message join.
|
|
4
|
+
*
|
|
5
|
+
* It reaches outside the delta: the in-flight scan reads every active
|
|
6
|
+
* feature's asyncapi delta. A closure over a cache rather than an argument
|
|
7
|
+
* computed up front, so it is paid only when its question is first asked —
|
|
8
|
+
* and it is paid by ANY feature that declares a message at all, because
|
|
9
|
+
* `asyncapi.message-conflict`'s question ("does an in-flight feature define
|
|
10
|
+
* this elsewhere?") is asked of every healthy declaration — unlike the
|
|
11
|
+
* OpenAPI mirror, whose `definedElsewhere` is reached only inside a breach
|
|
12
|
+
* branch. That standing cost matters most on `archive`'s gate, which runs
|
|
13
|
+
* without a FleetContext, so each read here is a real parse.
|
|
14
|
+
*
|
|
15
|
+
* The consumer scan that used to sit beside it — who still consumes a message
|
|
16
|
+
* a service retires — is the consumer index's now (`core/consumers/`), paid
|
|
17
|
+
* only by a feature that actually retires production: `loam diff` asks the
|
|
18
|
+
* same question, and the two copies had drifted apart in which documents they
|
|
19
|
+
* read.
|
|
20
|
+
*/
|
|
21
|
+
import { featureSpecPaths } from "../../repo/paths.js";
|
|
22
|
+
import { listFeatures } from "../../repo/repo.js";
|
|
23
|
+
import { readAsyncapi } from "../../asyncapi/read.js";
|
|
24
|
+
export function eventLookups(scope, context) {
|
|
25
|
+
const { docsDir, featureId } = scope;
|
|
26
|
+
// What OTHER features in flight declare, per (service, message) — the
|
|
27
|
+
// asyncapi mirror of pending.ts's activeOpAdditions, living HERE because
|
|
28
|
+
// it shares this module's laziness and its consumers. Removal markers do
|
|
29
|
+
// not count: a feature retiring a message is not adding it. First feature
|
|
30
|
+
// wins a clash — one name to archive first is enough to make progress.
|
|
31
|
+
// The senders ride the same walk: both questions read the same deltas, and
|
|
32
|
+
// a second walk is a second parse of every one of them on the archive gate.
|
|
33
|
+
let inFlight = null;
|
|
34
|
+
const scan = async () => {
|
|
35
|
+
if (inFlight === null) {
|
|
36
|
+
const declared = new Map();
|
|
37
|
+
const sent = new Map();
|
|
38
|
+
for (const feature of await listFeatures(docsDir, {}, context)) {
|
|
39
|
+
if (feature.id === featureId)
|
|
40
|
+
continue;
|
|
41
|
+
for (const svc of feature.services) {
|
|
42
|
+
const doc = await readAsyncapi(featureSpecPaths(feature.dir, svc).asyncapi, context);
|
|
43
|
+
for (const m of doc.messages) {
|
|
44
|
+
if (m.remove === true)
|
|
45
|
+
continue;
|
|
46
|
+
const k = `${svc} ${m.name}`;
|
|
47
|
+
if (!declared.has(k))
|
|
48
|
+
declared.set(k, feature.id);
|
|
49
|
+
}
|
|
50
|
+
for (const name of doc.sent)
|
|
51
|
+
if (!sent.has(name))
|
|
52
|
+
sent.set(name, feature.id);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
inFlight = { declared, sent };
|
|
56
|
+
}
|
|
57
|
+
return inFlight;
|
|
58
|
+
};
|
|
59
|
+
const messageDefinedElsewhere = async (service, message) => (await scan()).declared.get(`${service} ${message}`);
|
|
60
|
+
const messageSentElsewhere = async (message) => (await scan()).sent.get(message);
|
|
61
|
+
return { messageDefinedElsewhere, messageSentElsewhere };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=lookups.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookups.js","sourceRoot":"","sources":["../../../../src/core/coherence/events/lookups.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAyBtD,MAAM,UAAU,YAAY,CAAC,KAAiB,EAAE,OAAsB;IACpE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAErC,sEAAsE;IACtE,yEAAyE;IACzE,yEAAyE;IACzE,0EAA0E;IAC1E,uEAAuE;IACvE,2EAA2E;IAC3E,4EAA4E;IAC5E,IAAI,QAAQ,GAAwE,IAAI,CAAC;IACzF,MAAM,IAAI,GAAG,KAAK,IAA2E,EAAE;QAC7F,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;YAC3C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;YACvC,KAAK,MAAM,OAAO,IAAI,MAAM,YAAY,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC;gBAC/D,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS;oBAAE,SAAS;gBACvC,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;oBACnC,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,gBAAgB,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;oBACrF,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;wBAC7B,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI;4BAAE,SAAS;wBAChC,MAAM,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;wBAC7B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;4BAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;oBACpD,CAAC;oBACD,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,IAAI;wBAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;4BAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;gBAC/E,CAAC;YACH,CAAC;YACD,QAAQ,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAChC,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;IACF,MAAM,uBAAuB,GAAG,KAAK,EAAE,OAAe,EAAE,OAAe,EAA+B,EAAE,CACtG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC;IACvD,MAAM,oBAAoB,GAAG,KAAK,EAAE,OAAe,EAA+B,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAEtH,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,CAAC;AAC3D,CAAC","sourcesContent":["/**\n * The event axis's fleet question, read lazily — ../lookups.ts's pattern on\n * the message join.\n *\n * It reaches outside the delta: the in-flight scan reads every active\n * feature's asyncapi delta. A closure over a cache rather than an argument\n * computed up front, so it is paid only when its question is first asked —\n * and it is paid by ANY feature that declares a message at all, because\n * `asyncapi.message-conflict`'s question (\"does an in-flight feature define\n * this elsewhere?\") is asked of every healthy declaration — unlike the\n * OpenAPI mirror, whose `definedElsewhere` is reached only inside a breach\n * branch. That standing cost matters most on `archive`'s gate, which runs\n * without a FleetContext, so each read here is a real parse.\n *\n * The consumer scan that used to sit beside it — who still consumes a message\n * a service retires — is the consumer index's now (`core/consumers/`), paid\n * only by a feature that actually retires production: `loam diff` asks the\n * same question, and the two copies had drifted apart in which documents they\n * read.\n */\nimport { featureSpecPaths } from \"../../repo/paths.js\";\nimport { listFeatures } from \"../../repo/repo.js\";\nimport { readAsyncapi } from \"../../asyncapi/read.js\";\nimport type { FleetContext } from \"../../fleet-context.js\";\nimport type { DocsDir } from \"../../kernel/ids/dirs.js\";\n\n/** What the event checks may ask about the world outside this feature's own files. */\nexport interface EventLookups {\n /** The in-flight feature (if any) whose asyncapi delta adds or edits (service, message). */\n messageDefinedElsewhere(service: string, message: string): Promise<string | undefined>;\n /**\n * The in-flight feature (if any) whose asyncapi delta declares an `action:\n * send` for `message`, on any service — the producer a consumer this feature\n * adds would be waiting for (`./produced.ts`). Senders only, for\n * `ConsumerIndex.producers`' reason: every consumer declares the message too,\n * with `action: receive`, and counting that named the consumer its own\n * producer.\n */\n messageSentElsewhere(message: string): Promise<string | undefined>;\n}\n\n/** The identity of the feature being graded — what the lazy scans exclude. */\nexport interface EventScope {\n docsDir: DocsDir;\n featureId: string;\n}\n\nexport function eventLookups(scope: EventScope, context?: FleetContext): EventLookups {\n const { docsDir, featureId } = scope;\n\n // What OTHER features in flight declare, per (service, message) — the\n // asyncapi mirror of pending.ts's activeOpAdditions, living HERE because\n // it shares this module's laziness and its consumers. Removal markers do\n // not count: a feature retiring a message is not adding it. First feature\n // wins a clash — one name to archive first is enough to make progress.\n // The senders ride the same walk: both questions read the same deltas, and\n // a second walk is a second parse of every one of them on the archive gate.\n let inFlight: { declared: Map<string, string>; sent: Map<string, string> } | null = null;\n const scan = async (): Promise<{ declared: Map<string, string>; sent: Map<string, string> }> => {\n if (inFlight === null) {\n const declared = new Map<string, string>();\n const sent = new Map<string, string>();\n for (const feature of await listFeatures(docsDir, {}, context)) {\n if (feature.id === featureId) continue;\n for (const svc of feature.services) {\n const doc = await readAsyncapi(featureSpecPaths(feature.dir, svc).asyncapi, context);\n for (const m of doc.messages) {\n if (m.remove === true) continue;\n const k = `${svc} ${m.name}`;\n if (!declared.has(k)) declared.set(k, feature.id);\n }\n for (const name of doc.sent) if (!sent.has(name)) sent.set(name, feature.id);\n }\n }\n inFlight = { declared, sent };\n }\n return inFlight;\n };\n const messageDefinedElsewhere = async (service: string, message: string): Promise<string | undefined> =>\n (await scan()).declared.get(`${service} ${message}`);\n const messageSentElsewhere = async (message: string): Promise<string | undefined> => (await scan()).sent.get(message);\n\n return { messageDefinedElsewhere, messageSentElsewhere };\n}\n"]}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { stageMergedProject } from "../../c4/project/staged.js";
|
|
2
|
+
import { externalProducerOf } from "../../c4/resolve/external.js";
|
|
3
|
+
import { serviceResolver } from "../../c4/resolve/service.js";
|
|
4
|
+
import { extendingModels } from "../../c4/service-model/fleet/extending.js";
|
|
5
|
+
import { enumeratedServiceIds } from "../../repo/service-target.js";
|
|
6
|
+
import { producersByMessage } from "../../asyncapi/producers.js";
|
|
7
|
+
/**
|
|
8
|
+
* The fleet services that would send `message` after this merge, sorted —
|
|
9
|
+
* positive evidence only. A service this feature carries an event delta for
|
|
10
|
+
* (or whose delta does not read) sends what the simulated merge leaves it and
|
|
11
|
+
* nothing else; every other service sends what its living contract does. Read
|
|
12
|
+
* alone, the living half would let a feature retiring a message from both of
|
|
13
|
+
* its senders pass on each one's living contract.
|
|
14
|
+
*/
|
|
15
|
+
export async function fleetSendersAfter(declared, consumers, message) {
|
|
16
|
+
const touched = new Set([...declared.featureDocs.keys(), ...declared.unreadable]);
|
|
17
|
+
const living = (await consumers.producers(message)).filter((id) => !touched.has(id));
|
|
18
|
+
const merged = [...declared.sentAfter].filter(([, sent]) => sent.includes(message)).map(([id]) => id);
|
|
19
|
+
return [...new Set([...living, ...merged])].sort();
|
|
20
|
+
}
|
|
21
|
+
export async function unproducedIssues(req) {
|
|
22
|
+
const { scope, declared, consumers, lookups, context } = req;
|
|
23
|
+
if (req.claims.length === 0)
|
|
24
|
+
return [];
|
|
25
|
+
// One finding per (consumer, message), however many lines and edges claim
|
|
26
|
+
// it — the grain service scope reports at, so the two counts agree.
|
|
27
|
+
const groups = new Map();
|
|
28
|
+
for (const claim of req.claims) {
|
|
29
|
+
const key = JSON.stringify([claim.service, claim.message]);
|
|
30
|
+
groups.set(key, [...(groups.get(key) ?? []), claim]);
|
|
31
|
+
}
|
|
32
|
+
// The post-merge map, staged at most once and only when the living answers
|
|
33
|
+
// ran out; null when it cannot be had, which suspends rather than convicts.
|
|
34
|
+
let staged;
|
|
35
|
+
const mergedMap = () => (staged ??= (async () => {
|
|
36
|
+
const project = await stageMergedProject({
|
|
37
|
+
...scope,
|
|
38
|
+
documents: [],
|
|
39
|
+
...(context === undefined ? {} : { load: (path) => context.loadLikeC4(path) }),
|
|
40
|
+
models: await extendingModels(scope.docsDir, context),
|
|
41
|
+
});
|
|
42
|
+
return project.kind === "read" ? project.doc : null;
|
|
43
|
+
})());
|
|
44
|
+
/** true = sent; false = nothing sends it; undefined = loam could not look. */
|
|
45
|
+
const produced = async (message) => {
|
|
46
|
+
if ((await fleetSendersAfter(declared, consumers, message)).length > 0)
|
|
47
|
+
return true;
|
|
48
|
+
if ((await consumers.externalProducer(message)) !== null)
|
|
49
|
+
return true;
|
|
50
|
+
const map = await mergedMap();
|
|
51
|
+
if (map === null)
|
|
52
|
+
return undefined;
|
|
53
|
+
return externalProducerOf(message, map, serviceResolver(map.elements, req.known), req.known) !== null;
|
|
54
|
+
};
|
|
55
|
+
// Read only once some consumer has no producer, which a healthy feature
|
|
56
|
+
// never reaches: the fleet's contracts are already behind the consumer
|
|
57
|
+
// index's memo, but this read is a plain one (it is the walk service scope
|
|
58
|
+
// suspends on, and must be the same one).
|
|
59
|
+
let suspended;
|
|
60
|
+
const doubt = () => (suspended ??= (async () => declared.unreadable.size > 0 ||
|
|
61
|
+
(await producersByMessage(scope.docsDir, await enumeratedServiceIds(scope.docsDir, context), context)).unreadable.length >
|
|
62
|
+
0)());
|
|
63
|
+
const issues = [];
|
|
64
|
+
for (const [, claims] of [...groups].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) {
|
|
65
|
+
const [first] = claims;
|
|
66
|
+
if (first === undefined)
|
|
67
|
+
continue;
|
|
68
|
+
const { service, message } = first;
|
|
69
|
+
const sent = await produced(message);
|
|
70
|
+
if (sent !== false)
|
|
71
|
+
continue;
|
|
72
|
+
if (await doubt())
|
|
73
|
+
continue;
|
|
74
|
+
const where = claims.map((c) => c.via).join(", ");
|
|
75
|
+
const pending = await lookups.messageSentElsewhere(message);
|
|
76
|
+
if (pending !== undefined) {
|
|
77
|
+
issues.push({
|
|
78
|
+
severity: "warn",
|
|
79
|
+
code: claims.some((c) => c.source === "requirement") ? "spec-event.message-pending" : "c4-event.message-pending",
|
|
80
|
+
subject: service,
|
|
81
|
+
message: `${service}: ${where} consumes '${message}', whose only sender is in-flight ${pending} — archive it first: ` +
|
|
82
|
+
`archived before it, this feature leaves '${message}' with no producer and the next \`loam validate --all\` ` +
|
|
83
|
+
`reports spine.message-unproduced against ${service}`,
|
|
84
|
+
});
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
issues.push({
|
|
88
|
+
severity: "error",
|
|
89
|
+
code: "spine.message-unproduced",
|
|
90
|
+
subject: service,
|
|
91
|
+
message: `${service}: ${where} consumes '${message}', but after this merge no service in the fleet and no #external ` +
|
|
92
|
+
`element would declare it is sent — the message would have no producer anywhere, and the next ` +
|
|
93
|
+
`\`loam validate --all\` reports this same code against ${service}. Add the producer's send (an action: send ` +
|
|
94
|
+
`operation in its asyncapi.yaml, living or in this feature's specs/<service>/ delta), draw the #external ` +
|
|
95
|
+
`system publishing it (a publishes edge from an #external element), or drop the consumption from this feature`,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return issues;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=produced.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"produced.js","sourceRoot":"","sources":["../../../../src/core/coherence/events/produced.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Does anything still SEND what this feature makes a service consume?\n *\n * `spine.message-unproduced` asked at feature scope — the question validate's\n * service target asks of every living consumer\n * (`commands/validate/service/events/message-producers.ts`), asked here of the\n * consumers this feature's merge would ADD. Until it was, a feature whose\n * delta newly `Consumes:` (or draws a `consumes` edge into) a message no\n * service and no #external element sends passed the feature gate, archived at\n * exit 0 under \"living spec + landscape are now complete + current.\", and the\n * very next `validate --all` reported the error against the consumer\n * (the real-fleet review, 2026-10-21). `./events.ts` had already computed who\n * sends a message after the merge — for retirements only.\n *\n * THE FLEET'S SENDERS ARE THE RETIREMENT GATE'S, read after the merge\n * (`fleetSendersAfter` below, which `./events.ts` calls too): a living\n * service's contract, except that a service this feature carries an event\n * delta for answers with what the merge leaves it (`declared.sentAfter`) and\n * nothing else. The consumer itself counts, as it does at service scope — a\n * relay that reads and writes one name produces it.\n *\n * THE OUTSIDE PRODUCER IS ASKED OF THE MAP THE MERGE LEAVES, and here the two\n * gates part on purpose. The retirement gate reads only the living map and\n * errs toward refusing a retirement (`./events.ts` says why). A consumer is the\n * opposite shape: its question is whether `validate --all` will find a\n * producer once the archive lands, and the landscape merge only ADDS — a\n * tagged `publishes` edge from an #external system is on that map. Reading\n * the delta alone was not enough, because a delta re-declares a living system\n * as an untagged stub (`salesforce = softwareSystem 'salesforce'`): the edge\n * lands, the living element keeps its #external tag, and the fleet is clean —\n * while a delta-only read saw no tag and refused. So the living map is asked\n * first (memoised, cheap), and only then the staged post-merge map\n * (`core/c4/project/staged.ts`, the archive's own merge), parsed once per\n * feature and only on the path where nothing else sends the message.\n *\n * THE SAME SUSPENSION. \"Nobody sends this\" is an argument from absence, and\n * service scope makes it only over a fleet whose every contract reads; one\n * unreadable `asyncapi.yaml` anywhere suspends it, because that file may be the\n * producer. A feature delta that does not read suspends it too — its own\n * `asyncapi.invalid` already gates — and so does a post-merge map that cannot\n * be staged: loam could not look, which is never \"nobody publishes it\".\n *\n * SOFTENED for a producer still in flight, on the `-pending` precedent every\n * other cross-feature join here follows: when another active feature's delta\n * declares the send, the message is \"introduced by another feature still in\n * flight\" — `spec-event.message-pending` for a requirement line, and\n * `c4-event.message-pending` for an edge. A warning, so two features meant to\n * ship together stay green while both are open, and its words say what the\n * wrong order costs.\n */\nimport type { LoadedDoc } from \"../../c4/likec4.js\";\nimport { stageMergedProject } from \"../../c4/project/staged.js\";\nimport { externalProducerOf } from \"../../c4/resolve/external.js\";\nimport { serviceResolver } from \"../../c4/resolve/service.js\";\nimport { extendingModels } from \"../../c4/service-model/fleet/extending.js\";\nimport type { Issue } from \"../../vocabulary/issue.js\";\nimport type { PathableService, RawServiceId } from \"../../kernel/ids/service.js\";\nimport { enumeratedServiceIds } from \"../../repo/service-target.js\";\nimport { producersByMessage } from \"../../asyncapi/producers.js\";\nimport type { FleetContext } from \"../../fleet-context.js\";\nimport type { ConsumerIndex } from \"../../consumers/consumers.js\";\nimport type { DeclaredEvents, EventDeltaScope } from \"./declared.js\";\nimport type { EventLookups } from \"./lookups.js\";\n\n/** One place this feature's delta makes a service consume a message. */\nexport interface ConsumeClaim {\n service: PathableService;\n message: string;\n /** Which document says so — a requirement's `Consumes:` line, or a tagged `consumes` edge. */\n source: \"requirement\" | \"edge\";\n /** How a reader finds it: `requirement 'X'`, or `edge a → b`. */\n via: string;\n}\n\n/**\n * The fleet services that would send `message` after this merge, sorted —\n * positive evidence only. A service this feature carries an event delta for\n * (or whose delta does not read) sends what the simulated merge leaves it and\n * nothing else; every other service sends what its living contract does. Read\n * alone, the living half would let a feature retiring a message from both of\n * its senders pass on each one's living contract.\n */\nexport async function fleetSendersAfter(declared: DeclaredEvents, consumers: ConsumerIndex, message: string): Promise<string[]> {\n const touched = new Set<string>([...declared.featureDocs.keys(), ...declared.unreadable]);\n const living = (await consumers.producers(message)).filter((id) => !touched.has(id));\n const merged = [...declared.sentAfter].filter(([, sent]) => sent.includes(message)).map(([id]) => id);\n return [...new Set([...living, ...merged])].sort();\n}\n\n/** Everything the producer question reads, already computed by `./events.ts`. */\nexport interface ProducedRequest {\n scope: EventDeltaScope;\n declared: DeclaredEvents;\n consumers: ConsumerIndex;\n lookups: EventLookups;\n claims: readonly ConsumeClaim[];\n /** The services the merge leaves a directory for — the enumerated fleet plus this feature's `specs/`. */\n known: ReadonlySet<RawServiceId>;\n context?: FleetContext;\n}\n\nexport async function unproducedIssues(req: ProducedRequest): Promise<Issue[]> {\n const { scope, declared, consumers, lookups, context } = req;\n if (req.claims.length === 0) return [];\n // One finding per (consumer, message), however many lines and edges claim\n // it — the grain service scope reports at, so the two counts agree.\n const groups = new Map<string, ConsumeClaim[]>();\n for (const claim of req.claims) {\n const key = JSON.stringify([claim.service, claim.message]);\n groups.set(key, [...(groups.get(key) ?? []), claim]);\n }\n // The post-merge map, staged at most once and only when the living answers\n // ran out; null when it cannot be had, which suspends rather than convicts.\n let staged: Promise<LoadedDoc | null> | undefined;\n const mergedMap = (): Promise<LoadedDoc | null> =>\n (staged ??= (async () => {\n const project = await stageMergedProject({\n ...scope,\n documents: [],\n ...(context === undefined ? {} : { load: (path: string) => context.loadLikeC4(path) }),\n models: await extendingModels(scope.docsDir, context),\n });\n return project.kind === \"read\" ? project.doc : null;\n })());\n /** true = sent; false = nothing sends it; undefined = loam could not look. */\n const produced = async (message: string): Promise<boolean | undefined> => {\n if ((await fleetSendersAfter(declared, consumers, message)).length > 0) return true;\n if ((await consumers.externalProducer(message)) !== null) return true;\n const map = await mergedMap();\n if (map === null) return undefined;\n return externalProducerOf(message, map, serviceResolver(map.elements, req.known), req.known) !== null;\n };\n // Read only once some consumer has no producer, which a healthy feature\n // never reaches: the fleet's contracts are already behind the consumer\n // index's memo, but this read is a plain one (it is the walk service scope\n // suspends on, and must be the same one).\n let suspended: Promise<boolean> | undefined;\n const doubt = (): Promise<boolean> =>\n (suspended ??= (async () =>\n declared.unreadable.size > 0 ||\n (await producersByMessage(scope.docsDir, await enumeratedServiceIds(scope.docsDir, context), context)).unreadable.length >\n 0)());\n\n const issues: Issue[] = [];\n for (const [, claims] of [...groups].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) {\n const [first] = claims;\n if (first === undefined) continue;\n const { service, message } = first;\n const sent = await produced(message);\n if (sent !== false) continue;\n if (await doubt()) continue;\n const where = claims.map((c) => c.via).join(\", \");\n const pending = await lookups.messageSentElsewhere(message);\n if (pending !== undefined) {\n issues.push({\n severity: \"warn\",\n code: claims.some((c) => c.source === \"requirement\") ? \"spec-event.message-pending\" : \"c4-event.message-pending\",\n subject: service,\n message:\n `${service}: ${where} consumes '${message}', whose only sender is in-flight ${pending} — archive it first: ` +\n `archived before it, this feature leaves '${message}' with no producer and the next \\`loam validate --all\\` ` +\n `reports spine.message-unproduced against ${service}`,\n });\n continue;\n }\n issues.push({\n severity: \"error\",\n code: \"spine.message-unproduced\",\n subject: service,\n message:\n `${service}: ${where} consumes '${message}', but after this merge no service in the fleet and no #external ` +\n `element would declare it is sent — the message would have no producer anywhere, and the next ` +\n `\\`loam validate --all\\` reports this same code against ${service}. Add the producer's send (an action: send ` +\n `operation in its asyncapi.yaml, living or in this feature's specs/<service>/ delta), draw the #external ` +\n `system publishing it (a publishes edge from an #external element), or drop the consumption from this feature`,\n });\n }\n return issues;\n}\n"]}
|