@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.2
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 +2635 -86
- 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 +599 -0
- package/SCHEMA.md +2355 -256
- 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 +323 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +180 -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 +252 -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 +72 -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 +204 -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 +270 -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 +251 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +251 -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/{agents-stamp.js → agent/agents-stamp.js} +50 -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 +337 -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.js → asyncapi/read.js} +95 -109
- 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 +48 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +174 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/likec4.js +90 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +158 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +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 +187 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/project/staged.js +220 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/service.js +159 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/resolve/steps.js +144 -0
- package/dist/core/c4/resolve/steps.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 +139 -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 +174 -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 +287 -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/deployment/delta.js +188 -0
- package/dist/core/deployment/delta.js.map +1 -0
- package/dist/core/deployment/objects.js +145 -0
- package/dist/core/deployment/objects.js.map +1 -0
- package/dist/core/diff/base-git.js +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 +7 -64
- 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 +120 -78
- 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 +137 -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 +210 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +277 -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 +196 -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 +197 -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 +72 -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 +58 -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 -295
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/migrate-openspec.js +0 -950
- package/dist/commands/migrate-openspec.js.map +0 -1
- package/dist/commands/new.js +0 -413
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/rebase.js +0 -356
- package/dist/commands/rebase.js.map +0 -1
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/status.js +0 -262
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unarchive.js.map +0 -1
- package/dist/commands/validate.js +0 -1773
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/verify.js +0 -775
- package/dist/commands/verify.js.map +0 -1
- package/dist/commands/vouch.js +0 -421
- package/dist/commands/vouch.js.map +0 -1
- package/dist/core/agent.js +0 -2173
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agents-stamp.js.map +0 -1
- package/dist/core/arch.js +0 -130
- package/dist/core/arch.js.map +0 -1
- package/dist/core/asyncapi.js.map +0 -1
- package/dist/core/brief.js +0 -755
- package/dist/core/brief.js.map +0 -1
- package/dist/core/coherence.js +0 -577
- package/dist/core/coherence.js.map +0 -1
- package/dist/core/concurrency.js.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/delta.js +0 -476
- package/dist/core/delta.js.map +0 -1
- package/dist/core/dependencies.js +0 -356
- package/dist/core/dependencies.js.map +0 -1
- package/dist/core/doctor.js +0 -596
- package/dist/core/doctor.js.map +0 -1
- package/dist/core/document-bytes.js.map +0 -1
- package/dist/core/explore.js.map +0 -1
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/gherkin.js +0 -463
- package/dist/core/gherkin.js.map +0 -1
- package/dist/core/health.js +0 -67
- package/dist/core/health.js.map +0 -1
- package/dist/core/ids.js +0 -122
- package/dist/core/ids.js.map +0 -1
- package/dist/core/issue.js +0 -9
- package/dist/core/issue.js.map +0 -1
- package/dist/core/json.js +0 -74
- package/dist/core/json.js.map +0 -1
- package/dist/core/likec4.js +0 -489
- package/dist/core/likec4.js.map +0 -1
- package/dist/core/maturity.js +0 -66
- package/dist/core/maturity.js.map +0 -1
- package/dist/core/openapi-merge.js +0 -552
- package/dist/core/openapi-merge.js.map +0 -1
- package/dist/core/openapi.js.map +0 -1
- package/dist/core/openspec-inventory.js +0 -1440
- package/dist/core/openspec-inventory.js.map +0 -1
- package/dist/core/path-safety.js.map +0 -1
- package/dist/core/provenance.js +0 -787
- package/dist/core/provenance.js.map +0 -1
- package/dist/core/records.js.map +0 -1
- package/dist/core/repo.js +0 -438
- package/dist/core/repo.js.map +0 -1
- package/dist/core/report.js.map +0 -1
- package/dist/core/spec.js +0 -505
- package/dist/core/spec.js.map +0 -1
- package/dist/core/staging.js +0 -890
- package/dist/core/staging.js.map +0 -1
- package/dist/core/status.js +0 -1132
- package/dist/core/status.js.map +0 -1
- package/dist/core/steps.js +0 -72
- package/dist/core/steps.js.map +0 -1
- package/dist/core/verify.js +0 -807
- package/dist/core/verify.js.map +0 -1
- package/dist/core/version.js.map +0 -1
- /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
- /package/dist/core/{records.js → kernel/records.js} +0 -0
package/dist/core/delta.js
DELETED
|
@@ -1,476 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Does the diff apply to the thing it claims to change?
|
|
3
|
-
*
|
|
4
|
-
* A requirement delta is a diff against a living spec, and nothing used to check
|
|
5
|
-
* that it lands. Every failure mode here is silent today: MODIFIED of a
|
|
6
|
-
* requirement that does not exist is merged as a creation, ADDED of one that
|
|
7
|
-
* does exist REPLACES it (scenarios and all) while the author believes they are
|
|
8
|
-
* adding, and a heading that nearly matches the delta grammar parses as plain
|
|
9
|
-
* prose so archive merges nothing at all and says nothing about it.
|
|
10
|
-
*
|
|
11
|
-
* The last of those has a legal-looking cousin: a requirement under an ordinary
|
|
12
|
-
* prose heading (`## Behavior`, `## Error Handling`) is BASE too, and BASE never
|
|
13
|
-
* merges. Upstream OpenSpec deltas are written that way, so the answer is to name
|
|
14
|
-
* what will be lost rather than to start merging prose sections.
|
|
15
|
-
*
|
|
16
|
-
* These run inside the archive gate, because the merge is where the damage lands.
|
|
17
|
-
*/
|
|
18
|
-
import { existsSync } from "node:fs";
|
|
19
|
-
import { readFile } from "node:fs/promises";
|
|
20
|
-
import { relative } from "node:path";
|
|
21
|
-
import { featureSpecPaths, featureSpecServices, listFeatures, servicePaths, SPEC_AXES, } from "./repo.js";
|
|
22
|
-
import { KIND_RE, REQUIREMENT_DIGEST_LENGTH, REQUIREMENT_DIGEST_RE, basedOnDeclarations, isRequirementsHeading, parseRequirements, requirementDigest, requirementIdProblems, sectionHeadings, } from "./spec.js";
|
|
23
|
-
/**
|
|
24
|
-
* `## <word> Requirement(s)` — the shape an author reaches for. Anything matching
|
|
25
|
-
* this but not the real grammar is a near miss: `## ADDED Requirement` (singular),
|
|
26
|
-
* `## NEW Requirements`, `## ADDED Requirements:`. A bare `## Requirements` is not
|
|
27
|
-
* a near miss — quoting the living state inside a delta is legal.
|
|
28
|
-
*/
|
|
29
|
-
const NEAR_SECTION_RE = /^##\s+[A-Za-z]+\s+Requirements?\s*:?\s*$/i;
|
|
30
|
-
/**
|
|
31
|
-
* OpenSpec's fourth delta operation. NEAR_SECTION_RE already catches it, but the
|
|
32
|
-
* generic advice would mislead: a RENAMED body is FROM/TO backtick bullets, not
|
|
33
|
-
* `### Requirement:` headings, so it parses to zero requirements and even the
|
|
34
|
-
* whole-file check below has nothing to count — the heading is the only place to
|
|
35
|
-
* stop it. Rename semantics stay unimplemented (the corpus never uses them); the
|
|
36
|
-
* error says what to write instead.
|
|
37
|
-
*/
|
|
38
|
-
const RENAMED_SECTION_RE = /^##\s+RENAMED\s+Requirements?\s*:?\s*$/i;
|
|
39
|
-
// The one non-delta heading whose requirements are SUPPOSED not to merge — a
|
|
40
|
-
// delta quoting the living state for context — is `## Requirements`, matched by
|
|
41
|
-
// the shared isRequirementsHeading (spec.ts): the same definition that fixes
|
|
42
|
-
// archive's rewrite boundary, so "legal to quote" and "where the merge writes"
|
|
43
|
-
// cannot drift apart. Every other heading — `## Behavior`, `## Error Handling`,
|
|
44
|
-
// `## Notes` — leaves its requirements as BASE, which the merge skips, so the
|
|
45
|
-
// author wrote a change that will never land.
|
|
46
|
-
/** Key for the (service, axis, requirement) triple a feature claims. The two
|
|
47
|
-
* axes are separate namespaces on purpose — an arch requirement cannot conflict
|
|
48
|
-
* with a business requirement of the same name, they merge into different files. */
|
|
49
|
-
function key(service, axis, identity) {
|
|
50
|
-
return `${service}\0${axis.file}\0${identity}`;
|
|
51
|
-
}
|
|
52
|
-
/** Stable ID when present; exact heading for a legacy requirement. */
|
|
53
|
-
function requirementKey(requirement) {
|
|
54
|
-
return requirement.id === undefined ? `name:${requirement.name}` : `id:${requirement.id}`;
|
|
55
|
-
}
|
|
56
|
-
export async function deltaShapeIssues(docsDir, featureDir, featureId, context) {
|
|
57
|
-
const issues = [];
|
|
58
|
-
const services = await featureSpecServices(featureDir, context);
|
|
59
|
-
if (services.length === 0)
|
|
60
|
-
return issues;
|
|
61
|
-
// What OTHER features in flight claim. Only built when a claim has to be
|
|
62
|
-
// checked — the common case never pays for the scan.
|
|
63
|
-
let inFlight = null;
|
|
64
|
-
const claimedElsewhere = async (which, service, axis, requirement) => {
|
|
65
|
-
inFlight ??= await activeClaims(docsDir, featureId, context);
|
|
66
|
-
const map = inFlight[which];
|
|
67
|
-
return map.get(key(service, axis, requirementKey(requirement)))
|
|
68
|
-
?? map.get(key(service, axis, `name:${requirement.name}`));
|
|
69
|
-
};
|
|
70
|
-
const addedElsewhere = (service, axis, requirement) => claimedElsewhere("added", service, axis, requirement);
|
|
71
|
-
// Both requirement-carrying files per service run the same checks — one code
|
|
72
|
-
// path parameterized by filename, the merge's own factoring. `where` names
|
|
73
|
-
// the arch file in messages so a finding cannot be chased into the wrong
|
|
74
|
-
// document; spec.md keeps its historical spelling.
|
|
75
|
-
for (const service of services) {
|
|
76
|
-
for (const axis of SPEC_AXES) {
|
|
77
|
-
const specPath = featureSpecPaths(featureDir, service)[axis.key];
|
|
78
|
-
if (!existsSync(specPath))
|
|
79
|
-
continue;
|
|
80
|
-
const raw = context === undefined
|
|
81
|
-
? await readFile(specPath, "utf8")
|
|
82
|
-
: await context.readText(specPath);
|
|
83
|
-
const where = axis.key === "spec" ? service : `${service} (arch.spec.md)`;
|
|
84
|
-
for (const heading of sectionHeadings(raw)) {
|
|
85
|
-
if (KIND_RE.test(heading.text) || !NEAR_SECTION_RE.test(heading.text))
|
|
86
|
-
continue;
|
|
87
|
-
issues.push({
|
|
88
|
-
severity: "error",
|
|
89
|
-
code: "delta.unknown-section",
|
|
90
|
-
subject: service,
|
|
91
|
-
message: RENAMED_SECTION_RE.test(heading.text)
|
|
92
|
-
? `${where}: '${heading.text}' (line ${heading.line}) is OpenSpec rename syntax, which loam does not merge — carry one stable Requirement-ID through a MODIFIED requirement, or express a legacy rename as a REMOVED requirement plus an ADDED one; otherwise the rename happens to nothing`
|
|
93
|
-
: `${where}: '${heading.text}' (line ${heading.line}) is not a delta section — use '## ADDED Requirements', '## MODIFIED Requirements' or '## REMOVED Requirements', or everything under it merges as nothing`,
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
const reqs = context === undefined ? parseRequirements(raw) : await context.readRequirements(specPath);
|
|
97
|
-
for (const problem of requirementIdProblems(reqs)) {
|
|
98
|
-
if (problem.kind === "invalid") {
|
|
99
|
-
issues.push({
|
|
100
|
-
severity: "error",
|
|
101
|
-
code: "delta.requirement-id-invalid",
|
|
102
|
-
subject: service,
|
|
103
|
-
message: `${where}: requirement '${problem.requirement}' has invalid Requirement-ID '${problem.value}' — use 1-128 characters matching [A-Za-z][A-Za-z0-9._-]*`,
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
else if (problem.kind === "repeated") {
|
|
107
|
-
issues.push({
|
|
108
|
-
severity: "error",
|
|
109
|
-
code: "delta.requirement-id-repeated",
|
|
110
|
-
subject: service,
|
|
111
|
-
message: `${where}: requirement '${problem.requirement}' declares Requirement-ID ${problem.values.length} times — identity must be declared exactly once`,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
issues.push({
|
|
116
|
-
severity: "error",
|
|
117
|
-
code: "delta.requirement-id-duplicate",
|
|
118
|
-
subject: service,
|
|
119
|
-
message: `${where}: Requirement-ID '${problem.id}' is shared by ${problem.requirements.map((name) => `'${name}'`).join(", ")} — one ID may identify only one requirement`,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
// The `Based-On:` pin as a DOCUMENT question, settled before anything is
|
|
124
|
-
// compared against the living spec: a value that is not a digest, or two
|
|
125
|
-
// of them on one requirement, is a pin nobody can evaluate — and a pin
|
|
126
|
-
// that silently protects nothing is worse than no pin at all, because its
|
|
127
|
-
// author believes they are covered. ADDED is refused for the same reason
|
|
128
|
-
// rather than ignored: a requirement with no living version cannot have
|
|
129
|
-
// been written against one, so the line is a misunderstanding today and a
|
|
130
|
-
// digest-shaped lie on the day someone turns it into a MODIFIED.
|
|
131
|
-
for (const r of reqs) {
|
|
132
|
-
const declared = basedOnDeclarations(r);
|
|
133
|
-
if (declared.length > 1) {
|
|
134
|
-
issues.push({
|
|
135
|
-
severity: "error",
|
|
136
|
-
code: "delta.baseline-invalid",
|
|
137
|
-
subject: service,
|
|
138
|
-
message: `${where}: requirement '${r.name}' declares Based-On ${declared.length} times — a delta is written against exactly one living version`,
|
|
139
|
-
});
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
const pin = declared[0];
|
|
143
|
-
if (pin === undefined)
|
|
144
|
-
continue;
|
|
145
|
-
if (!REQUIREMENT_DIGEST_RE.test(pin)) {
|
|
146
|
-
issues.push({
|
|
147
|
-
severity: "error",
|
|
148
|
-
code: "delta.baseline-invalid",
|
|
149
|
-
subject: service,
|
|
150
|
-
message: `${where}: requirement '${r.name}' has invalid Based-On '${pin}' — expected ${REQUIREMENT_DIGEST_LENGTH} lowercase hex characters, as \`loam rebase\` writes them`,
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
else if (r.kind === "ADDED") {
|
|
154
|
-
issues.push({
|
|
155
|
-
severity: "error",
|
|
156
|
-
code: "delta.baseline-invalid",
|
|
157
|
-
subject: service,
|
|
158
|
-
message: `${where}: ADDED requirement '${r.name}' carries Based-On '${pin}', but an added requirement has no living version to be based on — drop the line, or make it MODIFIED`,
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
// The whole-file version of the near-miss check, and the one that cannot be
|
|
163
|
-
// dodged: NEAR_SECTION_RE only recognizes single-word misses (`## NEW
|
|
164
|
-
// Requirements`), so `## NEWLY ADDED Requirements` — or requirements under a
|
|
165
|
-
// prose heading, or under no heading at all — still parses everything as BASE
|
|
166
|
-
// and archive merges nothing, silently. Same failure class as the BOM incident
|
|
167
|
-
// (see spec.ts). A file that MIXES delta sections with quoted BASE requirements
|
|
168
|
-
// is legal authoring; a file with requirements and no delta kind anywhere is a
|
|
169
|
-
// delta that would do nothing, which cannot be what its author meant.
|
|
170
|
-
if (reqs.length > 0 && reqs.every((r) => r.kind === "BASE")) {
|
|
171
|
-
const rel = relative(docsDir, specPath).split(/[\\/]/).join("/");
|
|
172
|
-
issues.push({
|
|
173
|
-
severity: "error",
|
|
174
|
-
code: "delta.no-delta-sections",
|
|
175
|
-
subject: service,
|
|
176
|
-
message: `${service}: ${rel} contains ${reqs.length} requirement(s) but no '## ADDED|MODIFIED|REMOVED Requirements' section — this delta would merge nothing`,
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
const livingPath = servicePaths(docsDir, service)[axis.key];
|
|
180
|
-
const living = existsSync(livingPath)
|
|
181
|
-
? context === undefined
|
|
182
|
-
? parseRequirements(await readFile(livingPath, "utf8"))
|
|
183
|
-
: await context.readRequirements(livingPath)
|
|
184
|
-
: [];
|
|
185
|
-
// How the axis's living document is named in messages — spec.md keeps the
|
|
186
|
-
// historical "living spec", the arch axis says which file it means.
|
|
187
|
-
const livingDoc = axis.key === "spec" ? "living spec" : "living arch.spec.md";
|
|
188
|
-
const livingNames = new Set(living.map((r) => r.name));
|
|
189
|
-
const livingByName = new Map();
|
|
190
|
-
const livingById = new Map();
|
|
191
|
-
for (const requirement of living) {
|
|
192
|
-
const named = livingByName.get(requirement.name) ?? [];
|
|
193
|
-
named.push(requirement);
|
|
194
|
-
livingByName.set(requirement.name, named);
|
|
195
|
-
if (requirement.id !== undefined) {
|
|
196
|
-
const identified = livingById.get(requirement.id) ?? [];
|
|
197
|
-
identified.push(requirement);
|
|
198
|
-
livingById.set(requirement.id, identified);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
for (const problem of requirementIdProblems(living)) {
|
|
202
|
-
issues.push({
|
|
203
|
-
severity: "error",
|
|
204
|
-
code: "delta.living-requirement-id-invalid",
|
|
205
|
-
subject: service,
|
|
206
|
-
message: problem.kind === "invalid"
|
|
207
|
-
? `${where}: the ${livingDoc} requirement '${problem.requirement}' has invalid Requirement-ID '${problem.value}', so this delta cannot select it safely`
|
|
208
|
-
: problem.kind === "repeated"
|
|
209
|
-
? `${where}: the ${livingDoc} requirement '${problem.requirement}' declares Requirement-ID more than once, so this delta cannot select it safely`
|
|
210
|
-
: `${where}: the ${livingDoc} shares Requirement-ID '${problem.id}' across ${problem.requirements.map((name) => `'${name}'`).join(", ")}, so this delta cannot select one safely`,
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
// Two living requirements under one heading make the delta algebra
|
|
214
|
-
// disagree with itself on the SAME input: MODIFIED replaces the first
|
|
215
|
-
// match (findIndex) while REMOVED deletes every match (filter). So one
|
|
216
|
-
// delta edits one of the twins and leaves the other, and the next one
|
|
217
|
-
// deletes both — and neither outcome is what an author reading the
|
|
218
|
-
// living document could have predicted. Gating rather than advisory,
|
|
219
|
-
// because there is no reading of the delta that makes the merge correct;
|
|
220
|
-
// the fix is in the living document, and it is one rename.
|
|
221
|
-
for (const [name, twins] of livingByName) {
|
|
222
|
-
if (twins.length < 2)
|
|
223
|
-
continue;
|
|
224
|
-
issues.push({
|
|
225
|
-
severity: "error",
|
|
226
|
-
code: "delta.living-duplicate-requirement",
|
|
227
|
-
subject: service,
|
|
228
|
-
message: `${where}: the ${livingDoc} declares ${twins.length} requirements named '${name}' — MODIFIED would rewrite only the first and REMOVED would delete both, so no delta applies to it predictably. Give them distinct names (or distinct Requirement-IDs and headings) first.`,
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
// Lowercased living name -> its exact spelling, for the near-duplicate warning.
|
|
232
|
-
const livingFolded = new Map(living.map((r) => [r.name.toLowerCase(), r.name]));
|
|
233
|
-
/**
|
|
234
|
-
* The pin, against the living requirement this delta actually selects.
|
|
235
|
-
*
|
|
236
|
-
* This is the check `delta.modified-conflict` cannot be: that one names
|
|
237
|
-
* the other feature while BOTH are in flight, and the collision that
|
|
238
|
-
* happens on a fleet outlives the window. A archives, leaves `features/`,
|
|
239
|
-
* and stops being an active claim; B revalidates GREEN, and its MODIFIED —
|
|
240
|
-
* carrying the full text it wrote against the pre-A document — replaces
|
|
241
|
-
* A's requirement wholesale, scenarios and all, with `+0 ~1 -0` and exit
|
|
242
|
-
* 0. Nothing downstream can even detect it afterwards: `unarchive A`
|
|
243
|
-
* refuses `snapshot-stale`, and `--force` takes B out with it.
|
|
244
|
-
*
|
|
245
|
-
* A digest of what the author read closes that by not depending on
|
|
246
|
-
* timing at all. Stale is an ERROR and gates, because there is no reading
|
|
247
|
-
* of a stale delta under which the merge is what its author meant.
|
|
248
|
-
* Missing is a warning and does not: a delta adopted from OpenSpec never
|
|
249
|
-
* had the line, and refusing to archive an entire migrated corpus is not
|
|
250
|
-
* a safety property, it is an outage.
|
|
251
|
-
*/
|
|
252
|
-
const checkBaseline = (r, selected) => {
|
|
253
|
-
// A pin the document pass already refused is not also stale: that would
|
|
254
|
-
// send its author to `loam rebase` for a problem rebase does not fix.
|
|
255
|
-
const declared = basedOnDeclarations(r);
|
|
256
|
-
if (declared.length > 1)
|
|
257
|
-
return;
|
|
258
|
-
if (r.basedOn !== undefined && !REQUIREMENT_DIGEST_RE.test(r.basedOn))
|
|
259
|
-
return;
|
|
260
|
-
const current = requirementDigest(selected);
|
|
261
|
-
if (r.basedOn === undefined) {
|
|
262
|
-
issues.push({
|
|
263
|
-
severity: "warn",
|
|
264
|
-
code: "delta.baseline-missing",
|
|
265
|
-
subject: service,
|
|
266
|
-
message: `${where}: ${r.kind} requirement '${r.name}' carries no Based-On, so nothing can say whether the living text moved since this delta was written. Run \`loam rebase ${featureId}\` to pin it (Based-On: ${current}).`,
|
|
267
|
-
});
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
if (r.basedOn === current)
|
|
271
|
-
return;
|
|
272
|
-
issues.push({
|
|
273
|
-
severity: "error",
|
|
274
|
-
code: "delta.baseline-stale",
|
|
275
|
-
subject: service,
|
|
276
|
-
message: `${where}: ${r.kind} requirement '${r.name}' was written against living version ${r.basedOn}, but the ${livingDoc} now holds ${current} — someone landed a change to it in between. ` +
|
|
277
|
-
(r.kind === "MODIFIED"
|
|
278
|
-
? `This MODIFIED carries its FULL new text, so merging it would replace theirs outright.`
|
|
279
|
-
: `Merging this REMOVED would delete what they landed.`) +
|
|
280
|
-
` Re-read the living requirement, fold in what you still mean, then run \`loam rebase ${featureId}\`.`,
|
|
281
|
-
});
|
|
282
|
-
};
|
|
283
|
-
for (const r of reqs) {
|
|
284
|
-
// BASE in a delta file means the requirement is under no delta section, so
|
|
285
|
-
// the merge skips it. Reported rather than merged: deciding that `## Behavior`
|
|
286
|
-
// means ADDED would be archive guessing at intent, and it would guess wrong
|
|
287
|
-
// for every prose section that quotes a requirement as documentation. A
|
|
288
|
-
// requirement above every heading has no heading to name, and no claim to be
|
|
289
|
-
// written in the delta grammar at all — same judgement as `## Requirements`.
|
|
290
|
-
//
|
|
291
|
-
// A warning that GATES archive — the one check where the two axes
|
|
292
|
-
// diverge. Severity says whether the document is valid: this shape is
|
|
293
|
-
// legal OpenSpec, so an error would fail `loam validate` on every
|
|
294
|
-
// adopted repo whose active deltas still use it. Gating says whether
|
|
295
|
-
// the merge is safe: it is not — the merge would silently drop authored
|
|
296
|
-
// content, the exact loss this module exists to prevent — so archive
|
|
297
|
-
// refuses, and `--approve` remains the way to say the loss is meant.
|
|
298
|
-
if (r.kind === "BASE") {
|
|
299
|
-
if (r.section !== undefined && !isRequirementsHeading(r.section)) {
|
|
300
|
-
issues.push({
|
|
301
|
-
severity: "warn",
|
|
302
|
-
gates: true,
|
|
303
|
-
code: "delta.requirement-not-merged",
|
|
304
|
-
subject: service,
|
|
305
|
-
message: `${where}: requirement '${r.name}' sits under '${r.section}', which is not a delta section — archive will NOT merge it. Move it under '## ADDED Requirements' (or MODIFIED/REMOVED), or drop it if it is documentation.`,
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
continue;
|
|
309
|
-
}
|
|
310
|
-
if (r.kind === "ADDED") {
|
|
311
|
-
const idMatches = r.id === undefined ? [] : (livingById.get(r.id) ?? []);
|
|
312
|
-
const nameMatches = livingByName.get(r.name) ?? [];
|
|
313
|
-
const nameSelectsOther = r.id !== undefined && nameMatches.some((candidate) => candidate.id !== r.id);
|
|
314
|
-
if (nameSelectsOther) {
|
|
315
|
-
issues.push({
|
|
316
|
-
severity: "error",
|
|
317
|
-
code: "delta.requirement-identity-collision",
|
|
318
|
-
subject: service,
|
|
319
|
-
message: `${where}: ADDED requirement '${r.name}' carries Requirement-ID '${r.id}', but that heading already identifies a different living requirement — ID and name cannot select different identities`,
|
|
320
|
-
});
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
if ((r.id === undefined && livingNames.has(r.name)) || idMatches.length > 0) {
|
|
324
|
-
issues.push({
|
|
325
|
-
severity: "error",
|
|
326
|
-
code: "delta.added-duplicate",
|
|
327
|
-
subject: service,
|
|
328
|
-
message: r.id === undefined
|
|
329
|
-
? `${where}: ADDED requirement '${r.name}' already exists in the ${livingDoc} — the merge would REPLACE it, scenarios and all. Use MODIFIED, or rename.`
|
|
330
|
-
: `${where}: ADDED requirement '${r.name}' uses Requirement-ID '${r.id}', which already exists in the ${livingDoc} — use MODIFIED to change that identity`,
|
|
331
|
-
});
|
|
332
|
-
continue;
|
|
333
|
-
}
|
|
334
|
-
// Merge identity is exact string equality (applyRequirementDelta), so a
|
|
335
|
-
// name that differs only in case slips past the duplicate check above and
|
|
336
|
-
// lands as a SECOND requirement next to the living one. A warning, not an
|
|
337
|
-
// error: the author may genuinely mean a distinct requirement, but with
|
|
338
|
-
// LLM authors the case drift is the likely story. Never fires together
|
|
339
|
-
// with added-duplicate — an exact match continues before this runs.
|
|
340
|
-
const near = livingFolded.get(r.name.toLowerCase());
|
|
341
|
-
if (near !== undefined) {
|
|
342
|
-
issues.push({
|
|
343
|
-
severity: "warn",
|
|
344
|
-
code: "delta.added-near-duplicate",
|
|
345
|
-
subject: service,
|
|
346
|
-
message: `${where}: ADDED requirement '${r.name}' differs only in case from living requirement '${near}' — the merge matches names exactly, so both would coexist. Match the living spelling and use MODIFIED, or pick a distinct name.`,
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
const other = await addedElsewhere(service, axis, r);
|
|
350
|
-
if (other !== undefined) {
|
|
351
|
-
issues.push({
|
|
352
|
-
severity: "warn",
|
|
353
|
-
code: "delta.added-conflict",
|
|
354
|
-
subject: service,
|
|
355
|
-
message: `${where}: requirement '${r.name}' is also added by ${other} — whichever archives first lands it, and the second archive is refused (delta.added-duplicate) unless --approve`,
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
continue;
|
|
359
|
-
}
|
|
360
|
-
// MODIFIED vs MODIFIED on ONE living requirement. The ADDED case has
|
|
361
|
-
// been caught since delta.added-conflict: two features adding the same
|
|
362
|
-
// name collide loudly, because the second archive is refused. Two
|
|
363
|
-
// features CHANGING the same requirement collide in total silence —
|
|
364
|
-
// both deltas apply cleanly, and whichever archives second replaces
|
|
365
|
-
// the first's text, scenarios and all, with a version written against
|
|
366
|
-
// a document that no longer exists. A warning, not a gate: the second
|
|
367
|
-
// author may well be rewriting on purpose, and only they can say.
|
|
368
|
-
const alsoChanged = await claimedElsewhere("changed", service, axis, r);
|
|
369
|
-
if (alsoChanged !== undefined) {
|
|
370
|
-
issues.push({
|
|
371
|
-
severity: "warn",
|
|
372
|
-
code: "delta.modified-conflict",
|
|
373
|
-
subject: service,
|
|
374
|
-
message: `${where}: ${r.kind} requirement '${r.name}' is also changed by ${alsoChanged} — both deltas apply cleanly, so whichever archives second REPLACES the other's text wholesale. Agree on one owner, or fold the two changes together.`,
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
if (r.id !== undefined) {
|
|
378
|
-
const idMatches = livingById.get(r.id) ?? [];
|
|
379
|
-
const nameMatches = livingByName.get(r.name) ?? [];
|
|
380
|
-
const nameSelectsOther = nameMatches.some((candidate) => candidate.id !== r.id);
|
|
381
|
-
// The second disjunct is defensive rather than reachable: a living
|
|
382
|
-
// requirement under this heading that the ID did NOT select must carry
|
|
383
|
-
// some other ID, which is what `nameSelectsOther` already says. It is
|
|
384
|
-
// kept because it states the rule the reader is being told — ID and
|
|
385
|
-
// heading must select the same identity — without depending on that
|
|
386
|
-
// derivation holding after the next edit.
|
|
387
|
-
if (nameSelectsOther || (idMatches.length === 0 && nameMatches.length > 0)) {
|
|
388
|
-
issues.push({
|
|
389
|
-
severity: "error",
|
|
390
|
-
code: "delta.requirement-identity-collision",
|
|
391
|
-
subject: service,
|
|
392
|
-
message: `${where}: ${r.kind} requirement '${r.name}' carries Requirement-ID '${r.id}', but its ID and heading select different living requirements — fix the ID or heading; archive will not guess`,
|
|
393
|
-
});
|
|
394
|
-
continue;
|
|
395
|
-
}
|
|
396
|
-
// A differing heading is the explicit loam rename mechanism: the
|
|
397
|
-
// stable ID selects the old requirement, MODIFIED supplies its new name.
|
|
398
|
-
//
|
|
399
|
-
// Total in the ID, deliberately: an ID that matches SEVERAL living
|
|
400
|
-
// requirements has already been refused as
|
|
401
|
-
// `delta.living-requirement-id-invalid` (severity error, so archive is
|
|
402
|
-
// gated either way), and the living document is where it gets fixed.
|
|
403
|
-
// Falling through instead added `delta.modified-unknown` — "does not
|
|
404
|
-
// exist … Did you mean ADDED?" — beside it, which is both false and
|
|
405
|
-
// the more actionable-sounding of the two, and it sends the author to
|
|
406
|
-
// edit the delta over a problem that is not in the delta. There is no
|
|
407
|
-
// baseline to check against an ambiguous selection, so the pin is
|
|
408
|
-
// simply not graded until the ambiguity is gone.
|
|
409
|
-
if (idMatches.length > 0) {
|
|
410
|
-
const selected = idMatches.length === 1 ? idMatches[0] : undefined;
|
|
411
|
-
if (selected !== undefined)
|
|
412
|
-
checkBaseline(r, selected);
|
|
413
|
-
continue;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
else if (livingNames.has(r.name)) {
|
|
417
|
-
// Twins under one heading are already refused
|
|
418
|
-
// (`delta.living-duplicate-requirement`), and applyRequirementDelta
|
|
419
|
-
// takes the first either way — so the pin is compared against the
|
|
420
|
-
// same requirement the merge would rewrite.
|
|
421
|
-
checkBaseline(r, livingByName.get(r.name)[0]);
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
424
|
-
const other = await addedElsewhere(service, axis, r);
|
|
425
|
-
if (other !== undefined) {
|
|
426
|
-
issues.push({
|
|
427
|
-
severity: "warn",
|
|
428
|
-
code: r.kind === "MODIFIED" ? "delta.modified-pending" : "delta.removed-pending",
|
|
429
|
-
subject: service,
|
|
430
|
-
message: `${where}: ${r.kind} requirement '${r.name}' is not in the ${livingDoc} yet — ${other} introduces it. Archive ${other} first.`,
|
|
431
|
-
});
|
|
432
|
-
continue;
|
|
433
|
-
}
|
|
434
|
-
issues.push({
|
|
435
|
-
severity: "error",
|
|
436
|
-
code: r.kind === "MODIFIED" ? "delta.modified-unknown" : "delta.removed-unknown",
|
|
437
|
-
subject: service,
|
|
438
|
-
message: r.kind === "MODIFIED"
|
|
439
|
-
? `${where}: MODIFIED requirement '${r.name}' does not exist in the ${livingDoc} — the merge would create it. Did you mean ADDED?`
|
|
440
|
-
: `${where}: REMOVED requirement '${r.name}' does not exist in the ${livingDoc} — there is nothing to remove`,
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
return issues;
|
|
446
|
-
}
|
|
447
|
-
async function activeClaims(docsDir, exclude, context) {
|
|
448
|
-
const added = new Map();
|
|
449
|
-
const changed = new Map();
|
|
450
|
-
for (const feature of await listFeatures(docsDir, {}, context)) {
|
|
451
|
-
if (feature.id === exclude)
|
|
452
|
-
continue;
|
|
453
|
-
for (const service of feature.services) {
|
|
454
|
-
for (const axis of SPEC_AXES) {
|
|
455
|
-
const path = featureSpecPaths(feature.dir, service)[axis.key];
|
|
456
|
-
if (!existsSync(path))
|
|
457
|
-
continue;
|
|
458
|
-
const reqs = context === undefined
|
|
459
|
-
? parseRequirements(await readFile(path, "utf8"))
|
|
460
|
-
: await context.readRequirements(path);
|
|
461
|
-
for (const r of reqs) {
|
|
462
|
-
const map = r.kind === "ADDED" ? added : r.kind === "MODIFIED" || r.kind === "REMOVED" ? changed : null;
|
|
463
|
-
if (map === null)
|
|
464
|
-
continue;
|
|
465
|
-
for (const identity of new Set([requirementKey(r), `name:${r.name}`])) {
|
|
466
|
-
const k = key(service, axis, identity);
|
|
467
|
-
if (!map.has(k))
|
|
468
|
-
map.set(k, feature.id);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
return { added, changed };
|
|
475
|
-
}
|
|
476
|
-
//# sourceMappingURL=delta.js.map
|
package/dist/core/delta.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"delta.js","sourceRoot":"","sources":["../../src/core/delta.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Does the diff apply to the thing it claims to change?\n *\n * A requirement delta is a diff against a living spec, and nothing used to check\n * that it lands. Every failure mode here is silent today: MODIFIED of a\n * requirement that does not exist is merged as a creation, ADDED of one that\n * does exist REPLACES it (scenarios and all) while the author believes they are\n * adding, and a heading that nearly matches the delta grammar parses as plain\n * prose so archive merges nothing at all and says nothing about it.\n *\n * The last of those has a legal-looking cousin: a requirement under an ordinary\n * prose heading (`## Behavior`, `## Error Handling`) is BASE too, and BASE never\n * merges. Upstream OpenSpec deltas are written that way, so the answer is to name\n * what will be lost rather than to start merging prose sections.\n *\n * These run inside the archive gate, because the merge is where the damage lands.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { relative } from \"node:path\";\nimport type { Issue } from \"./issue.js\";\nimport {\n featureSpecPaths,\n featureSpecServices,\n listFeatures,\n servicePaths,\n SPEC_AXES,\n type SpecAxis,\n} from \"./repo.js\";\nimport {\n KIND_RE,\n REQUIREMENT_DIGEST_LENGTH,\n REQUIREMENT_DIGEST_RE,\n basedOnDeclarations,\n isRequirementsHeading,\n parseRequirements,\n requirementDigest,\n requirementIdProblems,\n sectionHeadings,\n type Requirement,\n} from \"./spec.js\";\nimport type { FleetContext } from \"./fleet-context.js\";\n\n/**\n * `## <word> Requirement(s)` — the shape an author reaches for. Anything matching\n * this but not the real grammar is a near miss: `## ADDED Requirement` (singular),\n * `## NEW Requirements`, `## ADDED Requirements:`. A bare `## Requirements` is not\n * a near miss — quoting the living state inside a delta is legal.\n */\nconst NEAR_SECTION_RE = /^##\\s+[A-Za-z]+\\s+Requirements?\\s*:?\\s*$/i;\n\n/**\n * OpenSpec's fourth delta operation. NEAR_SECTION_RE already catches it, but the\n * generic advice would mislead: a RENAMED body is FROM/TO backtick bullets, not\n * `### Requirement:` headings, so it parses to zero requirements and even the\n * whole-file check below has nothing to count — the heading is the only place to\n * stop it. Rename semantics stay unimplemented (the corpus never uses them); the\n * error says what to write instead.\n */\nconst RENAMED_SECTION_RE = /^##\\s+RENAMED\\s+Requirements?\\s*:?\\s*$/i;\n\n// The one non-delta heading whose requirements are SUPPOSED not to merge — a\n// delta quoting the living state for context — is `## Requirements`, matched by\n// the shared isRequirementsHeading (spec.ts): the same definition that fixes\n// archive's rewrite boundary, so \"legal to quote\" and \"where the merge writes\"\n// cannot drift apart. Every other heading — `## Behavior`, `## Error Handling`,\n// `## Notes` — leaves its requirements as BASE, which the merge skips, so the\n// author wrote a change that will never land.\n\n/** Key for the (service, axis, requirement) triple a feature claims. The two\n * axes are separate namespaces on purpose — an arch requirement cannot conflict\n * with a business requirement of the same name, they merge into different files. */\nfunction key(service: string, axis: SpecAxis, identity: string): string {\n return `${service}\\0${axis.file}\\0${identity}`;\n}\n\n/** Stable ID when present; exact heading for a legacy requirement. */\nfunction requirementKey(requirement: Pick<Requirement, \"id\" | \"name\">): string {\n return requirement.id === undefined ? `name:${requirement.name}` : `id:${requirement.id}`;\n}\n\nexport async function deltaShapeIssues(\n docsDir: string,\n featureDir: string,\n featureId: string,\n context?: FleetContext,\n): Promise<Issue[]> {\n const issues: Issue[] = [];\n const services = await featureSpecServices(featureDir, context);\n if (services.length === 0) return issues;\n\n // What OTHER features in flight claim. Only built when a claim has to be\n // checked — the common case never pays for the scan.\n let inFlight: ActiveClaims | null = null;\n const claimedElsewhere = async (\n which: keyof ActiveClaims,\n service: string,\n axis: SpecAxis,\n requirement: Pick<Requirement, \"id\" | \"name\">,\n ): Promise<string | undefined> => {\n inFlight ??= await activeClaims(docsDir, featureId, context);\n const map = inFlight[which];\n return map.get(key(service, axis, requirementKey(requirement)))\n ?? map.get(key(service, axis, `name:${requirement.name}`));\n };\n const addedElsewhere = (\n service: string,\n axis: SpecAxis,\n requirement: Pick<Requirement, \"id\" | \"name\">,\n ): Promise<string | undefined> => claimedElsewhere(\"added\", service, axis, requirement);\n\n // Both requirement-carrying files per service run the same checks — one code\n // path parameterized by filename, the merge's own factoring. `where` names\n // the arch file in messages so a finding cannot be chased into the wrong\n // document; spec.md keeps its historical spelling.\n for (const service of services) {\n for (const axis of SPEC_AXES) {\n const specPath = featureSpecPaths(featureDir, service)[axis.key];\n if (!existsSync(specPath)) continue;\n const raw = context === undefined\n ? await readFile(specPath, \"utf8\")\n : await context.readText(specPath);\n const where = axis.key === \"spec\" ? service : `${service} (arch.spec.md)`;\n\n for (const heading of sectionHeadings(raw)) {\n if (KIND_RE.test(heading.text) || !NEAR_SECTION_RE.test(heading.text)) continue;\n issues.push({\n severity: \"error\",\n code: \"delta.unknown-section\",\n subject: service,\n message: RENAMED_SECTION_RE.test(heading.text)\n ? `${where}: '${heading.text}' (line ${heading.line}) is OpenSpec rename syntax, which loam does not merge — carry one stable Requirement-ID through a MODIFIED requirement, or express a legacy rename as a REMOVED requirement plus an ADDED one; otherwise the rename happens to nothing`\n : `${where}: '${heading.text}' (line ${heading.line}) is not a delta section — use '## ADDED Requirements', '## MODIFIED Requirements' or '## REMOVED Requirements', or everything under it merges as nothing`,\n });\n }\n\n const reqs = context === undefined ? parseRequirements(raw) : await context.readRequirements(specPath);\n\n for (const problem of requirementIdProblems(reqs)) {\n if (problem.kind === \"invalid\") {\n issues.push({\n severity: \"error\",\n code: \"delta.requirement-id-invalid\",\n subject: service,\n message: `${where}: requirement '${problem.requirement}' has invalid Requirement-ID '${problem.value}' — use 1-128 characters matching [A-Za-z][A-Za-z0-9._-]*`,\n });\n } else if (problem.kind === \"repeated\") {\n issues.push({\n severity: \"error\",\n code: \"delta.requirement-id-repeated\",\n subject: service,\n message: `${where}: requirement '${problem.requirement}' declares Requirement-ID ${problem.values.length} times — identity must be declared exactly once`,\n });\n } else {\n issues.push({\n severity: \"error\",\n code: \"delta.requirement-id-duplicate\",\n subject: service,\n message: `${where}: Requirement-ID '${problem.id}' is shared by ${problem.requirements.map((name) => `'${name}'`).join(\", \")} — one ID may identify only one requirement`,\n });\n }\n }\n\n // The `Based-On:` pin as a DOCUMENT question, settled before anything is\n // compared against the living spec: a value that is not a digest, or two\n // of them on one requirement, is a pin nobody can evaluate — and a pin\n // that silently protects nothing is worse than no pin at all, because its\n // author believes they are covered. ADDED is refused for the same reason\n // rather than ignored: a requirement with no living version cannot have\n // been written against one, so the line is a misunderstanding today and a\n // digest-shaped lie on the day someone turns it into a MODIFIED.\n for (const r of reqs) {\n const declared = basedOnDeclarations(r);\n if (declared.length > 1) {\n issues.push({\n severity: \"error\",\n code: \"delta.baseline-invalid\",\n subject: service,\n message: `${where}: requirement '${r.name}' declares Based-On ${declared.length} times — a delta is written against exactly one living version`,\n });\n continue;\n }\n const pin = declared[0];\n if (pin === undefined) continue;\n if (!REQUIREMENT_DIGEST_RE.test(pin)) {\n issues.push({\n severity: \"error\",\n code: \"delta.baseline-invalid\",\n subject: service,\n message: `${where}: requirement '${r.name}' has invalid Based-On '${pin}' — expected ${REQUIREMENT_DIGEST_LENGTH} lowercase hex characters, as \\`loam rebase\\` writes them`,\n });\n } else if (r.kind === \"ADDED\") {\n issues.push({\n severity: \"error\",\n code: \"delta.baseline-invalid\",\n subject: service,\n message: `${where}: ADDED requirement '${r.name}' carries Based-On '${pin}', but an added requirement has no living version to be based on — drop the line, or make it MODIFIED`,\n });\n }\n }\n\n // The whole-file version of the near-miss check, and the one that cannot be\n // dodged: NEAR_SECTION_RE only recognizes single-word misses (`## NEW\n // Requirements`), so `## NEWLY ADDED Requirements` — or requirements under a\n // prose heading, or under no heading at all — still parses everything as BASE\n // and archive merges nothing, silently. Same failure class as the BOM incident\n // (see spec.ts). A file that MIXES delta sections with quoted BASE requirements\n // is legal authoring; a file with requirements and no delta kind anywhere is a\n // delta that would do nothing, which cannot be what its author meant.\n if (reqs.length > 0 && reqs.every((r) => r.kind === \"BASE\")) {\n const rel = relative(docsDir, specPath).split(/[\\\\/]/).join(\"/\");\n issues.push({\n severity: \"error\",\n code: \"delta.no-delta-sections\",\n subject: service,\n message: `${service}: ${rel} contains ${reqs.length} requirement(s) but no '## ADDED|MODIFIED|REMOVED Requirements' section — this delta would merge nothing`,\n });\n }\n\n const livingPath = servicePaths(docsDir, service)[axis.key];\n const living = existsSync(livingPath)\n ? context === undefined\n ? parseRequirements(await readFile(livingPath, \"utf8\"))\n : await context.readRequirements(livingPath)\n : [];\n // How the axis's living document is named in messages — spec.md keeps the\n // historical \"living spec\", the arch axis says which file it means.\n const livingDoc = axis.key === \"spec\" ? \"living spec\" : \"living arch.spec.md\";\n const livingNames = new Set(living.map((r) => r.name));\n const livingByName = new Map<string, Requirement[]>();\n const livingById = new Map<string, Requirement[]>();\n for (const requirement of living) {\n const named = livingByName.get(requirement.name) ?? [];\n named.push(requirement);\n livingByName.set(requirement.name, named);\n if (requirement.id !== undefined) {\n const identified = livingById.get(requirement.id) ?? [];\n identified.push(requirement);\n livingById.set(requirement.id, identified);\n }\n }\n for (const problem of requirementIdProblems(living)) {\n issues.push({\n severity: \"error\",\n code: \"delta.living-requirement-id-invalid\",\n subject: service,\n message:\n problem.kind === \"invalid\"\n ? `${where}: the ${livingDoc} requirement '${problem.requirement}' has invalid Requirement-ID '${problem.value}', so this delta cannot select it safely`\n : problem.kind === \"repeated\"\n ? `${where}: the ${livingDoc} requirement '${problem.requirement}' declares Requirement-ID more than once, so this delta cannot select it safely`\n : `${where}: the ${livingDoc} shares Requirement-ID '${problem.id}' across ${problem.requirements.map((name) => `'${name}'`).join(\", \")}, so this delta cannot select one safely`,\n });\n }\n // Two living requirements under one heading make the delta algebra\n // disagree with itself on the SAME input: MODIFIED replaces the first\n // match (findIndex) while REMOVED deletes every match (filter). So one\n // delta edits one of the twins and leaves the other, and the next one\n // deletes both — and neither outcome is what an author reading the\n // living document could have predicted. Gating rather than advisory,\n // because there is no reading of the delta that makes the merge correct;\n // the fix is in the living document, and it is one rename.\n for (const [name, twins] of livingByName) {\n if (twins.length < 2) continue;\n issues.push({\n severity: \"error\",\n code: \"delta.living-duplicate-requirement\",\n subject: service,\n message: `${where}: the ${livingDoc} declares ${twins.length} requirements named '${name}' — MODIFIED would rewrite only the first and REMOVED would delete both, so no delta applies to it predictably. Give them distinct names (or distinct Requirement-IDs and headings) first.`,\n });\n }\n\n // Lowercased living name -> its exact spelling, for the near-duplicate warning.\n const livingFolded = new Map(living.map((r) => [r.name.toLowerCase(), r.name] as const));\n\n /**\n * The pin, against the living requirement this delta actually selects.\n *\n * This is the check `delta.modified-conflict` cannot be: that one names\n * the other feature while BOTH are in flight, and the collision that\n * happens on a fleet outlives the window. A archives, leaves `features/`,\n * and stops being an active claim; B revalidates GREEN, and its MODIFIED —\n * carrying the full text it wrote against the pre-A document — replaces\n * A's requirement wholesale, scenarios and all, with `+0 ~1 -0` and exit\n * 0. Nothing downstream can even detect it afterwards: `unarchive A`\n * refuses `snapshot-stale`, and `--force` takes B out with it.\n *\n * A digest of what the author read closes that by not depending on\n * timing at all. Stale is an ERROR and gates, because there is no reading\n * of a stale delta under which the merge is what its author meant.\n * Missing is a warning and does not: a delta adopted from OpenSpec never\n * had the line, and refusing to archive an entire migrated corpus is not\n * a safety property, it is an outage.\n */\n const checkBaseline = (r: Requirement, selected: Requirement): void => {\n // A pin the document pass already refused is not also stale: that would\n // send its author to `loam rebase` for a problem rebase does not fix.\n const declared = basedOnDeclarations(r);\n if (declared.length > 1) return;\n if (r.basedOn !== undefined && !REQUIREMENT_DIGEST_RE.test(r.basedOn)) return;\n const current = requirementDigest(selected);\n if (r.basedOn === undefined) {\n issues.push({\n severity: \"warn\",\n code: \"delta.baseline-missing\",\n subject: service,\n message: `${where}: ${r.kind} requirement '${r.name}' carries no Based-On, so nothing can say whether the living text moved since this delta was written. Run \\`loam rebase ${featureId}\\` to pin it (Based-On: ${current}).`,\n });\n return;\n }\n if (r.basedOn === current) return;\n issues.push({\n severity: \"error\",\n code: \"delta.baseline-stale\",\n subject: service,\n message:\n `${where}: ${r.kind} requirement '${r.name}' was written against living version ${r.basedOn}, but the ${livingDoc} now holds ${current} — someone landed a change to it in between. ` +\n (r.kind === \"MODIFIED\"\n ? `This MODIFIED carries its FULL new text, so merging it would replace theirs outright.`\n : `Merging this REMOVED would delete what they landed.`) +\n ` Re-read the living requirement, fold in what you still mean, then run \\`loam rebase ${featureId}\\`.`,\n });\n };\n\n for (const r of reqs) {\n // BASE in a delta file means the requirement is under no delta section, so\n // the merge skips it. Reported rather than merged: deciding that `## Behavior`\n // means ADDED would be archive guessing at intent, and it would guess wrong\n // for every prose section that quotes a requirement as documentation. A\n // requirement above every heading has no heading to name, and no claim to be\n // written in the delta grammar at all — same judgement as `## Requirements`.\n //\n // A warning that GATES archive — the one check where the two axes\n // diverge. Severity says whether the document is valid: this shape is\n // legal OpenSpec, so an error would fail `loam validate` on every\n // adopted repo whose active deltas still use it. Gating says whether\n // the merge is safe: it is not — the merge would silently drop authored\n // content, the exact loss this module exists to prevent — so archive\n // refuses, and `--approve` remains the way to say the loss is meant.\n if (r.kind === \"BASE\") {\n if (r.section !== undefined && !isRequirementsHeading(r.section)) {\n issues.push({\n severity: \"warn\",\n gates: true,\n code: \"delta.requirement-not-merged\",\n subject: service,\n message: `${where}: requirement '${r.name}' sits under '${r.section}', which is not a delta section — archive will NOT merge it. Move it under '## ADDED Requirements' (or MODIFIED/REMOVED), or drop it if it is documentation.`,\n });\n }\n continue;\n }\n\n if (r.kind === \"ADDED\") {\n const idMatches = r.id === undefined ? [] : (livingById.get(r.id) ?? []);\n const nameMatches = livingByName.get(r.name) ?? [];\n const nameSelectsOther = r.id !== undefined && nameMatches.some((candidate) => candidate.id !== r.id);\n if (nameSelectsOther) {\n issues.push({\n severity: \"error\",\n code: \"delta.requirement-identity-collision\",\n subject: service,\n message: `${where}: ADDED requirement '${r.name}' carries Requirement-ID '${r.id}', but that heading already identifies a different living requirement — ID and name cannot select different identities`,\n });\n continue;\n }\n if ((r.id === undefined && livingNames.has(r.name)) || idMatches.length > 0) {\n issues.push({\n severity: \"error\",\n code: \"delta.added-duplicate\",\n subject: service,\n message: r.id === undefined\n ? `${where}: ADDED requirement '${r.name}' already exists in the ${livingDoc} — the merge would REPLACE it, scenarios and all. Use MODIFIED, or rename.`\n : `${where}: ADDED requirement '${r.name}' uses Requirement-ID '${r.id}', which already exists in the ${livingDoc} — use MODIFIED to change that identity`,\n });\n continue;\n }\n // Merge identity is exact string equality (applyRequirementDelta), so a\n // name that differs only in case slips past the duplicate check above and\n // lands as a SECOND requirement next to the living one. A warning, not an\n // error: the author may genuinely mean a distinct requirement, but with\n // LLM authors the case drift is the likely story. Never fires together\n // with added-duplicate — an exact match continues before this runs.\n const near = livingFolded.get(r.name.toLowerCase());\n if (near !== undefined) {\n issues.push({\n severity: \"warn\",\n code: \"delta.added-near-duplicate\",\n subject: service,\n message: `${where}: ADDED requirement '${r.name}' differs only in case from living requirement '${near}' — the merge matches names exactly, so both would coexist. Match the living spelling and use MODIFIED, or pick a distinct name.`,\n });\n }\n const other = await addedElsewhere(service, axis, r);\n if (other !== undefined) {\n issues.push({\n severity: \"warn\",\n code: \"delta.added-conflict\",\n subject: service,\n message: `${where}: requirement '${r.name}' is also added by ${other} — whichever archives first lands it, and the second archive is refused (delta.added-duplicate) unless --approve`,\n });\n }\n continue;\n }\n\n // MODIFIED vs MODIFIED on ONE living requirement. The ADDED case has\n // been caught since delta.added-conflict: two features adding the same\n // name collide loudly, because the second archive is refused. Two\n // features CHANGING the same requirement collide in total silence —\n // both deltas apply cleanly, and whichever archives second replaces\n // the first's text, scenarios and all, with a version written against\n // a document that no longer exists. A warning, not a gate: the second\n // author may well be rewriting on purpose, and only they can say.\n const alsoChanged = await claimedElsewhere(\"changed\", service, axis, r);\n if (alsoChanged !== undefined) {\n issues.push({\n severity: \"warn\",\n code: \"delta.modified-conflict\",\n subject: service,\n message: `${where}: ${r.kind} requirement '${r.name}' is also changed by ${alsoChanged} — both deltas apply cleanly, so whichever archives second REPLACES the other's text wholesale. Agree on one owner, or fold the two changes together.`,\n });\n }\n\n if (r.id !== undefined) {\n const idMatches = livingById.get(r.id) ?? [];\n const nameMatches = livingByName.get(r.name) ?? [];\n const nameSelectsOther = nameMatches.some((candidate) => candidate.id !== r.id);\n // The second disjunct is defensive rather than reachable: a living\n // requirement under this heading that the ID did NOT select must carry\n // some other ID, which is what `nameSelectsOther` already says. It is\n // kept because it states the rule the reader is being told — ID and\n // heading must select the same identity — without depending on that\n // derivation holding after the next edit.\n if (nameSelectsOther || (idMatches.length === 0 && nameMatches.length > 0)) {\n issues.push({\n severity: \"error\",\n code: \"delta.requirement-identity-collision\",\n subject: service,\n message: `${where}: ${r.kind} requirement '${r.name}' carries Requirement-ID '${r.id}', but its ID and heading select different living requirements — fix the ID or heading; archive will not guess`,\n });\n continue;\n }\n // A differing heading is the explicit loam rename mechanism: the\n // stable ID selects the old requirement, MODIFIED supplies its new name.\n //\n // Total in the ID, deliberately: an ID that matches SEVERAL living\n // requirements has already been refused as\n // `delta.living-requirement-id-invalid` (severity error, so archive is\n // gated either way), and the living document is where it gets fixed.\n // Falling through instead added `delta.modified-unknown` — \"does not\n // exist … Did you mean ADDED?\" — beside it, which is both false and\n // the more actionable-sounding of the two, and it sends the author to\n // edit the delta over a problem that is not in the delta. There is no\n // baseline to check against an ambiguous selection, so the pin is\n // simply not graded until the ambiguity is gone.\n if (idMatches.length > 0) {\n const selected = idMatches.length === 1 ? idMatches[0] : undefined;\n if (selected !== undefined) checkBaseline(r, selected);\n continue;\n }\n } else if (livingNames.has(r.name)) {\n // Twins under one heading are already refused\n // (`delta.living-duplicate-requirement`), and applyRequirementDelta\n // takes the first either way — so the pin is compared against the\n // same requirement the merge would rewrite.\n checkBaseline(r, livingByName.get(r.name)![0]!);\n continue;\n }\n\n const other = await addedElsewhere(service, axis, r);\n if (other !== undefined) {\n issues.push({\n severity: \"warn\",\n code: r.kind === \"MODIFIED\" ? \"delta.modified-pending\" : \"delta.removed-pending\",\n subject: service,\n message: `${where}: ${r.kind} requirement '${r.name}' is not in the ${livingDoc} yet — ${other} introduces it. Archive ${other} first.`,\n });\n continue;\n }\n issues.push({\n severity: \"error\",\n code: r.kind === \"MODIFIED\" ? \"delta.modified-unknown\" : \"delta.removed-unknown\",\n subject: service,\n message:\n r.kind === \"MODIFIED\"\n ? `${where}: MODIFIED requirement '${r.name}' does not exist in the ${livingDoc} — the merge would create it. Did you mean ADDED?`\n : `${where}: REMOVED requirement '${r.name}' does not exist in the ${livingDoc} — there is nothing to remove`,\n });\n }\n }\n }\n\n return issues;\n}\n\n/**\n * What other ACTIVE features claim, per (service, axis, requirement): what they\n * ADD, and — separately — what they CHANGE or REMOVE. The two are separate\n * indexes because they mean opposite things to the reader: an addition\n * elsewhere explains why a MODIFIED target is missing today, a change elsewhere\n * warns that the target is contested. One scan builds both; scanning twice\n * would double the fleet walk for the same bytes.\n */\ninterface ActiveClaims {\n added: Map<string, string>;\n changed: Map<string, string>;\n}\n\nasync function activeClaims(\n docsDir: string,\n exclude: string,\n context?: FleetContext,\n): Promise<ActiveClaims> {\n const added = new Map<string, string>();\n const changed = new Map<string, string>();\n for (const feature of await listFeatures(docsDir, {}, context)) {\n if (feature.id === exclude) continue;\n for (const service of feature.services) {\n for (const axis of SPEC_AXES) {\n const path = featureSpecPaths(feature.dir, service)[axis.key];\n if (!existsSync(path)) continue;\n const reqs = context === undefined\n ? parseRequirements(await readFile(path, \"utf8\"))\n : await context.readRequirements(path);\n for (const r of reqs) {\n const map = r.kind === \"ADDED\" ? added : r.kind === \"MODIFIED\" || r.kind === \"REMOVED\" ? changed : null;\n if (map === null) continue;\n for (const identity of new Set([requirementKey(r), `name:${r.name}`])) {\n const k = key(service, axis, identity);\n if (!map.has(k)) map.set(k, feature.id);\n }\n }\n }\n }\n }\n return { added, changed };\n}\n"]}
|