@ybotok/loam 0.1.0-beta.2 → 0.2.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2570 -61
- package/COMPARISON.md +80 -63
- package/CONTRIBUTING.md +84 -0
- package/MIGRATING-from-OpenSpec.md +213 -54
- package/QUICKSTART.md +125 -0
- package/README.md +450 -150
- package/ROADMAP.md +494 -0
- package/SCHEMA.md +2362 -245
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +701 -0
- package/dist/cli.js +113 -19
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +209 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +268 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +77 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +159 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +317 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +161 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +111 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +237 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +27 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +251 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/context/context.js +99 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +283 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +279 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +205 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +9 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +93 -0
- package/dist/commands/diff/diff.js.map +1 -0
- package/dist/commands/diff/print.js +38 -0
- package/dist/commands/diff/print.js.map +1 -0
- package/dist/commands/doctor.js +5 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +151 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +29 -24
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +115 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +54 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +146 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +246 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +149 -0
- package/dist/commands/gherkin/reconcile.js.map +1 -0
- package/dist/commands/gherkin/render.js +77 -0
- package/dist/commands/gherkin/render.js.map +1 -0
- package/dist/commands/init/example.js +204 -0
- package/dist/commands/init/example.js.map +1 -0
- package/dist/commands/init/first-hour.js +28 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +146 -71
- package/dist/commands/init/init.js.map +1 -0
- package/dist/commands/init/mcp.js +131 -0
- package/dist/commands/init/mcp.js.map +1 -0
- package/dist/commands/init/options.js +78 -0
- package/dist/commands/init/options.js.map +1 -0
- package/dist/commands/instructions.js +82 -14
- package/dist/commands/instructions.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +65 -0
- package/dist/commands/list/campaign/campaign.js.map +1 -0
- package/dist/commands/list/campaign/owners.js +65 -0
- package/dist/commands/list/campaign/owners.js.map +1 -0
- package/dist/commands/list/json.js +157 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +343 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +301 -0
- package/dist/commands/list/print.js.map +1 -0
- package/dist/commands/list/review.js +120 -0
- package/dist/commands/list/review.js.map +1 -0
- package/dist/commands/list/views.js +105 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +183 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +34 -0
- package/dist/commands/mcp/mcp.js.map +1 -0
- package/dist/commands/mcp/serve.js +55 -0
- package/dist/commands/mcp/serve.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/active.js +170 -0
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
- package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/living.js +62 -0
- package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/target.js +219 -0
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +19 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/read.js +49 -0
- package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
- package/dist/commands/migrate-openspec/print.js +89 -0
- package/dist/commands/migrate-openspec/print.js.map +1 -0
- package/dist/commands/new/commit.js +76 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/new.js +283 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +355 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +203 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/policy/format.js +152 -0
- package/dist/commands/policy/format.js.map +1 -0
- package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
- package/dist/commands/policy/gate.js.map +1 -0
- package/dist/commands/rebase/edit.js +106 -0
- package/dist/commands/rebase/edit.js.map +1 -0
- package/dist/commands/rebase/living.js +185 -0
- package/dist/commands/rebase/living.js.map +1 -0
- package/dist/commands/rebase/plan.js +245 -0
- package/dist/commands/rebase/plan.js.map +1 -0
- package/dist/commands/rebase/rebase.js +275 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +192 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +133 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +172 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +178 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/marks.js +24 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/{show.js → show/service.js} +63 -152
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +77 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/json.js +45 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +157 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +119 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +189 -0
- package/dist/commands/steps/steps.js.map +1 -0
- package/dist/commands/subsystem/edit.js +192 -0
- package/dist/commands/subsystem/edit.js.map +1 -0
- package/dist/commands/subsystem/move.js +265 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +115 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +101 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +103 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +94 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +70 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +160 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +67 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +194 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +296 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +55 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +254 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +76 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/checks/vocabulary.js +31 -0
- package/dist/commands/validate/checks/vocabulary.js.map +1 -0
- package/dist/commands/validate/feature.js +216 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +69 -0
- package/dist/commands/validate/fleet/census.js.map +1 -0
- package/dist/commands/validate/fleet/kind-tags.js +39 -0
- package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
- package/dist/commands/validate/fleet/landscape.js +353 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +52 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +236 -0
- package/dist/commands/validate/fleet/obligations.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/print.js +63 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/place.js +13 -0
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/steps.js +197 -0
- package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
- package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +40 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +59 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +92 -0
- package/dist/commands/validate/links/corpus.js.map +1 -0
- package/dist/commands/validate/links/glossary.js +75 -0
- package/dist/commands/validate/links/glossary.js.map +1 -0
- package/dist/commands/validate/report.js +269 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/service/api.js +338 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +219 -0
- package/dist/commands/validate/service/events/events.js.map +1 -0
- package/dist/commands/validate/service/events/message-producers.js +77 -0
- package/dist/commands/validate/service/events/message-producers.js.map +1 -0
- package/dist/commands/validate/service/evidence-pins.js +131 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/service.js +250 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +219 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +113 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/validate.js +338 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +182 -0
- package/dist/commands/verify/cross/diff.js.map +1 -0
- package/dist/commands/verify/evidence/contract.js +32 -0
- package/dist/commands/verify/evidence/contract.js.map +1 -0
- package/dist/commands/verify/evidence/pins.js +52 -0
- package/dist/commands/verify/evidence/pins.js.map +1 -0
- package/dist/commands/verify/evidence/read.js +72 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +241 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +226 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +223 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +246 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +217 -0
- package/dist/commands/verify/verify.js.map +1 -0
- package/dist/commands/vouch/contract.js +11 -0
- package/dist/commands/vouch/contract.js.map +1 -0
- package/dist/commands/vouch/pack/contract.js +2 -0
- package/dist/commands/vouch/pack/contract.js.map +1 -0
- package/dist/commands/vouch/pack/pack.js +266 -0
- package/dist/commands/vouch/pack/pack.js.map +1 -0
- package/dist/commands/vouch/pack/print.js +271 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +142 -0
- package/dist/commands/vouch/pack/sections.js.map +1 -0
- package/dist/commands/vouch/prompt/confirm.js +46 -0
- package/dist/commands/vouch/prompt/confirm.js.map +1 -0
- package/dist/commands/vouch/report.js +101 -0
- package/dist/commands/vouch/report.js.map +1 -0
- package/dist/commands/vouch/run.js +285 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +125 -0
- package/dist/commands/vouch/sample/plan.js.map +1 -0
- package/dist/commands/vouch/sample/print.js +109 -0
- package/dist/commands/vouch/sample/print.js.map +1 -0
- package/dist/commands/vouch/vet/verify.js +123 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +176 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/artifacts.js +220 -0
- package/dist/core/agent/agents-md/artifacts.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +324 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/cycle.js +165 -0
- package/dist/core/agent/agents-md/cycle.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +34 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +41 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +62 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +32 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +60 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +246 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
- package/dist/core/agent/agents-md/spine.js +40 -0
- package/dist/core/agent/agents-md/spine.js.map +1 -0
- package/dist/core/agent/agents-md.js +170 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/agent/agents-stamp.js +155 -0
- package/dist/core/agent/agents-stamp.js.map +1 -0
- package/dist/core/agent/contract.js +2 -0
- package/dist/core/agent/contract.js.map +1 -0
- package/dist/core/agent/protocol.js +193 -0
- package/dist/core/agent/protocol.js.map +1 -0
- package/dist/core/agent/scaffold.js +259 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +103 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +150 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +228 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +133 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +334 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +262 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +105 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +105 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +209 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +65 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +188 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +16 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +297 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +110 -0
- package/dist/core/asyncapi/baseline/plan.js.map +1 -0
- package/dist/core/asyncapi/baseline/surfaces.js +54 -0
- package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
- package/dist/core/asyncapi/depth.js +164 -0
- package/dist/core/asyncapi/depth.js.map +1 -0
- package/dist/core/asyncapi/digest.js +141 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +91 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +33 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +308 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +215 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +107 -0
- package/dist/core/asyncapi/merge/pin.js.map +1 -0
- package/dist/core/asyncapi/model.js +11 -0
- package/dist/core/asyncapi/model.js.map +1 -0
- package/dist/core/asyncapi/producers.js +50 -0
- package/dist/core/asyncapi/producers.js.map +1 -0
- package/dist/core/asyncapi/read.js +239 -0
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +225 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +250 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +194 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/targets.js +226 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +47 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +282 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/likec4.js +88 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +57 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +75 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/project/architecture.js +45 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/documents.js +58 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +183 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/resolve/service.js +113 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/seed/fleet-file.js +201 -0
- package/dist/core/c4/seed/fleet-file.js.map +1 -0
- package/dist/core/c4/seed/items.js +91 -0
- package/dist/core/c4/seed/items.js.map +1 -0
- package/dist/core/c4/seed/stamp.js +48 -0
- package/dist/core/c4/seed/stamp.js.map +1 -0
- package/dist/core/c4/seed/template.js +109 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/source-mask.js +82 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +227 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +101 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +10 -0
- package/dist/core/c4/splice/contract.js.map +1 -0
- package/dist/core/c4/splice/delta-blocks.js +126 -0
- package/dist/core/c4/splice/delta-blocks.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +36 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +269 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +194 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/workspace.js +172 -0
- package/dist/core/c4/workspace.js.map +1 -0
- package/dist/core/capabilities/authoring/notes.js +141 -0
- package/dist/core/capabilities/authoring/notes.js.map +1 -0
- package/dist/core/capabilities/capabilities.js +124 -0
- package/dist/core/capabilities/capabilities.js.map +1 -0
- package/dist/core/capabilities/delta/doc.js +50 -0
- package/dist/core/capabilities/delta/doc.js.map +1 -0
- package/dist/core/capabilities/delta/overlay.js +129 -0
- package/dist/core/capabilities/delta/overlay.js.map +1 -0
- package/dist/core/capabilities/delta/summary.js +57 -0
- package/dist/core/capabilities/delta/summary.js.map +1 -0
- package/dist/core/capabilities/delta/tree.js +43 -0
- package/dist/core/capabilities/delta/tree.js.map +1 -0
- package/dist/core/capabilities/delta/uncovered.js +222 -0
- package/dist/core/capabilities/delta/uncovered.js.map +1 -0
- package/dist/core/capabilities/findings.js +342 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +181 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +143 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +199 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +126 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +277 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +177 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +74 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/coherence.js +251 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/declared.js +269 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +206 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +204 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +166 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +122 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/merged.js +40 -0
- package/dist/core/coherence/events/merged.js.map +1 -0
- package/dist/core/coherence/living.js +198 -0
- package/dist/core/coherence/living.js.map +1 -0
- package/dist/core/coherence/lookups.js +155 -0
- package/dist/core/coherence/lookups.js.map +1 -0
- package/dist/core/coherence/pending.js +39 -0
- package/dist/core/coherence/pending.js.map +1 -0
- package/dist/core/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.js.map +1 -0
- package/dist/core/delta/claims.js +73 -0
- package/dist/core/delta/claims.js.map +1 -0
- package/dist/core/delta/delta.js +296 -0
- package/dist/core/delta/delta.js.map +1 -0
- package/dist/core/delta/document.js +177 -0
- package/dist/core/delta/document.js.map +1 -0
- package/dist/core/delta/scope.js +48 -0
- package/dist/core/delta/scope.js.map +1 -0
- package/dist/core/delta/select.js +237 -0
- package/dist/core/delta/select.js.map +1 -0
- package/dist/core/dependencies/dependencies.js +141 -0
- package/dist/core/dependencies/dependencies.js.map +1 -0
- package/dist/core/dependencies/facts.js +165 -0
- package/dist/core/dependencies/facts.js.map +1 -0
- package/dist/core/dependencies/fanin.js +88 -0
- package/dist/core/dependencies/fanin.js.map +1 -0
- package/dist/core/dependencies/graph.js +106 -0
- package/dist/core/dependencies/graph.js.map +1 -0
- package/dist/core/diff/base-git.js +148 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +209 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/current-state.js +96 -0
- package/dist/core/diff/current-state.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +188 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/semantic.js +243 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/diff/victims.js +247 -0
- package/dist/core/diff/victims.js.map +1 -0
- package/dist/core/docs.js +59 -55
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +222 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +135 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +275 -0
- package/dist/core/doctor/doctor.js.map +1 -0
- package/dist/core/doctor/report.js +13 -0
- package/dist/core/doctor/report.js.map +1 -0
- package/dist/core/doctor/residue.js +110 -0
- package/dist/core/doctor/residue.js.map +1 -0
- package/dist/core/document/apply.js +77 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
- package/dist/core/document/frontmatter.js.map +1 -0
- package/dist/core/document/grammar/directives.js +143 -0
- package/dist/core/document/grammar/directives.js.map +1 -0
- package/dist/core/document/parse.js +263 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +221 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +241 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +79 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +175 -0
- package/dist/core/envelope/json.js.map +1 -0
- package/dist/core/{version.js → envelope/version.js} +3 -3
- package/dist/core/envelope/version.js.map +1 -0
- package/dist/core/explain/families.js +175 -0
- package/dist/core/explain/families.js.map +1 -0
- package/dist/core/explain/fix-tables.js +178 -0
- package/dist/core/explain/fix-tables.js.map +1 -0
- package/dist/core/explain/lookup.js +181 -0
- package/dist/core/explain/lookup.js.map +1 -0
- package/dist/core/explain/refusals.js +49 -0
- package/dist/core/explain/refusals.js.map +1 -0
- package/dist/core/explain/terms.js +144 -0
- package/dist/core/explain/terms.js.map +1 -0
- package/dist/core/explore/describe.js +105 -0
- package/dist/core/explore/describe.js.map +1 -0
- package/dist/core/{explore.js → explore/explore.js} +50 -101
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +132 -77
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +201 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +205 -0
- package/dist/core/gate/partners.js.map +1 -0
- package/dist/core/gate/report.js +47 -0
- package/dist/core/gate/report.js.map +1 -0
- package/dist/core/gate/verification.js +113 -0
- package/dist/core/gate/verification.js.map +1 -0
- package/dist/core/gherkin/digest.js +60 -0
- package/dist/core/gherkin/digest.js.map +1 -0
- package/dist/core/gherkin/emit.js +177 -0
- package/dist/core/gherkin/emit.js.map +1 -0
- package/dist/core/gherkin/read.js +76 -0
- package/dist/core/gherkin/read.js.map +1 -0
- package/dist/core/gherkin/stale.js +234 -0
- package/dist/core/gherkin/stale.js.map +1 -0
- package/dist/core/gherkin/stamp.js +77 -0
- package/dist/core/gherkin/stamp.js.map +1 -0
- package/dist/core/gherkin/steps/catalogue.js +154 -0
- package/dist/core/gherkin/steps/catalogue.js.map +1 -0
- package/dist/core/gherkin/steps/inventory.js +98 -0
- package/dist/core/gherkin/steps/inventory.js.map +1 -0
- package/dist/core/gherkin/steps/phrase.js +72 -0
- package/dist/core/gherkin/steps/phrase.js.map +1 -0
- package/dist/core/glossary/delta.js +106 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +86 -0
- package/dist/core/glossary/tree.js.map +1 -0
- package/dist/core/kernel/concurrency.js.map +1 -0
- package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
- package/dist/core/kernel/document-bytes.js.map +1 -0
- package/dist/core/kernel/fences.js +42 -0
- package/dist/core/kernel/fences.js.map +1 -0
- package/dist/core/kernel/ids/capability.js +72 -0
- package/dist/core/kernel/ids/capability.js.map +1 -0
- package/dist/core/kernel/ids/dirs.js +33 -0
- package/dist/core/kernel/ids/dirs.js.map +1 -0
- package/dist/core/kernel/ids/feature.js +75 -0
- package/dist/core/kernel/ids/feature.js.map +1 -0
- package/dist/core/kernel/ids/service.js +156 -0
- package/dist/core/kernel/ids/service.js.map +1 -0
- package/dist/core/kernel/ids/subsystem.js +63 -0
- package/dist/core/kernel/ids/subsystem.js.map +1 -0
- package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +68 -0
- package/dist/core/links/backlinks.js.map +1 -0
- package/dist/core/links/case.js +74 -0
- package/dist/core/links/case.js.map +1 -0
- package/dist/core/links/corpus.js +104 -0
- package/dist/core/links/corpus.js.map +1 -0
- package/dist/core/links/findings.js +110 -0
- package/dist/core/links/findings.js.map +1 -0
- package/dist/core/links/parse.js +236 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +111 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +72 -0
- package/dist/core/mcp/author-tools.js.map +1 -0
- package/dist/core/mcp/framing.js +46 -0
- package/dist/core/mcp/framing.js.map +1 -0
- package/dist/core/mcp/protocol.js +280 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/tools.js +314 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/obligations/obligations.js +106 -0
- package/dist/core/obligations/obligations.js.map +1 -0
- package/dist/core/openapi/baseline/gate.js +166 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +112 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +175 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/depth.js +122 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +189 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +44 -106
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +234 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +26 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +208 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +256 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +128 -0
- package/dist/core/openapi/merge/pin.js.map +1 -0
- package/dist/core/openspec/decide/capabilities.js +244 -0
- package/dist/core/openspec/decide/capabilities.js.map +1 -0
- package/dist/core/openspec/decide/dispositions.js +63 -0
- package/dist/core/openspec/decide/dispositions.js.map +1 -0
- package/dist/core/openspec/decide/renames.js +179 -0
- package/dist/core/openspec/decide/renames.js.map +1 -0
- package/dist/core/openspec/decide/verdict.js +84 -0
- package/dist/core/openspec/decide/verdict.js.map +1 -0
- package/dist/core/openspec/inventory.js +221 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +76 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +65 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +235 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +200 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +260 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +133 -0
- package/dist/core/openspec/scan/walk.js.map +1 -0
- package/dist/core/openspec/scan/workspace.js +71 -0
- package/dist/core/openspec/scan/workspace.js.map +1 -0
- package/dist/core/owners/codeowners.js +141 -0
- package/dist/core/owners/codeowners.js.map +1 -0
- package/dist/core/pack/features.js +120 -0
- package/dist/core/pack/features.js.map +1 -0
- package/dist/core/pack/joins.js +112 -0
- package/dist/core/pack/joins.js.map +1 -0
- package/dist/core/pack/living.js +118 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +76 -0
- package/dist/core/pack/pack.js.map +1 -0
- package/dist/core/permissions/permissions.js +87 -0
- package/dist/core/permissions/permissions.js.map +1 -0
- package/dist/core/projection/api.js +84 -0
- package/dist/core/projection/api.js.map +1 -0
- package/dist/core/projection/arch-slice.js +63 -0
- package/dist/core/projection/arch-slice.js.map +1 -0
- package/dist/core/projection/events.js +34 -0
- package/dist/core/projection/events.js.map +1 -0
- package/dist/core/provenance/findings.js +208 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +225 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +182 -0
- package/dist/core/provenance/gitq/moves.js.map +1 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
- package/dist/core/provenance/sample/scope.js +238 -0
- package/dist/core/provenance/sample/scope.js.map +1 -0
- package/dist/core/provenance/sample/sections.js +61 -0
- package/dist/core/provenance/sample/sections.js.map +1 -0
- package/dist/core/provenance/sources.js +263 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +232 -0
- package/dist/core/provenance/stamp.js.map +1 -0
- package/dist/core/provenance/walk.js +157 -0
- package/dist/core/provenance/walk.js.map +1 -0
- package/dist/core/repo/authored/paths.js +192 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +236 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +248 -0
- package/dist/core/repo/repo.js.map +1 -0
- package/dist/core/repo/service-target.js +153 -0
- package/dist/core/repo/service-target.js.map +1 -0
- package/dist/core/repo/state.js +58 -0
- package/dist/core/repo/state.js.map +1 -0
- package/dist/core/repo/tree/find.js +52 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +64 -0
- package/dist/core/repo/tree/fs.js.map +1 -0
- package/dist/core/repo/tree/marker.js +61 -0
- package/dist/core/repo/tree/marker.js.map +1 -0
- package/dist/core/repo/tree/views.js +172 -0
- package/dist/core/repo/tree/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +234 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +99 -2
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +131 -0
- package/dist/core/scaffold/landscape.js.map +1 -0
- package/dist/core/scaffold/readme.js +84 -0
- package/dist/core/scaffold/readme.js.map +1 -0
- package/dist/core/staging/commit.js +241 -0
- package/dist/core/staging/commit.js.map +1 -0
- package/dist/core/staging/interrupted.js +96 -0
- package/dist/core/staging/interrupted.js.map +1 -0
- package/dist/core/staging/lock.js +206 -0
- package/dist/core/staging/lock.js.map +1 -0
- package/dist/core/staging/recovery/finding.js +35 -0
- package/dist/core/staging/recovery/finding.js.map +1 -0
- package/dist/core/staging/recovery/intent.js +98 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +126 -0
- package/dist/core/staging/recovery/recover.js.map +1 -0
- package/dist/core/staging/recovery/residue.js +62 -0
- package/dist/core/staging/recovery/residue.js.map +1 -0
- package/dist/core/staging/snapshot.js +202 -0
- package/dist/core/staging/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +171 -0
- package/dist/core/staging/txn/forward.js.map +1 -0
- package/dist/core/staging/txn/journal.js +139 -0
- package/dist/core/staging/txn/journal.js.map +1 -0
- package/dist/core/staging/txn/transaction.js +75 -0
- package/dist/core/staging/txn/transaction.js.map +1 -0
- package/dist/core/staging/writes.js +113 -0
- package/dist/core/staging/writes.js.map +1 -0
- package/dist/core/status/actions/execution.js +49 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +102 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +171 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +207 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +150 -0
- package/dist/core/status/feature/next.js.map +1 -0
- package/dist/core/status/feature/state.js +21 -0
- package/dist/core/status/feature/state.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +187 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +207 -0
- package/dist/core/status/fleet/next.js.map +1 -0
- package/dist/core/status/interrupted.js +97 -0
- package/dist/core/status/interrupted.js.map +1 -0
- package/dist/core/status/report.js +31 -0
- package/dist/core/status/report.js.map +1 -0
- package/dist/core/status/scan.js +41 -0
- package/dist/core/status/scan.js.map +1 -0
- package/dist/core/status/verification.js +201 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/usecases/capability.js +169 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +116 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +103 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +235 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +137 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/operations.js +111 -0
- package/dist/core/usecases/operations.js.map +1 -0
- package/dist/core/usecases/place.js +44 -0
- package/dist/core/usecases/place.js.map +1 -0
- package/dist/core/usecases/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +173 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +150 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +201 -0
- package/dist/core/verify/checklist.js.map +1 -0
- package/dist/core/verify/claims/identity.js +61 -0
- package/dist/core/verify/claims/identity.js.map +1 -0
- package/dist/core/verify/cross/diff.js +97 -0
- package/dist/core/verify/cross/diff.js.map +1 -0
- package/dist/core/verify/evidence/contract.js +169 -0
- package/dist/core/verify/evidence/contract.js.map +1 -0
- package/dist/core/verify/file.js +257 -0
- package/dist/core/verify/file.js.map +1 -0
- package/dist/core/verify/pins/lint.js +157 -0
- package/dist/core/verify/pins/lint.js.map +1 -0
- package/dist/core/verify/pins/pin.js +95 -0
- package/dist/core/verify/pins/pin.js.map +1 -0
- package/dist/core/verify/record.js +142 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +89 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +57 -0
- package/dist/core/verify/store/render.js.map +1 -0
- package/dist/core/vocabulary/health.js +91 -0
- package/dist/core/vocabulary/health.js.map +1 -0
- package/dist/core/vocabulary/issue.js +55 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +145 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/{report.js → vocabulary/report.js} +30 -2
- package/dist/core/vocabulary/report.js.map +1 -0
- package/dist/core/vocabulary/steps.js +266 -0
- package/dist/core/vocabulary/steps.js.map +1 -0
- package/dist/core/workspace/discover.js +239 -0
- package/dist/core/workspace/discover.js.map +1 -0
- package/dist/core/workspace/render.js +52 -0
- package/dist/core/workspace/render.js.map +1 -0
- package/examples/README.md +189 -0
- package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
- package/examples/docs/architecture/capabilities.yaml +31 -0
- package/examples/docs/architecture/landscape.likec4 +280 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/subsystems.likec4 +11 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
- package/examples/docs/capabilities/checkout/spec.md +55 -0
- package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
- package/examples/docs/capabilities/order-notifications/spec.md +43 -0
- package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
- package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
- package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
- package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
- package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
- package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
- package/examples/docs/glossary/order.md +15 -0
- package/examples/docs/glossary/payments/authorization.md +14 -0
- package/examples/docs/likec4.config.json +9 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +109 -0
- package/examples/docs/services/checkout-web/spec.md +91 -0
- package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
- package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
- package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
- package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
- package/examples/docs/services/order-service/arch.spec.md +127 -0
- package/examples/docs/services/order-service/asyncapi.yaml +108 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +138 -0
- package/examples/docs/services/order-service/openapi.yaml +257 -0
- package/examples/docs/services/order-service/runbook.md +62 -0
- package/examples/docs/services/order-service/spec.md +134 -0
- package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
- package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
- package/examples/docs/services/payment-service/arch.spec.md +73 -0
- package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
- package/examples/docs/services/payment-service/health.yaml +39 -0
- package/examples/docs/services/payment-service/model.likec4 +67 -0
- package/examples/docs/services/payment-service/openapi.yaml +151 -0
- package/examples/docs/services/payment-service/runbook.md +37 -0
- package/examples/docs/services/payment-service/spec.md +88 -0
- package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
- package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
- package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
- package/examples/docs/services/platform/identity-service/runbook.md +95 -0
- package/examples/docs/services/platform/identity-service/spec.md +119 -0
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
- package/examples/docs/services/platform/notification-service/health.yaml +35 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
- package/examples/docs/services/platform/notification-service/runbook.md +48 -0
- package/examples/docs/services/platform/notification-service/spec.md +112 -0
- package/examples/docs/services/platform/subsystem.yaml +2 -0
- package/examples/fleet.yaml +57 -0
- package/package.json +19 -6
- package/dist/commands/adopt.js +0 -240
- package/dist/commands/adopt.js.map +0 -1
- package/dist/commands/archive.js +0 -1313
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/delta.js +0 -388
- package/dist/commands/delta.js.map +0 -1
- package/dist/commands/docs-repo-gate.js.map +0 -1
- package/dist/commands/format.js +0 -17
- package/dist/commands/format.js.map +0 -1
- package/dist/commands/gherkin.js +0 -309
- package/dist/commands/gherkin.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/list.js +0 -291
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/migrate-openspec.js +0 -950
- package/dist/commands/migrate-openspec.js.map +0 -1
- package/dist/commands/new.js +0 -413
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/rebase.js +0 -356
- package/dist/commands/rebase.js.map +0 -1
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/status.js +0 -254
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unarchive.js.map +0 -1
- package/dist/commands/validate.js +0 -1591
- 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 -343
- package/dist/commands/vouch.js.map +0 -1
- package/dist/core/agent.js +0 -2065
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agents-stamp.js +0 -68
- 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/brief.js +0 -733
- 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 -559
- package/dist/core/doctor.js.map +0 -1
- package/dist/core/document-bytes.js.map +0 -1
- package/dist/core/explore.js.map +0 -1
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/gherkin.js +0 -463
- package/dist/core/gherkin.js.map +0 -1
- package/dist/core/health.js +0 -67
- package/dist/core/health.js.map +0 -1
- package/dist/core/ids.js +0 -122
- package/dist/core/ids.js.map +0 -1
- package/dist/core/issue.js +0 -9
- package/dist/core/issue.js.map +0 -1
- package/dist/core/json.js +0 -74
- package/dist/core/json.js.map +0 -1
- package/dist/core/likec4.js +0 -479
- 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 -720
- package/dist/core/provenance.js.map +0 -1
- package/dist/core/records.js.map +0 -1
- package/dist/core/repo.js +0 -436
- package/dist/core/repo.js.map +0 -1
- package/dist/core/report.js.map +0 -1
- package/dist/core/spec.js +0 -481
- 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 -1104
- package/dist/core/status.js.map +0 -1
- package/dist/core/steps.js +0 -72
- package/dist/core/steps.js.map +0 -1
- package/dist/core/verify.js +0 -807
- package/dist/core/verify.js.map +0 -1
- package/dist/core/version.js.map +0 -1
- /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
- /package/dist/core/{records.js → kernel/records.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncapi.js","sourceRoot":"","sources":["../../../../../src/commands/archive/plan/contracts/asyncapi.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The AsyncAPI contract merge: the feature's asyncapi deltas folded into each\n * living event contract — the event axis's mirror of ./openapi.ts, slot-keyed\n * where that one is path-keyed.\n *\n * Nothing is written. Everything lands in the `Plan`, so a failure on any axis\n * leaves the living docs exactly as they were.\n */\nimport { existsSync } from \"node:fs\";\nimport { parse } from \"yaml\";\nimport { repoPath } from \"../../../../core/envelope/json.js\";\nimport { planWrite, readUtf8 } from \"../../../../core/staging/writes.js\";\nimport { featureSpecPaths } from \"../../../../core/repo/paths.js\";\nimport { locateServicePaths } from \"../../../../core/repo/service-target.js\";\nimport { readAsyncapi } from \"../../../../core/asyncapi/read.js\";\nimport { asyncapiSlots, type AsyncapiSection } from \"../../../../core/asyncapi/digest.js\";\nimport { asyncapiSurfaces } from \"../../../../core/asyncapi/baseline/surfaces.js\";\nimport { AsyncapiMergeError } from \"../../../../core/asyncapi/merge/error.js\";\nimport { stripAsyncapiMarkers } from \"../../../../core/asyncapi/merge/markers.js\";\nimport { mergeAsyncapiSlots, type AsyncapiMergeResult } from \"../../../../core/asyncapi/merge/merge.js\";\nimport { ArchiveFailure } from \"../refusal.js\";\nimport { type Gated, type Plan } from \"../state.js\";\nimport type { FleetContext } from \"../../../../core/fleet-context.js\";\nimport type { IssueCode } from \"../../../../core/vocabulary/issue.js\";\nimport type { DocsDir } from \"../../../../core/kernel/ids/dirs.js\";\n\n/** The per-section overwrite code — three codes, one per slot shape, mirroring the OpenAPI axis's. */\nfunction modifiedCode(section: AsyncapiSection): IssueCode {\n if (section === \"components.messages\") return \"asyncapi.message-modified\";\n return section === \"channels\" ? \"asyncapi.channel-modified\" : \"asyncapi.operation-modified\";\n}\n\nexport async function planAsyncapiContracts(\n config: { docsDir: DocsDir; fleet?: FleetContext },\n gated: Gated,\n plan: Plan,\n say: (line?: string) => void,\n): Promise<void> {\n const { featureDir, deltaServices } = gated;\n const { writes, planWarns, planGates, asyncapiRemovals } = plan;\n for (const svc of deltaServices) {\n const featAsyncapi = featureSpecPaths(featureDir, svc).asyncapi;\n if (!existsSync(featAsyncapi)) continue;\n const featText = await readUtf8(featAsyncapi);\n const featDoc = await readAsyncapi(featAsyncapi);\n // Coherence grades `asyncapi.invalid` and gates on it; the merge stays\n // mechanical under --approve for the OpenAPI planner's reason: a document\n // loam cannot read is one it cannot merge, and that is the same answer as\n // any other merge it could not compute — nothing is written.\n if (featDoc.unreadable) {\n throw new ArchiveFailure(\n \"merge-failed\",\n `feature asyncapi ${repoPath(config.docsDir, featAsyncapi)} for ${svc} does not read as an AsyncAPI document (${featDoc.error ?? \"not a YAML mapping\"}) — the event axis cannot be merged; fix the file, or delete it if this feature has no contract delta`,\n );\n }\n const names = featDoc.messages.filter((m) => m.remove !== true).map((m) => m.name);\n // An `x-loam-remove` NESTED on an inline channel message retires nothing:\n // an inline message is channel-slot interior (SCHEMA.md's decision), so\n // the marker is just channel content — and when the restated channel is\n // otherwise identical to living, not even that: the merge deduplicates it\n // away and the marker lands in no bucket at all. The merge is safe either\n // way (the deep strip keeps the key out of living), but the author asked\n // for a removal that will not happen, and silence there is how a retired\n // message would stay on the wire — openapi.remove-marker-path-level's\n // lesson at the nested depth. Gated like the other plan-visible breaches,\n // --approve and all.\n for (const m of featDoc.messages) {\n if (m.remove !== true || !m.slot.startsWith(\"channels.\")) continue;\n const channel = m.slot.slice(\"channels.\".length, m.slot.lastIndexOf(\".messages.\"));\n planGates.push({\n severity: \"error\",\n code: \"asyncapi.remove-marker-inline\",\n subject: svc,\n message: `${svc}: '${m.slot}' carries x-loam-remove nested on an inline channel message — inline messages are channel interior, not slots, so this retires nothing. Retire the whole channel (x-loam-remove: true at channels.${channel}), or declare the message under components.messages (the channel $ref-ing it) and put the marker there.`,\n });\n }\n // The shared context, for the OpenAPI planner's reason: once per delta\n // service must not mean one fleet walk per delta service.\n const livingAsyncapi = (await locateServicePaths(config.docsDir, svc, config.fleet)).asyncapi;\n try {\n if (!existsSync(livingAsyncapi)) {\n // A removal against a non-existent contract is gated by coherence;\n // under --approve the strip drops the markers, so the one thing left\n // to decide is whether a document remains. It must not when nothing\n // survives: an asyncapi.yaml's very PRESENCE is graded on this axis\n // (absence is `service.no-asyncapi`'s question, silence otherwise),\n // so a slotless or all-markers delta creating an empty living\n // contract would put a presence claim on a service that has none.\n // SLOTS only, deliberately, now that component surfaces merge: a\n // document holding schemas and no channel, operation or message\n // declares no event at all, and creating it would make exactly the\n // presence claim this branch exists to refuse.\n const surviving = asyncapiSlots(parse(featText)).filter((slot) => !slot.remove);\n if (surviving.length === 0) {\n say(` asyncapi: ${svc} — nothing to merge (the delta declares no surviving slots), no living asyncapi.yaml created`);\n continue;\n }\n writes.push(planWrite(livingAsyncapi, stripAsyncapiMarkers(featText, svc)));\n say(` asyncapi: ${svc} — created (${names.join(\", \")})`);\n continue;\n }\n const merge: AsyncapiMergeResult = mergeAsyncapiSlots(await readUtf8(livingAsyncapi), featText, svc);\n // What the delta declares OUTSIDE the three slot sections — the one\n // question the merge result cannot answer for the silence below, because\n // a merge that wrote nothing reports nothing to distinguish \"the delta\n // was all quotes\" from \"the delta was all schemas and I dropped them\".\n const surfaces = asyncapiSurfaces(parse(featText));\n if (merge.text !== null) {\n writes.push(planWrite(livingAsyncapi, merge.text));\n // The parenthesised list names the MESSAGES the delta declares, and a\n // delta whose whole change is a component surface has none — so this\n // printed `merged ()`, the same empty-parenthesis lie the create\n // branch above is commented for: it reads as \"this merge wrote\n // nothing\" about a merge that just published a shared schema to every\n // consumer of the fleet. Drop the parentheses when there is nothing to\n // put in them; the surface lines below name what actually moved.\n say(` asyncapi: ${svc} — merged${names.length > 0 ? ` (${names.join(\", \")})` : \"\"}`);\n } else if (surfaces.length > 0) {\n // \"The plan wrote less than my delta spells\" is the sentence a reader\n // cannot infer from an unchanged file — this file's own comment below\n // names it for slots, and a components-only delta is the shape where\n // silence is indistinguishable from the defect that made it merge\n // nothing at all. Not a warning: every surface being a quote is\n // correct authoring and the correct merge.\n say(` asyncapi: ${svc} — nothing to write: every one of the ${surfaces.length} component surface(s) this delta declares already stands as living has it`);\n }\n if (merge.removed.length > 0) {\n asyncapiRemovals.push({ service: svc, slots: merge.removed.map((slot) => slot.label) });\n for (const slot of merge.removed) say(` - removes ${slot.label}`);\n }\n // Said out loud, because \"the plan wrote less than my delta spells\" is\n // the one thing a reader cannot infer from a merged file. Not a warning:\n // quoting the contract around your change is correct authoring, and\n // leaving the quote alone is the correct merge.\n for (const slot of merge.quoted) {\n say(` · quotes ${slot.label} — unchanged since it was pinned, left as living has it`);\n }\n // The surface half's mirrors of the three lines around them. A component\n // surface reaches the reader by exactly the same three sentences a slot\n // does, because it is graded by exactly the same verdict.\n for (const id of merge.componentsQuoted) {\n say(` · quotes components.${id} — unchanged since it was pinned, left as living has it`);\n }\n // Stale surfaces reaching the merge at all means --approve pushed past\n // the gate's asyncapi.baseline-stale — the plan still names what it cost.\n for (const slot of merge.baselineStale) {\n say(` ⚠ stale baseline on ${slot.label} — the living value moved since this delta was pinned; the overwrite is what --approve chose`);\n }\n for (const id of merge.componentsStale) {\n say(` ⚠ stale baseline on components.${id} — the living value moved since this delta was pinned; the overwrite is what --approve chose`);\n }\n for (const id of merge.componentsModified) {\n planWarns.push({\n severity: \"warn\",\n code: \"asyncapi.component-modified\",\n subject: svc,\n message: `${svc}: the delta declares components.${id}, which the living AsyncAPI already has with different content — the merge overwrites the living component wholesale`,\n });\n say(` ⚠ overwrites components.${id} — the living definition differs`);\n }\n for (const slot of merge.modified) {\n planWarns.push({\n severity: \"warn\",\n code: modifiedCode(slot.section),\n subject: svc,\n message: `${svc}: the delta redefines ${slot.label}, which the living AsyncAPI already has — the merge overwrites the living slot wholesale`,\n });\n say(` ⚠ overwrites ${slot.label} — the living definition differs`);\n }\n for (const ref of merge.unresolved) {\n planGates.push({\n severity: \"error\",\n code: \"asyncapi.ref-unresolved\",\n subject: svc,\n message: `${svc}: $ref '${ref}' resolves in neither the feature's asyncapi.yaml nor the living one — the merged document would carry a dangling reference`,\n });\n }\n } catch (err) {\n if (err instanceof AsyncapiMergeError) throw new ArchiveFailure(\"merge-failed\", err.message);\n throw err;\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The OpenAPI contract merge: the feature's openapi deltas folded into each
|
|
3
|
+
* living service API — the half of the archive plan that answers to the
|
|
4
|
+
* contract axis, split out of ../specs.ts so the requirements merge and the
|
|
5
|
+
* contract merges stop sharing one file.
|
|
6
|
+
*
|
|
7
|
+
* Nothing is written. Everything lands in the `Plan`, so a failure on any axis
|
|
8
|
+
* leaves the living docs exactly as they were.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync } from "node:fs";
|
|
11
|
+
import { repoPath } from "../../../../core/envelope/json.js";
|
|
12
|
+
import { planWrite, readUtf8 } from "../../../../core/staging/writes.js";
|
|
13
|
+
import { featureSpecPaths } from "../../../../core/repo/paths.js";
|
|
14
|
+
import { locateServicePaths } from "../../../../core/repo/service-target.js";
|
|
15
|
+
import { readOpenapi } from "../../../../core/openapi/doc.js";
|
|
16
|
+
import { OpenapiMergeError } from "../../../../core/openapi/merge/error.js";
|
|
17
|
+
import { stripOpenapiRemovalMarkers } from "../../../../core/openapi/merge/markers.js";
|
|
18
|
+
import { mergeOpenapiPaths } from "../../../../core/openapi/merge/merge.js";
|
|
19
|
+
import { ArchiveFailure } from "../refusal.js";
|
|
20
|
+
import {} from "../state.js";
|
|
21
|
+
export async function planOpenapiContracts(config, gated, plan, say) {
|
|
22
|
+
const { featureDir, deltaServices } = gated;
|
|
23
|
+
const { writes, planWarns, planGates, openapiRemovals } = plan;
|
|
24
|
+
// OpenAPI merge — fold the feature's openapi deltas into the living service APIs.
|
|
25
|
+
for (const svc of deltaServices) {
|
|
26
|
+
const featOpenapi = featureSpecPaths(featureDir, svc).openapi;
|
|
27
|
+
if (!existsSync(featOpenapi))
|
|
28
|
+
continue;
|
|
29
|
+
const featText = await readUtf8(featOpenapi);
|
|
30
|
+
// The shared context: this planner runs once per delta service, and a
|
|
31
|
+
// context-less locate is a full fleet walk per service.
|
|
32
|
+
const livingOpenapi = (await locateServicePaths(config.docsDir, svc, config.fleet)).openapi;
|
|
33
|
+
const featDoc = await readOpenapi(featOpenapi);
|
|
34
|
+
// Every other reader of this flag suspends its own judgement when it is set
|
|
35
|
+
// — validate grades `openapi.invalid`, show and status print that the file
|
|
36
|
+
// does not parse. Archive was the only one that never looked, and it is the
|
|
37
|
+
// command that WRITES: a feature openapi.yaml holding a sequence instead of
|
|
38
|
+
// a mapping was planned verbatim into services/<svc>/openapi.yaml, `ok:
|
|
39
|
+
// true`, printing `created ()` because the reader saw no operations in it.
|
|
40
|
+
// A document loam cannot read is one it cannot merge, and that is the same
|
|
41
|
+
// answer as any other merge it could not compute: nothing is written.
|
|
42
|
+
if (featDoc.unreadable) {
|
|
43
|
+
throw new ArchiveFailure("merge-failed", `feature openapi ${repoPath(config.docsDir, featOpenapi)} for ${svc} does not read as an OpenAPI document (${featDoc.error ?? "not a YAML mapping"}) — the API axis cannot be merged; fix the file, or delete it if this feature has no contract delta`);
|
|
44
|
+
}
|
|
45
|
+
const ops = featDoc.ops.filter((op) => !op.remove).map((op) => op.id);
|
|
46
|
+
// An `x-loam-remove: true` written at PATH level retires nothing: the marker
|
|
47
|
+
// addresses one operation, and beside the methods there is no operation for
|
|
48
|
+
// it to address. The merge now strips it on every branch, so the living
|
|
49
|
+
// contract is safe either way — but the author asked for a removal that will
|
|
50
|
+
// not happen, and silence there is how a retired endpoint stayed live.
|
|
51
|
+
// Gated like the other plan-visible breaches, --approve and all.
|
|
52
|
+
for (const path of featDoc.pathLevelRemovals) {
|
|
53
|
+
planGates.push({
|
|
54
|
+
severity: "error",
|
|
55
|
+
code: "openapi.remove-marker-path-level",
|
|
56
|
+
subject: svc,
|
|
57
|
+
message: `${svc}: '${path}' carries x-loam-remove at PATH level, beside the methods — a removal marker names ONE operation, so this retires nothing and is not a contract key either. Move it inside the operation you are retiring (with its operationId), or delete it.`,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (!existsSync(livingOpenapi)) {
|
|
61
|
+
// A removal against a non-existent contract is gated by coherence. Keep
|
|
62
|
+
// the feature-only marker out of living docs even under --approve — and
|
|
63
|
+
// ask the DOCUMENT, not the operation reader: a marker with no
|
|
64
|
+
// operationId is invisible to `operations()`, so gating the strip on
|
|
65
|
+
// "does the reader see a removal" let exactly that marker through into a
|
|
66
|
+
// living contract, published to every consumer of the fleet.
|
|
67
|
+
const content = stripOpenapiRemovalMarkers(featText, svc);
|
|
68
|
+
writes.push(planWrite(livingOpenapi, content));
|
|
69
|
+
say(` openapi: ${svc} — created (${ops.join(", ")})`);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
let merge;
|
|
73
|
+
try {
|
|
74
|
+
merge = mergeOpenapiPaths(await readUtf8(livingOpenapi), featText, svc);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
if (err instanceof OpenapiMergeError)
|
|
78
|
+
throw new ArchiveFailure("merge-failed", err.message);
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
const { text, modified, pathItemModified, removed, quoted, pathItemQuoted, pathItemStale, componentsModified, componentsAdded, componentsQuoted, componentsStale, unresolved, } = merge;
|
|
82
|
+
if (text !== null) {
|
|
83
|
+
writes.push(planWrite(livingOpenapi, text));
|
|
84
|
+
// The parenthesised list names the OPERATIONS the delta merged, and a
|
|
85
|
+
// delta whose whole change is a component has none — so this printed
|
|
86
|
+
// `merged ()`, the same empty-parenthesis lie the create branch above
|
|
87
|
+
// is commented for: it reads as "this merge wrote nothing" about a
|
|
88
|
+
// merge that just published a shared schema to every consumer of the
|
|
89
|
+
// fleet. Name the components it added instead, and drop the
|
|
90
|
+
// parentheses entirely when there is nothing to put in them — a delta
|
|
91
|
+
// that only EDITED existing surfaces is named by the lines below.
|
|
92
|
+
const mergedNames = ops.length > 0 ? ops : componentsAdded.map((comp) => `component ${comp}`);
|
|
93
|
+
say(` openapi: ${svc} — merged${mergedNames.length > 0 ? ` (${mergedNames.join(", ")})` : ""}`);
|
|
94
|
+
}
|
|
95
|
+
if (removed.length > 0) {
|
|
96
|
+
openapiRemovals.push({ service: svc, operations: removed });
|
|
97
|
+
for (const label of removed)
|
|
98
|
+
say(` - removes ${label}`);
|
|
99
|
+
}
|
|
100
|
+
// Said out loud, because "the plan wrote less than my delta spells" is
|
|
101
|
+
// the one thing a reader cannot infer from a merged file. Not a warning:
|
|
102
|
+
// quoting the contract around your change is correct authoring, and
|
|
103
|
+
// leaving the quote alone is the correct merge. The path-level and
|
|
104
|
+
// component quotes get the same sentence for the same reason.
|
|
105
|
+
for (const label of quoted)
|
|
106
|
+
say(` · quotes ${label} — unchanged since it was pinned, left as living has it`);
|
|
107
|
+
for (const label of pathItemQuoted) {
|
|
108
|
+
say(` · quotes path-level ${label} — unchanged since it was pinned, left as living has it`);
|
|
109
|
+
}
|
|
110
|
+
for (const comp of componentsQuoted) {
|
|
111
|
+
say(` · quotes component ${comp} — unchanged since it was pinned, left as living has it`);
|
|
112
|
+
}
|
|
113
|
+
// Stale surfaces reaching the merge at all means --approve pushed past
|
|
114
|
+
// the gate's openapi.baseline-stale — the plan still names what it cost.
|
|
115
|
+
for (const label of pathItemStale) {
|
|
116
|
+
say(` ⚠ stale baseline on path-level ${label} — the living value moved since this delta was pinned; the overwrite is what --approve chose`);
|
|
117
|
+
}
|
|
118
|
+
for (const comp of componentsStale) {
|
|
119
|
+
say(` ⚠ stale baseline on component ${comp} — the living value moved since this delta was pinned; the overwrite is what --approve chose`);
|
|
120
|
+
}
|
|
121
|
+
for (const label of modified) {
|
|
122
|
+
planWarns.push({
|
|
123
|
+
severity: "warn",
|
|
124
|
+
code: "openapi.op-modified",
|
|
125
|
+
subject: svc,
|
|
126
|
+
message: `${svc}: the delta redefines ${label}, which the living OpenAPI already has — the merge overwrites the living operation wholesale`,
|
|
127
|
+
});
|
|
128
|
+
say(` ⚠ overwrites ${label} — the living definition differs`);
|
|
129
|
+
}
|
|
130
|
+
for (const label of pathItemModified) {
|
|
131
|
+
planWarns.push({
|
|
132
|
+
severity: "warn",
|
|
133
|
+
code: "openapi.path-item-modified",
|
|
134
|
+
subject: svc,
|
|
135
|
+
message: `${svc}: the delta redefines the path-level key ${label}, which the living OpenAPI already has — the merge overwrites it wholesale, and it applies to EVERY operation on that path, including ones this feature never mentions`,
|
|
136
|
+
});
|
|
137
|
+
say(` ⚠ overwrites path-level ${label} — the living definition differs`);
|
|
138
|
+
}
|
|
139
|
+
for (const comp of componentsModified) {
|
|
140
|
+
planWarns.push({
|
|
141
|
+
severity: "warn",
|
|
142
|
+
code: "openapi.component-modified",
|
|
143
|
+
subject: svc,
|
|
144
|
+
message: `${svc}: the delta declares component '${comp}', which the living OpenAPI already defines differently — the merge overwrites the living component wholesale`,
|
|
145
|
+
});
|
|
146
|
+
say(` ⚠ overwrites component ${comp} — the living definition differs`);
|
|
147
|
+
}
|
|
148
|
+
for (const u of unresolved) {
|
|
149
|
+
planGates.push({
|
|
150
|
+
severity: "error",
|
|
151
|
+
code: "openapi.ref-unresolved",
|
|
152
|
+
subject: svc,
|
|
153
|
+
message: `${svc}: $ref '${u.ref}' (referenced from ${u.from}) resolves in neither the feature's openapi.yaml nor the living one — the merged document would carry a dangling reference`,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=openapi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.js","sourceRoot":"","sources":["../../../../../src/commands/archive/plan/contracts/openapi.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The OpenAPI contract merge: the feature's openapi deltas folded into each\n * living service API — the half of the archive plan that answers to the\n * contract axis, split out of ../specs.ts so the requirements merge and the\n * contract merges stop sharing one file.\n *\n * Nothing is written. Everything lands in the `Plan`, so a failure on any axis\n * leaves the living docs exactly as they were.\n */\nimport { existsSync } from \"node:fs\";\nimport { repoPath } from \"../../../../core/envelope/json.js\";\nimport { planWrite, readUtf8 } from \"../../../../core/staging/writes.js\";\nimport { featureSpecPaths } from \"../../../../core/repo/paths.js\";\nimport { locateServicePaths } from \"../../../../core/repo/service-target.js\";\nimport { readOpenapi } from \"../../../../core/openapi/doc.js\";\nimport { OpenapiMergeError } from \"../../../../core/openapi/merge/error.js\";\nimport { stripOpenapiRemovalMarkers } from \"../../../../core/openapi/merge/markers.js\";\nimport { mergeOpenapiPaths, type OpenapiMergeResult } from \"../../../../core/openapi/merge/merge.js\";\nimport { ArchiveFailure } from \"../refusal.js\";\nimport { type Gated, type Plan } from \"../state.js\";\nimport type { DocsDir } from \"../../../../core/kernel/ids/dirs.js\";\nimport type { FleetContext } from \"../../../../core/fleet-context.js\";\n\nexport async function planOpenapiContracts(\n config: { docsDir: DocsDir; fleet?: FleetContext },\n gated: Gated,\n plan: Plan,\n say: (line?: string) => void,\n): Promise<void> {\n const { featureDir, deltaServices } = gated;\n const { writes, planWarns, planGates, openapiRemovals } = plan;\n // OpenAPI merge — fold the feature's openapi deltas into the living service APIs.\n for (const svc of deltaServices) {\n const featOpenapi = featureSpecPaths(featureDir, svc).openapi;\n if (!existsSync(featOpenapi)) continue;\n const featText = await readUtf8(featOpenapi);\n // The shared context: this planner runs once per delta service, and a\n // context-less locate is a full fleet walk per service.\n const livingOpenapi = (await locateServicePaths(config.docsDir, svc, config.fleet)).openapi;\n const featDoc = await readOpenapi(featOpenapi);\n // Every other reader of this flag suspends its own judgement when it is set\n // — validate grades `openapi.invalid`, show and status print that the file\n // does not parse. Archive was the only one that never looked, and it is the\n // command that WRITES: a feature openapi.yaml holding a sequence instead of\n // a mapping was planned verbatim into services/<svc>/openapi.yaml, `ok:\n // true`, printing `created ()` because the reader saw no operations in it.\n // A document loam cannot read is one it cannot merge, and that is the same\n // answer as any other merge it could not compute: nothing is written.\n if (featDoc.unreadable) {\n throw new ArchiveFailure(\n \"merge-failed\",\n `feature openapi ${repoPath(config.docsDir, featOpenapi)} for ${svc} does not read as an OpenAPI document (${featDoc.error ?? \"not a YAML mapping\"}) — the API axis cannot be merged; fix the file, or delete it if this feature has no contract delta`,\n );\n }\n const ops = featDoc.ops.filter((op) => !op.remove).map((op) => op.id);\n // An `x-loam-remove: true` written at PATH level retires nothing: the marker\n // addresses one operation, and beside the methods there is no operation for\n // it to address. The merge now strips it on every branch, so the living\n // contract is safe either way — but the author asked for a removal that will\n // not happen, and silence there is how a retired endpoint stayed live.\n // Gated like the other plan-visible breaches, --approve and all.\n for (const path of featDoc.pathLevelRemovals) {\n planGates.push({\n severity: \"error\",\n code: \"openapi.remove-marker-path-level\",\n subject: svc,\n message: `${svc}: '${path}' carries x-loam-remove at PATH level, beside the methods — a removal marker names ONE operation, so this retires nothing and is not a contract key either. Move it inside the operation you are retiring (with its operationId), or delete it.`,\n });\n }\n if (!existsSync(livingOpenapi)) {\n // A removal against a non-existent contract is gated by coherence. Keep\n // the feature-only marker out of living docs even under --approve — and\n // ask the DOCUMENT, not the operation reader: a marker with no\n // operationId is invisible to `operations()`, so gating the strip on\n // \"does the reader see a removal\" let exactly that marker through into a\n // living contract, published to every consumer of the fleet.\n const content = stripOpenapiRemovalMarkers(featText, svc);\n writes.push(planWrite(livingOpenapi, content));\n say(` openapi: ${svc} — created (${ops.join(\", \")})`);\n } else {\n let merge: OpenapiMergeResult;\n try {\n merge = mergeOpenapiPaths(await readUtf8(livingOpenapi), featText, svc);\n } catch (err) {\n if (err instanceof OpenapiMergeError) throw new ArchiveFailure(\"merge-failed\", err.message);\n throw err;\n }\n const {\n text, modified, pathItemModified, removed, quoted, pathItemQuoted, pathItemStale,\n componentsModified, componentsAdded, componentsQuoted, componentsStale, unresolved,\n } = merge;\n if (text !== null) {\n writes.push(planWrite(livingOpenapi, text));\n // The parenthesised list names the OPERATIONS the delta merged, and a\n // delta whose whole change is a component has none — so this printed\n // `merged ()`, the same empty-parenthesis lie the create branch above\n // is commented for: it reads as \"this merge wrote nothing\" about a\n // merge that just published a shared schema to every consumer of the\n // fleet. Name the components it added instead, and drop the\n // parentheses entirely when there is nothing to put in them — a delta\n // that only EDITED existing surfaces is named by the lines below.\n const mergedNames = ops.length > 0 ? ops : componentsAdded.map((comp) => `component ${comp}`);\n say(` openapi: ${svc} — merged${mergedNames.length > 0 ? ` (${mergedNames.join(\", \")})` : \"\"}`);\n }\n if (removed.length > 0) {\n openapiRemovals.push({ service: svc, operations: removed });\n for (const label of removed) say(` - removes ${label}`);\n }\n // Said out loud, because \"the plan wrote less than my delta spells\" is\n // the one thing a reader cannot infer from a merged file. Not a warning:\n // quoting the contract around your change is correct authoring, and\n // leaving the quote alone is the correct merge. The path-level and\n // component quotes get the same sentence for the same reason.\n for (const label of quoted) say(` · quotes ${label} — unchanged since it was pinned, left as living has it`);\n for (const label of pathItemQuoted) {\n say(` · quotes path-level ${label} — unchanged since it was pinned, left as living has it`);\n }\n for (const comp of componentsQuoted) {\n say(` · quotes component ${comp} — unchanged since it was pinned, left as living has it`);\n }\n // Stale surfaces reaching the merge at all means --approve pushed past\n // the gate's openapi.baseline-stale — the plan still names what it cost.\n for (const label of pathItemStale) {\n say(` ⚠ stale baseline on path-level ${label} — the living value moved since this delta was pinned; the overwrite is what --approve chose`);\n }\n for (const comp of componentsStale) {\n say(` ⚠ stale baseline on component ${comp} — the living value moved since this delta was pinned; the overwrite is what --approve chose`);\n }\n for (const label of modified) {\n planWarns.push({\n severity: \"warn\",\n code: \"openapi.op-modified\",\n subject: svc,\n message: `${svc}: the delta redefines ${label}, which the living OpenAPI already has — the merge overwrites the living operation wholesale`,\n });\n say(` ⚠ overwrites ${label} — the living definition differs`);\n }\n for (const label of pathItemModified) {\n planWarns.push({\n severity: \"warn\",\n code: \"openapi.path-item-modified\",\n subject: svc,\n message: `${svc}: the delta redefines the path-level key ${label}, which the living OpenAPI already has — the merge overwrites it wholesale, and it applies to EVERY operation on that path, including ones this feature never mentions`,\n });\n say(` ⚠ overwrites path-level ${label} — the living definition differs`);\n }\n for (const comp of componentsModified) {\n planWarns.push({\n severity: \"warn\",\n code: \"openapi.component-modified\",\n subject: svc,\n message: `${svc}: the delta declares component '${comp}', which the living OpenAPI already defines differently — the merge overwrites the living component wholesale`,\n });\n say(` ⚠ overwrites component ${comp} — the living definition differs`);\n }\n for (const u of unresolved) {\n planGates.push({\n severity: \"error\",\n code: \"openapi.ref-unresolved\",\n subject: svc,\n message: `${svc}: $ref '${u.ref}' (referenced from ${u.from}) resolves in neither the feature's openapi.yaml nor the living one — the merged document would carry a dangling reference`,\n });\n }\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every refusal that happens before a byte is planned.
|
|
3
|
+
*
|
|
4
|
+
* They are gathered here because they share one doctrine that is easy to lose:
|
|
5
|
+
* `--approve` overrides judgments about the FEATURE, and nothing else. A service
|
|
6
|
+
* directory whose name the id grammar refuses, a living document holding git
|
|
7
|
+
* conflict markers, a requirement outside `## Requirements` — those are
|
|
8
|
+
* mechanical facts about paths and files, so `--approve` does not reach them,
|
|
9
|
+
* and the dry run is gated too, since a plan built on one describes a merge loam
|
|
10
|
+
* must never perform.
|
|
11
|
+
*
|
|
12
|
+
* `null` means the refusal has already been printed and the exit code set.
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { fail, repoPath, sayExplain } from "../../../core/envelope/json.js";
|
|
17
|
+
import { approveOverrides, gatesArchive } from "../../../core/vocabulary/issue.js";
|
|
18
|
+
import { recoverInterruptedCommit } from "../../../core/staging/recovery/recover.js";
|
|
19
|
+
import { readUtf8 } from "../../../core/staging/writes.js";
|
|
20
|
+
import { loadFile } from "../../../core/c4/likec4.js";
|
|
21
|
+
import { archiveDir as archiveRoot, featurePaths, featureSpecPaths, SPEC_AXES } from "../../../core/repo/paths.js";
|
|
22
|
+
import { livingCapabilityPaths } from "../../../core/repo/authored/paths.js";
|
|
23
|
+
import { featureCapabilityDeltas } from "../../../core/capabilities/delta/tree.js";
|
|
24
|
+
import { locateServicePaths } from "../../../core/repo/service-target.js";
|
|
25
|
+
import { featureSpecServices, missingFeatureMessage, resolveFeature } from "../../../core/repo/repo.js";
|
|
26
|
+
import { featureCoherence } from "../../../core/coherence/coherence.js";
|
|
27
|
+
import { invalidSpecServiceFindings, livingMergeConflicts, unknownDeltaServices, } from "../../../core/coherence/living.js";
|
|
28
|
+
import { SEVERITY_MARK } from "../../../core/vocabulary/report.js";
|
|
29
|
+
import { isRequirementsHeading, parseRequirements } from "../../../core/document/parse.js";
|
|
30
|
+
import { refuseFindings, refuseJson, sayRecovery } from "./refusal.js";
|
|
31
|
+
import {} from "./state.js";
|
|
32
|
+
export async function gate(config, featureId, opts, say) {
|
|
33
|
+
const json = opts.json === true;
|
|
34
|
+
const dryRun = opts.dryRun === true;
|
|
35
|
+
// the living docs half-written, and every other command in loam would have
|
|
36
|
+
// planned against them as if they were the truth. Under the same lock, so the
|
|
37
|
+
// repair cannot race a writer. It refuses when the half-merged files have been
|
|
38
|
+
// edited since — that is a human's call, not a merge's.
|
|
39
|
+
const recovered = await recoverInterruptedCommit(config.docsDir);
|
|
40
|
+
if (recovered !== null && !json)
|
|
41
|
+
sayRecovery(recovered);
|
|
42
|
+
const feature = await resolveFeature(config.docsDir, featureId, "exclude");
|
|
43
|
+
if (!feature) {
|
|
44
|
+
fail(json, "unknown-target", await missingFeatureMessage(config.docsDir, featureId));
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
// The raw argument's last appearance: from here on the feature answers only to
|
|
48
|
+
// its canonical id — tags, coherence, and the self-exclusion scans all match
|
|
49
|
+
// on `id`, and `archive FEAT-5-slug` must plan exactly like `archive FEAT-5`.
|
|
50
|
+
const { id, dirName, dir: featureDir } = feature;
|
|
51
|
+
// Parse delta.likec4 ONCE for the whole run: the coherence gate and the
|
|
52
|
+
// architecture merge below read the same file, and loading it spins up a
|
|
53
|
+
// fresh Langium workspace each time. Nothing writes it in between.
|
|
54
|
+
const deltaLikec4 = featurePaths(featureDir).delta;
|
|
55
|
+
const deltaDoc = existsSync(deltaLikec4) ? await loadFile(deltaLikec4) : undefined;
|
|
56
|
+
const deltaServices = await featureSpecServices(featureDir);
|
|
57
|
+
// The business corpus's delta tree, walked once HERE and carried on `Gated`:
|
|
58
|
+
// the conflict-marker scan, the strayed-requirement scan and the merge itself
|
|
59
|
+
// all ask which capability documents this feature rewrites, and three walks
|
|
60
|
+
// are three chances to answer differently. `featureCoherence` below walks it
|
|
61
|
+
// again on its own — it is called without `config.fleet`, the same
|
|
62
|
+
// no-context path `core/coherence/declared.ts` already documents paying for
|
|
63
|
+
// the arch delta — so this is not the run's only walk, only the one every
|
|
64
|
+
// phase downstream of the gate shares.
|
|
65
|
+
const capabilityDeltas = (config.fleet === undefined
|
|
66
|
+
? await featureCapabilityDeltas(featureDir)
|
|
67
|
+
: await config.fleet.featureCapabilityDeltas(featureDir)).docs;
|
|
68
|
+
// A `specs/<svc>/` whose NAME is not a legal service id, refused before
|
|
69
|
+
// anything joins that name into a path: the conflict scan below probes
|
|
70
|
+
// `services/<svc>/<axis>` with it, and the requirements merge would
|
|
71
|
+
// materialise `services/<svc>/` from it — a directory `service.id-invalid`
|
|
72
|
+
// then calls an error on the next `validate --all`, and one no loam command
|
|
73
|
+
// can address or re-create. The set comes from coherence/living.ts's
|
|
74
|
+
// `invalidSpecServiceFindings` — the same function validate reads — so the
|
|
75
|
+
// two gates cannot drift.
|
|
76
|
+
//
|
|
77
|
+
// --approve does not apply, exactly as with the conflict-marker refusal
|
|
78
|
+
// below: --approve overrides judgments about the FEATURE, and a name the id
|
|
79
|
+
// grammar refuses is a mechanical fact about the path it would become. The
|
|
80
|
+
// dry run is gated too: a plan built on that name describes a merge loam
|
|
81
|
+
// must never perform.
|
|
82
|
+
const illegalServices = await invalidSpecServiceFindings(featureDir);
|
|
83
|
+
if (illegalServices.length > 0) {
|
|
84
|
+
const msg = `archive ${id} — BLOCKED: ${illegalServices.length} per-service delta(s) named by an illegal service id; --approve does not override this`;
|
|
85
|
+
if (json) {
|
|
86
|
+
refuseFindings("not-coherent", msg, illegalServices, `features/${dirName}`);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
console.error(`${msg}:`);
|
|
90
|
+
for (const f of illegalServices)
|
|
91
|
+
console.error(` ✗ ${f.message}`);
|
|
92
|
+
console.error(`\n--approve does not override this — the directory the merge would create is one loam can never address, mechanically.`);
|
|
93
|
+
// Every arm in this file refuses by hand — it prints a headline, a list and
|
|
94
|
+
// a closing sentence rather than the one message `fail()` takes — so the
|
|
95
|
+
// code and its lookup have to be asked for explicitly. `sayExplain` is
|
|
96
|
+
// called rather than the format being copied six times, and the code passed
|
|
97
|
+
// is the SAME one the `--json` branch a few lines up emits: text and
|
|
98
|
+
// envelope must name one refusal, or a reader who switches modes to find
|
|
99
|
+
// the code is handed a different answer than the one they saw.
|
|
100
|
+
sayExplain("not-coherent");
|
|
101
|
+
process.exitCode = 1;
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
// Git conflict markers in a LIVING document this merge would rewrite, before
|
|
105
|
+
// anything else is asked of it. Both sides of somebody's merge are in the
|
|
106
|
+
// file, so nothing it says is anyone's text — and the requirements rewrite
|
|
107
|
+
// deletes whichever marker lines fall inside the section it owns, turning a
|
|
108
|
+
// conflict anyone can see into a file nobody can tell is wrong. Checked ahead
|
|
109
|
+
// of the coherence gate for `inspectLandscape`'s reason: a conflicted
|
|
110
|
+
// document parses, so every verdict downstream of it is an opinion about half
|
|
111
|
+
// of two people's work.
|
|
112
|
+
//
|
|
113
|
+
// --approve does not apply, exactly as with the strayed-requirement refusal
|
|
114
|
+
// below: --approve overrides judgments about the FEATURE, and this is a fact
|
|
115
|
+
// about the living document.
|
|
116
|
+
const conflicted = await livingMergeConflicts(config.docsDir, deltaServices, capabilityDeltas.map((d) => d.id));
|
|
117
|
+
if (conflicted.length > 0) {
|
|
118
|
+
const msg = `archive ${id} — BLOCKED: ${conflicted.length} living document(s) still hold git conflict markers`;
|
|
119
|
+
if (json) {
|
|
120
|
+
refuseFindings("merge-failed", msg, conflicted, `features/${dirName}`);
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
console.error(`${msg}:`);
|
|
124
|
+
for (const f of conflicted)
|
|
125
|
+
console.error(` ✗ ${f.message}`);
|
|
126
|
+
console.error(`\n--approve does not override this — the loss is mechanical, not a judgment call.`);
|
|
127
|
+
sayExplain("merge-failed");
|
|
128
|
+
process.exitCode = 1;
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
// Gate: GATING issues block the archive. Severity and gating are two
|
|
132
|
+
// different questions (issue.ts): errors gate because the merge would write
|
|
133
|
+
// something wrong, and the rare warning marked `gates` blocks too — the
|
|
134
|
+
// document is legal but the merge would drop authored content. Advisory
|
|
135
|
+
// warnings are printed (and carried into --json) but never block, matching
|
|
136
|
+
// validate's own doctrine (report.ts: "warnings never gate"). --approve
|
|
137
|
+
// overrides the gating issues ONLY, and must say exactly which ones it is
|
|
138
|
+
// walking past. A dry run is gated too: a plan for a merge that would be
|
|
139
|
+
// refused describes nothing that will happen.
|
|
140
|
+
const issues = await featureCoherence({ docsDir: config.docsDir, featureDir, featureId: id, preloadedDelta: deltaDoc });
|
|
141
|
+
// The issues --approve cannot move, carved out before the gate below reads
|
|
142
|
+
// the rest. The register is issue.ts's `approveOverrides` — the same data
|
|
143
|
+
// the `overridable` key in the envelope is resolved from — never a code
|
|
144
|
+
// string spelled here, because two spellings of "what the flag moves" would
|
|
145
|
+
// drift. Today the register holds one code: a `metadata { service }` binding
|
|
146
|
+
// the id grammar refuses, anywhere in a tagged element's spliced block. The
|
|
147
|
+
// landscape merge would splice that name into the living map verbatim, and
|
|
148
|
+
// the new-service scan would probe `services/<binding>/` with it — a '../'
|
|
149
|
+
// collapses the probe out of services/ altogether — so the refusal is a
|
|
150
|
+
// mechanical fact about the path the name becomes, not a judgment about the
|
|
151
|
+
// feature. Same doctrine as the illegal-specs-name refusal above; the dry
|
|
152
|
+
// run is gated the same way, and the --json envelope stays not-coherent
|
|
153
|
+
// with every issue attached, exactly like the overridable branch below, so
|
|
154
|
+
// a consumer branches on the code and not on which refusal path fired.
|
|
155
|
+
const nonOverridable = issues.filter((i) => !approveOverrides(i));
|
|
156
|
+
if (nonOverridable.length > 0) {
|
|
157
|
+
const msg = `archive ${id} — BLOCKED: ${nonOverridable.length} element binding(s) name an illegal service id; --approve does not override this`;
|
|
158
|
+
if (json) {
|
|
159
|
+
refuseJson("not-coherent", msg, issues, `features/${dirName}`);
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
console.error(`${msg}:`);
|
|
163
|
+
// The whole list, not just the carve-out: the reader is about to fix the
|
|
164
|
+
// feature, and the issues --approve COULD have moved are work they still
|
|
165
|
+
// owe — hiding them here made the second refusal a surprise. The closing
|
|
166
|
+
// line says which of the marks the flag cannot move.
|
|
167
|
+
for (const i of issues)
|
|
168
|
+
console.error(` ${SEVERITY_MARK[i.severity]} ${i.message}`);
|
|
169
|
+
console.error(`\nOf these, --approve does not override the ${nonOverridable.length} illegal binding(s) — the merge would write a name loam can never resolve into services/, mechanically. Fix the binding(s); the other issues gate as usual.`);
|
|
170
|
+
sayExplain("not-coherent");
|
|
171
|
+
process.exitCode = 1;
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const gating = issues.filter(gatesArchive);
|
|
175
|
+
const advisory = issues.filter((i) => !gatesArchive(i));
|
|
176
|
+
if (gating.length > 0 && !opts.approve) {
|
|
177
|
+
const msg = `archive ${id} — BLOCKED: not coherent (${gating.length} gating issue(s), ${advisory.length} advisory warning(s))`;
|
|
178
|
+
if (json) {
|
|
179
|
+
refuseJson("not-coherent", msg, issues, `features/${dirName}`);
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
console.error(`${msg}:`);
|
|
183
|
+
for (const i of issues)
|
|
184
|
+
console.error(` ${SEVERITY_MARK[i.severity]} ${i.message}`);
|
|
185
|
+
console.error(`\nFix the gating issues (advisory warnings never block), or re-run with --approve to override them (may corrupt the living docs).`);
|
|
186
|
+
sayExplain("not-coherent");
|
|
187
|
+
process.exitCode = 1;
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
if (gating.length > 0) {
|
|
191
|
+
say(`⚠ archiving despite ${gating.length} gating issue(s) (--approve):`);
|
|
192
|
+
for (const i of gating)
|
|
193
|
+
say(` ${SEVERITY_MARK[i.severity]} ${i.message}`);
|
|
194
|
+
say();
|
|
195
|
+
}
|
|
196
|
+
if (advisory.length > 0) {
|
|
197
|
+
say(`⚠ ${advisory.length} warning(s) (non-blocking):`);
|
|
198
|
+
for (const i of advisory)
|
|
199
|
+
say(` ⚠ ${i.message}`);
|
|
200
|
+
say();
|
|
201
|
+
}
|
|
202
|
+
// A `specs/<svc>/` addressed to a service that exists nowhere. `validate`
|
|
203
|
+
// graded this and archive did not, which is the half that costs something:
|
|
204
|
+
// `specs/<svc>/` is what the merge MATERIALISES `services/<svc>/` from, so a
|
|
205
|
+
// one-character slip in `--touches` archived at exit 0 and left the fleet a
|
|
206
|
+
// living service nobody meant to adopt. The set comes from coherence/living.ts's
|
|
207
|
+
// `unknownDeltaServices` — the same function validate reads — so the two
|
|
208
|
+
// gates cannot drift into disagreeing about which ids are real.
|
|
209
|
+
//
|
|
210
|
+
// Gated exactly like a coherence error, --approve included: which service you
|
|
211
|
+
// meant is a judgment about the FEATURE. A feature that genuinely introduces
|
|
212
|
+
// one has a better escape hatch than --approve anyway — tag its element in
|
|
213
|
+
// delta.likec4, which is also what makes the fleet map true afterwards.
|
|
214
|
+
const unknownServices = await unknownDeltaServices(config.docsDir, featureDir, id, { preloadedDelta: deltaDoc });
|
|
215
|
+
if (unknownServices.length > 0 && !opts.approve) {
|
|
216
|
+
const msg = `archive ${id} — BLOCKED: ${unknownServices.length} per-service delta(s) address a service that does not exist`;
|
|
217
|
+
if (json) {
|
|
218
|
+
refuseFindings("not-coherent", msg, unknownServices, `features/${dirName}`);
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
console.error(`${msg}:`);
|
|
222
|
+
for (const f of unknownServices)
|
|
223
|
+
console.error(` ✗ ${f.message}`);
|
|
224
|
+
console.error(`\nFix the id, or introduce the service in this feature's delta.likec4 — or re-run with --approve to create it anyway.`);
|
|
225
|
+
sayExplain("not-coherent");
|
|
226
|
+
process.exitCode = 1;
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
if (unknownServices.length > 0) {
|
|
230
|
+
say(`⚠ archiving despite ${unknownServices.length} unknown service(s) (--approve) — this merge creates them:`);
|
|
231
|
+
for (const f of unknownServices)
|
|
232
|
+
say(` ✗ ${f.message}`);
|
|
233
|
+
say();
|
|
234
|
+
}
|
|
235
|
+
// A LIVING requirement outside `## Requirements` is a merge loam cannot do
|
|
236
|
+
// correctly: the rewrite replaces only the requirements RUN inside that
|
|
237
|
+
// section (rewriteRequirementsRun) while parseRequirements collects from
|
|
238
|
+
// every section — so the strayed requirement keeps its authored copy in the
|
|
239
|
+
// preserved prose AND lands again in the rewritten run, and the next
|
|
240
|
+
// archive's MODIFIED replaces only one of them. Refused rather than
|
|
241
|
+
// repaired: excising blocks from prose programmatically would be archive
|
|
242
|
+
// editing text it does not understand. --approve does not apply — it
|
|
243
|
+
// overrides judgments about the FEATURE, and this is neither.
|
|
244
|
+
const strayed = [];
|
|
245
|
+
const scanStrayed = async (livingPath, subject) => {
|
|
246
|
+
if (!existsSync(livingPath))
|
|
247
|
+
return;
|
|
248
|
+
for (const r of parseRequirements(await readUtf8(livingPath))) {
|
|
249
|
+
// The ONE definition of the heading (spec.ts): the guard and the rewrite
|
|
250
|
+
// boundary match the same way, so they cannot disagree about "outside".
|
|
251
|
+
if (r.section !== undefined && isRequirementsHeading(r.section))
|
|
252
|
+
continue;
|
|
253
|
+
const where = r.section === undefined ? "above every heading" : `under '${r.section}'`;
|
|
254
|
+
strayed.push({
|
|
255
|
+
severity: "error",
|
|
256
|
+
code: "living.requirement-outside-requirements",
|
|
257
|
+
subject,
|
|
258
|
+
message: `${subject}: living requirement '${r.name}' sits ${where} in ${repoPath(config.docsDir, livingPath)} — the merge rewrites only '## Requirements', so it would land in the file twice. Re-home it under '## Requirements' first, then re-run.`,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
for (const svc of deltaServices) {
|
|
263
|
+
for (const axis of SPEC_AXES) {
|
|
264
|
+
if (!existsSync(featureSpecPaths(featureDir, svc)[axis.key]))
|
|
265
|
+
continue;
|
|
266
|
+
// The shared context, because this sits in a deltaServices × SPEC_AXES
|
|
267
|
+
// loop: without it every iteration re-walks and re-reads the fleet.
|
|
268
|
+
await scanStrayed((await locateServicePaths(config.docsDir, svc, config.fleet))[axis.key], svc);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// The business corpus, for the identical mechanical reason: a capability
|
|
272
|
+
// document is narrative ABOVE `## Requirements`, `rewriteRequirementsRun`
|
|
273
|
+
// rewrites only the run inside that heading, and a requirement filed under
|
|
274
|
+
// `## Notes` would keep its authored copy in the preserved prose AND land
|
|
275
|
+
// again in the rewritten run.
|
|
276
|
+
for (const doc of capabilityDeltas) {
|
|
277
|
+
await scanStrayed(livingCapabilityPaths(config.docsDir, doc.id).spec, doc.id);
|
|
278
|
+
}
|
|
279
|
+
if (strayed.length > 0) {
|
|
280
|
+
const msg = `archive ${id} — BLOCKED: ${strayed.length} living requirement(s) outside '## Requirements'`;
|
|
281
|
+
if (json) {
|
|
282
|
+
refuseJson("living-outside-requirements", msg, strayed, `features/${dirName}`);
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
console.error(`${msg}:`);
|
|
286
|
+
for (const i of strayed)
|
|
287
|
+
console.error(` ✗ ${i.message}`);
|
|
288
|
+
console.error(`\n--approve does not override this — the duplication is mechanical, not a judgment call.`);
|
|
289
|
+
sayExplain("living-outside-requirements");
|
|
290
|
+
process.exitCode = 1;
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
// Pre-flight: the archive destination must be free, or the final move would fail
|
|
294
|
+
// after the living docs were already rewritten.
|
|
295
|
+
const archiveDir = archiveRoot(config.docsDir);
|
|
296
|
+
const archiveDest = join(archiveDir, dirName);
|
|
297
|
+
if (existsSync(archiveDest)) {
|
|
298
|
+
fail(json, "archive-exists", `archive ${id} — BLOCKED: features/archive/${dirName} already exists. Remove or rename it, then re-run.`);
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
say(`archive ${id}${dryRun ? " (dry run)" : ""}\n`);
|
|
302
|
+
return {
|
|
303
|
+
id,
|
|
304
|
+
dirName,
|
|
305
|
+
featureDir,
|
|
306
|
+
deltaDoc,
|
|
307
|
+
deltaServices,
|
|
308
|
+
capabilityDeltas,
|
|
309
|
+
gating,
|
|
310
|
+
advisory,
|
|
311
|
+
archiveDir,
|
|
312
|
+
archiveDest,
|
|
313
|
+
recovered,
|
|
314
|
+
issues,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
//# sourceMappingURL=gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../../../src/commands/archive/plan/gate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Every refusal that happens before a byte is planned.\n *\n * They are gathered here because they share one doctrine that is easy to lose:\n * `--approve` overrides judgments about the FEATURE, and nothing else. A service\n * directory whose name the id grammar refuses, a living document holding git\n * conflict markers, a requirement outside `## Requirements` — those are\n * mechanical facts about paths and files, so `--approve` does not reach them,\n * and the dry run is gated too, since a plan built on one describes a merge loam\n * must never perform.\n *\n * `null` means the refusal has already been printed and the exit code set.\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fail, repoPath, sayExplain } from \"../../../core/envelope/json.js\";\nimport { approveOverrides, gatesArchive, type Issue } from \"../../../core/vocabulary/issue.js\";\nimport { recoverInterruptedCommit } from \"../../../core/staging/recovery/recover.js\";\nimport { readUtf8 } from \"../../../core/staging/writes.js\";\nimport { loadFile } from \"../../../core/c4/likec4.js\";\nimport { archiveDir as archiveRoot, featurePaths, featureSpecPaths, SPEC_AXES } from \"../../../core/repo/paths.js\";\nimport { livingCapabilityPaths } from \"../../../core/repo/authored/paths.js\";\nimport { featureCapabilityDeltas } from \"../../../core/capabilities/delta/tree.js\";\nimport { locateServicePaths } from \"../../../core/repo/service-target.js\";\nimport { featureSpecServices, missingFeatureMessage, resolveFeature } from \"../../../core/repo/repo.js\";\nimport { featureCoherence } from \"../../../core/coherence/coherence.js\";\nimport {\n invalidSpecServiceFindings,\n livingMergeConflicts,\n unknownDeltaServices,\n} from \"../../../core/coherence/living.js\";\nimport { SEVERITY_MARK } from \"../../../core/vocabulary/report.js\";\nimport { isRequirementsHeading, parseRequirements } from \"../../../core/document/parse.js\";\nimport { refuseFindings, refuseJson, sayRecovery, type ArchiveOptions } from \"./refusal.js\";\nimport { type Gated } from \"./state.js\";\nimport type { DocsDir } from \"../../../core/kernel/ids/dirs.js\";\nimport type { FleetContext } from \"../../../core/fleet-context.js\";\n\nexport async function gate(\n config: { docsDir: DocsDir; fleet?: FleetContext },\n featureId: string,\n opts: ArchiveOptions,\n say: (line?: string) => void,\n): Promise<Gated | null> {\n const json = opts.json === true;\n const dryRun = opts.dryRun === true;\n // the living docs half-written, and every other command in loam would have\n // planned against them as if they were the truth. Under the same lock, so the\n // repair cannot race a writer. It refuses when the half-merged files have been\n // edited since — that is a human's call, not a merge's.\n const recovered = await recoverInterruptedCommit(config.docsDir);\n if (recovered !== null && !json) sayRecovery(recovered);\n\n const feature = await resolveFeature(config.docsDir, featureId, \"exclude\");\n if (!feature) {\n fail(json, \"unknown-target\", await missingFeatureMessage(config.docsDir, featureId));\n return null;\n }\n // The raw argument's last appearance: from here on the feature answers only to\n // its canonical id — tags, coherence, and the self-exclusion scans all match\n // on `id`, and `archive FEAT-5-slug` must plan exactly like `archive FEAT-5`.\n const { id, dirName, dir: featureDir } = feature;\n\n // Parse delta.likec4 ONCE for the whole run: the coherence gate and the\n // architecture merge below read the same file, and loading it spins up a\n // fresh Langium workspace each time. Nothing writes it in between.\n const deltaLikec4 = featurePaths(featureDir).delta;\n const deltaDoc = existsSync(deltaLikec4) ? await loadFile(deltaLikec4) : undefined;\n\n const deltaServices = await featureSpecServices(featureDir);\n // The business corpus's delta tree, walked once HERE and carried on `Gated`:\n // the conflict-marker scan, the strayed-requirement scan and the merge itself\n // all ask which capability documents this feature rewrites, and three walks\n // are three chances to answer differently. `featureCoherence` below walks it\n // again on its own — it is called without `config.fleet`, the same\n // no-context path `core/coherence/declared.ts` already documents paying for\n // the arch delta — so this is not the run's only walk, only the one every\n // phase downstream of the gate shares.\n const capabilityDeltas = (\n config.fleet === undefined\n ? await featureCapabilityDeltas(featureDir)\n : await config.fleet.featureCapabilityDeltas(featureDir)\n ).docs;\n\n // A `specs/<svc>/` whose NAME is not a legal service id, refused before\n // anything joins that name into a path: the conflict scan below probes\n // `services/<svc>/<axis>` with it, and the requirements merge would\n // materialise `services/<svc>/` from it — a directory `service.id-invalid`\n // then calls an error on the next `validate --all`, and one no loam command\n // can address or re-create. The set comes from coherence/living.ts's\n // `invalidSpecServiceFindings` — the same function validate reads — so the\n // two gates cannot drift.\n //\n // --approve does not apply, exactly as with the conflict-marker refusal\n // below: --approve overrides judgments about the FEATURE, and a name the id\n // grammar refuses is a mechanical fact about the path it would become. The\n // dry run is gated too: a plan built on that name describes a merge loam\n // must never perform.\n const illegalServices = await invalidSpecServiceFindings(featureDir);\n if (illegalServices.length > 0) {\n const msg = `archive ${id} — BLOCKED: ${illegalServices.length} per-service delta(s) named by an illegal service id; --approve does not override this`;\n if (json) {\n refuseFindings(\"not-coherent\", msg, illegalServices, `features/${dirName}`);\n return null;\n }\n console.error(`${msg}:`);\n for (const f of illegalServices) console.error(` ✗ ${f.message}`);\n console.error(`\\n--approve does not override this — the directory the merge would create is one loam can never address, mechanically.`);\n // Every arm in this file refuses by hand — it prints a headline, a list and\n // a closing sentence rather than the one message `fail()` takes — so the\n // code and its lookup have to be asked for explicitly. `sayExplain` is\n // called rather than the format being copied six times, and the code passed\n // is the SAME one the `--json` branch a few lines up emits: text and\n // envelope must name one refusal, or a reader who switches modes to find\n // the code is handed a different answer than the one they saw.\n sayExplain(\"not-coherent\");\n process.exitCode = 1;\n return null;\n }\n\n // Git conflict markers in a LIVING document this merge would rewrite, before\n // anything else is asked of it. Both sides of somebody's merge are in the\n // file, so nothing it says is anyone's text — and the requirements rewrite\n // deletes whichever marker lines fall inside the section it owns, turning a\n // conflict anyone can see into a file nobody can tell is wrong. Checked ahead\n // of the coherence gate for `inspectLandscape`'s reason: a conflicted\n // document parses, so every verdict downstream of it is an opinion about half\n // of two people's work.\n //\n // --approve does not apply, exactly as with the strayed-requirement refusal\n // below: --approve overrides judgments about the FEATURE, and this is a fact\n // about the living document.\n const conflicted = await livingMergeConflicts(config.docsDir, deltaServices, capabilityDeltas.map((d) => d.id));\n if (conflicted.length > 0) {\n const msg = `archive ${id} — BLOCKED: ${conflicted.length} living document(s) still hold git conflict markers`;\n if (json) {\n refuseFindings(\"merge-failed\", msg, conflicted, `features/${dirName}`);\n return null;\n }\n console.error(`${msg}:`);\n for (const f of conflicted) console.error(` ✗ ${f.message}`);\n console.error(`\\n--approve does not override this — the loss is mechanical, not a judgment call.`);\n sayExplain(\"merge-failed\");\n process.exitCode = 1;\n return null;\n }\n\n // Gate: GATING issues block the archive. Severity and gating are two\n // different questions (issue.ts): errors gate because the merge would write\n // something wrong, and the rare warning marked `gates` blocks too — the\n // document is legal but the merge would drop authored content. Advisory\n // warnings are printed (and carried into --json) but never block, matching\n // validate's own doctrine (report.ts: \"warnings never gate\"). --approve\n // overrides the gating issues ONLY, and must say exactly which ones it is\n // walking past. A dry run is gated too: a plan for a merge that would be\n // refused describes nothing that will happen.\n const issues = await featureCoherence({ docsDir: config.docsDir, featureDir, featureId: id, preloadedDelta: deltaDoc });\n // The issues --approve cannot move, carved out before the gate below reads\n // the rest. The register is issue.ts's `approveOverrides` — the same data\n // the `overridable` key in the envelope is resolved from — never a code\n // string spelled here, because two spellings of \"what the flag moves\" would\n // drift. Today the register holds one code: a `metadata { service }` binding\n // the id grammar refuses, anywhere in a tagged element's spliced block. The\n // landscape merge would splice that name into the living map verbatim, and\n // the new-service scan would probe `services/<binding>/` with it — a '../'\n // collapses the probe out of services/ altogether — so the refusal is a\n // mechanical fact about the path the name becomes, not a judgment about the\n // feature. Same doctrine as the illegal-specs-name refusal above; the dry\n // run is gated the same way, and the --json envelope stays not-coherent\n // with every issue attached, exactly like the overridable branch below, so\n // a consumer branches on the code and not on which refusal path fired.\n const nonOverridable = issues.filter((i) => !approveOverrides(i));\n if (nonOverridable.length > 0) {\n const msg = `archive ${id} — BLOCKED: ${nonOverridable.length} element binding(s) name an illegal service id; --approve does not override this`;\n if (json) {\n refuseJson(\"not-coherent\", msg, issues, `features/${dirName}`);\n return null;\n }\n console.error(`${msg}:`);\n // The whole list, not just the carve-out: the reader is about to fix the\n // feature, and the issues --approve COULD have moved are work they still\n // owe — hiding them here made the second refusal a surprise. The closing\n // line says which of the marks the flag cannot move.\n for (const i of issues) console.error(` ${SEVERITY_MARK[i.severity]} ${i.message}`);\n console.error(\n `\\nOf these, --approve does not override the ${nonOverridable.length} illegal binding(s) — the merge would write a name loam can never resolve into services/, mechanically. Fix the binding(s); the other issues gate as usual.`,\n );\n sayExplain(\"not-coherent\");\n process.exitCode = 1;\n return null;\n }\n const gating = issues.filter(gatesArchive);\n const advisory = issues.filter((i) => !gatesArchive(i));\n if (gating.length > 0 && !opts.approve) {\n const msg = `archive ${id} — BLOCKED: not coherent (${gating.length} gating issue(s), ${advisory.length} advisory warning(s))`;\n if (json) {\n refuseJson(\"not-coherent\", msg, issues, `features/${dirName}`);\n return null;\n }\n console.error(`${msg}:`);\n for (const i of issues) console.error(` ${SEVERITY_MARK[i.severity]} ${i.message}`);\n console.error(`\\nFix the gating issues (advisory warnings never block), or re-run with --approve to override them (may corrupt the living docs).`);\n sayExplain(\"not-coherent\");\n process.exitCode = 1;\n return null;\n }\n if (gating.length > 0) {\n say(`⚠ archiving despite ${gating.length} gating issue(s) (--approve):`);\n for (const i of gating) say(` ${SEVERITY_MARK[i.severity]} ${i.message}`);\n say();\n }\n if (advisory.length > 0) {\n say(`⚠ ${advisory.length} warning(s) (non-blocking):`);\n for (const i of advisory) say(` ⚠ ${i.message}`);\n say();\n }\n\n // A `specs/<svc>/` addressed to a service that exists nowhere. `validate`\n // graded this and archive did not, which is the half that costs something:\n // `specs/<svc>/` is what the merge MATERIALISES `services/<svc>/` from, so a\n // one-character slip in `--touches` archived at exit 0 and left the fleet a\n // living service nobody meant to adopt. The set comes from coherence/living.ts's\n // `unknownDeltaServices` — the same function validate reads — so the two\n // gates cannot drift into disagreeing about which ids are real.\n //\n // Gated exactly like a coherence error, --approve included: which service you\n // meant is a judgment about the FEATURE. A feature that genuinely introduces\n // one has a better escape hatch than --approve anyway — tag its element in\n // delta.likec4, which is also what makes the fleet map true afterwards.\n const unknownServices = await unknownDeltaServices(config.docsDir, featureDir, id, { preloadedDelta: deltaDoc });\n if (unknownServices.length > 0 && !opts.approve) {\n const msg = `archive ${id} — BLOCKED: ${unknownServices.length} per-service delta(s) address a service that does not exist`;\n if (json) {\n refuseFindings(\"not-coherent\", msg, unknownServices, `features/${dirName}`);\n return null;\n }\n console.error(`${msg}:`);\n for (const f of unknownServices) console.error(` ✗ ${f.message}`);\n console.error(`\\nFix the id, or introduce the service in this feature's delta.likec4 — or re-run with --approve to create it anyway.`);\n sayExplain(\"not-coherent\");\n process.exitCode = 1;\n return null;\n }\n if (unknownServices.length > 0) {\n say(`⚠ archiving despite ${unknownServices.length} unknown service(s) (--approve) — this merge creates them:`);\n for (const f of unknownServices) say(` ✗ ${f.message}`);\n say();\n }\n\n // A LIVING requirement outside `## Requirements` is a merge loam cannot do\n // correctly: the rewrite replaces only the requirements RUN inside that\n // section (rewriteRequirementsRun) while parseRequirements collects from\n // every section — so the strayed requirement keeps its authored copy in the\n // preserved prose AND lands again in the rewritten run, and the next\n // archive's MODIFIED replaces only one of them. Refused rather than\n // repaired: excising blocks from prose programmatically would be archive\n // editing text it does not understand. --approve does not apply — it\n // overrides judgments about the FEATURE, and this is neither.\n const strayed: Issue[] = [];\n const scanStrayed = async (livingPath: string, subject: string): Promise<void> => {\n if (!existsSync(livingPath)) return;\n for (const r of parseRequirements(await readUtf8(livingPath))) {\n // The ONE definition of the heading (spec.ts): the guard and the rewrite\n // boundary match the same way, so they cannot disagree about \"outside\".\n if (r.section !== undefined && isRequirementsHeading(r.section)) continue;\n const where = r.section === undefined ? \"above every heading\" : `under '${r.section}'`;\n strayed.push({\n severity: \"error\",\n code: \"living.requirement-outside-requirements\",\n subject,\n message: `${subject}: living requirement '${r.name}' sits ${where} in ${repoPath(config.docsDir, livingPath)} — the merge rewrites only '## Requirements', so it would land in the file twice. Re-home it under '## Requirements' first, then re-run.`,\n });\n }\n };\n for (const svc of deltaServices) {\n for (const axis of SPEC_AXES) {\n if (!existsSync(featureSpecPaths(featureDir, svc)[axis.key])) continue;\n // The shared context, because this sits in a deltaServices × SPEC_AXES\n // loop: without it every iteration re-walks and re-reads the fleet.\n await scanStrayed((await locateServicePaths(config.docsDir, svc, config.fleet))[axis.key], svc);\n }\n }\n // The business corpus, for the identical mechanical reason: a capability\n // document is narrative ABOVE `## Requirements`, `rewriteRequirementsRun`\n // rewrites only the run inside that heading, and a requirement filed under\n // `## Notes` would keep its authored copy in the preserved prose AND land\n // again in the rewritten run.\n for (const doc of capabilityDeltas) {\n await scanStrayed(livingCapabilityPaths(config.docsDir, doc.id).spec, doc.id);\n }\n if (strayed.length > 0) {\n const msg = `archive ${id} — BLOCKED: ${strayed.length} living requirement(s) outside '## Requirements'`;\n if (json) {\n refuseJson(\"living-outside-requirements\", msg, strayed, `features/${dirName}`);\n return null;\n }\n console.error(`${msg}:`);\n for (const i of strayed) console.error(` ✗ ${i.message}`);\n console.error(`\\n--approve does not override this — the duplication is mechanical, not a judgment call.`);\n sayExplain(\"living-outside-requirements\");\n process.exitCode = 1;\n return null;\n }\n\n // Pre-flight: the archive destination must be free, or the final move would fail\n // after the living docs were already rewritten.\n const archiveDir = archiveRoot(config.docsDir);\n const archiveDest = join(archiveDir, dirName);\n if (existsSync(archiveDest)) {\n fail(json, \"archive-exists\", `archive ${id} — BLOCKED: features/archive/${dirName} already exists. Remove or rename it, then re-run.`);\n return null;\n }\n\n say(`archive ${id}${dryRun ? \" (dry run)\" : \"\"}\\n`);\n\n return {\n id,\n dirName,\n featureDir,\n deltaDoc,\n deltaServices,\n capabilityDeltas,\n gating,\n advisory,\n archiveDir,\n archiveDest,\n recovered,\n issues,\n };\n}\n"]}
|