@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
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fleet's capability vocabulary: which business capabilities exist, by
|
|
3
|
+
* declared name, so a requirement's `Capability:` line resolves or refuses
|
|
4
|
+
* instead of silently labelling.
|
|
5
|
+
*
|
|
6
|
+
* It is a fleet document (`architecture/capabilities.yaml`, beside the
|
|
7
|
+
* landscape and the permissions vocabulary) because a capability crosses
|
|
8
|
+
* services by definition — "registration" is realized by requirements in four
|
|
9
|
+
* repositories, and a per-service copy would be N spellings of one word.
|
|
10
|
+
*
|
|
11
|
+
* What this is NOT, deliberately: a domain model, and not an authored prose
|
|
12
|
+
* layer either. SCHEMA.md rejected a free-text `capability:` label because
|
|
13
|
+
* nothing could check it; a DECLARED name is different in exactly the way that
|
|
14
|
+
* mattered there — the id exists in this file or it does not, so an unknown
|
|
15
|
+
* name is an error with close candidates, a declaration nothing realizes is a
|
|
16
|
+
* warning, and the vocabulary cannot drift while looking authoritative. The
|
|
17
|
+
* long-lived capability documents themselves (one page per capability, revised
|
|
18
|
+
* by features) stay outside loam — that is the roadmap's evidence-gated Later
|
|
19
|
+
* item, and the rollup built over these names is the evidence that decides it.
|
|
20
|
+
*
|
|
21
|
+
* The OPT-IN also differs from the authorization axis, on purpose: there the
|
|
22
|
+
* `Requires:` line is the opt-in and a missing permissions.yaml is an error at
|
|
23
|
+
* the line; here the FILE is the opt-in — a fleet with no capabilities.yaml
|
|
24
|
+
* produces no capability findings at all (`core/capabilities/findings.ts`
|
|
25
|
+
* holds the rule and the reason).
|
|
26
|
+
*/
|
|
27
|
+
import { readFile } from "node:fs/promises";
|
|
28
|
+
import { existsSync } from "node:fs";
|
|
29
|
+
import { parse as parseYaml } from "yaml";
|
|
30
|
+
import { isRecord } from "../kernel/records.js";
|
|
31
|
+
import { capabilitiesPath } from "../repo/paths.js";
|
|
32
|
+
import { capabilityDocsDir } from "../repo/authored/paths.js";
|
|
33
|
+
import { readCapabilityTree } from "./tree.js";
|
|
34
|
+
const NO_TREE = { present: false, docs: [], undocumented: [] };
|
|
35
|
+
const EMPTY = { present: false, byId: new Map(), tree: NO_TREE };
|
|
36
|
+
/**
|
|
37
|
+
* Read the vocabulary — exactly `permissions.ts`'s defensive ladder, because
|
|
38
|
+
* the two files fail the same ways: a missing file is silence, a YAML error or
|
|
39
|
+
* a non-mapping shape is `invalid` (one finding for the whole run, the family
|
|
40
|
+
* suppressed behind it), an empty document is a present-and-empty vocabulary,
|
|
41
|
+
* and a declaration whose body is not a mapping is treated as `{}` rather than
|
|
42
|
+
* refusing the whole file over one leaf.
|
|
43
|
+
*/
|
|
44
|
+
export async function readCapabilities(path) {
|
|
45
|
+
if (!existsSync(path))
|
|
46
|
+
return EMPTY;
|
|
47
|
+
let doc;
|
|
48
|
+
try {
|
|
49
|
+
doc = parseYaml(await readFile(path, "utf8"));
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
return { ...EMPTY, present: true, invalid: e instanceof Error ? e.message : String(e) };
|
|
53
|
+
}
|
|
54
|
+
if (doc === null || doc === undefined)
|
|
55
|
+
return { ...EMPTY, present: true };
|
|
56
|
+
if (!isRecord(doc))
|
|
57
|
+
return { ...EMPTY, present: true, invalid: "the document is not a mapping" };
|
|
58
|
+
const block = doc["capabilities"];
|
|
59
|
+
if (block === undefined)
|
|
60
|
+
return { ...EMPTY, present: true };
|
|
61
|
+
if (!isRecord(block)) {
|
|
62
|
+
return { ...EMPTY, present: true, invalid: "`capabilities` is not a mapping of capability id to its declaration" };
|
|
63
|
+
}
|
|
64
|
+
const byId = new Map();
|
|
65
|
+
for (const [id, body] of Object.entries(block)) {
|
|
66
|
+
const decl = isRecord(body) ? body : {};
|
|
67
|
+
byId.set(id, {
|
|
68
|
+
id,
|
|
69
|
+
source: "yaml",
|
|
70
|
+
...(typeof decl["description"] === "string" ? { description: decl["description"] } : {}),
|
|
71
|
+
...(typeof decl["owner"] === "string" ? { owner: decl["owner"] } : {}),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return { ...EMPTY, present: true, byId };
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* THE vocabulary — both sides read and merged, and the only shape a grader
|
|
78
|
+
* should ever be handed.
|
|
79
|
+
*
|
|
80
|
+
* `readCapabilities` above stays exported for the one reader that genuinely
|
|
81
|
+
* means the file alone (its own tests), but nothing that grades a fleet may use
|
|
82
|
+
* it: a `Capability:` line naming an id the tree declares and the YAML does not
|
|
83
|
+
* would resolve through the union and fail through the file, so a second
|
|
84
|
+
* spelling of "the vocabulary" is a second answer to `capability.unknown`.
|
|
85
|
+
*
|
|
86
|
+
* WHERE AN ID SITS ON BOTH SIDES THE YAML'S METADATA SURVIVES, and not by
|
|
87
|
+
* precedence — the document has nothing to overwrite it with. `description` and
|
|
88
|
+
* `owner` are fields, and this axis's own rule is that an entry without prose
|
|
89
|
+
* stays a line in YAML; the document's contribution is the narrative and the
|
|
90
|
+
* requirements, which are prose, and loam reads frontmatter, never prose. So a
|
|
91
|
+
* capability declared only in the tree has no owner in `loam list
|
|
92
|
+
* capabilities`, and that is the honest reading rather than a gap: nobody wrote
|
|
93
|
+
* one down. What the merge adds on that side is `spec` and `source`.
|
|
94
|
+
*
|
|
95
|
+
* An UNREADABLE YAML suspends the whole family (`gradableCapabilityIds` in
|
|
96
|
+
* `./findings.ts` is the one statement of that ladder), and the tree is still
|
|
97
|
+
* walked and still carried: `capability.doc-missing` is a fact about
|
|
98
|
+
* directories that no YAML failure makes untrue, and suppressing it behind an
|
|
99
|
+
* unrelated broken file would hide a half-created capability until somebody
|
|
100
|
+
* fixed a document it has nothing to do with.
|
|
101
|
+
*/
|
|
102
|
+
export async function readCapabilityVocabulary(docsDir) {
|
|
103
|
+
const [yaml, tree] = await Promise.all([
|
|
104
|
+
readCapabilities(capabilitiesPath(docsDir)),
|
|
105
|
+
readCapabilityTree(capabilityDocsDir(docsDir)),
|
|
106
|
+
]);
|
|
107
|
+
const byId = new Map(yaml.byId);
|
|
108
|
+
for (const doc of tree.docs) {
|
|
109
|
+
const declared = byId.get(doc.id);
|
|
110
|
+
byId.set(doc.id, {
|
|
111
|
+
...declared,
|
|
112
|
+
id: doc.id,
|
|
113
|
+
source: declared === undefined ? "tree" : "both",
|
|
114
|
+
spec: doc.spec,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
...yaml,
|
|
119
|
+
present: yaml.present || tree.present,
|
|
120
|
+
byId,
|
|
121
|
+
tree,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../../src/core/capabilities/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAuB,MAAM,WAAW,CAAC;AAwDpE,MAAM,OAAO,GAAmB,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;AAC/E,MAAM,KAAK,GAAyB,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAEvF;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY;IACjD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,SAAS,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1F,CAAC;IACD,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC1E,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC;IAEjG,MAAM,KAAK,GAAG,GAAG,CAAC,cAAc,CAAC,CAAC;IAClC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC5D,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,qEAAqE,EAAE,CAAC;IACrH,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC3C,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACxC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE;YACX,EAAE;YACF,MAAM,EAAE,MAAM;YACd,GAAG,CAAC,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxF,GAAG,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACvE,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,OAAgB;IAC7D,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACrC,gBAAgB,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC3C,kBAAkB,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;KAC/C,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE;YACf,GAAG,QAAQ;YACX,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,MAAM,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;YAChD,IAAI,EAAE,GAAG,CAAC,IAAI;SACf,CAAC,CAAC;IACL,CAAC;IACD,OAAO;QACL,GAAG,IAAI;QACP,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO;QACrC,IAAI;QACJ,IAAI;KACL,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The fleet's capability vocabulary: which business capabilities exist, by\n * declared name, so a requirement's `Capability:` line resolves or refuses\n * instead of silently labelling.\n *\n * It is a fleet document (`architecture/capabilities.yaml`, beside the\n * landscape and the permissions vocabulary) because a capability crosses\n * services by definition — \"registration\" is realized by requirements in four\n * repositories, and a per-service copy would be N spellings of one word.\n *\n * What this is NOT, deliberately: a domain model, and not an authored prose\n * layer either. SCHEMA.md rejected a free-text `capability:` label because\n * nothing could check it; a DECLARED name is different in exactly the way that\n * mattered there — the id exists in this file or it does not, so an unknown\n * name is an error with close candidates, a declaration nothing realizes is a\n * warning, and the vocabulary cannot drift while looking authoritative. The\n * long-lived capability documents themselves (one page per capability, revised\n * by features) stay outside loam — that is the roadmap's evidence-gated Later\n * item, and the rollup built over these names is the evidence that decides it.\n *\n * The OPT-IN also differs from the authorization axis, on purpose: there the\n * `Requires:` line is the opt-in and a missing permissions.yaml is an error at\n * the line; here the FILE is the opt-in — a fleet with no capabilities.yaml\n * produces no capability findings at all (`core/capabilities/findings.ts`\n * holds the rule and the reason).\n */\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { parse as parseYaml } from \"yaml\";\nimport { isRecord } from \"../kernel/records.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\nimport { capabilitiesPath } from \"../repo/paths.js\";\nimport { capabilityDocsDir } from \"../repo/authored/paths.js\";\nimport { readCapabilityTree, type CapabilityTree } from \"./tree.js\";\n\n/** One declared capability. The id is the full key, slashes preserved. */\nexport interface Capability {\n /**\n * The token a requirement's `Capability:` line writes. Nesting is spelled\n * INSIDE the id (`payments/refunds`) and never collapsed — the key is\n * exactly the string a requirement names, greppable as written.\n */\n id: string;\n description?: string;\n /**\n * A team or a person — deliberately `owner:`, not permissions' `owned_by:`,\n * because that field carries \"defining service\" semantics a capability does\n * not have. Never resolved against anything; a blank is a worse answer than\n * an unverified one.\n */\n owner?: string;\n /**\n * Which side declared this id. `yaml` is a name in\n * `architecture/capabilities.yaml` with no document; `tree` is a\n * `capabilities/<id>/spec.md` the YAML does not name; `both` is the same id\n * on both sides, which is normal rather than a duplicate — the YAML declared\n * the word first and somebody has since written the document for it.\n *\n * Recorded rather than derived at each reader, because the two sides carry\n * different fixes: a `yaml`-only capability is fixed by writing the document,\n * a `tree`-only one needs no fix at all, and a message that could not tell\n * them apart would advise editing a file that may not exist.\n */\n source: \"yaml\" | \"tree\" | \"both\";\n /** `capabilities/<id>/spec.md`, absolute, when the tree declares this id. */\n spec?: string;\n}\n\nexport interface CapabilityVocabulary {\n /**\n * False when NEITHER `architecture/capabilities.yaml` nor `capabilities/`\n * exists. Either one is the axis's opt-in, so a fleet holding neither\n * produces no capability finding at all, however many `Capability:` lines its\n * requirements already carry.\n */\n present: boolean;\n /**\n * Why `architecture/capabilities.yaml` could not be read as a vocabulary,\n * when it could not. The TREE has no such state: a directory either lists or\n * it does not, and an unreadable one is a filesystem failure the walk lets\n * throw rather than a document loam misread.\n */\n invalid?: string;\n /** Declared capabilities, keyed by the full id — the union of both sides. */\n byId: Map<string, Capability>;\n /** What the `capabilities/` walk found, for the graders that need the paths. */\n tree: CapabilityTree;\n}\n\nconst NO_TREE: CapabilityTree = { present: false, docs: [], undocumented: [] };\nconst EMPTY: CapabilityVocabulary = { present: false, byId: new Map(), tree: NO_TREE };\n\n/**\n * Read the vocabulary — exactly `permissions.ts`'s defensive ladder, because\n * the two files fail the same ways: a missing file is silence, a YAML error or\n * a non-mapping shape is `invalid` (one finding for the whole run, the family\n * suppressed behind it), an empty document is a present-and-empty vocabulary,\n * and a declaration whose body is not a mapping is treated as `{}` rather than\n * refusing the whole file over one leaf.\n */\nexport async function readCapabilities(path: string): Promise<CapabilityVocabulary> {\n if (!existsSync(path)) return EMPTY;\n let doc: unknown;\n try {\n doc = parseYaml(await readFile(path, \"utf8\"));\n } catch (e) {\n return { ...EMPTY, present: true, invalid: e instanceof Error ? e.message : String(e) };\n }\n if (doc === null || doc === undefined) return { ...EMPTY, present: true };\n if (!isRecord(doc)) return { ...EMPTY, present: true, invalid: \"the document is not a mapping\" };\n\n const block = doc[\"capabilities\"];\n if (block === undefined) return { ...EMPTY, present: true };\n if (!isRecord(block)) {\n return { ...EMPTY, present: true, invalid: \"`capabilities` is not a mapping of capability id to its declaration\" };\n }\n\n const byId = new Map<string, Capability>();\n for (const [id, body] of Object.entries(block)) {\n const decl = isRecord(body) ? body : {};\n byId.set(id, {\n id,\n source: \"yaml\",\n ...(typeof decl[\"description\"] === \"string\" ? { description: decl[\"description\"] } : {}),\n ...(typeof decl[\"owner\"] === \"string\" ? { owner: decl[\"owner\"] } : {}),\n });\n }\n return { ...EMPTY, present: true, byId };\n}\n\n/**\n * THE vocabulary — both sides read and merged, and the only shape a grader\n * should ever be handed.\n *\n * `readCapabilities` above stays exported for the one reader that genuinely\n * means the file alone (its own tests), but nothing that grades a fleet may use\n * it: a `Capability:` line naming an id the tree declares and the YAML does not\n * would resolve through the union and fail through the file, so a second\n * spelling of \"the vocabulary\" is a second answer to `capability.unknown`.\n *\n * WHERE AN ID SITS ON BOTH SIDES THE YAML'S METADATA SURVIVES, and not by\n * precedence — the document has nothing to overwrite it with. `description` and\n * `owner` are fields, and this axis's own rule is that an entry without prose\n * stays a line in YAML; the document's contribution is the narrative and the\n * requirements, which are prose, and loam reads frontmatter, never prose. So a\n * capability declared only in the tree has no owner in `loam list\n * capabilities`, and that is the honest reading rather than a gap: nobody wrote\n * one down. What the merge adds on that side is `spec` and `source`.\n *\n * An UNREADABLE YAML suspends the whole family (`gradableCapabilityIds` in\n * `./findings.ts` is the one statement of that ladder), and the tree is still\n * walked and still carried: `capability.doc-missing` is a fact about\n * directories that no YAML failure makes untrue, and suppressing it behind an\n * unrelated broken file would hide a half-created capability until somebody\n * fixed a document it has nothing to do with.\n */\nexport async function readCapabilityVocabulary(docsDir: DocsDir): Promise<CapabilityVocabulary> {\n const [yaml, tree] = await Promise.all([\n readCapabilities(capabilitiesPath(docsDir)),\n readCapabilityTree(capabilityDocsDir(docsDir)),\n ]);\n const byId = new Map(yaml.byId);\n for (const doc of tree.docs) {\n const declared = byId.get(doc.id);\n byId.set(doc.id, {\n ...declared,\n id: doc.id,\n source: declared === undefined ? \"tree\" : \"both\",\n spec: doc.spec,\n });\n }\n return {\n ...yaml,\n present: yaml.present || tree.present,\n byId,\n tree,\n };\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The capability document's own three grades, applied to a FEATURE'S DELTA.
|
|
3
|
+
*
|
|
4
|
+
* `../findings.ts` grades the living `capabilities/<id>/spec.md` and files
|
|
5
|
+
* Findings for `loam validate`. This is the same three rules shaped as archive
|
|
6
|
+
* Issues — the twin `capabilityUnknownFindings`/`capabilityUnknownIssues`
|
|
7
|
+
* already are one directory over, and for the identical reason: severity says
|
|
8
|
+
* whether the DOCUMENT is valid, gating says whether the MERGE is safe, and the
|
|
9
|
+
* two questions are asked by two different commands about the same text.
|
|
10
|
+
*
|
|
11
|
+
* WITHOUT THIS THE DELTA PATH IS A HOLE THROUGH THE RULE. A capability
|
|
12
|
+
* requirement carrying `Operations:` is a service requirement filed at the
|
|
13
|
+
* business altitude — the one thing that makes a second requirements corpus
|
|
14
|
+
* worth having is that it does not become a second place to write the first
|
|
15
|
+
* one. Graded only on the living document, that requirement merges cleanly and
|
|
16
|
+
* earns its error afterwards, against a file whoever reads the finding did not
|
|
17
|
+
* write and cannot un-merge. So the delta is graded BEFORE the merge, where the
|
|
18
|
+
* author is still holding the document.
|
|
19
|
+
*
|
|
20
|
+
* ADDED AND MODIFIED ONLY. A REMOVED requirement is being retired: demanding a
|
|
21
|
+
* `Requirement-ID:` on it, or refusing the `Operations:` line it is deleting,
|
|
22
|
+
* would ask for an edit to text that is about to stop existing. A BASE
|
|
23
|
+
* requirement is a delta quoting living context, already named by
|
|
24
|
+
* `delta.requirement-not-merged`, and it merges nothing — two findings for one
|
|
25
|
+
* mistake is the failure to avoid.
|
|
26
|
+
*
|
|
27
|
+
* NO CODES OF ITS OWN, and no message of its own. Every sentence comes from
|
|
28
|
+
* `capabilityDocFindings`, whose `where` parameter is what points them at the
|
|
29
|
+
* feature's copy of the document.
|
|
30
|
+
*/
|
|
31
|
+
import { capabilityDocFindings } from "../findings.js";
|
|
32
|
+
/**
|
|
33
|
+
* The three grades, as archive-gating Issues, over the requirements a
|
|
34
|
+
* capability delta would actually merge.
|
|
35
|
+
*
|
|
36
|
+
* `target.where` is the delta's repo-relative path so a reader is sent to the
|
|
37
|
+
* file they wrote, and `target.subject` is the capability id so a `--json`
|
|
38
|
+
* consumer groups by promise rather than by path — the same split every other
|
|
39
|
+
* capability grade uses.
|
|
40
|
+
*/
|
|
41
|
+
export function capabilityDocIssues(reqs, target) {
|
|
42
|
+
const merging = reqs.filter((r) => r.kind === "ADDED" || r.kind === "MODIFIED");
|
|
43
|
+
return capabilityDocFindings(merging, target.subject, target.where).map((f) => ({
|
|
44
|
+
severity: f.severity,
|
|
45
|
+
code: f.code,
|
|
46
|
+
subject: f.subject,
|
|
47
|
+
message: f.message,
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=doc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doc.js","sourceRoot":"","sources":["../../../../src/core/capabilities/delta/doc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,qBAAqB,EAAyB,MAAM,gBAAgB,CAAC;AAI9E;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAmB,EAAE,MAAwB;IAC/E,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;IAChF,OAAO,qBAAqB,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9E,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,OAAO,EAAE,CAAC,CAAC,OAAO;KACnB,CAAC,CAAC,CAAC;AACN,CAAC","sourcesContent":["/**\n * The capability document's own three grades, applied to a FEATURE'S DELTA.\n *\n * `../findings.ts` grades the living `capabilities/<id>/spec.md` and files\n * Findings for `loam validate`. This is the same three rules shaped as archive\n * Issues — the twin `capabilityUnknownFindings`/`capabilityUnknownIssues`\n * already are one directory over, and for the identical reason: severity says\n * whether the DOCUMENT is valid, gating says whether the MERGE is safe, and the\n * two questions are asked by two different commands about the same text.\n *\n * WITHOUT THIS THE DELTA PATH IS A HOLE THROUGH THE RULE. A capability\n * requirement carrying `Operations:` is a service requirement filed at the\n * business altitude — the one thing that makes a second requirements corpus\n * worth having is that it does not become a second place to write the first\n * one. Graded only on the living document, that requirement merges cleanly and\n * earns its error afterwards, against a file whoever reads the finding did not\n * write and cannot un-merge. So the delta is graded BEFORE the merge, where the\n * author is still holding the document.\n *\n * ADDED AND MODIFIED ONLY. A REMOVED requirement is being retired: demanding a\n * `Requirement-ID:` on it, or refusing the `Operations:` line it is deleting,\n * would ask for an edit to text that is about to stop existing. A BASE\n * requirement is a delta quoting living context, already named by\n * `delta.requirement-not-merged`, and it merges nothing — two findings for one\n * mistake is the failure to avoid.\n *\n * NO CODES OF ITS OWN, and no message of its own. Every sentence comes from\n * `capabilityDocFindings`, whose `where` parameter is what points them at the\n * feature's copy of the document.\n */\nimport { capabilityDocFindings, type CapabilityTarget } from \"../findings.js\";\nimport type { Requirement } from \"../../document/spec.js\";\nimport type { Issue } from \"../../vocabulary/issue.js\";\n\n/**\n * The three grades, as archive-gating Issues, over the requirements a\n * capability delta would actually merge.\n *\n * `target.where` is the delta's repo-relative path so a reader is sent to the\n * file they wrote, and `target.subject` is the capability id so a `--json`\n * consumer groups by promise rather than by path — the same split every other\n * capability grade uses.\n */\nexport function capabilityDocIssues(reqs: Requirement[], target: CapabilityTarget): Issue[] {\n const merging = reqs.filter((r) => r.kind === \"ADDED\" || r.kind === \"MODIFIED\");\n return capabilityDocFindings(merging, target.subject, target.where).map((f) => ({\n severity: f.severity,\n code: f.code,\n subject: f.subject,\n message: f.message,\n }));\n}\n"]}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fleet's capability vocabulary AS THIS FEATURE'S MERGE WOULD LEAVE IT —
|
|
3
|
+
* the living declarations unioned with what the feature's own capability deltas
|
|
4
|
+
* add.
|
|
5
|
+
*
|
|
6
|
+
* WHY THIS EXISTS AT ALL. Without it the axis's headline flow is refused by an
|
|
7
|
+
* error code of its own making. `capabilityRequirementIndex` builds from
|
|
8
|
+
* `vocab.tree.docs`, the LIVING tree, and `realizesUnknownIssues` runs against
|
|
9
|
+
* it inside a feature delta as an ERROR that gates archive. So an author who
|
|
10
|
+
* writes `CHECKOUT-REFUND-ONCE` into
|
|
11
|
+
* `features/FEAT-9/capabilities/checkout/spec.md` and
|
|
12
|
+
* `Realizes: checkout#CHECKOUT-REFUND-ONCE` into
|
|
13
|
+
* `features/FEAT-9/specs/billing/spec.md` — the two halves of one change, in one
|
|
14
|
+
* feature — is told the target does not exist. It does not exist YET, and the
|
|
15
|
+
* same archive that would land the pointer lands the promise it points at.
|
|
16
|
+
*
|
|
17
|
+
* THE GRADE IS TAKEN AGAINST THE POST-MERGE FLEET, which is the only reading
|
|
18
|
+
* under which both directions of the join mean anything inside a feature. It is
|
|
19
|
+
* the same judgement the contract axis already makes one axis over, where
|
|
20
|
+
* `spec-api.op-undefined` is graded against feature ∪ living rather than living
|
|
21
|
+
* alone.
|
|
22
|
+
*
|
|
23
|
+
* IT WIDENS; IT MUST NOT BLIND. Every entry naming something neither side
|
|
24
|
+
* declares still fails, with the same message and the same close-name
|
|
25
|
+
* candidates — now drawn from the widened set, so a typo against a requirement
|
|
26
|
+
* the same feature is adding gets the useful suggestion rather than a list of
|
|
27
|
+
* ids the author was not writing about.
|
|
28
|
+
*
|
|
29
|
+
* THE LADDER SURVIVES. An unreadable `architecture/capabilities.yaml` is still
|
|
30
|
+
* `invalid`, and `declared: null` still suspends the whole family: a feature
|
|
31
|
+
* delta cannot make an unreadable vocabulary readable, and grading a hundred
|
|
32
|
+
* entries against a file nobody can parse is the cascade `../findings.ts`
|
|
33
|
+
* suppresses.
|
|
34
|
+
*/
|
|
35
|
+
import { requirementDigest } from "../../document/spec.js";
|
|
36
|
+
/**
|
|
37
|
+
* The vocabulary a feature's deltas would leave behind: every living
|
|
38
|
+
* declaration, plus every capability id this feature introduces.
|
|
39
|
+
*
|
|
40
|
+
* `present` widens too, and that is the point rather than a side effect: a
|
|
41
|
+
* feature writing the fleet's FIRST capability document is what creates
|
|
42
|
+
* `capabilities/`, so it is the act of opting in. Grading its own joins against
|
|
43
|
+
* the vocabulary it is about to create catches the typo before the merge; the
|
|
44
|
+
* alternative — silence until the document is living — reports the same typo on
|
|
45
|
+
* somebody else's next `validate --all`, against a document they did not write.
|
|
46
|
+
*
|
|
47
|
+
* `tree` is deliberately NOT widened. It lists the LIVING documents under
|
|
48
|
+
* `capabilities/`, and `capabilityRequirementIndex` reads every one of them and
|
|
49
|
+
* declares every non-REMOVED requirement it finds. Splicing a feature's delta
|
|
50
|
+
* path into that list would apply the living rule to a delta — which is right
|
|
51
|
+
* for ADDED and wrong for BASE, the kind a delta uses to QUOTE living context
|
|
52
|
+
* and that the merge never writes. The feature side arrives through
|
|
53
|
+
* `withFeatureRequirements` below instead, where the delta kinds decide.
|
|
54
|
+
*
|
|
55
|
+
* An id a feature introduces is recorded `source: "tree"` with no `spec`: the
|
|
56
|
+
* tree is the side that will declare it once the merge lands, and there is no
|
|
57
|
+
* living document to name yet. Nothing in the feature-grading path reads either
|
|
58
|
+
* field — they exist for the fleet-scope messages, which never see this value.
|
|
59
|
+
*/
|
|
60
|
+
export function withFeatureCapabilities(vocab, ids) {
|
|
61
|
+
if (ids.length === 0)
|
|
62
|
+
return vocab;
|
|
63
|
+
const byId = new Map(vocab.byId);
|
|
64
|
+
for (const id of ids) {
|
|
65
|
+
if (byId.has(id))
|
|
66
|
+
continue;
|
|
67
|
+
byId.set(id, { id, source: "tree" });
|
|
68
|
+
}
|
|
69
|
+
return { ...vocab, present: true, byId };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The `Realizes:` index a feature's deltas would leave behind: the living
|
|
73
|
+
* requirement ids per capability, plus the ids this feature ADDS or MODIFIES.
|
|
74
|
+
*
|
|
75
|
+
* ADDED and MODIFIED, never REMOVED and never BASE.
|
|
76
|
+
*
|
|
77
|
+
* BASE is where the exclusion earns its keep: a `## Requirements` section
|
|
78
|
+
* inside a delta QUOTES living context for a reader, and the merge never writes
|
|
79
|
+
* it — so an id appearing only there will not exist after the archive either,
|
|
80
|
+
* and widening on it would resolve a `Realizes:` in silence and leave the fleet
|
|
81
|
+
* holding a pointer at a promise nobody ever wrote.
|
|
82
|
+
*
|
|
83
|
+
* REMOVED is excluded for honesty rather than for effect. A REMOVED requirement
|
|
84
|
+
* that names something living is already in the index through the LIVING half,
|
|
85
|
+
* so leaving it out changes no answer; what it must not do is make a delta that
|
|
86
|
+
* removes something absent — already `delta.removed-unknown` — look resolvable
|
|
87
|
+
* on top of that.
|
|
88
|
+
*
|
|
89
|
+
* WHAT THIS DOES NOT CLOSE, stated because the shape invites the assumption: a
|
|
90
|
+
* feature that REMOVES a capability requirement a LIVING service requirement
|
|
91
|
+
* realizes archives clean, and the next `validate --all` reports
|
|
92
|
+
* `capability.realizes-unknown` against a service document nobody touched.
|
|
93
|
+
* Catching that needs the join taken in the other direction — the living
|
|
94
|
+
* `Realizes:` corpus against this feature's removals — which is the mirror of
|
|
95
|
+
* the ROADMAP's `capability.uncovered` and belongs with it, not here.
|
|
96
|
+
*
|
|
97
|
+
* A capability the feature introduces gets an entry even when its delta adds no
|
|
98
|
+
* requirements, and the empty set is a real answer rather than a filler: it is
|
|
99
|
+
* what tells `resolveRealizes` to say "declares no requirements yet" instead of
|
|
100
|
+
* "has no document at all", which are two different fixes.
|
|
101
|
+
*
|
|
102
|
+
* `declared === null` returns the index untouched — the ladder, one level down.
|
|
103
|
+
*/
|
|
104
|
+
export function withFeatureRequirements(index, deltas) {
|
|
105
|
+
if (index.declared === null || deltas.length === 0)
|
|
106
|
+
return index;
|
|
107
|
+
const byCapability = new Map(index.byCapability);
|
|
108
|
+
const digests = new Map(index.digests);
|
|
109
|
+
for (const delta of deltas) {
|
|
110
|
+
const ids = new Set(byCapability.get(delta.id) ?? []);
|
|
111
|
+
// The delta's OWN digest wins for a MODIFIED id: inside a feature window,
|
|
112
|
+
// the version a `Realizes:` pin should agree with is the one this feature
|
|
113
|
+
// is about to merge, not the living one it is replacing. Overwriting is
|
|
114
|
+
// therefore the point, not a collision.
|
|
115
|
+
const withDigests = new Map(digests.get(delta.id) ?? []);
|
|
116
|
+
for (const r of delta.reqs) {
|
|
117
|
+
if (r.kind !== "ADDED" && r.kind !== "MODIFIED")
|
|
118
|
+
continue;
|
|
119
|
+
if (r.id === undefined)
|
|
120
|
+
continue;
|
|
121
|
+
ids.add(r.id);
|
|
122
|
+
withDigests.set(r.id, requirementDigest(r));
|
|
123
|
+
}
|
|
124
|
+
byCapability.set(delta.id, ids);
|
|
125
|
+
digests.set(delta.id, withDigests);
|
|
126
|
+
}
|
|
127
|
+
return { declared: index.declared, byCapability, digests };
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=overlay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlay.js","sourceRoot":"","sources":["../../../../src/core/capabilities/delta/overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,EAAE,iBAAiB,EAAoB,MAAM,wBAAwB,CAAC;AAY7E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAA2B,EAC3B,GAAsB;IAEtB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAqB,KAAK,CAAC,IAAI,CAAC,CAAC;IACrD,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAiC,EACjC,MAAyC;IAEzC,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACjE,MAAM,YAAY,GAAG,IAAI,GAAG,CAA8B,KAAK,CAAC,YAAY,CAAC,CAAC;IAC9E,MAAM,OAAO,GAAG,IAAI,GAAG,CAAsC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5E,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QACtD,0EAA0E;QAC1E,0EAA0E;QAC1E,wEAAwE;QACxE,wCAAwC;QACxC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAiB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QACzE,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YAC3B,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU;gBAAE,SAAS;YAC1D,IAAI,CAAC,CAAC,EAAE,KAAK,SAAS;gBAAE,SAAS;YACjC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACd,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;AAC7D,CAAC","sourcesContent":["/**\n * The fleet's capability vocabulary AS THIS FEATURE'S MERGE WOULD LEAVE IT —\n * the living declarations unioned with what the feature's own capability deltas\n * add.\n *\n * WHY THIS EXISTS AT ALL. Without it the axis's headline flow is refused by an\n * error code of its own making. `capabilityRequirementIndex` builds from\n * `vocab.tree.docs`, the LIVING tree, and `realizesUnknownIssues` runs against\n * it inside a feature delta as an ERROR that gates archive. So an author who\n * writes `CHECKOUT-REFUND-ONCE` into\n * `features/FEAT-9/capabilities/checkout/spec.md` and\n * `Realizes: checkout#CHECKOUT-REFUND-ONCE` into\n * `features/FEAT-9/specs/billing/spec.md` — the two halves of one change, in one\n * feature — is told the target does not exist. It does not exist YET, and the\n * same archive that would land the pointer lands the promise it points at.\n *\n * THE GRADE IS TAKEN AGAINST THE POST-MERGE FLEET, which is the only reading\n * under which both directions of the join mean anything inside a feature. It is\n * the same judgement the contract axis already makes one axis over, where\n * `spec-api.op-undefined` is graded against feature ∪ living rather than living\n * alone.\n *\n * IT WIDENS; IT MUST NOT BLIND. Every entry naming something neither side\n * declares still fails, with the same message and the same close-name\n * candidates — now drawn from the widened set, so a typo against a requirement\n * the same feature is adding gets the useful suggestion rather than a list of\n * ids the author was not writing about.\n *\n * THE LADDER SURVIVES. An unreadable `architecture/capabilities.yaml` is still\n * `invalid`, and `declared: null` still suspends the whole family: a feature\n * delta cannot make an unreadable vocabulary readable, and grading a hundred\n * entries against a file nobody can parse is the cascade `../findings.ts`\n * suppresses.\n */\nimport { requirementDigest, type Requirement } from \"../../document/spec.js\";\nimport type { Capability, CapabilityVocabulary } from \"../capabilities.js\";\nimport type { CapabilityRequirementIndex } from \"../realizes/join.js\";\n\n/** One capability document a feature's delta carries, already parsed. */\nexport interface FeatureCapabilityDelta {\n /** The capability id — the directory chain under `features/<FEAT>/capabilities/`. */\n id: string;\n /** The delta document's requirements, kinds and all. */\n reqs: Requirement[];\n}\n\n/**\n * The vocabulary a feature's deltas would leave behind: every living\n * declaration, plus every capability id this feature introduces.\n *\n * `present` widens too, and that is the point rather than a side effect: a\n * feature writing the fleet's FIRST capability document is what creates\n * `capabilities/`, so it is the act of opting in. Grading its own joins against\n * the vocabulary it is about to create catches the typo before the merge; the\n * alternative — silence until the document is living — reports the same typo on\n * somebody else's next `validate --all`, against a document they did not write.\n *\n * `tree` is deliberately NOT widened. It lists the LIVING documents under\n * `capabilities/`, and `capabilityRequirementIndex` reads every one of them and\n * declares every non-REMOVED requirement it finds. Splicing a feature's delta\n * path into that list would apply the living rule to a delta — which is right\n * for ADDED and wrong for BASE, the kind a delta uses to QUOTE living context\n * and that the merge never writes. The feature side arrives through\n * `withFeatureRequirements` below instead, where the delta kinds decide.\n *\n * An id a feature introduces is recorded `source: \"tree\"` with no `spec`: the\n * tree is the side that will declare it once the merge lands, and there is no\n * living document to name yet. Nothing in the feature-grading path reads either\n * field — they exist for the fleet-scope messages, which never see this value.\n */\nexport function withFeatureCapabilities(\n vocab: CapabilityVocabulary,\n ids: readonly string[],\n): CapabilityVocabulary {\n if (ids.length === 0) return vocab;\n const byId = new Map<string, Capability>(vocab.byId);\n for (const id of ids) {\n if (byId.has(id)) continue;\n byId.set(id, { id, source: \"tree\" });\n }\n return { ...vocab, present: true, byId };\n}\n\n/**\n * The `Realizes:` index a feature's deltas would leave behind: the living\n * requirement ids per capability, plus the ids this feature ADDS or MODIFIES.\n *\n * ADDED and MODIFIED, never REMOVED and never BASE.\n *\n * BASE is where the exclusion earns its keep: a `## Requirements` section\n * inside a delta QUOTES living context for a reader, and the merge never writes\n * it — so an id appearing only there will not exist after the archive either,\n * and widening on it would resolve a `Realizes:` in silence and leave the fleet\n * holding a pointer at a promise nobody ever wrote.\n *\n * REMOVED is excluded for honesty rather than for effect. A REMOVED requirement\n * that names something living is already in the index through the LIVING half,\n * so leaving it out changes no answer; what it must not do is make a delta that\n * removes something absent — already `delta.removed-unknown` — look resolvable\n * on top of that.\n *\n * WHAT THIS DOES NOT CLOSE, stated because the shape invites the assumption: a\n * feature that REMOVES a capability requirement a LIVING service requirement\n * realizes archives clean, and the next `validate --all` reports\n * `capability.realizes-unknown` against a service document nobody touched.\n * Catching that needs the join taken in the other direction — the living\n * `Realizes:` corpus against this feature's removals — which is the mirror of\n * the ROADMAP's `capability.uncovered` and belongs with it, not here.\n *\n * A capability the feature introduces gets an entry even when its delta adds no\n * requirements, and the empty set is a real answer rather than a filler: it is\n * what tells `resolveRealizes` to say \"declares no requirements yet\" instead of\n * \"has no document at all\", which are two different fixes.\n *\n * `declared === null` returns the index untouched — the ladder, one level down.\n */\nexport function withFeatureRequirements(\n index: CapabilityRequirementIndex,\n deltas: readonly FeatureCapabilityDelta[],\n): CapabilityRequirementIndex {\n if (index.declared === null || deltas.length === 0) return index;\n const byCapability = new Map<string, ReadonlySet<string>>(index.byCapability);\n const digests = new Map<string, ReadonlyMap<string, string>>(index.digests);\n for (const delta of deltas) {\n const ids = new Set(byCapability.get(delta.id) ?? []);\n // The delta's OWN digest wins for a MODIFIED id: inside a feature window,\n // the version a `Realizes:` pin should agree with is the one this feature\n // is about to merge, not the living one it is replacing. Overwriting is\n // therefore the point, not a collision.\n const withDigests = new Map<string, string>(digests.get(delta.id) ?? []);\n for (const r of delta.reqs) {\n if (r.kind !== \"ADDED\" && r.kind !== \"MODIFIED\") continue;\n if (r.id === undefined) continue;\n ids.add(r.id);\n withDigests.set(r.id, requirementDigest(r));\n }\n byCapability.set(delta.id, ids);\n digests.set(delta.id, withDigests);\n }\n return { declared: index.declared, byCapability, digests };\n}\n"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What one feature's capability deltas CHANGE, summarized once for the two
|
|
3
|
+
* commands a person reads before an archive.
|
|
4
|
+
*
|
|
5
|
+
* `loam show <FEAT>` and `loam delta <FEAT>` mentioned the business corpus
|
|
6
|
+
* nowhere, and the consequence was the worst shape an informational surface can
|
|
7
|
+
* have: a feature carrying ONLY a capability delta — which is the first thing an
|
|
8
|
+
* analyst writes, and exactly what `loam new --capability` now scaffolds —
|
|
9
|
+
* displayed as a feature that carries nothing. The two surfaces a reader
|
|
10
|
+
* consults before running `loam archive` therefore disagreed with the archive
|
|
11
|
+
* that would refuse it.
|
|
12
|
+
*
|
|
13
|
+
* ONE SHAPE FOR BOTH, and that is the reason this lives in core rather than in
|
|
14
|
+
* either command. `show` needs the counts (its service rows are `+N ~N -N`) and
|
|
15
|
+
* `delta` needs the promises themselves (it is a task brief, and the id in
|
|
16
|
+
* `Realizes: <capability>#<id>` is the one thing the implementer has to copy
|
|
17
|
+
* exactly). Two derivations would be two answers to "what does this feature
|
|
18
|
+
* change here", from the two commands most likely to be read side by side.
|
|
19
|
+
*
|
|
20
|
+
* THE READER IS INJECTED, exactly as `../rollup.ts`'s is and for the same
|
|
21
|
+
* package-graph reason: `core/fleet-context.ts` imports this package for its
|
|
22
|
+
* memo, so nothing under `src/core/capabilities/` may import it back.
|
|
23
|
+
*
|
|
24
|
+
* BASE requirements are counted by neither. A delta's `## Requirements` section
|
|
25
|
+
* QUOTES living context for a reader and the merge never writes it, so counting
|
|
26
|
+
* one as a change would report a feature as touching a promise it only cites.
|
|
27
|
+
* `delta.requirement-not-merged` is the grade for BASE requirements the author
|
|
28
|
+
* did NOT mean to quote — it exempts `## Requirements` precisely because that
|
|
29
|
+
* heading is the deliberate quotation — and this module owes the same reading:
|
|
30
|
+
* quoted or stranded, a BASE requirement merges nothing, so it is no part of
|
|
31
|
+
* what this feature changes.
|
|
32
|
+
*/
|
|
33
|
+
import { compareIds } from "../../repo/entries.js";
|
|
34
|
+
/**
|
|
35
|
+
* Summarize each capability delta, ordered by capability id.
|
|
36
|
+
*
|
|
37
|
+
* `docs` comes from `featureCapabilityDeltas` (or a `FleetContext`'s memo of
|
|
38
|
+
* it), so it is already `compareIds`-ordered by the walk; the sort here is the
|
|
39
|
+
* statement that the order is part of the answer rather than a property of
|
|
40
|
+
* whoever happened to call.
|
|
41
|
+
*/
|
|
42
|
+
export async function capabilityDeltaSummaries(docs, read) {
|
|
43
|
+
const out = [];
|
|
44
|
+
for (const doc of docs) {
|
|
45
|
+
const reqs = await read(doc.spec);
|
|
46
|
+
out.push({
|
|
47
|
+
id: doc.id,
|
|
48
|
+
spec: doc.spec,
|
|
49
|
+
added: reqs.filter((r) => r.kind === "ADDED").length,
|
|
50
|
+
modified: reqs.filter((r) => r.kind === "MODIFIED").length,
|
|
51
|
+
removed: reqs.filter((r) => r.kind === "REMOVED").length,
|
|
52
|
+
promises: reqs.flatMap((r) => r.kind === "BASE" ? [] : [{ kind: r.kind, id: r.id ?? null, name: r.name }]),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return out.sort((a, b) => compareIds(a.id, b.id));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../../../src/core/capabilities/delta/summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAgCnD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,IAA8B,EAC9B,IAA8C;IAE9C,MAAM,GAAG,GAA6B,EAAE,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,MAAM;YACpD,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,MAAM;YAC1D,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,MAAM;YACxD,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3B,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAC5E;SACF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACpD,CAAC","sourcesContent":["/**\n * What one feature's capability deltas CHANGE, summarized once for the two\n * commands a person reads before an archive.\n *\n * `loam show <FEAT>` and `loam delta <FEAT>` mentioned the business corpus\n * nowhere, and the consequence was the worst shape an informational surface can\n * have: a feature carrying ONLY a capability delta — which is the first thing an\n * analyst writes, and exactly what `loam new --capability` now scaffolds —\n * displayed as a feature that carries nothing. The two surfaces a reader\n * consults before running `loam archive` therefore disagreed with the archive\n * that would refuse it.\n *\n * ONE SHAPE FOR BOTH, and that is the reason this lives in core rather than in\n * either command. `show` needs the counts (its service rows are `+N ~N -N`) and\n * `delta` needs the promises themselves (it is a task brief, and the id in\n * `Realizes: <capability>#<id>` is the one thing the implementer has to copy\n * exactly). Two derivations would be two answers to \"what does this feature\n * change here\", from the two commands most likely to be read side by side.\n *\n * THE READER IS INJECTED, exactly as `../rollup.ts`'s is and for the same\n * package-graph reason: `core/fleet-context.ts` imports this package for its\n * memo, so nothing under `src/core/capabilities/` may import it back.\n *\n * BASE requirements are counted by neither. A delta's `## Requirements` section\n * QUOTES living context for a reader and the merge never writes it, so counting\n * one as a change would report a feature as touching a promise it only cites.\n * `delta.requirement-not-merged` is the grade for BASE requirements the author\n * did NOT mean to quote — it exempts `## Requirements` precisely because that\n * heading is the deliberate quotation — and this module owes the same reading:\n * quoted or stranded, a BASE requirement merges nothing, so it is no part of\n * what this feature changes.\n */\nimport { compareIds } from \"../../repo/entries.js\";\nimport type { Requirement } from \"../../document/spec.js\";\nimport type { CapabilityDoc } from \"../tree.js\";\n\n/** One promise a delta adds, restates or retires — the `Realizes:` target it creates or removes. */\nexport interface CapabilityDeltaPromise {\n kind: \"ADDED\" | \"MODIFIED\" | \"REMOVED\";\n /**\n * Its `Requirement-ID:`, or null when the delta wrote none. Null rather than\n * absent because it is a real and reportable state, not a missing field: an\n * unidentified capability requirement is an ERROR\n * (`capability.requirement-unidentified`) that gates the archive, and a brief\n * that silently dropped the row would hide the requirement the author has to\n * fix.\n */\n id: string | null;\n /** Its `### Requirement:` heading. */\n name: string;\n}\n\n/** One capability document a feature's delta carries, and what it would merge. */\nexport interface CapabilityDeltaSummary {\n id: string;\n /** The delta document, absolute. Callers make it repo-relative for their own payload. */\n spec: string;\n added: number;\n modified: number;\n removed: number;\n /** Every non-BASE requirement, in document order — the promises this delta moves. */\n promises: CapabilityDeltaPromise[];\n}\n\n/**\n * Summarize each capability delta, ordered by capability id.\n *\n * `docs` comes from `featureCapabilityDeltas` (or a `FleetContext`'s memo of\n * it), so it is already `compareIds`-ordered by the walk; the sort here is the\n * statement that the order is part of the answer rather than a property of\n * whoever happened to call.\n */\nexport async function capabilityDeltaSummaries(\n docs: readonly CapabilityDoc[],\n read: (path: string) => Promise<Requirement[]>,\n): Promise<CapabilityDeltaSummary[]> {\n const out: CapabilityDeltaSummary[] = [];\n for (const doc of docs) {\n const reqs = await read(doc.spec);\n out.push({\n id: doc.id,\n spec: doc.spec,\n added: reqs.filter((r) => r.kind === \"ADDED\").length,\n modified: reqs.filter((r) => r.kind === \"MODIFIED\").length,\n removed: reqs.filter((r) => r.kind === \"REMOVED\").length,\n promises: reqs.flatMap((r) =>\n r.kind === \"BASE\" ? [] : [{ kind: r.kind, id: r.id ?? null, name: r.name }],\n ),\n });\n }\n return out.sort((a, b) => compareIds(a.id, b.id));\n}\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A feature's own capability deltas: `features/<FEAT>/capabilities/<id>/spec.md`.
|
|
3
|
+
*
|
|
4
|
+
* The business axis's answer to `specs/<svc>/spec.md`. A capability document is
|
|
5
|
+
* a requirements document like any other, so a feature that changes one writes
|
|
6
|
+
* a DELTA against it rather than editing the living text in place — which buys
|
|
7
|
+
* the three things the living tree has never had: a `Based-On:` pin, so two PRs
|
|
8
|
+
* touching one capability collide loudly instead of silently overwriting each
|
|
9
|
+
* other; the delta algebra's refusals (`delta.added-duplicate`,
|
|
10
|
+
* `delta.modified-unknown`, …), so a diff that lands nothing says so; and a
|
|
11
|
+
* business change that ships and unships with the feature that made it.
|
|
12
|
+
*
|
|
13
|
+
* BOTH LIFECYCLES COEXIST AND MUST. Nothing here makes a direct edit of
|
|
14
|
+
* `capabilities/<id>/spec.md` illegal — a fleet mid-adoption edits the document
|
|
15
|
+
* and always has. What a feature-local delta adds is a second, safer route, and
|
|
16
|
+
* a direct edit racing one surfaces as `delta.baseline-stale` instead of as
|
|
17
|
+
* today's silent loss.
|
|
18
|
+
*
|
|
19
|
+
* ONE CALL, because the walk is already written: `readCapabilityTree`
|
|
20
|
+
* implements the presence-classifies rule, the symlink-cycle guard and the
|
|
21
|
+
* `compareIds` ordering over any root. Re-deriving it here for the feature side
|
|
22
|
+
* would be two walks free to disagree about what a capability directory is.
|
|
23
|
+
*
|
|
24
|
+
* NO `FleetContext` PARAMETER, and that is load-bearing rather than stylistic:
|
|
25
|
+
* `core/fleet-context.ts` imports `../capabilities.js`, so nothing under
|
|
26
|
+
* `src/core/capabilities/` may import it back — a core-root↔capabilities
|
|
27
|
+
* package cycle `import/no-cycle` cannot see. The memo lives on the class and
|
|
28
|
+
* calls this; callers holding a context use `context.featureCapabilityDeltas`.
|
|
29
|
+
*/
|
|
30
|
+
import { readCapabilityTree } from "../tree.js";
|
|
31
|
+
import { featureCapabilityDeltasDir } from "../../repo/authored/paths.js";
|
|
32
|
+
/**
|
|
33
|
+
* The capability documents one feature's delta carries, ordered by id.
|
|
34
|
+
*
|
|
35
|
+
* `present: false` — and zero readdirs — when the feature has no
|
|
36
|
+
* `capabilities/` directory, which is every feature in a fleet that has not
|
|
37
|
+
* adopted the axis. That short-circuit is `readCapabilityTree`'s own
|
|
38
|
+
* `existsSync` and it is the whole cost such a fleet pays.
|
|
39
|
+
*/
|
|
40
|
+
export function featureCapabilityDeltas(featureDir) {
|
|
41
|
+
return readCapabilityTree(featureCapabilityDeltasDir(featureDir));
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../../../../src/core/capabilities/delta/tree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAE,kBAAkB,EAAuB,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAG1E;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAAsB;IAC5D,OAAO,kBAAkB,CAAC,0BAA0B,CAAC,UAAU,CAAC,CAAC,CAAC;AACpE,CAAC","sourcesContent":["/**\n * A feature's own capability deltas: `features/<FEAT>/capabilities/<id>/spec.md`.\n *\n * The business axis's answer to `specs/<svc>/spec.md`. A capability document is\n * a requirements document like any other, so a feature that changes one writes\n * a DELTA against it rather than editing the living text in place — which buys\n * the three things the living tree has never had: a `Based-On:` pin, so two PRs\n * touching one capability collide loudly instead of silently overwriting each\n * other; the delta algebra's refusals (`delta.added-duplicate`,\n * `delta.modified-unknown`, …), so a diff that lands nothing says so; and a\n * business change that ships and unships with the feature that made it.\n *\n * BOTH LIFECYCLES COEXIST AND MUST. Nothing here makes a direct edit of\n * `capabilities/<id>/spec.md` illegal — a fleet mid-adoption edits the document\n * and always has. What a feature-local delta adds is a second, safer route, and\n * a direct edit racing one surfaces as `delta.baseline-stale` instead of as\n * today's silent loss.\n *\n * ONE CALL, because the walk is already written: `readCapabilityTree`\n * implements the presence-classifies rule, the symlink-cycle guard and the\n * `compareIds` ordering over any root. Re-deriving it here for the feature side\n * would be two walks free to disagree about what a capability directory is.\n *\n * NO `FleetContext` PARAMETER, and that is load-bearing rather than stylistic:\n * `core/fleet-context.ts` imports `../capabilities.js`, so nothing under\n * `src/core/capabilities/` may import it back — a core-root↔capabilities\n * package cycle `import/no-cycle` cannot see. The memo lives on the class and\n * calls this; callers holding a context use `context.featureCapabilityDeltas`.\n */\nimport { readCapabilityTree, type CapabilityTree } from \"../tree.js\";\nimport { featureCapabilityDeltasDir } from \"../../repo/authored/paths.js\";\nimport type { FeatureDir } from \"../../kernel/ids/dirs.js\";\n\n/**\n * The capability documents one feature's delta carries, ordered by id.\n *\n * `present: false` — and zero readdirs — when the feature has no\n * `capabilities/` directory, which is every feature in a fleet that has not\n * adopted the axis. That short-circuit is `readCapabilityTree`'s own\n * `existsSync` and it is the whole cost such a fleet pays.\n */\nexport function featureCapabilityDeltas(featureDir: FeatureDir): Promise<CapabilityTree> {\n return readCapabilityTree(featureCapabilityDeltasDir(featureDir));\n}\n"]}
|