@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,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What one feature ADDS and what it NEEDS, read out of its own delta.
|
|
3
|
+
*
|
|
4
|
+
* The whole graph is built from these five lists and nothing else, which is why
|
|
5
|
+
* they are computed once per feature and indexed rather than re-derived per
|
|
6
|
+
* edge: a feature is a node here only because some other feature's requirement
|
|
7
|
+
* or operation resolves into it, and answering that per pair would be a fleet
|
|
8
|
+
* walk per pair.
|
|
9
|
+
*
|
|
10
|
+
* `reqKeys` returns BOTH spellings of a requirement's identity — the stable
|
|
11
|
+
* `Requirement-ID` and the exact heading — because a legacy requirement has only
|
|
12
|
+
* the second, and an edge that existed under one spelling and not the other
|
|
13
|
+
* would make the graph depend on when the corpus was migrated.
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync } from "node:fs";
|
|
16
|
+
import { FleetContext } from "../fleet-context.js";
|
|
17
|
+
import { serviceResolver } from "../c4/resolve/service.js";
|
|
18
|
+
import { operations } from "../openapi/doc.js";
|
|
19
|
+
import {} from "../repo/entries.js";
|
|
20
|
+
import { SPEC_AXES, featurePaths, featureSpecPaths } from "../repo/paths.js";
|
|
21
|
+
import { locateServicePaths } from "../repo/service-target.js";
|
|
22
|
+
import { enumeratedServiceIds, enumeratedServiceIndex } from "../repo/service-target.js";
|
|
23
|
+
export function reqKeys(requirement) {
|
|
24
|
+
return [
|
|
25
|
+
...(requirement.id === undefined ? [] : [`id:${requirement.id}`]),
|
|
26
|
+
`name:${requirement.name}`,
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
export function reqIndexKey(at) {
|
|
30
|
+
return `${at.service}\0${at.axis}\0${at.identity}`;
|
|
31
|
+
}
|
|
32
|
+
export function opIndexKey(at) {
|
|
33
|
+
return `${at.service}\0${at.operationId}`;
|
|
34
|
+
}
|
|
35
|
+
export function addOwner(index, key, at, feature) {
|
|
36
|
+
const owners = index.get(key) ?? { at, features: new Set() };
|
|
37
|
+
owners.features.add(feature);
|
|
38
|
+
index.set(key, owners);
|
|
39
|
+
}
|
|
40
|
+
export async function readFacts(docsDir, feature, context) {
|
|
41
|
+
const addedRequirements = [];
|
|
42
|
+
const changedRequirements = [];
|
|
43
|
+
const introducedOperations = [];
|
|
44
|
+
const requiredOperations = [];
|
|
45
|
+
/**
|
|
46
|
+
* The operationIds a service ALREADY has, per service.
|
|
47
|
+
*
|
|
48
|
+
* This is the whole difference between a dependency graph and a rumour mill.
|
|
49
|
+
* A feature's `openapi.yaml` is a COMPLETE document, not a patch — authors
|
|
50
|
+
* restate the living API around the slot they are changing — so every feature
|
|
51
|
+
* that so much as mentions `authorizePayment` used to be recorded as
|
|
52
|
+
* INTRODUCING it, and every other feature governing it as REQUIRING it. Two
|
|
53
|
+
* features quoting the same living operation therefore depended on each other
|
|
54
|
+
* in both directions: an invented cycle, an invented conflict, and an ordering
|
|
55
|
+
* for work that had none. `loam validate`'s coherence pass already subtracts
|
|
56
|
+
* the living contract this way (core/coherence/coherence.ts); this is the
|
|
57
|
+
* same subtraction, so the two cannot disagree about what "new" means.
|
|
58
|
+
*
|
|
59
|
+
* Cached per service inside the call and, through the FleetContext, across
|
|
60
|
+
* features: a fleet-wide graph asks about the same ten services N times.
|
|
61
|
+
*/
|
|
62
|
+
const livingByService = new Map();
|
|
63
|
+
const living = async (service) => {
|
|
64
|
+
let ids = livingByService.get(service);
|
|
65
|
+
if (ids === undefined) {
|
|
66
|
+
ids = new Set((await operations((await locateServicePaths(docsDir, service, context)).openapi, context))
|
|
67
|
+
.filter((op) => !op.remove)
|
|
68
|
+
.map((op) => op.id));
|
|
69
|
+
livingByService.set(service, ids);
|
|
70
|
+
}
|
|
71
|
+
return ids;
|
|
72
|
+
};
|
|
73
|
+
for (const service of feature.services) {
|
|
74
|
+
const paths = featureSpecPaths(feature.dir, service);
|
|
75
|
+
const livingIds = await living(service);
|
|
76
|
+
for (const axis of SPEC_AXES) {
|
|
77
|
+
const path = paths[axis.key];
|
|
78
|
+
if (!existsSync(path))
|
|
79
|
+
continue;
|
|
80
|
+
const requirements = await context.readRequirements(path);
|
|
81
|
+
for (const requirement of requirements) {
|
|
82
|
+
const fact = { service, axis: axis.file, requirement };
|
|
83
|
+
if (requirement.kind === "ADDED")
|
|
84
|
+
addedRequirements.push(fact);
|
|
85
|
+
if (requirement.kind === "MODIFIED" || requirement.kind === "REMOVED") {
|
|
86
|
+
changedRequirements.push(fact);
|
|
87
|
+
}
|
|
88
|
+
for (const operationId of requirement.operations) {
|
|
89
|
+
// Governing an operation the service already provides is not a
|
|
90
|
+
// dependency on anybody: the contract it needs is already merged.
|
|
91
|
+
if (livingIds.has(operationId))
|
|
92
|
+
continue;
|
|
93
|
+
requiredOperations.push({ service, operationId });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (existsSync(paths.openapi)) {
|
|
98
|
+
const featureOperations = await operations(paths.openapi, context);
|
|
99
|
+
for (const operation of featureOperations) {
|
|
100
|
+
if (livingIds.has(operation.id))
|
|
101
|
+
continue;
|
|
102
|
+
if (operation.remove)
|
|
103
|
+
requiredOperations.push({ service, operationId: operation.id });
|
|
104
|
+
else
|
|
105
|
+
introducedOperations.push({ service, operationId: operation.id });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// The C4 delta is the FOURTH place a feature names an operation, and it was
|
|
110
|
+
// the one the graph could not see: an edge carrying `metadata { op 'x' }` is
|
|
111
|
+
// a call this feature builds on `x`, which is exactly the "must land first"
|
|
112
|
+
// relation this module exists to compute. Validate already says so — it
|
|
113
|
+
// reports `c4-api.op-pending` when the op is defined by another feature in
|
|
114
|
+
// flight — so the graph disagreeing with the validator about the same pair of
|
|
115
|
+
// features was the graph being wrong, not quiet.
|
|
116
|
+
//
|
|
117
|
+
// Endpoints resolve through `serviceResolver` — the element's
|
|
118
|
+
// `metadata { service }` binding, title as fallback — the same join every
|
|
119
|
+
// other check uses, so renaming a box in a diagram cannot silently unhook it
|
|
120
|
+
// here either.
|
|
121
|
+
const deltaPath = featurePaths(feature.dir).delta;
|
|
122
|
+
if (existsSync(deltaPath)) {
|
|
123
|
+
const doc = await context.loadLikeC4(deltaPath);
|
|
124
|
+
// A delta that does not parse proves nothing about who depends on whom.
|
|
125
|
+
// `loam validate` owns that diagnosis (`delta.invalid`); inventing edges out
|
|
126
|
+
// of a half-read document would be worse than the silence.
|
|
127
|
+
if (doc.errors.length === 0) {
|
|
128
|
+
// One resolver for the whole delta: `serviceOf` rebuilds its id map on
|
|
129
|
+
// every call, and this loop asks once per edge. The enumerated fleet —
|
|
130
|
+
// `services/` plus this feature's own `specs/` directories, the same
|
|
131
|
+
// union `enumeratedTarget` probes below — rides into the resolver so a
|
|
132
|
+
// delta that models CONTAINERS keeps its edges attached: without it, an
|
|
133
|
+
// edge into `payment.api` resolves to a service called "api" that has
|
|
134
|
+
// never existed, the op lookup misses the living contract, and the graph
|
|
135
|
+
// invents a dependency (or orders two features that share nothing). An
|
|
136
|
+
// unenumerable services/ falls back to the feature's own names — every
|
|
137
|
+
// living probe would have found nothing there anyway.
|
|
138
|
+
const fleetIds = await enumeratedServiceIds(docsDir, context);
|
|
139
|
+
const svcOf = serviceResolver(doc.elements, new Set([...fleetIds, ...feature.services]));
|
|
140
|
+
// The resolver answers with document text and `living` builds a path, so
|
|
141
|
+
// the name crosses through the enumeration — coherence.ts grades its
|
|
142
|
+
// edges through the same bridge. A name no enumeration vouches for has
|
|
143
|
+
// no living contract anywhere: the op is required, exactly what the
|
|
144
|
+
// probe answered for an absent service.
|
|
145
|
+
const enumeratedTarget = enumeratedServiceIndex(docsDir, feature.services, context);
|
|
146
|
+
for (const rel of doc.relationships) {
|
|
147
|
+
if (rel.op === undefined)
|
|
148
|
+
continue;
|
|
149
|
+
const service = svcOf(rel.target);
|
|
150
|
+
const pathable = await enumeratedTarget(service);
|
|
151
|
+
if (pathable !== undefined && (await living(pathable)).has(rel.op))
|
|
152
|
+
continue;
|
|
153
|
+
requiredOperations.push({ service, operationId: rel.op });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
feature,
|
|
159
|
+
addedRequirements,
|
|
160
|
+
changedRequirements,
|
|
161
|
+
introducedOperations,
|
|
162
|
+
requiredOperations,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=facts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facts.js","sourceRoot":"","sources":["../../../src/core/dependencies/facts.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What one feature ADDS and what it NEEDS, read out of its own delta.\n *\n * The whole graph is built from these five lists and nothing else, which is why\n * they are computed once per feature and indexed rather than re-derived per\n * edge: a feature is a node here only because some other feature's requirement\n * or operation resolves into it, and answering that per pair would be a fleet\n * walk per pair.\n *\n * `reqKeys` returns BOTH spellings of a requirement's identity — the stable\n * `Requirement-ID` and the exact heading — because a legacy requirement has only\n * the second, and an edge that existed under one spelling and not the other\n * would make the graph depend on when the corpus was migrated.\n */\nimport { existsSync } from \"node:fs\";\nimport type { PathableService } from \"../kernel/ids/service.js\";\nimport { FleetContext } from \"../fleet-context.js\";\nimport { serviceResolver } from \"../c4/resolve/service.js\";\nimport { operations } from \"../openapi/doc.js\";\nimport { type FeatureEntry } from \"../repo/entries.js\";\nimport { SPEC_AXES, featurePaths, featureSpecPaths, type SpecAxis } from \"../repo/paths.js\";\nimport { locateServicePaths } from \"../repo/service-target.js\";\nimport { enumeratedServiceIds, enumeratedServiceIndex } from \"../repo/service-target.js\";\nimport type { Requirement } from \"../document/spec.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\n\nexport type DependencyReason =\n | {\n kind: \"requirement\";\n service: string;\n axis: SpecAxis[\"file\"];\n identity: string;\n }\n | { kind: \"operation\"; service: string; operationId: string };\n\nexport interface DependencyEdge {\n /** The feature that consumes/modifies something. */\n from: string;\n /** The feature that introduces it and therefore has to land first. */\n to: string;\n reasons: DependencyReason[];\n}\n\nexport interface FeatureConflict {\n kind: \"requirement\" | \"operation\";\n /**\n * How the owners collide.\n *\n * `added` — two features ADD the same identity (or define the same\n * operationId): whichever archives second replaces the first outright.\n *\n * `changed` — two features MODIFY or REMOVE the same living requirement.\n * That collision was invisible until now, and it is the more common one on a\n * fleet: nobody adds \"Cancel an order\" twice, but two teams editing its text\n * in the same week is a Tuesday. A MODIFIED requirement carries its FULL new\n * text, so the second archive does not merge the first one's wording — it\n * overwrites it, silently and completely.\n */\n change: \"added\" | \"changed\";\n service: string;\n axis?: SpecAxis[\"file\"];\n identity: string;\n features: string[];\n}\n\nexport interface DependencyNode {\n id: string;\n dirName: string;\n services: string[];\n dependsOn: string[];\n}\n\nexport interface DependencyGraph {\n nodes: DependencyNode[];\n edges: DependencyEdge[];\n conflicts: FeatureConflict[];\n /** Dependencies precede their consumers; cyclic members remain deterministic. */\n order: string[];\n /** Strongly connected components with more than one node (or a self-loop). */\n cycles: string[][];\n}\n\nexport interface FeatureFacts {\n feature: FeatureEntry;\n addedRequirements: Array<{\n service: string;\n axis: SpecAxis[\"file\"];\n requirement: Requirement;\n }>;\n changedRequirements: Array<{\n service: string;\n axis: SpecAxis[\"file\"];\n requirement: Requirement;\n }>;\n introducedOperations: Array<{ service: string; operationId: string }>;\n requiredOperations: Array<{ service: string; operationId: string }>;\n}\n\nexport function reqKeys(requirement: Pick<Requirement, \"id\" | \"name\">): string[] {\n return [\n ...(requirement.id === undefined ? [] : [`id:${requirement.id}`]),\n `name:${requirement.name}`,\n ];\n}\n\n/**\n * WHERE a collision happens, kept as fields rather than as a string.\n *\n * An index needs one scalar per entry to hash on, so the fields get NUL-joined\n * into a key — but the conflict records want those fields back, and splitting\n * the key apart again means asserting the pieces back into their types. That\n * assertion is a claim about data loam does not own: a service directory or a\n * requirement name containing a NUL would hand `axis` a fragment of an identity\n * with nothing to notice. Carrying the structured value beside the owner set\n * means the key is only ever a key, and the record is read, not reconstructed.\n */\nexport interface ReqAt {\n service: string;\n axis: SpecAxis[\"file\"];\n identity: string;\n}\n\nexport interface OpAt {\n service: string;\n operationId: string;\n}\n\nexport interface Owners<T> {\n readonly at: T;\n readonly features: Set<string>;\n}\n\nexport function reqIndexKey(at: ReqAt): string {\n return `${at.service}\\0${at.axis}\\0${at.identity}`;\n}\n\nexport function opIndexKey(at: OpAt): string {\n return `${at.service}\\0${at.operationId}`;\n}\n\nexport function addOwner<T>(index: Map<string, Owners<T>>, key: string, at: T, feature: string): void {\n const owners = index.get(key) ?? { at, features: new Set<string>() };\n owners.features.add(feature);\n index.set(key, owners);\n}\n\nexport async function readFacts(\n docsDir: DocsDir,\n feature: FeatureEntry,\n context: FleetContext,\n): Promise<FeatureFacts> {\n const addedRequirements: FeatureFacts[\"addedRequirements\"] = [];\n const changedRequirements: FeatureFacts[\"changedRequirements\"] = [];\n const introducedOperations: FeatureFacts[\"introducedOperations\"] = [];\n const requiredOperations: FeatureFacts[\"requiredOperations\"] = [];\n\n /**\n * The operationIds a service ALREADY has, per service.\n *\n * This is the whole difference between a dependency graph and a rumour mill.\n * A feature's `openapi.yaml` is a COMPLETE document, not a patch — authors\n * restate the living API around the slot they are changing — so every feature\n * that so much as mentions `authorizePayment` used to be recorded as\n * INTRODUCING it, and every other feature governing it as REQUIRING it. Two\n * features quoting the same living operation therefore depended on each other\n * in both directions: an invented cycle, an invented conflict, and an ordering\n * for work that had none. `loam validate`'s coherence pass already subtracts\n * the living contract this way (core/coherence/coherence.ts); this is the\n * same subtraction, so the two cannot disagree about what \"new\" means.\n *\n * Cached per service inside the call and, through the FleetContext, across\n * features: a fleet-wide graph asks about the same ten services N times.\n */\n const livingByService = new Map<string, Set<string>>();\n const living = async (service: PathableService): Promise<Set<string>> => {\n let ids = livingByService.get(service);\n if (ids === undefined) {\n ids = new Set(\n (await operations((await locateServicePaths(docsDir, service, context)).openapi, context))\n .filter((op) => !op.remove)\n .map((op) => op.id),\n );\n livingByService.set(service, ids);\n }\n return ids;\n };\n\n for (const service of feature.services) {\n const paths = featureSpecPaths(feature.dir, service);\n const livingIds = await living(service);\n for (const axis of SPEC_AXES) {\n const path = paths[axis.key];\n if (!existsSync(path)) continue;\n const requirements = await context.readRequirements(path);\n for (const requirement of requirements) {\n const fact = { service, axis: axis.file, requirement };\n if (requirement.kind === \"ADDED\") addedRequirements.push(fact);\n if (requirement.kind === \"MODIFIED\" || requirement.kind === \"REMOVED\") {\n changedRequirements.push(fact);\n }\n for (const operationId of requirement.operations) {\n // Governing an operation the service already provides is not a\n // dependency on anybody: the contract it needs is already merged.\n if (livingIds.has(operationId)) continue;\n requiredOperations.push({ service, operationId });\n }\n }\n }\n\n if (existsSync(paths.openapi)) {\n const featureOperations = await operations(paths.openapi, context);\n for (const operation of featureOperations) {\n if (livingIds.has(operation.id)) continue;\n if (operation.remove) requiredOperations.push({ service, operationId: operation.id });\n else introducedOperations.push({ service, operationId: operation.id });\n }\n }\n }\n\n // The C4 delta is the FOURTH place a feature names an operation, and it was\n // the one the graph could not see: an edge carrying `metadata { op 'x' }` is\n // a call this feature builds on `x`, which is exactly the \"must land first\"\n // relation this module exists to compute. Validate already says so — it\n // reports `c4-api.op-pending` when the op is defined by another feature in\n // flight — so the graph disagreeing with the validator about the same pair of\n // features was the graph being wrong, not quiet.\n //\n // Endpoints resolve through `serviceResolver` — the element's\n // `metadata { service }` binding, title as fallback — the same join every\n // other check uses, so renaming a box in a diagram cannot silently unhook it\n // here either.\n const deltaPath = featurePaths(feature.dir).delta;\n if (existsSync(deltaPath)) {\n const doc = await context.loadLikeC4(deltaPath);\n // A delta that does not parse proves nothing about who depends on whom.\n // `loam validate` owns that diagnosis (`delta.invalid`); inventing edges out\n // of a half-read document would be worse than the silence.\n if (doc.errors.length === 0) {\n // One resolver for the whole delta: `serviceOf` rebuilds its id map on\n // every call, and this loop asks once per edge. The enumerated fleet —\n // `services/` plus this feature's own `specs/` directories, the same\n // union `enumeratedTarget` probes below — rides into the resolver so a\n // delta that models CONTAINERS keeps its edges attached: without it, an\n // edge into `payment.api` resolves to a service called \"api\" that has\n // never existed, the op lookup misses the living contract, and the graph\n // invents a dependency (or orders two features that share nothing). An\n // unenumerable services/ falls back to the feature's own names — every\n // living probe would have found nothing there anyway.\n const fleetIds = await enumeratedServiceIds(docsDir, context);\n const svcOf = serviceResolver(doc.elements, new Set([...fleetIds, ...feature.services]));\n // The resolver answers with document text and `living` builds a path, so\n // the name crosses through the enumeration — coherence.ts grades its\n // edges through the same bridge. A name no enumeration vouches for has\n // no living contract anywhere: the op is required, exactly what the\n // probe answered for an absent service.\n const enumeratedTarget = enumeratedServiceIndex(docsDir, feature.services, context);\n for (const rel of doc.relationships) {\n if (rel.op === undefined) continue;\n const service = svcOf(rel.target);\n const pathable = await enumeratedTarget(service);\n if (pathable !== undefined && (await living(pathable)).has(rel.op)) continue;\n requiredOperations.push({ service, operationId: rel.op });\n }\n }\n }\n\n return {\n feature,\n addedRequirements,\n changedRequirements,\n introducedOperations,\n requiredOperations,\n };\n}\n"]}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fleet fan-in: for each service, how many DISTINCT other known services
|
|
3
|
+
* depend on it — the blast radius behind `loam list --needs-work
|
|
4
|
+
* --review-order`. Reviewing the most-depended-on service first is the one
|
|
5
|
+
* ordering a campaign lead cannot derive by eye from the worklist.
|
|
6
|
+
*
|
|
7
|
+
* Pure derivation, derived-never-stored, in the package that already owns
|
|
8
|
+
* who-depends-on-whom: `core/dependencies/` derives the feature ordering from
|
|
9
|
+
* artifact identities, and this module derives the service-level analog. The
|
|
10
|
+
* command layer (commands/list/review.ts) gathers the inputs from reads the
|
|
11
|
+
* repository already pays for and hands them in as data, so the module itself
|
|
12
|
+
* imports nothing — no IO, no parser import, never prints. The edge slice is
|
|
13
|
+
* structural for the same reason `core/vocabulary/maturity.ts`'s EdgeSource
|
|
14
|
+
* is: `core/c4/likec4.ts`'s `Rel` satisfies it without an import edge into
|
|
15
|
+
* the parser.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Distinct known consumers per service, as a count for every id in
|
|
19
|
+
* `req.services` (0 when nothing depends on it — a proven zero, since only
|
|
20
|
+
* positive evidence ever increments it).
|
|
21
|
+
*
|
|
22
|
+
* Three joins, unioned by DISTINCT consumer so overlapping evidence for one
|
|
23
|
+
* caller counts once:
|
|
24
|
+
* 1. a drawn edge WITHOUT `consumes` into a service — its source is a
|
|
25
|
+
* caller, whether or not the edge carries an `op` (an op edge and a plain
|
|
26
|
+
* edge are one claim of dependence each);
|
|
27
|
+
* 2. a drawn edge carrying `consumes` — the rule of
|
|
28
|
+
* core/c4/direction/direction.ts: `consumes` binds the edge's TARGET as
|
|
29
|
+
* the consumer, so the source is what it consumes from, and an edge drawn
|
|
30
|
+
* producer→consumer is fan-in on the SOURCE. Such an edge contributes
|
|
31
|
+
* join 2 ONLY: on the event spine THE ARROW FOLLOWS THE MESSAGE (the
|
|
32
|
+
* scaffolded landscape's own doctrine, examples/docs' landscape spells
|
|
33
|
+
* it), so the arrow of a delivery edge is not a call into its target —
|
|
34
|
+
* reading it as one would rank a pure event sink above a real dependency
|
|
35
|
+
* and hand a bound broker service one phantom dependant per consumer;
|
|
36
|
+
* 3. the landscape-independent requirement join — a service consumes a
|
|
37
|
+
* message some other service declares `action: send` for.
|
|
38
|
+
* Self-dependence proves nothing, and an endpoint outside the known-service
|
|
39
|
+
* set (an actor, an `#external` system, an unresolved id) is not a fleet
|
|
40
|
+
* caller — review order ranks work the FLEET depends on.
|
|
41
|
+
*/
|
|
42
|
+
export function fleetFanIn(req) {
|
|
43
|
+
const known = new Set(req.services);
|
|
44
|
+
const consumers = new Map();
|
|
45
|
+
const depend = (producer, consumer) => {
|
|
46
|
+
if (producer === consumer)
|
|
47
|
+
return;
|
|
48
|
+
if (!known.has(producer) || !known.has(consumer))
|
|
49
|
+
return;
|
|
50
|
+
const set = consumers.get(producer) ?? new Set();
|
|
51
|
+
set.add(consumer);
|
|
52
|
+
consumers.set(producer, set);
|
|
53
|
+
};
|
|
54
|
+
if (req.landscape.parses) {
|
|
55
|
+
const { relationships, svcOf } = req.landscape;
|
|
56
|
+
for (const r of relationships) {
|
|
57
|
+
const source = svcOf(r.source);
|
|
58
|
+
const target = svcOf(r.target);
|
|
59
|
+
// The variants of the join comment above: a delivery edge (consumes)
|
|
60
|
+
// claims producer→consumer, never a call into its target.
|
|
61
|
+
if (r.consumes === undefined)
|
|
62
|
+
depend(target, source);
|
|
63
|
+
else
|
|
64
|
+
depend(source, target);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Join 3. Producer index first: message name → every service declaring it
|
|
68
|
+
// sent. A message more than one service declares lands its subscribers on
|
|
69
|
+
// every declarer — the derivation never guesses which declaration wins.
|
|
70
|
+
const producers = new Map();
|
|
71
|
+
for (const [id, slice] of req.contracts) {
|
|
72
|
+
if (!known.has(id))
|
|
73
|
+
continue;
|
|
74
|
+
for (const message of slice.sent) {
|
|
75
|
+
producers.set(message, [...(producers.get(message) ?? []), id]);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
for (const [id, slice] of req.contracts) {
|
|
79
|
+
if (!known.has(id))
|
|
80
|
+
continue;
|
|
81
|
+
for (const message of slice.consumed) {
|
|
82
|
+
for (const producer of producers.get(message) ?? [])
|
|
83
|
+
depend(producer, id);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return new Map(req.services.map((id) => [id, consumers.get(id)?.size ?? 0]));
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=fanin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fanin.js","sourceRoot":"","sources":["../../../src/core/dependencies/fanin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AA2CH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,UAAU,CAAC,GAAiB;IAC1C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuB,CAAC;IACjD,MAAM,MAAM,GAAG,CAAC,QAAgB,EAAE,QAAgB,EAAQ,EAAE;QAC1D,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO;QAClC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO;QACzD,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;QACzD,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAClB,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC/B,CAAC,CAAC;IAEF,IAAI,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC;QAC/C,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAC/B,qEAAqE;YACrE,0DAA0D;YAC1D,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS;gBAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;;gBAChD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,0EAA0E;IAC1E,wEAAwE;IACxE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC9C,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QACxC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC7B,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YACjC,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;QACxC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC7B,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACrC,KAAK,MAAM,QAAQ,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE;gBAAE,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC","sourcesContent":["/**\n * Fleet fan-in: for each service, how many DISTINCT other known services\n * depend on it — the blast radius behind `loam list --needs-work\n * --review-order`. Reviewing the most-depended-on service first is the one\n * ordering a campaign lead cannot derive by eye from the worklist.\n *\n * Pure derivation, derived-never-stored, in the package that already owns\n * who-depends-on-whom: `core/dependencies/` derives the feature ordering from\n * artifact identities, and this module derives the service-level analog. The\n * command layer (commands/list/review.ts) gathers the inputs from reads the\n * repository already pays for and hands them in as data, so the module itself\n * imports nothing — no IO, no parser import, never prints. The edge slice is\n * structural for the same reason `core/vocabulary/maturity.ts`'s EdgeSource\n * is: `core/c4/likec4.ts`'s `Rel` satisfies it without an import edge into\n * the parser.\n */\n\n/** The slice of a drawn relationship the joins read. */\nexport interface FanInEdge {\n source: string;\n target: string;\n /** AsyncAPI message this edge CONSUMES — binds the TARGET as the consumer. */\n consumes?: string;\n}\n\n/** One service's contract slice: what it declares it sends, and what its living requirements consume. */\nexport interface FanInContracts {\n /** Message names this service's asyncapi.yaml reaches from an `action: send` operation. */\n sent: readonly string[];\n /** Message names the service's living (non-REMOVED) spec/arch requirements carry on `Consumes:` lines. */\n consumed: readonly string[];\n}\n\n/**\n * The fleet map's contribution, as a variant rather than optional fields: a\n * landscape either parses — and then it has relationships and a resolver — or\n * it proves nothing, and there is no half-state in which `parses: false`\n * arrives carrying edges anyway. Positive evidence only, the rule\n * `landscapeEvidence` (core/vocabulary/maturity.ts) spells for the same map:\n * an absent or unparseable landscape contributes NOTHING to the edge joins,\n * while the requirement join below still counts.\n */\nexport type FanInLandscape =\n | {\n parses: true;\n relationships: readonly FanInEdge[];\n /** The shared container-aware resolver (`core/c4/resolve/service.ts` serviceResolver), widened to plain strings. */\n svcOf: (id: string) => string;\n }\n | { parses: false };\n\nexport interface FanInRequest {\n /** Every known service id — the universe both ends of every join are filtered to. */\n services: readonly string[];\n landscape: FanInLandscape;\n contracts: ReadonlyMap<string, FanInContracts>;\n}\n\n/**\n * Distinct known consumers per service, as a count for every id in\n * `req.services` (0 when nothing depends on it — a proven zero, since only\n * positive evidence ever increments it).\n *\n * Three joins, unioned by DISTINCT consumer so overlapping evidence for one\n * caller counts once:\n * 1. a drawn edge WITHOUT `consumes` into a service — its source is a\n * caller, whether or not the edge carries an `op` (an op edge and a plain\n * edge are one claim of dependence each);\n * 2. a drawn edge carrying `consumes` — the rule of\n * core/c4/direction/direction.ts: `consumes` binds the edge's TARGET as\n * the consumer, so the source is what it consumes from, and an edge drawn\n * producer→consumer is fan-in on the SOURCE. Such an edge contributes\n * join 2 ONLY: on the event spine THE ARROW FOLLOWS THE MESSAGE (the\n * scaffolded landscape's own doctrine, examples/docs' landscape spells\n * it), so the arrow of a delivery edge is not a call into its target —\n * reading it as one would rank a pure event sink above a real dependency\n * and hand a bound broker service one phantom dependant per consumer;\n * 3. the landscape-independent requirement join — a service consumes a\n * message some other service declares `action: send` for.\n * Self-dependence proves nothing, and an endpoint outside the known-service\n * set (an actor, an `#external` system, an unresolved id) is not a fleet\n * caller — review order ranks work the FLEET depends on.\n */\nexport function fleetFanIn(req: FanInRequest): Map<string, number> {\n const known = new Set(req.services);\n const consumers = new Map<string, Set<string>>();\n const depend = (producer: string, consumer: string): void => {\n if (producer === consumer) return;\n if (!known.has(producer) || !known.has(consumer)) return;\n const set = consumers.get(producer) ?? new Set<string>();\n set.add(consumer);\n consumers.set(producer, set);\n };\n\n if (req.landscape.parses) {\n const { relationships, svcOf } = req.landscape;\n for (const r of relationships) {\n const source = svcOf(r.source);\n const target = svcOf(r.target);\n // The variants of the join comment above: a delivery edge (consumes)\n // claims producer→consumer, never a call into its target.\n if (r.consumes === undefined) depend(target, source);\n else depend(source, target);\n }\n }\n\n // Join 3. Producer index first: message name → every service declaring it\n // sent. A message more than one service declares lands its subscribers on\n // every declarer — the derivation never guesses which declaration wins.\n const producers = new Map<string, string[]>();\n for (const [id, slice] of req.contracts) {\n if (!known.has(id)) continue;\n for (const message of slice.sent) {\n producers.set(message, [...(producers.get(message) ?? []), id]);\n }\n }\n for (const [id, slice] of req.contracts) {\n if (!known.has(id)) continue;\n for (const message of slice.consumed) {\n for (const producer of producers.get(message) ?? []) depend(producer, id);\n }\n }\n\n return new Map(req.services.map((id) => [id, consumers.get(id)?.size ?? 0]));\n}\n"]}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The graph arithmetic: which edges exist, which of them form a cycle, and what
|
|
3
|
+
* order the features can be archived in.
|
|
4
|
+
*
|
|
5
|
+
* Kept apart from `./facts.ts` because it knows nothing about requirements or
|
|
6
|
+
* operations — it takes ids and edges. That is what makes the cycle detection
|
|
7
|
+
* and the ordering testable against a graph nobody had to build a fleet for,
|
|
8
|
+
* and it is why `compareIds` sorts every adjacency list: the answer has to be
|
|
9
|
+
* the same on two machines that enumerated the docs tree in different orders.
|
|
10
|
+
*/
|
|
11
|
+
import { compareIds } from "../repo/entries.js";
|
|
12
|
+
import {} from "./facts.js";
|
|
13
|
+
export function compareReasons(a, b) {
|
|
14
|
+
const ak = a.kind === "requirement"
|
|
15
|
+
? `${a.kind}\0${a.service}\0${a.axis}\0${a.identity}`
|
|
16
|
+
: `${a.kind}\0${a.service}\0${a.operationId}`;
|
|
17
|
+
const bk = b.kind === "requirement"
|
|
18
|
+
? `${b.kind}\0${b.service}\0${b.axis}\0${b.identity}`
|
|
19
|
+
: `${b.kind}\0${b.service}\0${b.operationId}`;
|
|
20
|
+
return compareIds(ak, bk);
|
|
21
|
+
}
|
|
22
|
+
export function edgeKey(from, to) {
|
|
23
|
+
return `${from}\0${to}`;
|
|
24
|
+
}
|
|
25
|
+
export function appendReason(edges, from, to, reason) {
|
|
26
|
+
if (from === to)
|
|
27
|
+
return;
|
|
28
|
+
const key = edgeKey(from, to);
|
|
29
|
+
const edge = edges.get(key) ?? { from, to, reasons: [] };
|
|
30
|
+
const encoded = JSON.stringify(reason);
|
|
31
|
+
if (!edge.reasons.some((item) => JSON.stringify(item) === encoded))
|
|
32
|
+
edge.reasons.push(reason);
|
|
33
|
+
edges.set(key, edge);
|
|
34
|
+
}
|
|
35
|
+
export function stronglyConnected(ids, edges) {
|
|
36
|
+
const adjacency = new Map(ids.map((id) => [id, []]));
|
|
37
|
+
for (const edge of edges)
|
|
38
|
+
adjacency.get(edge.from)?.push(edge.to);
|
|
39
|
+
for (const targets of adjacency.values())
|
|
40
|
+
targets.sort(compareIds);
|
|
41
|
+
let nextIndex = 0;
|
|
42
|
+
const indices = new Map();
|
|
43
|
+
const low = new Map();
|
|
44
|
+
const stack = [];
|
|
45
|
+
const onStack = new Set();
|
|
46
|
+
const components = [];
|
|
47
|
+
const visit = (id) => {
|
|
48
|
+
indices.set(id, nextIndex);
|
|
49
|
+
low.set(id, nextIndex);
|
|
50
|
+
nextIndex += 1;
|
|
51
|
+
stack.push(id);
|
|
52
|
+
onStack.add(id);
|
|
53
|
+
for (const target of adjacency.get(id) ?? []) {
|
|
54
|
+
if (!indices.has(target)) {
|
|
55
|
+
visit(target);
|
|
56
|
+
low.set(id, Math.min(low.get(id), low.get(target)));
|
|
57
|
+
}
|
|
58
|
+
else if (onStack.has(target)) {
|
|
59
|
+
low.set(id, Math.min(low.get(id), indices.get(target)));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (low.get(id) !== indices.get(id))
|
|
63
|
+
return;
|
|
64
|
+
const component = [];
|
|
65
|
+
while (stack.length > 0) {
|
|
66
|
+
const member = stack.pop();
|
|
67
|
+
onStack.delete(member);
|
|
68
|
+
component.push(member);
|
|
69
|
+
if (member === id)
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
component.sort(compareIds);
|
|
73
|
+
const selfLoop = component.length === 1
|
|
74
|
+
&& (adjacency.get(component[0]) ?? []).includes(component[0]);
|
|
75
|
+
if (component.length > 1 || selfLoop)
|
|
76
|
+
components.push(component);
|
|
77
|
+
};
|
|
78
|
+
for (const id of [...ids].sort(compareIds))
|
|
79
|
+
if (!indices.has(id))
|
|
80
|
+
visit(id);
|
|
81
|
+
return components.sort((a, b) => compareIds(a[0], b[0]));
|
|
82
|
+
}
|
|
83
|
+
export function dependencyFirstOrder(ids, edges) {
|
|
84
|
+
const deps = new Map(ids.map((id) => [id, []]));
|
|
85
|
+
for (const edge of edges)
|
|
86
|
+
deps.get(edge.from)?.push(edge.to);
|
|
87
|
+
for (const values of deps.values())
|
|
88
|
+
values.sort(compareIds);
|
|
89
|
+
const visited = new Set();
|
|
90
|
+
const visiting = new Set();
|
|
91
|
+
const order = [];
|
|
92
|
+
const visit = (id) => {
|
|
93
|
+
if (visited.has(id) || visiting.has(id))
|
|
94
|
+
return;
|
|
95
|
+
visiting.add(id);
|
|
96
|
+
for (const dependency of deps.get(id) ?? [])
|
|
97
|
+
visit(dependency);
|
|
98
|
+
visiting.delete(id);
|
|
99
|
+
visited.add(id);
|
|
100
|
+
order.push(id);
|
|
101
|
+
};
|
|
102
|
+
for (const id of [...ids].sort(compareIds))
|
|
103
|
+
visit(id);
|
|
104
|
+
return order;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../../../src/core/dependencies/graph.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The graph arithmetic: which edges exist, which of them form a cycle, and what\n * order the features can be archived in.\n *\n * Kept apart from `./facts.ts` because it knows nothing about requirements or\n * operations — it takes ids and edges. That is what makes the cycle detection\n * and the ordering testable against a graph nobody had to build a fleet for,\n * and it is why `compareIds` sorts every adjacency list: the answer has to be\n * the same on two machines that enumerated the docs tree in different orders.\n */\nimport { compareIds } from \"../repo/entries.js\";\nimport { type DependencyEdge, type DependencyReason } from \"./facts.js\";\n\nexport function compareReasons(a: DependencyReason, b: DependencyReason): number {\n const ak = a.kind === \"requirement\"\n ? `${a.kind}\\0${a.service}\\0${a.axis}\\0${a.identity}`\n : `${a.kind}\\0${a.service}\\0${a.operationId}`;\n const bk = b.kind === \"requirement\"\n ? `${b.kind}\\0${b.service}\\0${b.axis}\\0${b.identity}`\n : `${b.kind}\\0${b.service}\\0${b.operationId}`;\n return compareIds(ak, bk);\n}\n\nexport function edgeKey(from: string, to: string): string {\n return `${from}\\0${to}`;\n}\n\nexport function appendReason(\n edges: Map<string, DependencyEdge>,\n from: string,\n to: string,\n reason: DependencyReason,\n): void {\n if (from === to) return;\n const key = edgeKey(from, to);\n const edge = edges.get(key) ?? { from, to, reasons: [] };\n const encoded = JSON.stringify(reason);\n if (!edge.reasons.some((item) => JSON.stringify(item) === encoded)) edge.reasons.push(reason);\n edges.set(key, edge);\n}\n\nexport function stronglyConnected(ids: string[], edges: DependencyEdge[]): string[][] {\n const adjacency = new Map(ids.map((id) => [id, [] as string[]]));\n for (const edge of edges) adjacency.get(edge.from)?.push(edge.to);\n for (const targets of adjacency.values()) targets.sort(compareIds);\n\n let nextIndex = 0;\n const indices = new Map<string, number>();\n const low = new Map<string, number>();\n const stack: string[] = [];\n const onStack = new Set<string>();\n const components: string[][] = [];\n\n const visit = (id: string): void => {\n indices.set(id, nextIndex);\n low.set(id, nextIndex);\n nextIndex += 1;\n stack.push(id);\n onStack.add(id);\n\n for (const target of adjacency.get(id) ?? []) {\n if (!indices.has(target)) {\n visit(target);\n low.set(id, Math.min(low.get(id)!, low.get(target)!));\n } else if (onStack.has(target)) {\n low.set(id, Math.min(low.get(id)!, indices.get(target)!));\n }\n }\n if (low.get(id) !== indices.get(id)) return;\n const component: string[] = [];\n while (stack.length > 0) {\n const member = stack.pop()!;\n onStack.delete(member);\n component.push(member);\n if (member === id) break;\n }\n component.sort(compareIds);\n const selfLoop = component.length === 1\n && (adjacency.get(component[0]!) ?? []).includes(component[0]!);\n if (component.length > 1 || selfLoop) components.push(component);\n };\n\n for (const id of [...ids].sort(compareIds)) if (!indices.has(id)) visit(id);\n return components.sort((a, b) => compareIds(a[0]!, b[0]!));\n}\n\nexport function dependencyFirstOrder(ids: string[], edges: DependencyEdge[]): string[] {\n const deps = new Map(ids.map((id) => [id, [] as string[]]));\n for (const edge of edges) deps.get(edge.from)?.push(edge.to);\n for (const values of deps.values()) values.sort(compareIds);\n const visited = new Set<string>();\n const visiting = new Set<string>();\n const order: string[] = [];\n const visit = (id: string): void => {\n if (visited.has(id) || visiting.has(id)) return;\n visiting.add(id);\n for (const dependency of deps.get(id) ?? []) visit(dependency);\n visiting.delete(id);\n visited.add(id);\n order.push(id);\n };\n for (const id of [...ids].sort(compareIds)) visit(id);\n return order;\n}\n"]}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A feature's own topology: `features/<FEAT>/deployment/<name>.likec4`.
|
|
3
|
+
*
|
|
4
|
+
* Until this slot existed a change that stood up a standby cluster had to be
|
|
5
|
+
* written in two places at once — the requirement in the feature, the topology
|
|
6
|
+
* edited straight into `architecture/` — because `delta.likec4` refuses a
|
|
7
|
+
* `deployment { }` block and always will: that document re-declares the
|
|
8
|
+
* landscape's own identifiers and carries its own `specification`, so it cannot
|
|
9
|
+
* be staged beside the map in one LikeC4 project. A document that declares
|
|
10
|
+
* NEITHER can, which is exactly why the use-case axis put its flows in files of
|
|
11
|
+
* their own, and why this mirrors it rather than inventing a shape.
|
|
12
|
+
*
|
|
13
|
+
* WHAT MAKES IT WORK, and it was measured before the axis was written: LikeC4
|
|
14
|
+
* `extend` resolves across documents of one project. A feature writes
|
|
15
|
+
*
|
|
16
|
+
* deployment {
|
|
17
|
+
* extend eu {
|
|
18
|
+
* dcC = datacenter 'DC-C' { k8sC = cluster 'cluster-c' { … } }
|
|
19
|
+
* }
|
|
20
|
+
* eu.dcA.k8sA -> eu.dcC.k8sC 'async replication'
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* and the living region gains a datacenter with the living file untouched. So
|
|
24
|
+
* the merge is a copy, not a splice, and `unarchive` needs nothing new — a
|
|
25
|
+
* create is undone by deleting, which the snapshot manifest already records for
|
|
26
|
+
* every write in the plan.
|
|
27
|
+
*
|
|
28
|
+
* CREATE-ONLY, for `core/usecases/delta/flows.ts`'s reasons rather than a
|
|
29
|
+
* weaker version of them. A requirement delta merges INTO a living document and
|
|
30
|
+
* two features editing one requirement would overwrite each other silently; a
|
|
31
|
+
* topology document has no such algebra — the file is one block, the merge is a
|
|
32
|
+
* whole-file copy, and there is nothing to merge partially. Rewriting a living
|
|
33
|
+
* one through a feature would be a silent whole-file replacement with no pin to
|
|
34
|
+
* collide on, where editing `architecture/<name>.likec4` directly in the same
|
|
35
|
+
* pull request produces an ordinary git conflict a human resolves.
|
|
36
|
+
*
|
|
37
|
+
* ## Graded against the map its own merge would leave behind
|
|
38
|
+
*
|
|
39
|
+
* `ARCH-LOAM-FEATURE-CORPUS`, and this axis needs it more literally than the
|
|
40
|
+
* use-case one does: a feature that stands a service up in a new cluster
|
|
41
|
+
* declares that service in its `delta.likec4` and instances it here, so the
|
|
42
|
+
* element the topology names exists ONLY post-merge. Read against the living
|
|
43
|
+
* landscape it is unresolved, LikeC4 refuses the whole project, and loam would
|
|
44
|
+
* report a hole against a file whose only fault is arriving with the change
|
|
45
|
+
* that makes it true.
|
|
46
|
+
*
|
|
47
|
+
* The staging is `core/c4/project/staged.ts`, shared with the use-case slot
|
|
48
|
+
* rather than copied — the two would have disagreed first about the merge
|
|
49
|
+
* preview, which is the one thing both refusals rest on.
|
|
50
|
+
*/
|
|
51
|
+
import { existsSync } from "node:fs";
|
|
52
|
+
import { basename, join } from "node:path";
|
|
53
|
+
import { architectureDir } from "../c4/project/architecture.js";
|
|
54
|
+
import { stageMergedProject } from "../c4/project/staged.js";
|
|
55
|
+
import {} from "../c4/likec4.js";
|
|
56
|
+
import { relativeDocuments } from "../c4/project/documents.js";
|
|
57
|
+
import { featureDeploymentDir } from "../repo/authored/paths.js";
|
|
58
|
+
import { reservedArchitectureName } from "../repo/paths.js";
|
|
59
|
+
import {} from "../vocabulary/issue.js";
|
|
60
|
+
/**
|
|
61
|
+
* The topology documents one feature carries, ordered by path.
|
|
62
|
+
*
|
|
63
|
+
* Zero readdirs when the feature has no `deployment/` directory, which is every
|
|
64
|
+
* feature in a fleet that has not adopted the axis: `architectureDocuments`
|
|
65
|
+
* answers an absent directory with an empty list rather than a throw. That
|
|
66
|
+
* directory's existence is the whole per-feature opt-in.
|
|
67
|
+
*/
|
|
68
|
+
export async function featureDeployments(featureDir) {
|
|
69
|
+
return relativeDocuments(featureDeploymentDir(featureDir));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The LIVING path a feature-local topology document addresses.
|
|
73
|
+
*
|
|
74
|
+
* Straight into `architecture/`, with no subdirectory of its own — unlike
|
|
75
|
+
* `architecture/usecases/`, and the difference is the model rather than taste.
|
|
76
|
+
* A `deployment { }` block is part of the fleet's ONE architecture project and
|
|
77
|
+
* is read as such by every loader; filing it under a subdirectory would suggest
|
|
78
|
+
* a second project, which is exactly the reading `subsystems.likec4` and
|
|
79
|
+
* `landscape.likec4` already refuse by sitting at the top level together.
|
|
80
|
+
*
|
|
81
|
+
* `rel` is joined un-split, which `node:path` normalizes. What holds the join is
|
|
82
|
+
* PROVENANCE: every `rel` here came out of an `architectureDocuments` walk, so
|
|
83
|
+
* each component is a directory entry that exists. No caller takes one from argv.
|
|
84
|
+
*/
|
|
85
|
+
export function livingDeploymentPath(docsDir, rel) {
|
|
86
|
+
return join(architectureDir(docsDir), rel);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The two things that can go wrong about a topology document's NAME, before
|
|
90
|
+
* anything about its contents is asked.
|
|
91
|
+
*
|
|
92
|
+
* `deployment.doc-reserved` — the name is one loam owns inside `architecture/`.
|
|
93
|
+
* The merge writes straight into that directory, unlike a flow, which lands
|
|
94
|
+
* under `usecases/`, so `<name>` is free to collide with the living map, either
|
|
95
|
+
* of the two GENERATED views files (`subsystems.likec4` and `services.likec4`),
|
|
96
|
+
* or the flow tree. `reservedArchitectureName` carries which and why. It is
|
|
97
|
+
* asked FIRST and WITHOUT an existence test, because three of the four fail
|
|
98
|
+
* silently when the target does not exist yet.
|
|
99
|
+
*
|
|
100
|
+
* `deployment.doc-exists` — a topology document this feature introduces that
|
|
101
|
+
* the living `architecture/` already holds.
|
|
102
|
+
*
|
|
103
|
+
* An ERROR and never a warning-that-gates, for `usecase.flow-exists`'s reason:
|
|
104
|
+
* there is no legal reading of it. The merge would replace an authored topology
|
|
105
|
+
* wholesale, and no `--approve` makes that a different act than it is. Two
|
|
106
|
+
* features introducing the same file is the case that makes it load-bearing
|
|
107
|
+
* rather than pedantic — whichever archives first creates the living document,
|
|
108
|
+
* and the second is told before it merges that its own file is the one to
|
|
109
|
+
* delete.
|
|
110
|
+
*
|
|
111
|
+
* The collision is on the FILE, not on what is inside it. Two features may both
|
|
112
|
+
* extend the same living region from two documents of their own and both
|
|
113
|
+
* archive; that is the shape `extend` exists for, and refusing it would make the
|
|
114
|
+
* slot useless for the fleet-wide change it was built for.
|
|
115
|
+
*/
|
|
116
|
+
export async function deploymentDeltaIssues(docsDir, featureDir) {
|
|
117
|
+
const docs = await featureDeployments(featureDir);
|
|
118
|
+
const issues = [];
|
|
119
|
+
// The reservation runs FIRST and independently of existence, because three of
|
|
120
|
+
// the four names it refuses need not exist for the merge to be wrong. A
|
|
121
|
+
// topology copied over either GENERATED file — `subsystems.likec4` or
|
|
122
|
+
// `services.likec4` — is destroyed by the next `loam subsystem sync` and is
|
|
123
|
+
// invisible to every project load until then: the merge would report
|
|
124
|
+
// `created architecture/subsystems.likec4` and nothing downstream would ever
|
|
125
|
+
// say another word about it.
|
|
126
|
+
for (const doc of docs) {
|
|
127
|
+
const reason = reservedArchitectureName(doc.rel);
|
|
128
|
+
if (reason === null)
|
|
129
|
+
continue;
|
|
130
|
+
issues.push({
|
|
131
|
+
severity: "error",
|
|
132
|
+
code: "deployment.doc-reserved",
|
|
133
|
+
subject: doc.rel,
|
|
134
|
+
message: `features/<FEAT>/deployment/${doc.rel} would merge to architecture/${doc.rel}, and that name is loam's: ` +
|
|
135
|
+
`${reason}. Rename the feature's document — its name is yours to choose, and \`extend\` is how it adds to ` +
|
|
136
|
+
"what a living document already declares.",
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return issues.concat(docs
|
|
140
|
+
.filter((doc) => reservedArchitectureName(doc.rel) === null)
|
|
141
|
+
.filter((doc) => existsSync(livingDeploymentPath(docsDir, doc.rel)))
|
|
142
|
+
.map((doc) => ({
|
|
143
|
+
severity: "error",
|
|
144
|
+
code: "deployment.doc-exists",
|
|
145
|
+
subject: doc.rel,
|
|
146
|
+
message: `architecture/${doc.rel} already exists, so this feature's topology would replace an authored one wholesale — ` +
|
|
147
|
+
"a feature-local deployment document INTRODUCES topology, it does not rewrite it. " +
|
|
148
|
+
`Delete features/<FEAT>/deployment/${doc.rel} and edit architecture/${doc.rel} directly in this same change, ` +
|
|
149
|
+
"where git produces an ordinary conflict if somebody else is editing it too. " +
|
|
150
|
+
`To ADD to what that file declares, write a document of another name that says \`extend\` — ` +
|
|
151
|
+
`\`${suggest(doc.rel)}\` — which is what lets two features grow one region without touching each other.`,
|
|
152
|
+
})));
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Parse this feature's topology documents over the post-merge map.
|
|
156
|
+
*
|
|
157
|
+
* A feature with no `deployment/` directory is `read` at the cost of one walk
|
|
158
|
+
* over a directory that is not there — the axis's per-feature opt-in, and the
|
|
159
|
+
* whole price a fleet that has not adopted it pays. Nothing is staged, nothing
|
|
160
|
+
* is parsed, and no temp tree is made.
|
|
161
|
+
*
|
|
162
|
+
* The verdict is deliberately BINARY. The use-case overlay hands its caller the
|
|
163
|
+
* views it read because the axis has questions about their content; this one
|
|
164
|
+
* has none — a topology document is checked by being parseable against the map
|
|
165
|
+
* the merge will write, and everything else about it is graded by
|
|
166
|
+
* `loam validate --all` once it is living, exactly as the landscape is.
|
|
167
|
+
*/
|
|
168
|
+
export async function readFeatureDeployments(req) {
|
|
169
|
+
const docs = await featureDeployments(req.featureDir);
|
|
170
|
+
if (docs.length === 0)
|
|
171
|
+
return { kind: "read" };
|
|
172
|
+
// AFTER the early return: the fleet read is paid only by a feature that
|
|
173
|
+
// actually brings a topology document.
|
|
174
|
+
const models = req.models === undefined ? undefined : await req.models();
|
|
175
|
+
const staged = await stageMergedProject({
|
|
176
|
+
docsDir: req.docsDir,
|
|
177
|
+
featureDir: req.featureDir,
|
|
178
|
+
featureId: req.featureId,
|
|
179
|
+
documents: docs.map((doc) => ({ rel: doc.rel, path: doc.path })),
|
|
180
|
+
...(req.load === undefined ? {} : { load: req.load }),
|
|
181
|
+
...(models === undefined ? {} : { models }),
|
|
182
|
+
});
|
|
183
|
+
return staged.kind === "unreadable" ? { kind: "unreadable", errors: staged.errors } : { kind: "read" };
|
|
184
|
+
}
|
|
185
|
+
/** A free name near the colliding one, so the fix is a rename the author can copy. */
|
|
186
|
+
function suggest(rel) {
|
|
187
|
+
const name = basename(rel).replace(/\.likec4$/, "");
|
|
188
|
+
const dir = rel.slice(0, rel.length - basename(rel).length);
|
|
189
|
+
return `${dir}${name}-extend.likec4`;
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=delta.js.map
|