@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,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Does the diff apply to the thing it claims to change?
|
|
3
|
+
*
|
|
4
|
+
* A requirement delta is a diff against a living spec, and nothing used to check
|
|
5
|
+
* that it lands. Every failure mode here is silent today: MODIFIED of a
|
|
6
|
+
* requirement that does not exist is merged as a creation, ADDED of one that
|
|
7
|
+
* does exist REPLACES it (scenarios and all) while the author believes they are
|
|
8
|
+
* adding, and a heading that nearly matches the delta grammar parses as plain
|
|
9
|
+
* prose so archive merges nothing at all and says nothing about it.
|
|
10
|
+
*
|
|
11
|
+
* The last of those has a legal-looking cousin: a requirement under an ordinary
|
|
12
|
+
* prose heading (`## Behavior`, `## Error Handling`) is BASE too, and BASE never
|
|
13
|
+
* merges. Upstream OpenSpec deltas are written that way, so the answer is to name
|
|
14
|
+
* what will be lost rather than to start merging prose sections.
|
|
15
|
+
*
|
|
16
|
+
* These run inside the archive gate, because the merge is where the damage lands.
|
|
17
|
+
*
|
|
18
|
+
* TWO CORPORA, ONE ALGEBRA. A feature's delta documents live in two places —
|
|
19
|
+
* `specs/<svc>/{spec,arch.spec}.md` against the service tree, and
|
|
20
|
+
* `capabilities/<id>/spec.md` against the authored business tree — and every
|
|
21
|
+
* grade about a DOCUMENT and its living counterpart applies to both verbatim,
|
|
22
|
+
* with the capability id in `subject` where a service id would be. That is not
|
|
23
|
+
* a coincidence to exploit but the reason the business corpus was given deltas
|
|
24
|
+
* at all: a capability document is a requirements document, so the diff that
|
|
25
|
+
* changes one has exactly the same ways of not landing. A second implementation
|
|
26
|
+
* would be a second set of answers to `delta.added-duplicate`.
|
|
27
|
+
*
|
|
28
|
+
* The exception is the four CROSS-FEATURE warnings — `delta.added-conflict`,
|
|
29
|
+
* `delta.modified-conflict`, `delta.modified-pending`, `delta.removed-pending`
|
|
30
|
+
* — which ask what OTHER features in flight claim. `./claims.ts` indexes the
|
|
31
|
+
* service corpus only and states why; on the business axis those four are
|
|
32
|
+
* silent, which is a missing warning and never a wrong answer.
|
|
33
|
+
*
|
|
34
|
+
* This module is only the walk: which documents get read, in what order, and how
|
|
35
|
+
* each is handed a `DeltaScope`. The checks themselves are in `./document.ts`
|
|
36
|
+
* (a document against itself) and `./select.ts` (the delta against the living
|
|
37
|
+
* text). Their order is load-bearing and stays here, where it can be read in one
|
|
38
|
+
* screen.
|
|
39
|
+
*/
|
|
40
|
+
import { existsSync } from "node:fs";
|
|
41
|
+
import { readFile } from "node:fs/promises";
|
|
42
|
+
import { relative } from "node:path";
|
|
43
|
+
import { FleetContext } from "../fleet-context.js";
|
|
44
|
+
import { parseRequirements, readRequirementsDocument } from "../document/parse.js";
|
|
45
|
+
import {} from "../document/spec.js";
|
|
46
|
+
import { featureSpecPaths, SPEC_AXES } from "../repo/paths.js";
|
|
47
|
+
import { featureUseCasesDir, livingCapabilityPaths } from "../repo/authored/paths.js";
|
|
48
|
+
import { readCapabilityVocabulary } from "../capabilities/capabilities.js";
|
|
49
|
+
import { extendingModels } from "../c4/service-model/fleet/extending.js";
|
|
50
|
+
import { flowCoverage } from "../usecases/delta/claims.js";
|
|
51
|
+
import { changedPromiseFlowIssues } from "../usecases/delta/modified.js";
|
|
52
|
+
import { enumeratedServiceIds, locateServicePaths } from "../repo/service-target.js";
|
|
53
|
+
import { featureSpecServices } from "../repo/repo.js";
|
|
54
|
+
import { capabilityDocIssues } from "../capabilities/delta/doc.js";
|
|
55
|
+
import { featureCapabilityDeltas } from "../capabilities/delta/tree.js";
|
|
56
|
+
import { removedRealizedIssues, uncoveredIssues, } from "../capabilities/delta/uncovered.js";
|
|
57
|
+
import {} from "../vocabulary/issue.js";
|
|
58
|
+
import { claimLookup } from "./claims.js";
|
|
59
|
+
import { deltaDocumentIssues, livingDocumentIssues } from "./document.js";
|
|
60
|
+
import { indexLiving } from "./scope.js";
|
|
61
|
+
import { selectionIssues } from "./select.js";
|
|
62
|
+
/**
|
|
63
|
+
* The business corpus's ONE axis. A capability document carries the promise and
|
|
64
|
+
* nothing else — there is no `arch.spec.md` beside it, because "how it is
|
|
65
|
+
* built" is precisely the altitude a capability requirement may not describe
|
|
66
|
+
* (`capability.requirement-service-scoped` is that rule). It has no `key`
|
|
67
|
+
* because it indexes no `ServicePaths`, which is why `DeltaScope.axis` is the
|
|
68
|
+
* narrower `DeltaAxis` and not `SpecAxis`.
|
|
69
|
+
*/
|
|
70
|
+
const CAPABILITY_AXIS = { file: "spec.md" };
|
|
71
|
+
export async function deltaShapeIssues(docsDir, featureDir, featureId, context) {
|
|
72
|
+
const issues = [];
|
|
73
|
+
const services = await featureSpecServices(featureDir, context);
|
|
74
|
+
// One `existsSync` for a feature that carries no capability delta, which is
|
|
75
|
+
// every feature in a fleet that has not adopted the business axis.
|
|
76
|
+
const capabilities = context === undefined ? await featureCapabilityDeltas(featureDir) : await context.featureCapabilityDeltas(featureDir);
|
|
77
|
+
// The flows this feature brings, and one `existsSync` for a feature that
|
|
78
|
+
// brings none — which is every feature in a fleet that has not adopted the
|
|
79
|
+
// axis. The directory, not the documents: what is needed here is whether to
|
|
80
|
+
// pay for the overlay at all, and the walk that lists them happens once,
|
|
81
|
+
// inside it.
|
|
82
|
+
const hasFlows = existsSync(featureUseCasesDir(featureDir));
|
|
83
|
+
// The early return must ask about EVERY corpus. Asking only about services
|
|
84
|
+
// meant a capability-only feature — a business change with no service touched
|
|
85
|
+
// yet, which is exactly what an analyst writes first — was graded by nothing
|
|
86
|
+
// and archived whatever its delta said; asking only about those two would do
|
|
87
|
+
// the same to a feature whose whole content is a cross-service flow, which is
|
|
88
|
+
// the shape an architect answers an analyst with.
|
|
89
|
+
if (services.length === 0 && capabilities.docs.length === 0 && !hasFlows)
|
|
90
|
+
return issues;
|
|
91
|
+
// What OTHER features in flight claim. Only built when a claim has to be
|
|
92
|
+
// checked — the common case never pays for the scan.
|
|
93
|
+
const reads = {
|
|
94
|
+
claims: claimLookup(docsDir, featureId, context),
|
|
95
|
+
...(context === undefined ? {} : { context }),
|
|
96
|
+
};
|
|
97
|
+
// The two corpora's parsed requirements, kept as the walk produces them so
|
|
98
|
+
// the `Realizes:` join below can be taken without re-reading a byte. That
|
|
99
|
+
// join is the one question neither corpus can answer alone — which service
|
|
100
|
+
// requirement keeps which business promise — and this is the only place in
|
|
101
|
+
// loam where both sides are already open (`capabilities/delta/uncovered.ts`
|
|
102
|
+
// holds the rules; nothing here decides anything).
|
|
103
|
+
const serviceDeltas = [];
|
|
104
|
+
const capabilityDeltas = [];
|
|
105
|
+
// Each service axis beside its living document, for the one question that
|
|
106
|
+
// needs both: which living flow claims a requirement this feature changes.
|
|
107
|
+
const servicePairs = [];
|
|
108
|
+
// Both requirement-carrying files per service run the same checks — one code
|
|
109
|
+
// path parameterized by filename, the merge's own factoring. `where` names
|
|
110
|
+
// the arch file in messages so a finding cannot be chased into the wrong
|
|
111
|
+
// document; spec.md keeps its historical spelling.
|
|
112
|
+
for (const service of services) {
|
|
113
|
+
for (const axis of SPEC_AXES) {
|
|
114
|
+
const specPath = featureSpecPaths(featureDir, service)[axis.key];
|
|
115
|
+
if (!existsSync(specPath))
|
|
116
|
+
continue;
|
|
117
|
+
const scope = {
|
|
118
|
+
kind: "service",
|
|
119
|
+
subject: service,
|
|
120
|
+
axis,
|
|
121
|
+
featureId,
|
|
122
|
+
docsDir,
|
|
123
|
+
specPath,
|
|
124
|
+
where: axis.key === "spec" ? service : `${service} (arch.spec.md)`,
|
|
125
|
+
// How the axis's living document is named in messages — spec.md keeps
|
|
126
|
+
// the historical "living spec", the arch axis says which file it means.
|
|
127
|
+
livingDoc: axis.key === "spec" ? "living spec" : "living arch.spec.md",
|
|
128
|
+
};
|
|
129
|
+
const graded = await gradeDelta(scope, (await locateServicePaths(docsDir, service, context))[axis.key], reads);
|
|
130
|
+
issues.push(...graded.issues);
|
|
131
|
+
serviceDeltas.push({ service, file: axis.file, reqs: graded.reqs });
|
|
132
|
+
const paths = () => locateServicePaths(docsDir, service, context);
|
|
133
|
+
servicePairs.push({ id: service, axis: axis.key, reqs: graded.reqs, living: graded.living.all, paths });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
for (const doc of capabilities.docs) {
|
|
137
|
+
const scope = {
|
|
138
|
+
kind: "capability",
|
|
139
|
+
subject: doc.id,
|
|
140
|
+
axis: CAPABILITY_AXIS,
|
|
141
|
+
featureId,
|
|
142
|
+
docsDir,
|
|
143
|
+
specPath: doc.spec,
|
|
144
|
+
// `capability <id>`, not `capabilities/<id>` — the second reads as the
|
|
145
|
+
// LIVING directory, and every message this labels is about the FEATURE's
|
|
146
|
+
// delta of it. Sending an author to edit the wrong one of two files with
|
|
147
|
+
// the same name is the whole reason `where` and `livingDoc` are separate.
|
|
148
|
+
where: `capability ${doc.id}`,
|
|
149
|
+
livingDoc: `living capabilities/${doc.id}/spec.md`,
|
|
150
|
+
};
|
|
151
|
+
// Absent is a real and ordinary answer on this axis: the first feature to
|
|
152
|
+
// mention a capability is what creates its living document, so the whole
|
|
153
|
+
// delta grades against `[]` and every requirement in it is legitimately an
|
|
154
|
+
// addition.
|
|
155
|
+
const graded = await gradeDelta(scope, livingCapabilityPaths(docsDir, doc.id).spec, reads);
|
|
156
|
+
issues.push(...graded.issues);
|
|
157
|
+
// The document's own three rules, on the requirements this delta would
|
|
158
|
+
// MERGE — before the merge, where the author can still fix them. See
|
|
159
|
+
// `capabilities/delta/doc.ts` for why grading only the living copy leaves a
|
|
160
|
+
// hole straight through the altitude rule.
|
|
161
|
+
issues.push(...capabilityDocIssues(graded.reqs, {
|
|
162
|
+
where: relative(docsDir, doc.spec).split(/[\\/]/).join("/"),
|
|
163
|
+
subject: doc.id,
|
|
164
|
+
}));
|
|
165
|
+
capabilityDeltas.push({ id: doc.id, reqs: graded.reqs, living: graded.living.all });
|
|
166
|
+
}
|
|
167
|
+
// The other carrier of a promise, read once and only when this feature
|
|
168
|
+
// actually brings a flow: the `dynamic view`s under `features/<FEAT>/usecases/`,
|
|
169
|
+
// parsed over the map this feature's own merge would leave behind
|
|
170
|
+
// (`core/usecases/delta/overlay.ts`).
|
|
171
|
+
// A feature with no `usecases/` directory is a REAL empty answer, not an
|
|
172
|
+
// ungraded one: there is no flow, so "no flow keeps this" is true and the
|
|
173
|
+
// message may say it.
|
|
174
|
+
const flows = hasFlows
|
|
175
|
+
? await flowCoverage({
|
|
176
|
+
docsDir,
|
|
177
|
+
featureDir,
|
|
178
|
+
featureId,
|
|
179
|
+
capabilities: capabilityDeltas,
|
|
180
|
+
// Read HERE, through the invocation's index, because this module holds
|
|
181
|
+
// it and `core/usecases/` does not — every other read in this walk does
|
|
182
|
+
// the same, and `core/repo/service-target.ts` prices a fleet
|
|
183
|
+
// enumeration per call at ~13 ms on a 120-service fleet.
|
|
184
|
+
vocabulary: context === undefined ? await readCapabilityVocabulary(docsDir) : await context.capabilities(docsDir),
|
|
185
|
+
// The fleet the merge leaves: each `specs/<svc>/` of this feature becomes a
|
|
186
|
+
// `services/<svc>/`, so a hop into a service it introduces resolves to that
|
|
187
|
+
// service in the grade, as it will under the next `validate --all`.
|
|
188
|
+
known: new Set([...(await enumeratedServiceIds(docsDir, context)), ...services]),
|
|
189
|
+
// Decoded or refused by name (`readRequirementsDocument`), never `readFile`'s
|
|
190
|
+
// utf8 — a UTF-16 capability document would read as no requirements and
|
|
191
|
+
// convict every flow naming it.
|
|
192
|
+
read: async (path) => (context === undefined ? parseRequirements(await readRequirementsDocument(path)) : await context.readRequirements(path)),
|
|
193
|
+
// A function rather than the context itself: one memoised LikeC4 read
|
|
194
|
+
// does not justify an edge from `core/usecases/` to `fleet-context`, and
|
|
195
|
+
// the edge would push that package up a DAG level for nothing.
|
|
196
|
+
...(context === undefined ? {} : { load: (path) => context.loadLikeC4(path) }),
|
|
197
|
+
// The fleet's extending models, for the merge preview the overlay
|
|
198
|
+
// grades against — read HERE for `vocabulary`'s reason exactly, and as
|
|
199
|
+
// a thunk so the walk pays for it only when a flow is really there.
|
|
200
|
+
// Without it the preview is the pre-routing map and `usecase.flow-invalid`
|
|
201
|
+
// fails open on the one shape it exists for: a hop into
|
|
202
|
+
// `<service-fqn>.<container>`, which the archive routes into that
|
|
203
|
+
// service's own model (verification 2026-09-04, review F8).
|
|
204
|
+
models: () => extendingModels(docsDir, context),
|
|
205
|
+
})
|
|
206
|
+
: { promises: { kind: "read", kept: [] }, issues: [] };
|
|
207
|
+
const kept = flows.promises;
|
|
208
|
+
if (kept.kind === "unreadable") {
|
|
209
|
+
// ERROR, and the archive gate's own `NEVER_OVERRIDABLE` keeps `--approve`
|
|
210
|
+
// off it. This is the refusal that stops a flow being copied into
|
|
211
|
+
// `architecture/` and the NEXT reader's `loam validate --all` carrying the
|
|
212
|
+
// failure — including the case the overlay exists for, a hop naming an
|
|
213
|
+
// element the merge does not land. Mechanical, so it is not loam's judgement
|
|
214
|
+
// to override.
|
|
215
|
+
issues.push({
|
|
216
|
+
severity: "error",
|
|
217
|
+
code: "usecase.flow-invalid",
|
|
218
|
+
subject: featureId,
|
|
219
|
+
// The opening sentence does NOT say whose file is at fault, and that is
|
|
220
|
+
// deliberate: the corpus this reads is the feature's flows PLUS the living
|
|
221
|
+
// `architecture/` documents they are drawn over, so the failing path can
|
|
222
|
+
// be a living one — a landscape that no longer parses, a use case somebody
|
|
223
|
+
// else wrote. Every message carries its own path, so a reader can place
|
|
224
|
+
// it; an opening line that blamed `usecases/` would send them to the wrong
|
|
225
|
+
// file first.
|
|
226
|
+
message: `this feature's flows could not be graded against the map its own merge would leave behind, so the archive ` +
|
|
227
|
+
`would land an architecture/ nothing has checked. The corpus is the feature's usecases/ AND the living ` +
|
|
228
|
+
`architecture/ documents they are drawn over, so the fault may be in either — each message names its file. ` +
|
|
229
|
+
`${kept.errors.length} problem(s): ${kept.errors.join("; ")}`,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
// And the flows that DID read, graded as `validate --all` grades them once
|
|
233
|
+
// living: every hop against the post-merge map, every `#cap-`/`#req-` tag
|
|
234
|
+
// against the vocabulary and requirements the merge leaves
|
|
235
|
+
// (`core/usecases/grade/feature.ts`). Before this, a hop nothing backs and a
|
|
236
|
+
// `#req-` tag nothing resolves archived clean and turned the fleet red.
|
|
237
|
+
issues.push(...flows.issues);
|
|
238
|
+
// The `Realizes:` join, both directions, over documents this walk has already
|
|
239
|
+
// parsed. Skipped entirely when the feature carries no capability delta,
|
|
240
|
+
// which is every feature in a fleet that has not adopted the business axis —
|
|
241
|
+
// and the removal half asks for the living corpus only when something is
|
|
242
|
+
// actually retired, so even an adopting fleet pays the fleet-wide read on the
|
|
243
|
+
// features that earn it.
|
|
244
|
+
if (capabilityDeltas.length > 0) {
|
|
245
|
+
// The three arms travel as three, and flattening two of them to `[]` is
|
|
246
|
+
// the one thing this must not do: `capability.uncovered` says in words that
|
|
247
|
+
// no flow keeps the promise, so handing it an empty list for a corpus loam
|
|
248
|
+
// could not read or could not resolve makes it assert a negative it never
|
|
249
|
+
// evaluated — and gate on it. `claims.ts`'s header states the rule; this is
|
|
250
|
+
// where a caller could break it.
|
|
251
|
+
issues.push(...uncoveredIssues(capabilityDeltas, serviceDeltas, kept.kind === "read"
|
|
252
|
+
? { graded: true, kept: kept.kept }
|
|
253
|
+
: { graded: false, why: kept.kind === "ungraded" ? kept.why : kept.errors.join("; ") }));
|
|
254
|
+
issues.push(...(await removedRealizedIssues({
|
|
255
|
+
capabilities: capabilityDeltas,
|
|
256
|
+
deltas: serviceDeltas,
|
|
257
|
+
living: () => livingRealizers(docsDir, context),
|
|
258
|
+
})));
|
|
259
|
+
}
|
|
260
|
+
// The living flows whose `#req-` tag claims a promise this feature rewrites or
|
|
261
|
+
// retires (`core/usecases/delta/modified.ts`). Asked only when a requirement is
|
|
262
|
+
// MODIFIED or REMOVED, on either corpus, so no other feature reads a flow for it.
|
|
263
|
+
if ([...capabilityDeltas, ...servicePairs].some((doc) => doc.reqs.some((r) => r.kind === "MODIFIED" || r.kind === "REMOVED"))) {
|
|
264
|
+
const ctx = context ?? new FleetContext();
|
|
265
|
+
issues.push(...(await changedPromiseFlowIssues({
|
|
266
|
+
docsDir,
|
|
267
|
+
capabilities: capabilityDeltas,
|
|
268
|
+
services: servicePairs,
|
|
269
|
+
vocabulary: await ctx.capabilities(docsDir),
|
|
270
|
+
known: new Set(await enumeratedServiceIds(docsDir, ctx)),
|
|
271
|
+
serviceModel: (paths) => ctx.serviceModel(docsDir, paths),
|
|
272
|
+
architecture: () => ctx.architecture(docsDir),
|
|
273
|
+
readRequirements: (path) => ctx.readRequirements(path),
|
|
274
|
+
})));
|
|
275
|
+
}
|
|
276
|
+
return issues;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Every LIVING service requirements document in the fleet, for the one question
|
|
280
|
+
* that has to ask about services this feature never mentions: does anything out
|
|
281
|
+
* there still realize a capability requirement this feature retires?
|
|
282
|
+
*
|
|
283
|
+
* The same shape and the same cost `openapi.remove-op-consumed` pays through
|
|
284
|
+
* the consumer index (`core/consumers/`) one axis over, and for the same reason — the merge
|
|
285
|
+
* deletes the promise while the `Realizes:` line stays, so the very next
|
|
286
|
+
* `validate --all` reports a breach on a repository whose author was never in
|
|
287
|
+
* this feature. Called behind a thunk (`removedRealizedIssues` invokes it only
|
|
288
|
+
* when something is retired), so a feature that removes nothing never runs it.
|
|
289
|
+
*/
|
|
290
|
+
async function livingRealizers(docsDir, context) {
|
|
291
|
+
const out = [];
|
|
292
|
+
for (const service of await enumeratedServiceIds(docsDir, context)) {
|
|
293
|
+
const paths = await locateServicePaths(docsDir, service, context);
|
|
294
|
+
for (const axis of SPEC_AXES) {
|
|
295
|
+
const path = paths[axis.key];
|
|
296
|
+
if (!existsSync(path))
|
|
297
|
+
continue;
|
|
298
|
+
const reqs = context === undefined ? parseRequirements(await readFile(path, "utf8")) : await context.readRequirements(path);
|
|
299
|
+
out.push({ service, file: axis.file, reqs });
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return out;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* One delta document against one living document: the three passes, in the
|
|
306
|
+
* order that makes their messages readable.
|
|
307
|
+
*
|
|
308
|
+
* The order is load-bearing. `deltaDocumentIssues` settles what the delta says
|
|
309
|
+
* about itself, `livingDocumentIssues` settles whether the living text can be
|
|
310
|
+
* selected in at all, and only then does `selectionIssues` compare them — a pin
|
|
311
|
+
* the document pass already refused must not also be reported stale, which
|
|
312
|
+
* would send its author to `loam rebase` for a problem rebase does not fix.
|
|
313
|
+
*
|
|
314
|
+
* The parsed delta requirements come back with the issues because the capability
|
|
315
|
+
* corpus grades them a second way (`capabilityDocIssues`) and re-reading the
|
|
316
|
+
* file to do it would be a second parse of bytes already in hand — and, without
|
|
317
|
+
* a context, a second chance for the two passes to disagree about the document.
|
|
318
|
+
* The LIVING index rides back for the same reason once more: the removal
|
|
319
|
+
* direction of the `Realizes:` join has to resolve a REMOVED spelled by heading
|
|
320
|
+
* into the id it retires, and that id is a fact about the living document.
|
|
321
|
+
*/
|
|
322
|
+
async function gradeDelta(scope, livingPath, reads) {
|
|
323
|
+
const { claims, context } = reads;
|
|
324
|
+
const raw = context === undefined ? await readFile(scope.specPath, "utf8") : await context.readText(scope.specPath);
|
|
325
|
+
const reqs = context === undefined ? parseRequirements(raw) : await context.readRequirements(scope.specPath);
|
|
326
|
+
const living = indexLiving(!existsSync(livingPath)
|
|
327
|
+
? []
|
|
328
|
+
: context === undefined
|
|
329
|
+
? parseRequirements(await readFile(livingPath, "utf8"))
|
|
330
|
+
: await context.readRequirements(livingPath));
|
|
331
|
+
return {
|
|
332
|
+
reqs,
|
|
333
|
+
living,
|
|
334
|
+
issues: [
|
|
335
|
+
...deltaDocumentIssues(scope, raw, reqs),
|
|
336
|
+
...livingDocumentIssues(scope, living),
|
|
337
|
+
...(await selectionIssues(scope, reqs, living, claims)),
|
|
338
|
+
],
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
//# sourceMappingURL=delta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta.js","sourceRoot":"","sources":["../../../src/core/delta/delta.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Does the diff apply to the thing it claims to change?\n *\n * A requirement delta is a diff against a living spec, and nothing used to check\n * that it lands. Every failure mode here is silent today: MODIFIED of a\n * requirement that does not exist is merged as a creation, ADDED of one that\n * does exist REPLACES it (scenarios and all) while the author believes they are\n * adding, and a heading that nearly matches the delta grammar parses as plain\n * prose so archive merges nothing at all and says nothing about it.\n *\n * The last of those has a legal-looking cousin: a requirement under an ordinary\n * prose heading (`## Behavior`, `## Error Handling`) is BASE too, and BASE never\n * merges. Upstream OpenSpec deltas are written that way, so the answer is to name\n * what will be lost rather than to start merging prose sections.\n *\n * These run inside the archive gate, because the merge is where the damage lands.\n *\n * TWO CORPORA, ONE ALGEBRA. A feature's delta documents live in two places —\n * `specs/<svc>/{spec,arch.spec}.md` against the service tree, and\n * `capabilities/<id>/spec.md` against the authored business tree — and every\n * grade about a DOCUMENT and its living counterpart applies to both verbatim,\n * with the capability id in `subject` where a service id would be. That is not\n * a coincidence to exploit but the reason the business corpus was given deltas\n * at all: a capability document is a requirements document, so the diff that\n * changes one has exactly the same ways of not landing. A second implementation\n * would be a second set of answers to `delta.added-duplicate`.\n *\n * The exception is the four CROSS-FEATURE warnings — `delta.added-conflict`,\n * `delta.modified-conflict`, `delta.modified-pending`, `delta.removed-pending`\n * — which ask what OTHER features in flight claim. `./claims.ts` indexes the\n * service corpus only and states why; on the business axis those four are\n * silent, which is a missing warning and never a wrong answer.\n *\n * This module is only the walk: which documents get read, in what order, and how\n * each is handed a `DeltaScope`. The checks themselves are in `./document.ts`\n * (a document against itself) and `./select.ts` (the delta against the living\n * text). Their order is load-bearing and stays here, where it can be read in one\n * screen.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { relative } from \"node:path\";\nimport { FleetContext } from \"../fleet-context.js\";\nimport { parseRequirements, readRequirementsDocument } from \"../document/parse.js\";\nimport { type Requirement } from \"../document/spec.js\";\nimport { featureSpecPaths, SPEC_AXES } from \"../repo/paths.js\";\nimport { featureUseCasesDir, livingCapabilityPaths } from \"../repo/authored/paths.js\";\nimport { readCapabilityVocabulary } from \"../capabilities/capabilities.js\";\nimport { extendingModels } from \"../c4/service-model/fleet/extending.js\";\n\nimport { flowCoverage, type FlowPromises } from \"../usecases/delta/claims.js\";\nimport { changedPromiseFlowIssues, type ServiceDeltaPair } from \"../usecases/delta/modified.js\";\nimport { enumeratedServiceIds, locateServicePaths } from \"../repo/service-target.js\";\nimport { featureSpecServices } from \"../repo/repo.js\";\nimport { capabilityDocIssues } from \"../capabilities/delta/doc.js\";\nimport { featureCapabilityDeltas } from \"../capabilities/delta/tree.js\";\nimport {\n removedRealizedIssues,\n uncoveredIssues,\n type CapabilityDeltaDoc,\n type RealizingDoc,\n} from \"../capabilities/delta/uncovered.js\";\nimport { type Issue } from \"../vocabulary/issue.js\";\nimport { claimLookup, type ClaimLookup } from \"./claims.js\";\nimport { deltaDocumentIssues, livingDocumentIssues } from \"./document.js\";\nimport { indexLiving, type DeltaScope, type LivingIndex } from \"./scope.js\";\nimport { selectionIssues } from \"./select.js\";\nimport type { DocsDir, FeatureDir } from \"../kernel/ids/dirs.js\";\n\n/**\n * The business corpus's ONE axis. A capability document carries the promise and\n * nothing else — there is no `arch.spec.md` beside it, because \"how it is\n * built\" is precisely the altitude a capability requirement may not describe\n * (`capability.requirement-service-scoped` is that rule). It has no `key`\n * because it indexes no `ServicePaths`, which is why `DeltaScope.axis` is the\n * narrower `DeltaAxis` and not `SpecAxis`.\n */\nconst CAPABILITY_AXIS = { file: \"spec.md\" };\n\n/**\n * What every document in one feature's walk shares.\n *\n * A record rather than two more parameters because both values are about the\n * WALK and not about the document being graded — `gradeDelta` would otherwise\n * read as a four-argument function whose last two arguments never vary within\n * a run, which is how the next value gets added as a fifth.\n */\ninterface DeltaReads {\n /** What OTHER features in flight claim — lazy, so the common case never scans. */\n claims: ClaimLookup;\n /** The invocation's read index, when the caller threaded one. */\n context?: FleetContext;\n}\n\nexport async function deltaShapeIssues(\n docsDir: DocsDir,\n featureDir: FeatureDir,\n featureId: string,\n context?: FleetContext,\n): Promise<Issue[]> {\n const issues: Issue[] = [];\n const services = await featureSpecServices(featureDir, context);\n // One `existsSync` for a feature that carries no capability delta, which is\n // every feature in a fleet that has not adopted the business axis.\n const capabilities =\n context === undefined ? await featureCapabilityDeltas(featureDir) : await context.featureCapabilityDeltas(featureDir);\n // The flows this feature brings, and one `existsSync` for a feature that\n // brings none — which is every feature in a fleet that has not adopted the\n // axis. The directory, not the documents: what is needed here is whether to\n // pay for the overlay at all, and the walk that lists them happens once,\n // inside it.\n const hasFlows = existsSync(featureUseCasesDir(featureDir));\n // The early return must ask about EVERY corpus. Asking only about services\n // meant a capability-only feature — a business change with no service touched\n // yet, which is exactly what an analyst writes first — was graded by nothing\n // and archived whatever its delta said; asking only about those two would do\n // the same to a feature whose whole content is a cross-service flow, which is\n // the shape an architect answers an analyst with.\n if (services.length === 0 && capabilities.docs.length === 0 && !hasFlows) return issues;\n\n // What OTHER features in flight claim. Only built when a claim has to be\n // checked — the common case never pays for the scan.\n const reads: DeltaReads = {\n claims: claimLookup(docsDir, featureId, context),\n ...(context === undefined ? {} : { context }),\n };\n\n // The two corpora's parsed requirements, kept as the walk produces them so\n // the `Realizes:` join below can be taken without re-reading a byte. That\n // join is the one question neither corpus can answer alone — which service\n // requirement keeps which business promise — and this is the only place in\n // loam where both sides are already open (`capabilities/delta/uncovered.ts`\n // holds the rules; nothing here decides anything).\n const serviceDeltas: RealizingDoc[] = [];\n const capabilityDeltas: CapabilityDeltaDoc[] = [];\n // Each service axis beside its living document, for the one question that\n // needs both: which living flow claims a requirement this feature changes.\n const servicePairs: ServiceDeltaPair[] = [];\n\n // Both requirement-carrying files per service run the same checks — one code\n // path parameterized by filename, the merge's own factoring. `where` names\n // the arch file in messages so a finding cannot be chased into the wrong\n // document; spec.md keeps its historical spelling.\n for (const service of services) {\n for (const axis of SPEC_AXES) {\n const specPath = featureSpecPaths(featureDir, service)[axis.key];\n if (!existsSync(specPath)) continue;\n const scope: DeltaScope = {\n kind: \"service\",\n subject: service,\n axis,\n featureId,\n docsDir,\n specPath,\n where: axis.key === \"spec\" ? service : `${service} (arch.spec.md)`,\n // How the axis's living document is named in messages — spec.md keeps\n // the historical \"living spec\", the arch axis says which file it means.\n livingDoc: axis.key === \"spec\" ? \"living spec\" : \"living arch.spec.md\",\n };\n const graded = await gradeDelta(scope, (await locateServicePaths(docsDir, service, context))[axis.key], reads);\n issues.push(...graded.issues);\n serviceDeltas.push({ service, file: axis.file, reqs: graded.reqs });\n const paths = (): ReturnType<typeof locateServicePaths> => locateServicePaths(docsDir, service, context);\n servicePairs.push({ id: service, axis: axis.key, reqs: graded.reqs, living: graded.living.all, paths });\n }\n }\n\n for (const doc of capabilities.docs) {\n const scope: DeltaScope = {\n kind: \"capability\",\n subject: doc.id,\n axis: CAPABILITY_AXIS,\n featureId,\n docsDir,\n specPath: doc.spec,\n // `capability <id>`, not `capabilities/<id>` — the second reads as the\n // LIVING directory, and every message this labels is about the FEATURE's\n // delta of it. Sending an author to edit the wrong one of two files with\n // the same name is the whole reason `where` and `livingDoc` are separate.\n where: `capability ${doc.id}`,\n livingDoc: `living capabilities/${doc.id}/spec.md`,\n };\n // Absent is a real and ordinary answer on this axis: the first feature to\n // mention a capability is what creates its living document, so the whole\n // delta grades against `[]` and every requirement in it is legitimately an\n // addition.\n const graded = await gradeDelta(scope, livingCapabilityPaths(docsDir, doc.id).spec, reads);\n issues.push(...graded.issues);\n // The document's own three rules, on the requirements this delta would\n // MERGE — before the merge, where the author can still fix them. See\n // `capabilities/delta/doc.ts` for why grading only the living copy leaves a\n // hole straight through the altitude rule.\n issues.push(\n ...capabilityDocIssues(graded.reqs, {\n where: relative(docsDir, doc.spec).split(/[\\\\/]/).join(\"/\"),\n subject: doc.id,\n }),\n );\n capabilityDeltas.push({ id: doc.id, reqs: graded.reqs, living: graded.living.all });\n }\n\n // The other carrier of a promise, read once and only when this feature\n // actually brings a flow: the `dynamic view`s under `features/<FEAT>/usecases/`,\n // parsed over the map this feature's own merge would leave behind\n // (`core/usecases/delta/overlay.ts`).\n // A feature with no `usecases/` directory is a REAL empty answer, not an\n // ungraded one: there is no flow, so \"no flow keeps this\" is true and the\n // message may say it.\n const flows: { promises: FlowPromises; issues: Issue[] } = hasFlows\n ? await flowCoverage({\n docsDir,\n featureDir,\n featureId,\n capabilities: capabilityDeltas,\n // Read HERE, through the invocation's index, because this module holds\n // it and `core/usecases/` does not — every other read in this walk does\n // the same, and `core/repo/service-target.ts` prices a fleet\n // enumeration per call at ~13 ms on a 120-service fleet.\n vocabulary: context === undefined ? await readCapabilityVocabulary(docsDir) : await context.capabilities(docsDir),\n // The fleet the merge leaves: each `specs/<svc>/` of this feature becomes a\n // `services/<svc>/`, so a hop into a service it introduces resolves to that\n // service in the grade, as it will under the next `validate --all`.\n known: new Set([...(await enumeratedServiceIds(docsDir, context)), ...services]),\n // Decoded or refused by name (`readRequirementsDocument`), never `readFile`'s\n // utf8 — a UTF-16 capability document would read as no requirements and\n // convict every flow naming it.\n read: async (path) => (context === undefined ? parseRequirements(await readRequirementsDocument(path)) : await context.readRequirements(path)),\n // A function rather than the context itself: one memoised LikeC4 read\n // does not justify an edge from `core/usecases/` to `fleet-context`, and\n // the edge would push that package up a DAG level for nothing.\n ...(context === undefined ? {} : { load: (path: string) => context.loadLikeC4(path) }),\n // The fleet's extending models, for the merge preview the overlay\n // grades against — read HERE for `vocabulary`'s reason exactly, and as\n // a thunk so the walk pays for it only when a flow is really there.\n // Without it the preview is the pre-routing map and `usecase.flow-invalid`\n // fails open on the one shape it exists for: a hop into\n // `<service-fqn>.<container>`, which the archive routes into that\n // service's own model (verification 2026-09-04, review F8).\n models: () => extendingModels(docsDir, context),\n })\n : { promises: { kind: \"read\", kept: [] }, issues: [] };\n const kept = flows.promises;\n if (kept.kind === \"unreadable\") {\n // ERROR, and the archive gate's own `NEVER_OVERRIDABLE` keeps `--approve`\n // off it. This is the refusal that stops a flow being copied into\n // `architecture/` and the NEXT reader's `loam validate --all` carrying the\n // failure — including the case the overlay exists for, a hop naming an\n // element the merge does not land. Mechanical, so it is not loam's judgement\n // to override.\n issues.push({\n severity: \"error\",\n code: \"usecase.flow-invalid\",\n subject: featureId,\n // The opening sentence does NOT say whose file is at fault, and that is\n // deliberate: the corpus this reads is the feature's flows PLUS the living\n // `architecture/` documents they are drawn over, so the failing path can\n // be a living one — a landscape that no longer parses, a use case somebody\n // else wrote. Every message carries its own path, so a reader can place\n // it; an opening line that blamed `usecases/` would send them to the wrong\n // file first.\n message:\n `this feature's flows could not be graded against the map its own merge would leave behind, so the archive ` +\n `would land an architecture/ nothing has checked. The corpus is the feature's usecases/ AND the living ` +\n `architecture/ documents they are drawn over, so the fault may be in either — each message names its file. ` +\n `${kept.errors.length} problem(s): ${kept.errors.join(\"; \")}`,\n });\n }\n // And the flows that DID read, graded as `validate --all` grades them once\n // living: every hop against the post-merge map, every `#cap-`/`#req-` tag\n // against the vocabulary and requirements the merge leaves\n // (`core/usecases/grade/feature.ts`). Before this, a hop nothing backs and a\n // `#req-` tag nothing resolves archived clean and turned the fleet red.\n issues.push(...flows.issues);\n\n // The `Realizes:` join, both directions, over documents this walk has already\n // parsed. Skipped entirely when the feature carries no capability delta,\n // which is every feature in a fleet that has not adopted the business axis —\n // and the removal half asks for the living corpus only when something is\n // actually retired, so even an adopting fleet pays the fleet-wide read on the\n // features that earn it.\n if (capabilityDeltas.length > 0) {\n // The three arms travel as three, and flattening two of them to `[]` is\n // the one thing this must not do: `capability.uncovered` says in words that\n // no flow keeps the promise, so handing it an empty list for a corpus loam\n // could not read or could not resolve makes it assert a negative it never\n // evaluated — and gate on it. `claims.ts`'s header states the rule; this is\n // where a caller could break it.\n issues.push(\n ...uncoveredIssues(\n capabilityDeltas,\n serviceDeltas,\n kept.kind === \"read\"\n ? { graded: true, kept: kept.kept }\n : { graded: false, why: kept.kind === \"ungraded\" ? kept.why : kept.errors.join(\"; \") },\n ),\n );\n issues.push(\n ...(await removedRealizedIssues({\n capabilities: capabilityDeltas,\n deltas: serviceDeltas,\n living: () => livingRealizers(docsDir, context),\n })),\n );\n }\n\n // The living flows whose `#req-` tag claims a promise this feature rewrites or\n // retires (`core/usecases/delta/modified.ts`). Asked only when a requirement is\n // MODIFIED or REMOVED, on either corpus, so no other feature reads a flow for it.\n if ([...capabilityDeltas, ...servicePairs].some((doc) => doc.reqs.some((r) => r.kind === \"MODIFIED\" || r.kind === \"REMOVED\"))) {\n const ctx = context ?? new FleetContext();\n issues.push(\n ...(await changedPromiseFlowIssues({\n docsDir,\n capabilities: capabilityDeltas,\n services: servicePairs,\n vocabulary: await ctx.capabilities(docsDir),\n known: new Set(await enumeratedServiceIds(docsDir, ctx)),\n serviceModel: (paths) => ctx.serviceModel(docsDir, paths),\n architecture: () => ctx.architecture(docsDir),\n readRequirements: (path) => ctx.readRequirements(path),\n })),\n );\n }\n\n return issues;\n}\n\n/**\n * Every LIVING service requirements document in the fleet, for the one question\n * that has to ask about services this feature never mentions: does anything out\n * there still realize a capability requirement this feature retires?\n *\n * The same shape and the same cost `openapi.remove-op-consumed` pays through\n * the consumer index (`core/consumers/`) one axis over, and for the same reason — the merge\n * deletes the promise while the `Realizes:` line stays, so the very next\n * `validate --all` reports a breach on a repository whose author was never in\n * this feature. Called behind a thunk (`removedRealizedIssues` invokes it only\n * when something is retired), so a feature that removes nothing never runs it.\n */\nasync function livingRealizers(docsDir: DocsDir, context?: FleetContext): Promise<RealizingDoc[]> {\n const out: RealizingDoc[] = [];\n for (const service of await enumeratedServiceIds(docsDir, context)) {\n const paths = await locateServicePaths(docsDir, service, context);\n for (const axis of SPEC_AXES) {\n const path = paths[axis.key];\n if (!existsSync(path)) continue;\n const reqs =\n context === undefined ? parseRequirements(await readFile(path, \"utf8\")) : await context.readRequirements(path);\n out.push({ service, file: axis.file, reqs });\n }\n }\n return out;\n}\n\n/**\n * One delta document against one living document: the three passes, in the\n * order that makes their messages readable.\n *\n * The order is load-bearing. `deltaDocumentIssues` settles what the delta says\n * about itself, `livingDocumentIssues` settles whether the living text can be\n * selected in at all, and only then does `selectionIssues` compare them — a pin\n * the document pass already refused must not also be reported stale, which\n * would send its author to `loam rebase` for a problem rebase does not fix.\n *\n * The parsed delta requirements come back with the issues because the capability\n * corpus grades them a second way (`capabilityDocIssues`) and re-reading the\n * file to do it would be a second parse of bytes already in hand — and, without\n * a context, a second chance for the two passes to disagree about the document.\n * The LIVING index rides back for the same reason once more: the removal\n * direction of the `Realizes:` join has to resolve a REMOVED spelled by heading\n * into the id it retires, and that id is a fact about the living document.\n */\nasync function gradeDelta(\n scope: DeltaScope,\n livingPath: string,\n reads: DeltaReads,\n): Promise<{ issues: Issue[]; reqs: Requirement[]; living: LivingIndex }> {\n const { claims, context } = reads;\n const raw = context === undefined ? await readFile(scope.specPath, \"utf8\") : await context.readText(scope.specPath);\n const reqs = context === undefined ? parseRequirements(raw) : await context.readRequirements(scope.specPath);\n const living = indexLiving(\n !existsSync(livingPath)\n ? []\n : context === undefined\n ? parseRequirements(await readFile(livingPath, \"utf8\"))\n : await context.readRequirements(livingPath),\n );\n return {\n reqs,\n living,\n issues: [\n ...deltaDocumentIssues(scope, raw, reqs),\n ...livingDocumentIssues(scope, living),\n ...(await selectionIssues(scope, reqs, living, claims)),\n ],\n };\n}\n"]}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a requirements document says about ITSELF — graded before anything is
|
|
3
|
+
* compared against another document.
|
|
4
|
+
*
|
|
5
|
+
* Both the delta and the living spec come through here, because the failures are
|
|
6
|
+
* the same class: a heading that nearly matches the delta grammar, an identity
|
|
7
|
+
* declared twice or shared by two requirements, a `Based-On:` nobody can
|
|
8
|
+
* evaluate. Settling them first is what lets `./select.ts` assume the two
|
|
9
|
+
* documents are at least internally answerable — a pin the document pass already
|
|
10
|
+
* refused must not also be reported stale, which would send its author to
|
|
11
|
+
* `loam rebase` for a problem rebase does not fix.
|
|
12
|
+
*/
|
|
13
|
+
import { relative } from "node:path";
|
|
14
|
+
import {} from "../vocabulary/issue.js";
|
|
15
|
+
import { sectionHeadings } from "../document/parse.js";
|
|
16
|
+
import { basedOnDeclarations, KIND_RE, REQUIREMENT_DIGEST_LENGTH, REQUIREMENT_DIGEST_RE, requirementIdProblems, } from "../document/spec.js";
|
|
17
|
+
import {} from "./scope.js";
|
|
18
|
+
/**
|
|
19
|
+
* `## <word> Requirement(s)` — the shape an author reaches for. Anything matching
|
|
20
|
+
* this but not the real grammar is a near miss: `## ADDED Requirement` (singular),
|
|
21
|
+
* `## NEW Requirements`, `## ADDED Requirements:`. A bare `## Requirements` is not
|
|
22
|
+
* a near miss — quoting the living state inside a delta is legal.
|
|
23
|
+
*/
|
|
24
|
+
const NEAR_SECTION_RE = /^##\s+[A-Za-z]+\s+Requirements?\s*:?\s*$/i;
|
|
25
|
+
/**
|
|
26
|
+
* OpenSpec's fourth delta operation. NEAR_SECTION_RE already catches it, but the
|
|
27
|
+
* generic advice would mislead: a RENAMED body is FROM/TO backtick bullets, not
|
|
28
|
+
* `### Requirement:` headings, so it parses to zero requirements and even the
|
|
29
|
+
* whole-file check below has nothing to count — the heading is the only place to
|
|
30
|
+
* stop it. Rename semantics stay unimplemented (the corpus never uses them); the
|
|
31
|
+
* error says what to write instead.
|
|
32
|
+
*/
|
|
33
|
+
const RENAMED_SECTION_RE = /^##\s+RENAMED\s+Requirements?\s*:?\s*$/i;
|
|
34
|
+
// The one non-delta heading whose requirements are SUPPOSED not to merge — a
|
|
35
|
+
// delta quoting the living state for context — is `## Requirements`, matched by
|
|
36
|
+
// the shared isRequirementsHeading (spec.ts): the same definition that fixes
|
|
37
|
+
// archive's rewrite boundary, so "legal to quote" and "where the merge writes"
|
|
38
|
+
// cannot drift apart. Every other heading — `## Behavior`, `## Error Handling`,
|
|
39
|
+
// `## Notes` — leaves its requirements as BASE, which the merge skips, so the
|
|
40
|
+
// author wrote a change that will never land.
|
|
41
|
+
/** Everything wrong with the DELTA document on its own terms. */
|
|
42
|
+
export function deltaDocumentIssues(scope, raw, reqs) {
|
|
43
|
+
const { docsDir, subject, specPath, where } = scope;
|
|
44
|
+
const issues = [];
|
|
45
|
+
for (const heading of sectionHeadings(raw)) {
|
|
46
|
+
if (KIND_RE.test(heading.text) || !NEAR_SECTION_RE.test(heading.text))
|
|
47
|
+
continue;
|
|
48
|
+
issues.push({
|
|
49
|
+
severity: "error",
|
|
50
|
+
code: "delta.unknown-section",
|
|
51
|
+
subject,
|
|
52
|
+
message: RENAMED_SECTION_RE.test(heading.text)
|
|
53
|
+
? `${where}: '${heading.text}' (line ${heading.line}) is OpenSpec rename syntax, which loam does not merge — carry one stable Requirement-ID through a MODIFIED requirement, or express a legacy rename as a REMOVED requirement plus an ADDED one; otherwise the rename happens to nothing`
|
|
54
|
+
: `${where}: '${heading.text}' (line ${heading.line}) is not a delta section — use '## ADDED Requirements', '## MODIFIED Requirements' or '## REMOVED Requirements', or everything under it merges as nothing`,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
for (const problem of requirementIdProblems(reqs)) {
|
|
58
|
+
if (problem.kind === "invalid") {
|
|
59
|
+
issues.push({
|
|
60
|
+
severity: "error",
|
|
61
|
+
code: "delta.requirement-id-invalid",
|
|
62
|
+
subject,
|
|
63
|
+
message: `${where}: requirement '${problem.requirement}' has invalid Requirement-ID '${problem.value}' — use 1-128 characters matching [A-Za-z][A-Za-z0-9._-]*`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else if (problem.kind === "repeated") {
|
|
67
|
+
issues.push({
|
|
68
|
+
severity: "error",
|
|
69
|
+
code: "delta.requirement-id-repeated",
|
|
70
|
+
subject,
|
|
71
|
+
message: `${where}: requirement '${problem.requirement}' declares Requirement-ID ${problem.values.length} times — identity must be declared exactly once`,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
issues.push({
|
|
76
|
+
severity: "error",
|
|
77
|
+
code: "delta.requirement-id-duplicate",
|
|
78
|
+
subject,
|
|
79
|
+
message: `${where}: Requirement-ID '${problem.id}' is shared by ${problem.requirements.map((name) => `'${name}'`).join(", ")} — one ID may identify only one requirement`,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// The `Based-On:` pin as a DOCUMENT question, settled before anything is
|
|
84
|
+
// compared against the living spec: a value that is not a digest, or two
|
|
85
|
+
// of them on one requirement, is a pin nobody can evaluate — and a pin
|
|
86
|
+
// that silently protects nothing is worse than no pin at all, because its
|
|
87
|
+
// author believes they are covered. ADDED is refused for the same reason
|
|
88
|
+
// rather than ignored: a requirement with no living version cannot have
|
|
89
|
+
// been written against one, so the line is a misunderstanding today and a
|
|
90
|
+
// digest-shaped lie on the day someone turns it into a MODIFIED.
|
|
91
|
+
for (const r of reqs) {
|
|
92
|
+
const declared = basedOnDeclarations(r);
|
|
93
|
+
if (declared.length > 1) {
|
|
94
|
+
issues.push({
|
|
95
|
+
severity: "error",
|
|
96
|
+
code: "delta.baseline-invalid",
|
|
97
|
+
subject,
|
|
98
|
+
message: `${where}: requirement '${r.name}' declares Based-On ${declared.length} times — a delta is written against exactly one living version`,
|
|
99
|
+
});
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const pin = declared[0];
|
|
103
|
+
if (pin === undefined)
|
|
104
|
+
continue;
|
|
105
|
+
if (!REQUIREMENT_DIGEST_RE.test(pin)) {
|
|
106
|
+
issues.push({
|
|
107
|
+
severity: "error",
|
|
108
|
+
code: "delta.baseline-invalid",
|
|
109
|
+
subject,
|
|
110
|
+
message: `${where}: requirement '${r.name}' has invalid Based-On '${pin}' — expected ${REQUIREMENT_DIGEST_LENGTH} lowercase hex characters, as \`loam rebase\` writes them`,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
else if (r.kind === "ADDED") {
|
|
114
|
+
issues.push({
|
|
115
|
+
severity: "error",
|
|
116
|
+
code: "delta.baseline-invalid",
|
|
117
|
+
subject,
|
|
118
|
+
message: `${where}: ADDED requirement '${r.name}' carries Based-On '${pin}', but an added requirement has no living version to be based on — drop the line, or make it MODIFIED`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// The whole-file version of the near-miss check, and the one that cannot be
|
|
123
|
+
// dodged: NEAR_SECTION_RE only recognizes single-word misses (`## NEW
|
|
124
|
+
// Requirements`), so `## NEWLY ADDED Requirements` — or requirements under a
|
|
125
|
+
// prose heading, or under no heading at all — still parses everything as BASE
|
|
126
|
+
// and archive merges nothing, silently. Same failure class as the BOM incident
|
|
127
|
+
// (see spec.ts). A file that MIXES delta sections with quoted BASE requirements
|
|
128
|
+
// is legal authoring; a file with requirements and no delta kind anywhere is a
|
|
129
|
+
// delta that would do nothing, which cannot be what its author meant.
|
|
130
|
+
if (reqs.length > 0 && reqs.every((r) => r.kind === "BASE")) {
|
|
131
|
+
const rel = relative(docsDir, specPath).split(/[\\/]/).join("/");
|
|
132
|
+
issues.push({
|
|
133
|
+
severity: "error",
|
|
134
|
+
code: "delta.no-delta-sections",
|
|
135
|
+
subject,
|
|
136
|
+
message: `${subject}: ${rel} contains ${reqs.length} requirement(s) but no '## ADDED|MODIFIED|REMOVED Requirements' section — this delta would merge nothing`,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return issues;
|
|
140
|
+
}
|
|
141
|
+
/** Everything wrong with the LIVING document that stops a delta selecting in it. */
|
|
142
|
+
export function livingDocumentIssues(scope, living) {
|
|
143
|
+
const { subject, where, livingDoc } = scope;
|
|
144
|
+
const issues = [];
|
|
145
|
+
for (const problem of requirementIdProblems(living.all)) {
|
|
146
|
+
issues.push({
|
|
147
|
+
severity: "error",
|
|
148
|
+
code: "delta.living-requirement-id-invalid",
|
|
149
|
+
subject,
|
|
150
|
+
message: problem.kind === "invalid"
|
|
151
|
+
? `${where}: the ${livingDoc} requirement '${problem.requirement}' has invalid Requirement-ID '${problem.value}', so this delta cannot select it safely`
|
|
152
|
+
: problem.kind === "repeated"
|
|
153
|
+
? `${where}: the ${livingDoc} requirement '${problem.requirement}' declares Requirement-ID more than once, so this delta cannot select it safely`
|
|
154
|
+
: `${where}: the ${livingDoc} shares Requirement-ID '${problem.id}' across ${problem.requirements.map((name) => `'${name}'`).join(", ")}, so this delta cannot select one safely`,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
// Two living requirements under one heading make the delta algebra
|
|
158
|
+
// disagree with itself on the SAME input: MODIFIED replaces the first
|
|
159
|
+
// match (findIndex) while REMOVED deletes every match (filter). So one
|
|
160
|
+
// delta edits one of the twins and leaves the other, and the next one
|
|
161
|
+
// deletes both — and neither outcome is what an author reading the
|
|
162
|
+
// living document could have predicted. Gating rather than advisory,
|
|
163
|
+
// because there is no reading of the delta that makes the merge correct;
|
|
164
|
+
// the fix is in the living document, and it is one rename.
|
|
165
|
+
for (const [name, twins] of living.byName) {
|
|
166
|
+
if (twins.length < 2)
|
|
167
|
+
continue;
|
|
168
|
+
issues.push({
|
|
169
|
+
severity: "error",
|
|
170
|
+
code: "delta.living-duplicate-requirement",
|
|
171
|
+
subject,
|
|
172
|
+
message: `${where}: the ${livingDoc} declares ${twins.length} requirements named '${name}' — MODIFIED would rewrite only the first and REMOVED would delete both, so no delta applies to it predictably. Give them distinct names (or distinct Requirement-IDs and headings) first.`,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
return issues;
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.js","sourceRoot":"","sources":["../../../src/core/delta/document.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What a requirements document says about ITSELF — graded before anything is\n * compared against another document.\n *\n * Both the delta and the living spec come through here, because the failures are\n * the same class: a heading that nearly matches the delta grammar, an identity\n * declared twice or shared by two requirements, a `Based-On:` nobody can\n * evaluate. Settling them first is what lets `./select.ts` assume the two\n * documents are at least internally answerable — a pin the document pass already\n * refused must not also be reported stale, which would send its author to\n * `loam rebase` for a problem rebase does not fix.\n */\nimport { relative } from \"node:path\";\nimport { type Issue } from \"../vocabulary/issue.js\";\nimport { sectionHeadings } from \"../document/parse.js\";\nimport {\n basedOnDeclarations,\n KIND_RE,\n REQUIREMENT_DIGEST_LENGTH,\n REQUIREMENT_DIGEST_RE,\n requirementIdProblems,\n type Requirement,\n} from \"../document/spec.js\";\nimport { type DeltaScope, type LivingIndex } from \"./scope.js\";\n\n/**\n * `## <word> Requirement(s)` — the shape an author reaches for. Anything matching\n * this but not the real grammar is a near miss: `## ADDED Requirement` (singular),\n * `## NEW Requirements`, `## ADDED Requirements:`. A bare `## Requirements` is not\n * a near miss — quoting the living state inside a delta is legal.\n */\nconst NEAR_SECTION_RE = /^##\\s+[A-Za-z]+\\s+Requirements?\\s*:?\\s*$/i;\n\n/**\n * OpenSpec's fourth delta operation. NEAR_SECTION_RE already catches it, but the\n * generic advice would mislead: a RENAMED body is FROM/TO backtick bullets, not\n * `### Requirement:` headings, so it parses to zero requirements and even the\n * whole-file check below has nothing to count — the heading is the only place to\n * stop it. Rename semantics stay unimplemented (the corpus never uses them); the\n * error says what to write instead.\n */\nconst RENAMED_SECTION_RE = /^##\\s+RENAMED\\s+Requirements?\\s*:?\\s*$/i;\n\n// The one non-delta heading whose requirements are SUPPOSED not to merge — a\n// delta quoting the living state for context — is `## Requirements`, matched by\n// the shared isRequirementsHeading (spec.ts): the same definition that fixes\n// archive's rewrite boundary, so \"legal to quote\" and \"where the merge writes\"\n// cannot drift apart. Every other heading — `## Behavior`, `## Error Handling`,\n// `## Notes` — leaves its requirements as BASE, which the merge skips, so the\n// author wrote a change that will never land.\n\n/** Everything wrong with the DELTA document on its own terms. */\nexport function deltaDocumentIssues(scope: DeltaScope, raw: string, reqs: Requirement[]): Issue[] {\n const { docsDir, subject, specPath, where } = scope;\n const issues: Issue[] = [];\n for (const heading of sectionHeadings(raw)) {\n if (KIND_RE.test(heading.text) || !NEAR_SECTION_RE.test(heading.text)) continue;\n issues.push({\n severity: \"error\",\n code: \"delta.unknown-section\",\n subject,\n message: RENAMED_SECTION_RE.test(heading.text)\n ? `${where}: '${heading.text}' (line ${heading.line}) is OpenSpec rename syntax, which loam does not merge — carry one stable Requirement-ID through a MODIFIED requirement, or express a legacy rename as a REMOVED requirement plus an ADDED one; otherwise the rename happens to nothing`\n : `${where}: '${heading.text}' (line ${heading.line}) is not a delta section — use '## ADDED Requirements', '## MODIFIED Requirements' or '## REMOVED Requirements', or everything under it merges as nothing`,\n });\n }\n\n for (const problem of requirementIdProblems(reqs)) {\n if (problem.kind === \"invalid\") {\n issues.push({\n severity: \"error\",\n code: \"delta.requirement-id-invalid\",\n subject,\n message: `${where}: requirement '${problem.requirement}' has invalid Requirement-ID '${problem.value}' — use 1-128 characters matching [A-Za-z][A-Za-z0-9._-]*`,\n });\n } else if (problem.kind === \"repeated\") {\n issues.push({\n severity: \"error\",\n code: \"delta.requirement-id-repeated\",\n subject,\n message: `${where}: requirement '${problem.requirement}' declares Requirement-ID ${problem.values.length} times — identity must be declared exactly once`,\n });\n } else {\n issues.push({\n severity: \"error\",\n code: \"delta.requirement-id-duplicate\",\n subject,\n message: `${where}: Requirement-ID '${problem.id}' is shared by ${problem.requirements.map((name) => `'${name}'`).join(\", \")} — one ID may identify only one requirement`,\n });\n }\n }\n\n // The `Based-On:` pin as a DOCUMENT question, settled before anything is\n // compared against the living spec: a value that is not a digest, or two\n // of them on one requirement, is a pin nobody can evaluate — and a pin\n // that silently protects nothing is worse than no pin at all, because its\n // author believes they are covered. ADDED is refused for the same reason\n // rather than ignored: a requirement with no living version cannot have\n // been written against one, so the line is a misunderstanding today and a\n // digest-shaped lie on the day someone turns it into a MODIFIED.\n for (const r of reqs) {\n const declared = basedOnDeclarations(r);\n if (declared.length > 1) {\n issues.push({\n severity: \"error\",\n code: \"delta.baseline-invalid\",\n subject,\n message: `${where}: requirement '${r.name}' declares Based-On ${declared.length} times — a delta is written against exactly one living version`,\n });\n continue;\n }\n const pin = declared[0];\n if (pin === undefined) continue;\n if (!REQUIREMENT_DIGEST_RE.test(pin)) {\n issues.push({\n severity: \"error\",\n code: \"delta.baseline-invalid\",\n subject,\n message: `${where}: requirement '${r.name}' has invalid Based-On '${pin}' — expected ${REQUIREMENT_DIGEST_LENGTH} lowercase hex characters, as \\`loam rebase\\` writes them`,\n });\n } else if (r.kind === \"ADDED\") {\n issues.push({\n severity: \"error\",\n code: \"delta.baseline-invalid\",\n subject,\n message: `${where}: ADDED requirement '${r.name}' carries Based-On '${pin}', but an added requirement has no living version to be based on — drop the line, or make it MODIFIED`,\n });\n }\n }\n\n // The whole-file version of the near-miss check, and the one that cannot be\n // dodged: NEAR_SECTION_RE only recognizes single-word misses (`## NEW\n // Requirements`), so `## NEWLY ADDED Requirements` — or requirements under a\n // prose heading, or under no heading at all — still parses everything as BASE\n // and archive merges nothing, silently. Same failure class as the BOM incident\n // (see spec.ts). A file that MIXES delta sections with quoted BASE requirements\n // is legal authoring; a file with requirements and no delta kind anywhere is a\n // delta that would do nothing, which cannot be what its author meant.\n if (reqs.length > 0 && reqs.every((r) => r.kind === \"BASE\")) {\n const rel = relative(docsDir, specPath).split(/[\\\\/]/).join(\"/\");\n issues.push({\n severity: \"error\",\n code: \"delta.no-delta-sections\",\n subject,\n message: `${subject}: ${rel} contains ${reqs.length} requirement(s) but no '## ADDED|MODIFIED|REMOVED Requirements' section — this delta would merge nothing`,\n });\n }\n return issues;\n}\n\n/** Everything wrong with the LIVING document that stops a delta selecting in it. */\nexport function livingDocumentIssues(scope: DeltaScope, living: LivingIndex): Issue[] {\n const { subject, where, livingDoc } = scope;\n const issues: Issue[] = [];\n for (const problem of requirementIdProblems(living.all)) {\n issues.push({\n severity: \"error\",\n code: \"delta.living-requirement-id-invalid\",\n subject,\n message:\n problem.kind === \"invalid\"\n ? `${where}: the ${livingDoc} requirement '${problem.requirement}' has invalid Requirement-ID '${problem.value}', so this delta cannot select it safely`\n : problem.kind === \"repeated\"\n ? `${where}: the ${livingDoc} requirement '${problem.requirement}' declares Requirement-ID more than once, so this delta cannot select it safely`\n : `${where}: the ${livingDoc} shares Requirement-ID '${problem.id}' across ${problem.requirements.map((name) => `'${name}'`).join(\", \")}, so this delta cannot select one safely`,\n });\n }\n\n // Two living requirements under one heading make the delta algebra\n // disagree with itself on the SAME input: MODIFIED replaces the first\n // match (findIndex) while REMOVED deletes every match (filter). So one\n // delta edits one of the twins and leaves the other, and the next one\n // deletes both — and neither outcome is what an author reading the\n // living document could have predicted. Gating rather than advisory,\n // because there is no reading of the delta that makes the merge correct;\n // the fix is in the living document, and it is one rename.\n for (const [name, twins] of living.byName) {\n if (twins.length < 2) continue;\n issues.push({\n severity: \"error\",\n code: \"delta.living-duplicate-requirement\",\n subject,\n message: `${where}: the ${livingDoc} declares ${twins.length} requirements named '${name}' — MODIFIED would rewrite only the first and REMOVED would delete both, so no delta applies to it predictably. Give them distinct names (or distinct Requirement-IDs and headings) first.`,\n });\n }\n return issues;\n}\n"]}
|