@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5992 -82
- package/COMPARISON.md +168 -63
- package/CONTRIBUTING.md +121 -0
- package/MIGRATING-from-OpenSpec.md +238 -55
- package/QUICKSTART.md +302 -0
- package/README.md +653 -144
- package/ROADMAP.md +1035 -0
- package/SCHEMA.md +3916 -263
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +927 -0
- package/dist/cli.js +133 -21
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +204 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +309 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +74 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/closing.js +42 -0
- package/dist/commands/archive/closing.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/consumers.js +56 -0
- package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +193 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/document/head.js +151 -0
- package/dist/commands/archive/plan/document/head.js.map +1 -0
- package/dist/commands/archive/plan/document/links.js +284 -0
- package/dist/commands/archive/plan/document/links.js.map +1 -0
- package/dist/commands/archive/plan/document/run.js +136 -0
- package/dist/commands/archive/plan/document/run.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +319 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +298 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/model/extending.js +85 -0
- package/dist/commands/archive/plan/model/extending.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +106 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +318 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +30 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +355 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/archive/shipped.js +49 -0
- package/dist/commands/archive/shipped.js.map +1 -0
- package/dist/commands/context/context.js +166 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +305 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +367 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +221 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +6 -8
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +86 -0
- package/dist/commands/diff/diff.js.map +1 -0
- package/dist/commands/diff/print.js +38 -0
- package/dist/commands/diff/print.js.map +1 -0
- package/dist/commands/doctor.js +65 -5
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +227 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +39 -28
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +152 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +66 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +105 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +262 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +146 -0
- package/dist/commands/gherkin/reconcile.js.map +1 -0
- package/dist/commands/gherkin/render.js +77 -0
- package/dist/commands/gherkin/render.js.map +1 -0
- package/dist/commands/init/example.js +204 -0
- package/dist/commands/init/example.js.map +1 -0
- package/dist/commands/init/first-hour.js +72 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +142 -71
- package/dist/commands/init/init.js.map +1 -0
- package/dist/commands/init/mcp.js +131 -0
- package/dist/commands/init/mcp.js.map +1 -0
- package/dist/commands/init/options.js +78 -0
- package/dist/commands/init/options.js.map +1 -0
- package/dist/commands/instructions.js +72 -14
- package/dist/commands/instructions.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +63 -0
- package/dist/commands/list/campaign/campaign.js.map +1 -0
- package/dist/commands/list/campaign/owners.js +65 -0
- package/dist/commands/list/campaign/owners.js.map +1 -0
- package/dist/commands/list/json.js +155 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +358 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +344 -0
- package/dist/commands/list/print.js.map +1 -0
- package/dist/commands/list/review.js +120 -0
- package/dist/commands/list/review.js.map +1 -0
- package/dist/commands/list/suites/suites.js +140 -0
- package/dist/commands/list/suites/suites.js.map +1 -0
- package/dist/commands/list/views.js +108 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +238 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +75 -0
- package/dist/commands/mcp/mcp.js.map +1 -0
- package/dist/commands/mcp/serve.js +55 -0
- package/dist/commands/mcp/serve.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/active.js +175 -0
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
- package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/living.js +62 -0
- package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/stage.js +143 -0
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/target.js +219 -0
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js +86 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +18 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +40 -0
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/read.js +49 -0
- package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
- package/dist/commands/migrate-openspec/print.js +89 -0
- package/dist/commands/migrate-openspec/print.js.map +1 -0
- package/dist/commands/new/capability-template.js +118 -0
- package/dist/commands/new/capability-template.js.map +1 -0
- package/dist/commands/new/commit.js +62 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/modifies.js +206 -0
- package/dist/commands/new/modifies.js.map +1 -0
- package/dist/commands/new/new.js +328 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +279 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +199 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/policy/format.js +152 -0
- package/dist/commands/policy/format.js.map +1 -0
- package/dist/commands/{docs-repo-gate.js → policy/gate.js} +38 -11
- package/dist/commands/policy/gate.js.map +1 -0
- package/dist/commands/rebase/edit.js +106 -0
- package/dist/commands/rebase/edit.js.map +1 -0
- package/dist/commands/rebase/living.js +185 -0
- package/dist/commands/rebase/living.js.map +1 -0
- package/dist/commands/rebase/plan.js +245 -0
- package/dist/commands/rebase/plan.js.map +1 -0
- package/dist/commands/rebase/rebase.js +300 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +221 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +278 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +174 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +182 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/introduced.js +157 -0
- package/dist/commands/show/introduced.js.map +1 -0
- package/dist/commands/show/marks.js +53 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/show/service.js +239 -0
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +87 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/fleet-next.js +90 -0
- package/dist/commands/status/fleet-next.js.map +1 -0
- package/dist/commands/status/json.js +47 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +209 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +115 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +269 -0
- package/dist/commands/steps/steps.js.map +1 -0
- package/dist/commands/subsystem/edit.js +192 -0
- package/dist/commands/subsystem/edit.js.map +1 -0
- package/dist/commands/subsystem/move.js +325 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +113 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +98 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +318 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/exclude.js +132 -0
- package/dist/commands/subsystem/txn/exclude.js.map +1 -0
- package/dist/commands/subsystem/txn/links.js +128 -0
- package/dist/commands/subsystem/txn/links.js.map +1 -0
- package/dist/commands/subsystem/txn/report.js +174 -0
- package/dist/commands/subsystem/txn/report.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +196 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +249 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/tasks/actions.js +107 -0
- package/dist/commands/tasks/actions.js.map +1 -0
- package/dist/commands/tasks/render.js +253 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +119 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +176 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/unarchive/restore.js +254 -0
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +59 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +245 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +204 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +58 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/introduced.js +102 -0
- package/dist/commands/validate/checks/introduced.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +264 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +85 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/coverage/covers-after.js +105 -0
- package/dist/commands/validate/coverage/covers-after.js.map +1 -0
- package/dist/commands/validate/feature.js +222 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +93 -0
- package/dist/commands/validate/fleet/census.js.map +1 -0
- package/dist/commands/validate/fleet/kind-tags.js +39 -0
- package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
- package/dist/commands/validate/fleet/landscape.js +371 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +118 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/map/attest.js +98 -0
- package/dist/commands/validate/fleet/map/attest.js.map +1 -0
- package/dist/commands/validate/fleet/map/bindings.js +107 -0
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
- package/dist/commands/validate/fleet/map/consumers.js +244 -0
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
- package/dist/commands/validate/fleet/map/isolation.js +116 -0
- package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
- package/dist/commands/validate/fleet/map/usecases.js +54 -0
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +266 -0
- package/dist/commands/validate/fleet/obligations.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/print.js +71 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/place.js +13 -0
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
- package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +75 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/projects.js +278 -0
- package/dist/commands/validate/fleet/views/projects.js.map +1 -0
- package/dist/commands/validate/fleet/views/root-documents.js +83 -0
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +52 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +89 -0
- package/dist/commands/validate/links/corpus.js.map +1 -0
- package/dist/commands/validate/links/glossary.js +75 -0
- package/dist/commands/validate/links/glossary.js.map +1 -0
- package/dist/commands/validate/render/repeats.js +63 -0
- package/dist/commands/validate/render/repeats.js.map +1 -0
- package/dist/commands/validate/render/rollups.js +115 -0
- package/dist/commands/validate/render/rollups.js.map +1 -0
- package/dist/commands/validate/render/text.js +199 -0
- package/dist/commands/validate/render/text.js.map +1 -0
- package/dist/commands/validate/report.js +145 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/scope.js +113 -0
- package/dist/commands/validate/scope.js.map +1 -0
- package/dist/commands/validate/service/api.js +252 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/contracts/generated.js +134 -0
- package/dist/commands/validate/service/contracts/generated.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +241 -0
- package/dist/commands/validate/service/events/events.js.map +1 -0
- package/dist/commands/validate/service/events/message-producers.js +77 -0
- package/dist/commands/validate/service/events/message-producers.js.map +1 -0
- package/dist/commands/validate/service/evidence-pins.js +177 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/model/diverged.js +226 -0
- package/dist/commands/validate/service/model/diverged.js.map +1 -0
- package/dist/commands/validate/service/model/grade.js +163 -0
- package/dist/commands/validate/service/model/grade.js.map +1 -0
- package/dist/commands/validate/service/service.js +310 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +279 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +148 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/service/usecases/tags.js +113 -0
- package/dist/commands/validate/service/usecases/tags.js.map +1 -0
- package/dist/commands/validate/service/usecases/usecases.js +209 -0
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/validate.js +363 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +178 -0
- package/dist/commands/verify/cross/diff.js.map +1 -0
- package/dist/commands/verify/evidence/contract.js +32 -0
- package/dist/commands/verify/evidence/contract.js.map +1 -0
- package/dist/commands/verify/evidence/pins.js +52 -0
- package/dist/commands/verify/evidence/pins.js.map +1 -0
- package/dist/commands/verify/evidence/read.js +81 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +263 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +278 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +206 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +328 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +220 -0
- package/dist/commands/verify/verify.js.map +1 -0
- package/dist/commands/vouch/contract.js +11 -0
- package/dist/commands/vouch/contract.js.map +1 -0
- package/dist/commands/vouch/pack/contract.js +2 -0
- package/dist/commands/vouch/pack/contract.js.map +1 -0
- package/dist/commands/vouch/pack/pack.js +266 -0
- package/dist/commands/vouch/pack/pack.js.map +1 -0
- package/dist/commands/vouch/pack/print.js +266 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +141 -0
- package/dist/commands/vouch/pack/sections.js.map +1 -0
- package/dist/commands/vouch/prompt/confirm.js +46 -0
- package/dist/commands/vouch/prompt/confirm.js.map +1 -0
- package/dist/commands/vouch/report.js +101 -0
- package/dist/commands/vouch/report.js.map +1 -0
- package/dist/commands/vouch/run.js +230 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +111 -0
- package/dist/commands/vouch/sample/plan.js.map +1 -0
- package/dist/commands/vouch/sample/print.js +109 -0
- package/dist/commands/vouch/sample/print.js.map +1 -0
- package/dist/commands/vouch/vet/verify.js +155 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +169 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +299 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +46 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +44 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +78 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +104 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +138 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +273 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md.js +203 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -0
- package/dist/core/agent/agents-stamp.js.map +1 -0
- package/dist/core/agent/contract.js +2 -0
- package/dist/core/agent/contract.js.map +1 -0
- package/dist/core/agent/protocol.js +193 -0
- package/dist/core/agent/protocol.js.map +1 -0
- package/dist/core/agent/scaffold.js +254 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +144 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +151 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +193 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +280 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +373 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +323 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +220 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +188 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +311 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +67 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +210 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +19 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +338 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +43 -0
- package/dist/core/asyncapi/baseline/plan.js.map +1 -0
- package/dist/core/asyncapi/baseline/surfaces.js +54 -0
- package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
- package/dist/core/asyncapi/depth.js +164 -0
- package/dist/core/asyncapi/depth.js.map +1 -0
- package/dist/core/asyncapi/digest.js +146 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +92 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +38 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +290 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +195 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +83 -0
- package/dist/core/asyncapi/merge/pin.js.map +1 -0
- package/dist/core/asyncapi/model.js +11 -0
- package/dist/core/asyncapi/model.js.map +1 -0
- package/dist/core/asyncapi/producers.js +50 -0
- package/dist/core/asyncapi/producers.js.map +1 -0
- package/dist/core/asyncapi/read.js +263 -0
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +285 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +385 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +273 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/map/extend.js +84 -0
- package/dist/core/brief/map/extend.js.map +1 -0
- package/dist/core/brief/map/owed.js +266 -0
- package/dist/core/brief/map/owed.js.map +1 -0
- package/dist/core/brief/targets.js +304 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +58 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +190 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/direction/direction.js +114 -0
- package/dist/core/c4/direction/direction.js.map +1 -0
- package/dist/core/c4/likec4.js +243 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/locate/unlocated.js +150 -0
- package/dist/core/c4/locate/unlocated.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +160 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +110 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +113 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/prefetch/fleet.js +134 -0
- package/dist/core/c4/prefetch/fleet.js.map +1 -0
- package/dist/core/c4/project/architecture.js +161 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/batch.js +140 -0
- package/dist/core/c4/project/batch.js.map +1 -0
- package/dist/core/c4/project/documents.js +89 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +219 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/project/staged.js +277 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/attested.js +0 -0
- package/dist/core/c4/resolve/attested.js.map +1 -0
- package/dist/core/c4/resolve/external.js +51 -0
- package/dist/core/c4/resolve/external.js.map +1 -0
- package/dist/core/c4/resolve/service.js +174 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/resolve/steps.js +290 -0
- package/dist/core/c4/resolve/steps.js.map +1 -0
- package/dist/core/c4/resolve/systems.js +154 -0
- package/dist/core/c4/resolve/systems.js.map +1 -0
- package/dist/core/c4/root-project/exclude.js +352 -0
- package/dist/core/c4/root-project/exclude.js.map +1 -0
- package/dist/core/c4/seed/fleet-file.js +201 -0
- package/dist/core/c4/seed/fleet-file.js.map +1 -0
- package/dist/core/c4/seed/items.js +91 -0
- package/dist/core/c4/seed/items.js.map +1 -0
- package/dist/core/c4/seed/stamp.js +48 -0
- package/dist/core/c4/seed/stamp.js.map +1 -0
- package/dist/core/c4/seed/template.js +173 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/service-model/created/models.js +96 -0
- package/dist/core/c4/service-model/created/models.js.map +1 -0
- package/dist/core/c4/service-model/documents.js +47 -0
- package/dist/core/c4/service-model/documents.js.map +1 -0
- package/dist/core/c4/service-model/fleet/extending.js +82 -0
- package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
- package/dist/core/c4/service-model/load.js +165 -0
- package/dist/core/c4/service-model/load.js.map +1 -0
- package/dist/core/c4/service-model/renderer.js +128 -0
- package/dist/core/c4/service-model/renderer.js.map +1 -0
- package/dist/core/c4/service-model/shape.js +106 -0
- package/dist/core/c4/service-model/shape.js.map +1 -0
- package/dist/core/c4/service-model/slice.js +188 -0
- package/dist/core/c4/service-model/slice.js.map +1 -0
- package/dist/core/c4/source-mask.js +369 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +308 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +167 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +30 -0
- package/dist/core/c4/splice/contract.js.map +1 -0
- package/dist/core/c4/splice/delta-blocks.js +126 -0
- package/dist/core/c4/splice/delta-blocks.js.map +1 -0
- package/dist/core/c4/splice/identity/declared.js +87 -0
- package/dist/core/c4/splice/identity/declared.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +73 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/identity/existing.js +80 -0
- package/dist/core/c4/splice/identity/existing.js.map +1 -0
- package/dist/core/c4/splice/identity/interior.js +80 -0
- package/dist/core/c4/splice/identity/interior.js.map +1 -0
- package/dist/core/c4/splice/identity/owner.js +50 -0
- package/dist/core/c4/splice/identity/owner.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +337 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/model/merge.js +151 -0
- package/dist/core/c4/splice/model/merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +298 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/splice/text/spot.js +131 -0
- package/dist/core/c4/splice/text/spot.js.map +1 -0
- package/dist/core/c4/workspace.js +166 -0
- package/dist/core/c4/workspace.js.map +1 -0
- package/dist/core/capabilities/authoring/notes.js +141 -0
- package/dist/core/capabilities/authoring/notes.js.map +1 -0
- package/dist/core/capabilities/capabilities.js +124 -0
- package/dist/core/capabilities/capabilities.js.map +1 -0
- package/dist/core/capabilities/delta/doc.js +47 -0
- package/dist/core/capabilities/delta/doc.js.map +1 -0
- package/dist/core/capabilities/delta/overlay.js +129 -0
- package/dist/core/capabilities/delta/overlay.js.map +1 -0
- package/dist/core/capabilities/delta/summary.js +57 -0
- package/dist/core/capabilities/delta/summary.js.map +1 -0
- package/dist/core/capabilities/delta/tree.js +43 -0
- package/dist/core/capabilities/delta/tree.js.map +1 -0
- package/dist/core/capabilities/delta/uncovered.js +222 -0
- package/dist/core/capabilities/delta/uncovered.js.map +1 -0
- package/dist/core/capabilities/findings.js +338 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +174 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +123 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +205 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +104 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +267 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +185 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +75 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/calls/called.js +52 -0
- package/dist/core/coherence/calls/called.js.map +1 -0
- package/dist/core/coherence/coherence.js +332 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/consumed/operations.js +70 -0
- package/dist/core/coherence/consumed/operations.js.map +1 -0
- package/dist/core/coherence/consumed/refusal.js +38 -0
- package/dist/core/coherence/consumed/refusal.js.map +1 -0
- package/dist/core/coherence/covers/health.js +85 -0
- package/dist/core/coherence/covers/health.js.map +1 -0
- package/dist/core/coherence/declared.js +295 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +191 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +335 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +189 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +63 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/produced.js +100 -0
- package/dist/core/coherence/events/produced.js.map +1 -0
- package/dist/core/coherence/living.js +198 -0
- package/dist/core/coherence/living.js.map +1 -0
- package/dist/core/coherence/lookups.js +95 -0
- package/dist/core/coherence/lookups.js.map +1 -0
- package/dist/core/coherence/pending.js +39 -0
- package/dist/core/coherence/pending.js.map +1 -0
- package/dist/core/coherence/retired/archived.js +285 -0
- package/dist/core/coherence/retired/archived.js.map +1 -0
- package/dist/core/coherence/retired/event-pair.js +62 -0
- package/dist/core/coherence/retired/event-pair.js.map +1 -0
- package/dist/core/coherence/retired/merged.js +79 -0
- package/dist/core/coherence/retired/merged.js.map +1 -0
- package/dist/core/coherence/retired/retirement.js +49 -0
- package/dist/core/coherence/retired/retirement.js.map +1 -0
- package/dist/core/coherence/retired/revival/arrivals.js +131 -0
- package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
- package/dist/core/coherence/retired/revival/revived.js +297 -0
- package/dist/core/coherence/retired/revival/revived.js.map +1 -0
- package/dist/core/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.js.map +1 -0
- package/dist/core/consumers/after.js +113 -0
- package/dist/core/consumers/after.js.map +1 -0
- package/dist/core/consumers/consumers.js +296 -0
- package/dist/core/consumers/consumers.js.map +1 -0
- package/dist/core/consumers/current.js +211 -0
- package/dist/core/consumers/current.js.map +1 -0
- package/dist/core/consumers/scan.js +46 -0
- package/dist/core/consumers/scan.js.map +1 -0
- package/dist/core/consumers/state.js +27 -0
- package/dist/core/consumers/state.js.map +1 -0
- package/dist/core/delta/claims.js +73 -0
- package/dist/core/delta/claims.js.map +1 -0
- package/dist/core/delta/delta.js +341 -0
- package/dist/core/delta/delta.js.map +1 -0
- package/dist/core/delta/document.js +177 -0
- package/dist/core/delta/document.js.map +1 -0
- package/dist/core/delta/scope.js +48 -0
- package/dist/core/delta/scope.js.map +1 -0
- package/dist/core/delta/select.js +237 -0
- package/dist/core/delta/select.js.map +1 -0
- package/dist/core/dependencies/dependencies.js +141 -0
- package/dist/core/dependencies/dependencies.js.map +1 -0
- package/dist/core/dependencies/facts.js +165 -0
- package/dist/core/dependencies/facts.js.map +1 -0
- package/dist/core/dependencies/fanin.js +88 -0
- package/dist/core/dependencies/fanin.js.map +1 -0
- package/dist/core/dependencies/graph.js +106 -0
- package/dist/core/dependencies/graph.js.map +1 -0
- package/dist/core/deployment/delta.js +191 -0
- package/dist/core/deployment/delta.js.map +1 -0
- package/dist/core/deployment/objects.js +145 -0
- package/dist/core/deployment/objects.js.map +1 -0
- package/dist/core/diff/base-git.js +230 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +237 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/joins.js +136 -0
- package/dist/core/diff/joins.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +204 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/scope/edges.js +82 -0
- package/dist/core/diff/scope/edges.js.map +1 -0
- package/dist/core/diff/semantic.js +312 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/docs.js +37 -85
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +238 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +139 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +355 -0
- package/dist/core/doctor/doctor.js.map +1 -0
- package/dist/core/doctor/report.js +13 -0
- package/dist/core/doctor/report.js.map +1 -0
- package/dist/core/doctor/reports/scan.js +242 -0
- package/dist/core/doctor/reports/scan.js.map +1 -0
- package/dist/core/doctor/residue.js +110 -0
- package/dist/core/doctor/residue.js.map +1 -0
- package/dist/core/document/apply.js +224 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -2
- package/dist/core/document/frontmatter.js.map +1 -0
- package/dist/core/document/grammar/directives.js +143 -0
- package/dist/core/document/grammar/directives.js.map +1 -0
- package/dist/core/document/parse.js +286 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +238 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +234 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +89 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +209 -0
- package/dist/core/envelope/json.js.map +1 -0
- package/dist/core/{version.js → envelope/version.js} +3 -3
- package/dist/core/envelope/version.js.map +1 -0
- package/dist/core/explain/families.js +180 -0
- package/dist/core/explain/families.js.map +1 -0
- package/dist/core/explain/fix-tables.js +178 -0
- package/dist/core/explain/fix-tables.js.map +1 -0
- package/dist/core/explain/lookup.js +194 -0
- package/dist/core/explain/lookup.js.map +1 -0
- package/dist/core/explain/refusals.js +49 -0
- package/dist/core/explain/refusals.js.map +1 -0
- package/dist/core/explain/terms/documents.js +227 -0
- package/dist/core/explain/terms/documents.js.map +1 -0
- package/dist/core/explain/terms/done-check.js +144 -0
- package/dist/core/explain/terms/done-check.js.map +1 -0
- package/dist/core/explain/terms/entry.js +14 -0
- package/dist/core/explain/terms/entry.js.map +1 -0
- package/dist/core/explain/terms/stages.js +71 -0
- package/dist/core/explain/terms/stages.js.map +1 -0
- package/dist/core/explain/terms/tasks.js +97 -0
- package/dist/core/explain/terms/tasks.js.map +1 -0
- package/dist/core/explain/terms.js +103 -0
- package/dist/core/explain/terms.js.map +1 -0
- package/dist/core/explore/describe.js +105 -0
- package/dist/core/explore/describe.js.map +1 -0
- package/dist/core/explore/explore.js +204 -0
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +174 -146
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +208 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +246 -0
- package/dist/core/gate/partners.js.map +1 -0
- package/dist/core/gate/report.js +47 -0
- package/dist/core/gate/report.js.map +1 -0
- package/dist/core/gate/verification.js +176 -0
- package/dist/core/gate/verification.js.map +1 -0
- package/dist/core/gherkin/digest.js +60 -0
- package/dist/core/gherkin/digest.js.map +1 -0
- package/dist/core/gherkin/emit.js +177 -0
- package/dist/core/gherkin/emit.js.map +1 -0
- package/dist/core/gherkin/read.js +76 -0
- package/dist/core/gherkin/read.js.map +1 -0
- package/dist/core/gherkin/stale.js +210 -0
- package/dist/core/gherkin/stale.js.map +1 -0
- package/dist/core/gherkin/stamp.js +77 -0
- package/dist/core/gherkin/stamp.js.map +1 -0
- package/dist/core/gherkin/steps/catalogue.js +154 -0
- package/dist/core/gherkin/steps/catalogue.js.map +1 -0
- package/dist/core/gherkin/steps/inventory.js +98 -0
- package/dist/core/gherkin/steps/inventory.js.map +1 -0
- package/dist/core/gherkin/steps/phrase.js +72 -0
- package/dist/core/gherkin/steps/phrase.js.map +1 -0
- package/dist/core/glossary/delta.js +109 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +73 -0
- package/dist/core/glossary/tree.js.map +1 -0
- package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -0
- package/dist/core/kernel/concurrency.js.map +1 -0
- package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
- package/dist/core/kernel/document-bytes.js.map +1 -0
- package/dist/core/kernel/fences.js +42 -0
- package/dist/core/kernel/fences.js.map +1 -0
- package/dist/core/kernel/ids/capability.js +72 -0
- package/dist/core/kernel/ids/capability.js.map +1 -0
- package/dist/core/kernel/ids/dirs.js +33 -0
- package/dist/core/kernel/ids/dirs.js.map +1 -0
- package/dist/core/kernel/ids/feature.js +75 -0
- package/dist/core/kernel/ids/feature.js.map +1 -0
- package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
- package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
- package/dist/core/kernel/ids/service.js +156 -0
- package/dist/core/kernel/ids/service.js.map +1 -0
- package/dist/core/kernel/ids/subsystem.js +63 -0
- package/dist/core/kernel/ids/subsystem.js.map +1 -0
- package/dist/core/{path-safety.js → kernel/path-safety.js} +56 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/{records.js → kernel/records.js} +11 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +66 -0
- package/dist/core/links/backlinks.js.map +1 -0
- package/dist/core/links/case.js +74 -0
- package/dist/core/links/case.js.map +1 -0
- package/dist/core/links/corpus.js +118 -0
- package/dist/core/links/corpus.js.map +1 -0
- package/dist/core/links/findings.js +110 -0
- package/dist/core/links/findings.js.map +1 -0
- package/dist/core/links/parse.js +265 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +212 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +73 -0
- package/dist/core/mcp/author-tools.js.map +1 -0
- package/dist/core/mcp/framing.js +46 -0
- package/dist/core/mcp/framing.js.map +1 -0
- package/dist/core/mcp/protocol.js +280 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/tools.js +324 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/obligations/obligations.js +106 -0
- package/dist/core/obligations/obligations.js.map +1 -0
- package/dist/core/openapi/baseline/gate.js +207 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +142 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +174 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/contract-text.js +33 -0
- package/dist/core/openapi/contract-text.js.map +1 -0
- package/dist/core/openapi/contract-tree.js +301 -0
- package/dist/core/openapi/contract-tree.js.map +1 -0
- package/dist/core/openapi/depth.js +136 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +239 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +54 -108
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +199 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +16 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +204 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +232 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +110 -0
- package/dist/core/openapi/merge/pin.js.map +1 -0
- package/dist/core/openspec/decide/capabilities.js +244 -0
- package/dist/core/openspec/decide/capabilities.js.map +1 -0
- package/dist/core/openspec/decide/dispositions.js +63 -0
- package/dist/core/openspec/decide/dispositions.js.map +1 -0
- package/dist/core/openspec/decide/renames.js +179 -0
- package/dist/core/openspec/decide/renames.js.map +1 -0
- package/dist/core/openspec/decide/verdict.js +84 -0
- package/dist/core/openspec/decide/verdict.js.map +1 -0
- package/dist/core/openspec/inventory.js +220 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +78 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +70 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +241 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +191 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +304 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +116 -0
- package/dist/core/openspec/scan/walk.js.map +1 -0
- package/dist/core/openspec/scan/workspace.js +71 -0
- package/dist/core/openspec/scan/workspace.js.map +1 -0
- package/dist/core/owners/codeowners.js +141 -0
- package/dist/core/owners/codeowners.js.map +1 -0
- package/dist/core/pack/features.js +120 -0
- package/dist/core/pack/features.js.map +1 -0
- package/dist/core/pack/joins.js +112 -0
- package/dist/core/pack/joins.js.map +1 -0
- package/dist/core/pack/living.js +157 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +120 -0
- package/dist/core/pack/pack.js.map +1 -0
- package/dist/core/permissions/permissions.js +87 -0
- package/dist/core/permissions/permissions.js.map +1 -0
- package/dist/core/projection/api.js +84 -0
- package/dist/core/projection/api.js.map +1 -0
- package/dist/core/projection/arch-slice.js +63 -0
- package/dist/core/projection/arch-slice.js.map +1 -0
- package/dist/core/projection/events.js +34 -0
- package/dist/core/projection/events.js.map +1 -0
- package/dist/core/projection/introduced.js +14 -0
- package/dist/core/projection/introduced.js.map +1 -0
- package/dist/core/provenance/findings.js +244 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +201 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +139 -0
- package/dist/core/provenance/gitq/moves.js.map +1 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
- package/dist/core/provenance/sample/scope.js +238 -0
- package/dist/core/provenance/sample/scope.js.map +1 -0
- package/dist/core/provenance/sample/sections.js +61 -0
- package/dist/core/provenance/sample/sections.js.map +1 -0
- package/dist/core/provenance/sources.js +280 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +220 -0
- package/dist/core/provenance/stamp.js.map +1 -0
- package/dist/core/provenance/walk.js +157 -0
- package/dist/core/provenance/walk.js.map +1 -0
- package/dist/core/repo/authored/paths.js +210 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +322 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +308 -0
- package/dist/core/repo/repo.js.map +1 -0
- package/dist/core/repo/service-target.js +153 -0
- package/dist/core/repo/service-target.js.map +1 -0
- package/dist/core/repo/state.js +58 -0
- package/dist/core/repo/state.js.map +1 -0
- package/dist/core/repo/tree/find.js +61 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +90 -0
- package/dist/core/repo/tree/fs.js.map +1 -0
- package/dist/core/repo/tree/marker.js +61 -0
- package/dist/core/repo/tree/marker.js.map +1 -0
- package/dist/core/repo/tree/render/body.js +258 -0
- package/dist/core/repo/tree/render/body.js.map +1 -0
- package/dist/core/repo/tree/render/projects.js +182 -0
- package/dist/core/repo/tree/render/projects.js.map +1 -0
- package/dist/core/repo/tree/render/service/header.js +125 -0
- package/dist/core/repo/tree/render/service/header.js.map +1 -0
- package/dist/core/repo/tree/render/service/peers.js +28 -0
- package/dist/core/repo/tree/render/service/peers.js.map +1 -0
- package/dist/core/repo/tree/render/service/view-id.js +67 -0
- package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
- package/dist/core/repo/tree/render/service/views.js +78 -0
- package/dist/core/repo/tree/render/service/views.js.map +1 -0
- package/dist/core/repo/tree/render/stale.js +42 -0
- package/dist/core/repo/tree/render/stale.js.map +1 -0
- package/dist/core/repo/tree/render/text.js +84 -0
- package/dist/core/repo/tree/render/text.js.map +1 -0
- package/dist/core/repo/tree/render/views.js +293 -0
- package/dist/core/repo/tree/render/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +255 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +146 -14
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +239 -0
- package/dist/core/scaffold/landscape.js.map +1 -0
- package/dist/core/scaffold/legacy.js +271 -0
- package/dist/core/scaffold/legacy.js.map +1 -0
- package/dist/core/scaffold/readme.js +84 -0
- package/dist/core/scaffold/readme.js.map +1 -0
- package/dist/core/staging/commit.js +252 -0
- package/dist/core/staging/commit.js.map +1 -0
- package/dist/core/staging/interrupted.js +96 -0
- package/dist/core/staging/interrupted.js.map +1 -0
- package/dist/core/staging/lock.js +268 -0
- package/dist/core/staging/lock.js.map +1 -0
- package/dist/core/staging/recovery/finding.js +35 -0
- package/dist/core/staging/recovery/finding.js.map +1 -0
- package/dist/core/staging/recovery/intent.js +95 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +204 -0
- package/dist/core/staging/recovery/recover.js.map +1 -0
- package/dist/core/staging/recovery/residue.js +62 -0
- package/dist/core/staging/recovery/residue.js.map +1 -0
- package/dist/core/staging/snapshot/manifest.js +188 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/snapshot/snapshot.js +196 -0
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +181 -0
- package/dist/core/staging/txn/forward.js.map +1 -0
- package/dist/core/staging/txn/journal.js +139 -0
- package/dist/core/staging/txn/journal.js.map +1 -0
- package/dist/core/staging/txn/transaction.js +75 -0
- package/dist/core/staging/txn/transaction.js.map +1 -0
- package/dist/core/staging/writes.js +113 -0
- package/dist/core/staging/writes.js.map +1 -0
- package/dist/core/status/actions/execution.js +60 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +126 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +196 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +214 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +163 -0
- package/dist/core/status/feature/next.js.map +1 -0
- package/dist/core/status/feature/state.js +21 -0
- package/dist/core/status/feature/state.js.map +1 -0
- package/dist/core/status/feature/words.js +96 -0
- package/dist/core/status/feature/words.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +216 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +302 -0
- package/dist/core/status/fleet/next.js.map +1 -0
- package/dist/core/status/interrupted.js +97 -0
- package/dist/core/status/interrupted.js.map +1 -0
- package/dist/core/status/report.js +31 -0
- package/dist/core/status/report.js.map +1 -0
- package/dist/core/status/scan.js +41 -0
- package/dist/core/status/scan.js.map +1 -0
- package/dist/core/status/verification.js +216 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/tasks/packet.js +199 -0
- package/dist/core/tasks/packet.js.map +1 -0
- package/dist/core/tasks/record.js +43 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/sources.js +181 -0
- package/dist/core/tasks/sources.js.map +1 -0
- package/dist/core/tasks/stamps.js +76 -0
- package/dist/core/tasks/stamps.js.map +1 -0
- package/dist/core/tasks/unit.js +0 -0
- package/dist/core/tasks/unit.js.map +1 -0
- package/dist/core/usecases/capability.js +166 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +140 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +101 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/modified.js +315 -0
- package/dist/core/usecases/delta/modified.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +76 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +296 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/grade/capability-tag.js +93 -0
- package/dist/core/usecases/grade/capability-tag.js.map +1 -0
- package/dist/core/usecases/grade/feature.js +88 -0
- package/dist/core/usecases/grade/feature.js.map +1 -0
- package/dist/core/usecases/grade/requirement-tag.js +94 -0
- package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
- package/dist/core/usecases/grade/steps.js +266 -0
- package/dist/core/usecases/grade/steps.js.map +1 -0
- package/dist/core/usecases/grade/usecases.js +112 -0
- package/dist/core/usecases/grade/usecases.js.map +1 -0
- package/dist/core/usecases/operations.js +123 -0
- package/dist/core/usecases/operations.js.map +1 -0
- package/dist/core/usecases/place.js +44 -0
- package/dist/core/usecases/place.js.map +1 -0
- package/dist/core/usecases/service/exclude.js +119 -0
- package/dist/core/usecases/service/exclude.js.map +1 -0
- package/dist/core/usecases/service/flows.js +164 -0
- package/dist/core/usecases/service/flows.js.map +1 -0
- package/dist/core/usecases/suites/participants.js +83 -0
- package/dist/core/usecases/suites/participants.js.map +1 -0
- package/dist/core/usecases/suites/suites.js +45 -0
- package/dist/core/usecases/suites/suites.js.map +1 -0
- package/dist/core/usecases/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +180 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +170 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +259 -0
- package/dist/core/verify/checklist.js.map +1 -0
- package/dist/core/verify/claims/identity.js +61 -0
- package/dist/core/verify/claims/identity.js.map +1 -0
- package/dist/core/verify/cross/diff.js +97 -0
- package/dist/core/verify/cross/diff.js.map +1 -0
- package/dist/core/verify/evidence/contract.js +169 -0
- package/dist/core/verify/evidence/contract.js.map +1 -0
- package/dist/core/verify/location.js +67 -0
- package/dist/core/verify/location.js.map +1 -0
- package/dist/core/verify/pins/lint.js +158 -0
- package/dist/core/verify/pins/lint.js.map +1 -0
- package/dist/core/verify/pins/pin.js +95 -0
- package/dist/core/verify/pins/pin.js.map +1 -0
- package/dist/core/verify/read/file.js +224 -0
- package/dist/core/verify/read/file.js.map +1 -0
- package/dist/core/verify/read/shape.js +169 -0
- package/dist/core/verify/read/shape.js.map +1 -0
- package/dist/core/verify/read/union.js +105 -0
- package/dist/core/verify/read/union.js.map +1 -0
- package/dist/core/verify/record.js +165 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +99 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +61 -0
- package/dist/core/verify/store/render.js.map +1 -0
- package/dist/core/vocabulary/health.js +91 -0
- package/dist/core/vocabulary/health.js.map +1 -0
- package/dist/core/vocabulary/issue.js +59 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +216 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/vocabulary/report.js +90 -0
- package/dist/core/vocabulary/report.js.map +1 -0
- package/dist/core/vocabulary/steps.js +266 -0
- package/dist/core/vocabulary/steps.js.map +1 -0
- package/dist/core/workspace/discover.js +239 -0
- package/dist/core/workspace/discover.js.map +1 -0
- package/dist/core/workspace/render.js +52 -0
- package/dist/core/workspace/render.js.map +1 -0
- package/examples/README.md +232 -0
- package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
- package/examples/docs/architecture/capabilities.yaml +31 -0
- package/examples/docs/architecture/landscape.likec4 +336 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/services.likec4 +70 -0
- package/examples/docs/architecture/subsystems.likec4 +18 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +74 -0
- package/examples/docs/capabilities/checkout/spec.md +55 -0
- package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
- package/examples/docs/capabilities/order-notifications/spec.md +43 -0
- package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
- package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
- package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +132 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +31 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
- package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
- package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +73 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
- package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
- package/examples/docs/glossary/order.md +15 -0
- package/examples/docs/glossary/payments/authorization.md +14 -0
- package/examples/docs/likec4.config.json +8 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +92 -0
- package/examples/docs/services/checkout-web/spec.md +91 -0
- package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
- package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
- package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
- package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
- package/examples/docs/services/order-service/arch.spec.md +134 -0
- package/examples/docs/services/order-service/asyncapi.yaml +109 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +126 -0
- package/examples/docs/services/order-service/openapi.yaml +257 -0
- package/examples/docs/services/order-service/runbook.md +62 -0
- package/examples/docs/services/order-service/spec.md +134 -0
- package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
- package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
- package/examples/docs/services/payment-service/arch.spec.md +76 -0
- package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
- package/examples/docs/services/payment-service/health.yaml +39 -0
- package/examples/docs/services/payment-service/model.likec4 +68 -0
- package/examples/docs/services/payment-service/openapi.yaml +151 -0
- package/examples/docs/services/payment-service/runbook.md +37 -0
- package/examples/docs/services/payment-service/spec.md +88 -0
- package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
- package/examples/docs/services/platform/identity-service/arch.spec.md +120 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +81 -0
- package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
- package/examples/docs/services/platform/identity-service/runbook.md +95 -0
- package/examples/docs/services/platform/identity-service/spec.md +119 -0
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +200 -0
- package/examples/docs/services/platform/notification-service/health.yaml +40 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +97 -0
- package/examples/docs/services/platform/notification-service/runbook.md +48 -0
- package/examples/docs/services/platform/notification-service/spec.md +112 -0
- package/examples/docs/services/platform/subsystem.yaml +2 -0
- package/examples/fleet.yaml +57 -0
- package/package.json +19 -6
- package/dist/commands/adopt.js +0 -240
- package/dist/commands/adopt.js.map +0 -1
- package/dist/commands/archive.js +0 -1313
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/delta.js +0 -388
- package/dist/commands/delta.js.map +0 -1
- package/dist/commands/docs-repo-gate.js.map +0 -1
- package/dist/commands/format.js +0 -17
- package/dist/commands/format.js.map +0 -1
- package/dist/commands/gherkin.js +0 -309
- package/dist/commands/gherkin.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/list.js +0 -295
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/migrate-openspec.js +0 -950
- package/dist/commands/migrate-openspec.js.map +0 -1
- package/dist/commands/new.js +0 -413
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/rebase.js +0 -356
- package/dist/commands/rebase.js.map +0 -1
- package/dist/commands/show.js +0 -320
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/status.js +0 -262
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unarchive.js +0 -317
- package/dist/commands/unarchive.js.map +0 -1
- package/dist/commands/validate.js +0 -1773
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/verify.js +0 -775
- package/dist/commands/verify.js.map +0 -1
- package/dist/commands/vouch.js +0 -421
- package/dist/commands/vouch.js.map +0 -1
- package/dist/core/agent.js +0 -2173
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agents-stamp.js.map +0 -1
- package/dist/core/arch.js +0 -130
- package/dist/core/arch.js.map +0 -1
- package/dist/core/asyncapi.js +0 -253
- package/dist/core/asyncapi.js.map +0 -1
- package/dist/core/brief.js +0 -755
- package/dist/core/brief.js.map +0 -1
- package/dist/core/coherence.js +0 -577
- package/dist/core/coherence.js.map +0 -1
- package/dist/core/concurrency.js.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/delta.js +0 -476
- package/dist/core/delta.js.map +0 -1
- package/dist/core/dependencies.js +0 -356
- package/dist/core/dependencies.js.map +0 -1
- package/dist/core/doctor.js +0 -596
- package/dist/core/doctor.js.map +0 -1
- package/dist/core/document-bytes.js.map +0 -1
- package/dist/core/explore.js +0 -225
- package/dist/core/explore.js.map +0 -1
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/gherkin.js +0 -463
- package/dist/core/gherkin.js.map +0 -1
- package/dist/core/health.js +0 -67
- package/dist/core/health.js.map +0 -1
- package/dist/core/ids.js +0 -122
- package/dist/core/ids.js.map +0 -1
- package/dist/core/issue.js +0 -9
- package/dist/core/issue.js.map +0 -1
- package/dist/core/json.js +0 -74
- package/dist/core/json.js.map +0 -1
- package/dist/core/likec4.js +0 -489
- package/dist/core/likec4.js.map +0 -1
- package/dist/core/maturity.js +0 -66
- package/dist/core/maturity.js.map +0 -1
- package/dist/core/openapi-merge.js +0 -552
- package/dist/core/openapi-merge.js.map +0 -1
- package/dist/core/openapi.js.map +0 -1
- package/dist/core/openspec-inventory.js +0 -1440
- package/dist/core/openspec-inventory.js.map +0 -1
- package/dist/core/path-safety.js.map +0 -1
- package/dist/core/provenance.js +0 -787
- package/dist/core/provenance.js.map +0 -1
- package/dist/core/records.js.map +0 -1
- package/dist/core/repo.js +0 -438
- package/dist/core/repo.js.map +0 -1
- package/dist/core/report.js +0 -47
- package/dist/core/report.js.map +0 -1
- package/dist/core/spec.js +0 -505
- package/dist/core/spec.js.map +0 -1
- package/dist/core/staging.js +0 -890
- package/dist/core/staging.js.map +0 -1
- package/dist/core/status.js +0 -1132
- package/dist/core/status.js.map +0 -1
- package/dist/core/steps.js +0 -72
- package/dist/core/steps.js.map +0 -1
- package/dist/core/verify.js +0 -807
- package/dist/core/verify.js.map +0 -1
- package/dist/core/version.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partners.js","sourceRoot":"","sources":["../../../src/core/gate/partners.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The direct join partners of one service, derived from the LIVING landscape,\n * and the maturity grading of everything on either end of a join.\n *\n * The landscape is the only place the fleet's joins are drawn, so the partner\n * set is exactly the edges whose resolved source or target is the gated\n * service — resolved through `serviceResolver` with the ENUMERATED fleet\n * riding in, the same ride that keeps container-modelling landscapes attached\n * everywhere else (an edge into `paymentService.api` is an edge into the\n * service that owns it). A landscape that is absent or does not parse yields\n * NO partner set, never an empty one: `landscape` says which, and the check\n * layer turns \"could not look\" into `gate.partners-unknown` rather than\n * letting it read as \"no partners\".\n */\nimport { existsSync } from \"node:fs\";\nimport { errorText, type Elem, type Rel } from \"../c4/likec4.js\";\nimport { serviceResolver } from \"../c4/resolve/service.js\";\nimport {\n ACTOR_KINDS,\n EXTERNAL_TAG,\n INFRA_KINDS,\n landscapeEvidence,\n maturityGaps,\n serviceMaturity,\n MATURITY_LADDER,\n type Maturity,\n} from \"../vocabulary/maturity.js\";\nimport { compareIds, type ServiceEntry } from \"../repo/entries.js\";\nimport { landscapePath, servicePathsAt } from \"../repo/paths.js\";\nimport { enumeratedServices } from \"../repo/service-target.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport { ancestorIds } from \"../kernel/ids/fqn/ancestors.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\nimport type { RawServiceId } from \"../kernel/ids/service.js\";\nimport type { GatePartner, LandscapeRead, PartnerRole } from \"./report.js\";\n\nexport interface PartnerScanRequest {\n docsDir: DocsDir;\n /** The gated service — a name the enumeration approved (`resolveServiceTarget`). */\n service: RawServiceId;\n fleet: FleetContext;\n}\n\n/** One service graded on the adoption ladder, with what the next rung wants. */\nexport interface GradedService {\n maturity: Maturity;\n gaps: string[];\n}\n\nexport interface PartnerScan {\n landscape: LandscapeRead;\n /**\n * Why the landscape graded `invalid` — the parse-error tally or the read\n * failure's own words. Null on `read` and `absent`; the finding that fails\n * the gate must say what broke, not merely that something did.\n */\n landscapeProblem: string | null;\n /**\n * The gated service's own rung, graded under the landscape's evidence —\n * `gate.service-undocumented`'s subject. Fail-closed on the api question:\n * with no readable map, `landscapeEvidence` assumes an API is expected.\n */\n target: GradedService;\n /**\n * The same service graded with NO api expected of it — the reading that\n * does not depend on the landscape at all. The check layer answers from\n * THIS one when the map is absent or broken: the api question is then\n * unanswerable, and one unanswerable fact must not convict twice (the\n * landscape already carries its own finding).\n */\n targetWithoutApi: GradedService;\n /**\n * The gated service's own enumerated entry — carried so a finding can name\n * the directory it actually occupies. `services/<id>/` is right only for an\n * unfiled fleet, and a check that sends a reader to a directory they cannot\n * open has answered worse than not at all.\n */\n targetEntry: ServiceEntry;\n partners: GatePartner[];\n /**\n * The enumerated entries behind the partners that HAVE a `services/`\n * directory, in `partners` order — what the freshness check walks. Kept as\n * entries rather than names so the ids that travel on carry the\n * enumeration's provenance (`RawServiceId`), never a document's.\n */\n partnerEntries: ServiceEntry[];\n}\n\n/** Is this rung at or above `documented` — the fixed threshold check 1 grades against? */\nexport function atLeastDocumented(m: Maturity): boolean {\n return MATURITY_LADDER.indexOf(m) >= MATURITY_LADDER.indexOf(\"documented\");\n}\n\n/**\n * What the map says about one edge END: does it stand for a person, is it\n * INFRASTRUCTURE, and is it tagged `#external`? Walked up the ancestor chain\n * because all three facts are usually written on the containing system while\n * the edge is drawn from a nested element — but the walk STOPS at the first\n * element that stands for a service (an explicit binding or a title naming a\n * real directory, `serviceResolver`'s own first two rungs, checked after that\n * element's own facts are read). What sits above the service boundary is a\n * grouping, and a grouping's `#external` is the grouping's claim, not the\n * service's: without the stop, an adopted service drawn inside an `#external`\n * zone was exempted from `gate.partner-undocumented` and its real rung hidden.\n *\n * `infra` is read only off an element that stands for NO service AND sits\n * inside none, which is the asymmetry the `standsFor` local exists for. That is\n * `commands/validate/fleet/census.ts` in two steps and in its order:\n * `serviceLevelElements` drops everything drawn inside a service BEFORE\n * `drawnSystems` ever applies the kind test, so a service's own interior never\n * reaches it. Both halves are load-bearing. A `database` bound with\n * `metadata { service '<id>' }` is an adopted service that happens to be drawn\n * as a store — its side of the join IS recorded, and dropping it would hide a\n * real partner's rung. And a store drawn INSIDE its owner — `orderService.db`,\n * the ordinary way a team draws a private datastore — is that service's\n * interior: reading the kind off it convicted the WHOLE endpoint as\n * infrastructure, and `partnerScan` then dropped order-service from the partner\n * set, so a service this gate exists to grade vanished because of how somebody\n * drew its storage. The kind is the fallback for an element nothing else\n * answers for, never the override.\n */\nfunction endFacts(\n byId: Map<string, Elem>,\n known: ReadonlySet<string>,\n id: string,\n): { actor: boolean; infra: boolean; external: boolean } {\n let actor = false;\n let infra = false;\n let external = false;\n // The id itself, then each dotted ancestor — the same walk `serviceResolver`\n // resolves through, out of the one module that spells it\n // (`core/kernel/ids/fqn/ancestors.ts`).\n for (const candidate of ancestorIds(id)) {\n const e = byId.get(candidate);\n if (e === undefined) continue;\n const standsFor = e.service !== undefined || known.has(e.title);\n if (ACTOR_KINDS.has(e.kind.toLowerCase())) actor = true;\n if (!standsFor && INFRA_KINDS.has(e.kind.toLowerCase())) infra = true;\n if (e.tags.includes(EXTERNAL_TAG)) external = true;\n if (standsFor) {\n // Everything the walk has visited so far was drawn INSIDE this service,\n // so nothing visited so far was service-LEVEL and no kind read off it\n // answers for a service — `serviceLevelElements` filtering ahead of the\n // kind test, spelled as a walk. `actor` and `external` are deliberately\n // left standing: a person or an `#external` tag written on a container is\n // still a claim about this endpoint, while the store shape is a claim\n // about the owner's interior.\n infra = false;\n break;\n }\n }\n return { actor, infra, external };\n}\n\n/** How one edge joins the two ends, in the words the finding and the payload both use. */\nfunction viaOf(r: Rel): string[] {\n const typed = [\n ...(r.op === undefined ? [] : [`operation ${r.op}`]),\n ...(r.publishes === undefined ? [] : [`message ${r.publishes}`]),\n ...(r.consumes === undefined ? [] : [`message ${r.consumes}`]),\n ];\n if (typed.length > 0) return typed;\n return [r.title === undefined ? \"untyped edge\" : `edge '${r.title}'`];\n}\n\ninterface PartnerAccumulator {\n consumer: boolean;\n provider: boolean;\n external: boolean;\n via: Set<string>;\n}\n\nexport async function partnerScan(req: PartnerScanRequest): Promise<PartnerScan> {\n const { docsDir, service, fleet } = req;\n // The same memoized enumeration the command's resolveServiceTarget already\n // performed on this FleetContext — one walk answers both questions.\n const entries = await enumeratedServices(docsDir, fleet);\n // Keyed as plain strings on purpose: the lookups below arrive from the\n // resolver, whose names are document-asserted, and only a hit proves a\n // directory. The VALUES keep the enumeration's provenance.\n const entryById = new Map<string, ServiceEntry>(entries.map((e) => [e.id, e]));\n const known: ReadonlySet<string> = new Set(entries.map((e) => e.id));\n\n const lp = landscapePath(docsDir);\n let landscape: LandscapeRead = \"absent\";\n let landscapeProblem: string | null = null;\n let elements: Elem[] = [];\n let relationships: Rel[] = [];\n if (existsSync(lp)) {\n try {\n const doc = await fleet.loadLikeC4(lp);\n if (doc.errors.length > 0) {\n landscape = \"invalid\";\n const first = doc.errors[0];\n // Through `errorText` — the raw message had no line, and a dropped\n // quote's is a parser token list of thousands of lines.\n landscapeProblem =\n `${doc.errors.length} parse error(s)` +\n (first === undefined ? \"\" : ` — first: ${errorText(first)}`);\n } else {\n landscape = \"read\";\n elements = doc.elements;\n relationships = doc.relationships;\n }\n } catch (err) {\n // A landscape that could not be READ, graded as one that did not PARSE —\n // commands/validate/fleet/load.ts's containment doctrine, spelled here\n // because core cannot import it: \"could not be read\" and \"did not parse\"\n // have the same consequence (nothing may be concluded from this file).\n // The reason travels into the finding, message-preserving as\n // `unreadableLandscape` is; the read error must not kill the run — the\n // other three checks still have answers.\n landscape = \"invalid\";\n landscapeProblem = err instanceof Error ? err.message : String(err);\n }\n }\n const parses = landscape === \"read\";\n const svcOf: (id: string) => string = parses\n ? serviceResolver(elements, known)\n : (id: string) => id;\n const elementIds = elements.map((e) => e.id);\n\n // One service's ladder rung. `landscapeEvidence` is the ONE shared spelling\n // of the positive-evidence apiExpected rule (core/vocabulary/maturity.ts);\n // its own docblock warns against calling it per service inside a FLEET loop,\n // and this loop is not one — it runs over the gated service and its direct\n // partners, a handful, never the enumeration.\n const gradeWith = (entry: ServiceEntry, apiExpected: boolean): GradedService => {\n const input = {\n entry,\n archSpec: existsSync(servicePathsAt(entry.dir).archSpec),\n apiExpected,\n };\n return { maturity: serviceMaturity(input), gaps: maturityGaps(input) };\n };\n const grade = (entry: ServiceEntry): GradedService =>\n gradeWith(\n entry,\n landscapeEvidence({ id: entry.id, parses, relationships, elementIds, svcOf }).apiExpected,\n );\n\n // Unreachable by construction: the command layer resolved `service` against\n // the same memoized enumeration this scan just read, and refused\n // `unknown-service` when no directory answered. Failing closed here beats\n // grading a service nobody enumerated as if its absence were a rung.\n const targetEntry = entryById.get(service);\n if (targetEntry === undefined) {\n throw new Error(`gate: '${service}' vanished from the enumeration between resolve and scan`);\n }\n\n const byId = new Map(elements.map((e) => [e.id, e]));\n const acc = new Map<string, PartnerAccumulator>();\n const join = (name: string, role: PartnerRole, r: Rel, external: boolean): void => {\n const slot = acc.get(name) ?? { consumer: false, provider: false, external: false, via: new Set<string>() };\n if (role === \"consumer\") slot.consumer = true;\n else slot.provider = true;\n slot.external = slot.external || external;\n for (const v of viaOf(r)) slot.via.add(v);\n acc.set(name, slot);\n };\n for (const r of relationships) {\n const source = svcOf(r.source);\n const target = svcOf(r.target);\n // A self-edge (both ends resolve to the gated service — its own containers\n // talking to each other) names no partner.\n if (source === target) continue;\n if (target === service) {\n const facts = endFacts(byId, known, r.source);\n // A person is never a deploy participant, and neither is the fleet's own\n // infrastructure: the two kind exemptions every landscape census applies\n // (drawnSystems, commands/validate/fleet/census.ts), spelled here off the\n // same two sets so a gate and a validate run cannot disagree about what a\n // partner IS.\n //\n // The infra half is the newer one, and it had a measured cost. A\n // `database` the fleet owns and draws at fleet level joined every service\n // that reads it, with `maturity: null` because there is no\n // `services/<title>/` — so `gate.partner-undocumented` told the deployer\n // to \"adopt it, bind it … or tag it #external\", three remedies none of\n // which is true of a Postgres (measured on a one-service fixture,\n // 2026-09-07). It is dropped from the partner SET rather than exempted\n // from the finding, which is the actor precedent exactly: `partners` is\n // the list of counterparties whose DOCS the gate grades, and a store has\n // none to grade.\n if (!facts.actor && !facts.infra) join(source, \"consumer\", r, facts.external);\n } else if (source === service) {\n const facts = endFacts(byId, known, r.target);\n if (!facts.actor && !facts.infra) join(target, \"provider\", r, facts.external);\n }\n }\n\n // Sorted by id so identical state yields identical bytes — the accumulator's\n // order is the landscape's edge order, which a reformat may shuffle.\n const joined = [...acc.entries()].sort((a, b) => compareIds(a[0], b[0]));\n const partners: GatePartner[] = joined.map(([name, slot]) => {\n const entry = entryById.get(name);\n return {\n service: name,\n maturity: entry === undefined ? null : grade(entry).maturity,\n role: slot.consumer && slot.provider ? \"both\" : slot.consumer ? \"consumer\" : \"provider\",\n via: [...slot.via].sort(),\n // An adopted service is OURS whatever a zone's tag says: `external` and\n // a maturity rung together must be unrepresentable, or the rung the\n // payload carries is one the exemption hides and the human view drops.\n external: entry === undefined && slot.external,\n };\n });\n\n return {\n landscape,\n landscapeProblem,\n targetEntry,\n target: grade(targetEntry),\n targetWithoutApi: gradeWith(targetEntry, false),\n partners,\n partnerEntries: joined.flatMap(([name]) => {\n const entry = entryById.get(name);\n return entry === undefined ? [] : [entry];\n }),\n };\n}\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** The four checks, in report order. A closed set — the payload's `checks[].check` values. */
|
|
2
|
+
export const GATE_CHECKS = ["partners", "freshness", "verification", "interrupted"];
|
|
3
|
+
/**
|
|
4
|
+
* Fail iff any check carries an error-severity finding. `--strict` never moves
|
|
5
|
+
* this — like validate's `valid`, the verdict means the same thing in text and
|
|
6
|
+
* JSON whatever the exit code does, so two pipelines reading one repo can
|
|
7
|
+
* grade the same report differently and both be telling the truth
|
|
8
|
+
* (commands/validate/validate.ts documents the stance; gate copies it).
|
|
9
|
+
*/
|
|
10
|
+
export function gateVerdict(checks) {
|
|
11
|
+
return checks.some((c) => c.findings.some((f) => f.severity === "error")) ? "fail" : "pass";
|
|
12
|
+
}
|
|
13
|
+
export function gateSummary(checks) {
|
|
14
|
+
const of = (severity) => checks.reduce((n, c) => n + c.findings.filter((f) => f.severity === severity).length, 0);
|
|
15
|
+
return { errors: of("error"), warnings: of("warn") };
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Per-subject containment: one unreadable sibling degrades ONE subject's
|
|
19
|
+
* answer, with its path recorded, instead of killing the report the other
|
|
20
|
+
* subjects still have. The code is validate's own containment code
|
|
21
|
+
* (`guarded`, commands/validate/report.ts), reused so one breach is spelled
|
|
22
|
+
* one way — and it is an ERROR: an unanswerable check fails closed, because
|
|
23
|
+
* "nobody could look" must be distinguishable from "nothing is wrong" in the
|
|
24
|
+
* exit code as well as the payload. Anything carrying no errno and no path is
|
|
25
|
+
* a real bug, and still escapes untouched (reportRepositoryUnavailable's
|
|
26
|
+
* recognizer).
|
|
27
|
+
*/
|
|
28
|
+
export function unreadableSubject(kind, id, err) {
|
|
29
|
+
const e = err;
|
|
30
|
+
if (e.path === undefined && typeof e.errno !== "number")
|
|
31
|
+
throw err;
|
|
32
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
33
|
+
const consequence = kind === "service" ? "its freshness is unknown" : "its verification state is unknown";
|
|
34
|
+
return {
|
|
35
|
+
severity: "error",
|
|
36
|
+
code: kind === "service" ? "service.unreadable" : "feature.unreadable",
|
|
37
|
+
subject: id,
|
|
38
|
+
message: `${id}: ${e.path ?? "one of its documents"} could not be read, so ${consequence} — nobody could look, which is not the same as nothing being wrong. ${reason}` +
|
|
39
|
+
// The same sentence reportRepositoryUnavailable carries, for the same
|
|
40
|
+
// reason: Node reports EISDIR from read() with no path at all, so the
|
|
41
|
+
// commonest malformed-docs shape arrives here nameless.
|
|
42
|
+
(e.path === undefined
|
|
43
|
+
? " The failure named no path — that is how Node reports a directory sitting where a file belongs."
|
|
44
|
+
: ""),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/core/gate/report.ts"],"names":[],"mappings":"AAeA,8FAA8F;AAC9F,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,aAAa,CAAU,CAAC;AAoG7F;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,MAA4B;IACtD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AAC9F,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAA4B;IACtD,MAAM,EAAE,GAAG,CAAC,QAA0B,EAAU,EAAE,CAChD,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC3F,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;AACvD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAA2B,EAAE,EAAU,EAAE,GAAY;IACrF,MAAM,CAAC,GAAG,GAA4B,CAAC;IACvC,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;QAAE,MAAM,GAAG,CAAC;IACnE,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAChE,MAAM,WAAW,GACf,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,mCAAmC,CAAC;IACxF,OAAO;QACL,QAAQ,EAAE,OAAO;QACjB,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,oBAAoB;QACtE,OAAO,EAAE,EAAE;QACX,OAAO,EACL,GAAG,EAAE,KAAK,CAAC,CAAC,IAAI,IAAI,sBAAsB,0BAA0B,WAAW,uEAAuE,MAAM,EAAE;YAC9J,sEAAsE;YACtE,sEAAsE;YACtE,wDAAwD;YACxD,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS;gBACnB,CAAC,CAAC,iGAAiG;gBACnG,CAAC,CAAC,EAAE,CAAC;KACV,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The gate report — what `loam gate` computes before anything is printed.\n *\n * Shapes, verdict arithmetic and the per-subject containment classifier: no\n * filesystem, no process access, no printing. The four checks build findings\n * (`./checks.ts`, `./verification.ts`), the command layer renders them, and\n * this module is what the two agree through — the same split\n * `core/vocabulary/report.ts` gives `loam validate`, whose `Finding` shape\n * the checks reuse so one breach arrives in one shape whichever command\n * reports it.\n */\nimport type { Finding } from \"../vocabulary/report.js\";\nimport type { Maturity } from \"../vocabulary/maturity.js\";\nimport type { VerificationState } from \"../status/report.js\";\n\n/** The four checks, in report order. A closed set — the payload's `checks[].check` values. */\nexport const GATE_CHECKS = [\"partners\", \"freshness\", \"verification\", \"interrupted\"] as const;\nexport type GateCheckName = (typeof GATE_CHECKS)[number];\n\nexport interface GateCheck {\n check: GateCheckName;\n findings: Finding[];\n}\n\n/**\n * How the landscape read came out. `absent` and `invalid` are kept apart from\n * `read` because the partner set derived under either is NOT \"no partners\" —\n * it is \"could not look\", and `gate.partners-unknown` exists to keep a\n * pipeline from reading the empty list as a clean one.\n */\nexport type LandscapeRead = \"read\" | \"absent\" | \"invalid\";\n\n/**\n * What the partner is to the gated service: a `consumer` calls into it, a\n * `provider` is called by it, `both` when the landscape draws edges in both\n * directions.\n */\nexport type PartnerRole = \"consumer\" | \"provider\" | \"both\";\n\nexport interface GatePartner {\n /** The partner's resolved service name — a directory id when one exists, the drawn name otherwise. */\n service: string;\n /**\n * The partner's rung on the adoption ladder, or null when no `services/`\n * directory answers to the name at all — the state `gate.partner-undocumented`\n * names. Null is deliberately not a fifth rung: `empty` means \"exists,\n * nothing in it\", and a partner nobody adopted is a different fact.\n */\n maturity: Maturity | null;\n role: PartnerRole;\n /** The joins, sorted: `operation <op>`, `message <name>`, or the untyped edge's title. */\n via: string[];\n /** The element is tagged `#external` — somebody else's system, undocumented on purpose. */\n external: boolean;\n}\n\n/**\n * One feature touching the gated service — every active one, plus, under\n * `--since`, every one archived after the ref — with the verification\n * record's own projection beside it. Every field but `id` and `archived` is\n * `verificationState`'s (`core/status/verification.ts`) — never a second\n * derivation of \"verified\".\n */\nexport interface GateFeature extends VerificationState {\n id: string;\n /**\n * Present, and true, only on a row `--since` added: the feature shipped\n * after the ref, so its record is frozen history. Absent rather than\n * `false` on the in-flight rows, so a payload without `--since` is byte for\n * byte the one it was before the flag existed.\n */\n archived?: true;\n /**\n * Present only beside `archived`: the checklist digest `loam archive`\n * captured as the feature merged — what its frozen record was graded\n * against, so a record that had stopped answering the feature before it\n * shipped reads `stale` — or null when that archive captured none (a loam\n * that predates the capture, or a feature that had no record then). Under\n * null a record is read as frozen history, exactly as before the capture\n * existed, and the row says so rather than letting that reading pass for a\n * checked one.\n */\n checklistAtArchive?: string | null;\n}\n\n/**\n * `--since <ref>`, resolved: the docs-repo commit a deploy pipeline last\n * shipped from, and the `features/archive/` directory names that already\n * existed there AND still hold what they held then. Without it the\n * verification check reads in-flight features only, and a feature drops out of\n * the gate the moment it is archived — which under `--strict` made archiving\n * the cheapest way past an unverified-feature warning. With it, every feature\n * archived AFTER the ref is graded too: its directory absent there, or changed\n * since — a feature unarchived, edited and archived again ships again, at the\n * same path. Nothing is stored: the pipeline already knows its last deployed\n * docs commit, and git already knows what was archived at it.\n */\nexport interface GateSince {\n ref: string;\n commit: string;\n /** Archive directory names an earlier deploy already shipped exactly as they stand — the ones this gate leaves out. */\n shippedAtRef: ReadonlySet<string>;\n}\n\nexport interface GateReport {\n service: string;\n /** The `--since` bound the report was computed under, or null for in-flight features only. */\n since: { ref: string; commit: string } | null;\n landscape: LandscapeRead;\n partners: GatePartner[];\n features: GateFeature[];\n checks: GateCheck[];\n}\n\nexport type GateVerdict = \"pass\" | \"fail\";\n\n/**\n * Fail iff any check carries an error-severity finding. `--strict` never moves\n * this — like validate's `valid`, the verdict means the same thing in text and\n * JSON whatever the exit code does, so two pipelines reading one repo can\n * grade the same report differently and both be telling the truth\n * (commands/validate/validate.ts documents the stance; gate copies it).\n */\nexport function gateVerdict(checks: readonly GateCheck[]): GateVerdict {\n return checks.some((c) => c.findings.some((f) => f.severity === \"error\")) ? \"fail\" : \"pass\";\n}\n\nexport function gateSummary(checks: readonly GateCheck[]): { errors: number; warnings: number } {\n const of = (severity: \"error\" | \"warn\"): number =>\n checks.reduce((n, c) => n + c.findings.filter((f) => f.severity === severity).length, 0);\n return { errors: of(\"error\"), warnings: of(\"warn\") };\n}\n\n/**\n * Per-subject containment: one unreadable sibling degrades ONE subject's\n * answer, with its path recorded, instead of killing the report the other\n * subjects still have. The code is validate's own containment code\n * (`guarded`, commands/validate/report.ts), reused so one breach is spelled\n * one way — and it is an ERROR: an unanswerable check fails closed, because\n * \"nobody could look\" must be distinguishable from \"nothing is wrong\" in the\n * exit code as well as the payload. Anything carrying no errno and no path is\n * a real bug, and still escapes untouched (reportRepositoryUnavailable's\n * recognizer).\n */\nexport function unreadableSubject(kind: \"service\" | \"feature\", id: string, err: unknown): Finding {\n const e = err as NodeJS.ErrnoException;\n if (e.path === undefined && typeof e.errno !== \"number\") throw err;\n const reason = err instanceof Error ? err.message : String(err);\n const consequence =\n kind === \"service\" ? \"its freshness is unknown\" : \"its verification state is unknown\";\n return {\n severity: \"error\",\n code: kind === \"service\" ? \"service.unreadable\" : \"feature.unreadable\",\n subject: id,\n message:\n `${id}: ${e.path ?? \"one of its documents\"} could not be read, so ${consequence} — nobody could look, which is not the same as nothing being wrong. ${reason}` +\n // The same sentence reportRepositoryUnavailable carries, for the same\n // reason: Node reports EISDIR from read() with no path at all, so the\n // commonest malformed-docs shape arrives here nameless.\n (e.path === undefined\n ? \" The failure named no path — that is how Node reports a directory sitting where a file belongs.\"\n : \"\"),\n };\n}\n"]}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check 3 of `loam gate`: the verification records of every active feature
|
|
3
|
+
* touching the gated service, read through `verificationState`'s own graded
|
|
4
|
+
* verdicts — never a re-derivation of "verified" (that module's header is the
|
|
5
|
+
* contract). Split from `./checks.ts` when the four checks outgrew the line
|
|
6
|
+
* limit; this is the one check with a per-feature phase of its own, so it is
|
|
7
|
+
* the seam.
|
|
8
|
+
*
|
|
9
|
+
* Without `--since` it reads IN-FLIGHT features only, so a feature leaves the
|
|
10
|
+
* check the moment it is archived — and archive reads no verification record,
|
|
11
|
+
* deliberately (verify never gates the merge). Under `--strict` that made
|
|
12
|
+
* archiving the cheapest way past this check's warning, on a draft service
|
|
13
|
+
* and on a vouched one alike when the feature changed only a contract
|
|
14
|
+
* (`content_digest` covers the spec bodies, not openapi.yaml/asyncapi.yaml, so
|
|
15
|
+
* freshness cannot catch it either). `--since <ref>` closes it without any
|
|
16
|
+
* deployment state: every feature archived after the docs commit the pipeline last
|
|
17
|
+
* deployed from is graded too, by the same `verificationState`, under the
|
|
18
|
+
* same code, its row marked `archived: true` — "archived after" meaning its
|
|
19
|
+
* archive directory was absent at the ref OR differs from what it held there,
|
|
20
|
+
* since a feature unarchived, edited and archived again ships again from the
|
|
21
|
+
* same path. Its record is frozen, but not ungraded: it is held to the
|
|
22
|
+
* checklist `loam archive` captured as the feature merged
|
|
23
|
+
* (`readSnapshotChecklist`), so a record that had stopped answering the
|
|
24
|
+
* feature before it shipped is `stale` — archiving it no longer reads it
|
|
25
|
+
* `verified` again. An archive that captured none (an older loam) is read as
|
|
26
|
+
* frozen history, as before, and the row says so.
|
|
27
|
+
*
|
|
28
|
+
* Report, never fail: every finding here is a warning, by the item's own
|
|
29
|
+
* design — a deploy gate that hard-failed on unverified work would teach
|
|
30
|
+
* everyone that the cheapest way past it is an empty record.
|
|
31
|
+
*/
|
|
32
|
+
import { inOrder } from "../kernel/concurrency.js";
|
|
33
|
+
import { verificationState } from "../status/verification.js";
|
|
34
|
+
import { readSnapshotChecklist } from "../staging/snapshot/manifest.js";
|
|
35
|
+
import { listFeatures } from "../repo/repo.js";
|
|
36
|
+
import { featurePaths } from "../repo/paths.js";
|
|
37
|
+
import { compareIds } from "../repo/entries.js";
|
|
38
|
+
import { unreadableSubject } from "./report.js";
|
|
39
|
+
export async function verificationCheck(req) {
|
|
40
|
+
const { since } = req;
|
|
41
|
+
const all = await listFeatures(req.docsDir, { includeArchived: since !== undefined }, req.fleet);
|
|
42
|
+
// "Touching" = carries a specs/<svc>/ delta — the same definition
|
|
43
|
+
// `status --service` answers with. A feature whose C4 delta merely draws an
|
|
44
|
+
// edge into the service is deliberately out: counting it needs a delta parse
|
|
45
|
+
// per active feature, and it can be added additively if a fleet asks. An
|
|
46
|
+
// archived feature keeps its specs/ under features/archive/, so the one
|
|
47
|
+
// definition answers for both sides. "Archived after the ref" is "its
|
|
48
|
+
// archive directory was not there at the ref, or is not what it was there";
|
|
49
|
+
// a feature whose directory was there UNCHANGED shipped in an earlier
|
|
50
|
+
// deploy and is not this one's to answer for (`GateSince`).
|
|
51
|
+
const touching = all
|
|
52
|
+
.filter((f) => f.services.includes(req.service))
|
|
53
|
+
.filter((f) => !f.archived || (since !== undefined && !since.shippedAtRef.has(f.dirName)))
|
|
54
|
+
.sort((a, b) => compareIds(a.id, b.id) || compareIds(a.dirName, b.dirName));
|
|
55
|
+
// COST ACCEPTED: each touching feature with a record derives its checklist,
|
|
56
|
+
// which parses its delta. That is the per-feature cost
|
|
57
|
+
// core/status/fleet/fleet.ts refuses for the WHOLE fleet; a deploy-time
|
|
58
|
+
// command scoped to one service pays it for that service's features only —
|
|
59
|
+
// with the invocation's context threaded through `verificationState` into
|
|
60
|
+
// the derivation, so its enumerations are memo hits (one fleet walk per
|
|
61
|
+
// run, not one per feature) and the batch prefetch below genuinely seeds
|
|
62
|
+
// the delta parses. The prefetch is an accelerator only: a host that cannot
|
|
63
|
+
// batch degrades to per-feature parses with identical findings.
|
|
64
|
+
// An archived feature never derives a checklist (its record is frozen, see
|
|
65
|
+
// `verificationState`, and held to the one its archive captured), so
|
|
66
|
+
// prefetching its delta would parse for nobody.
|
|
67
|
+
await req.fleet.prefetchLikeC4(touching.filter((f) => !f.archived && f.has.delta).map((f) => featurePaths(f.dir).delta));
|
|
68
|
+
// inOrder caps the workspaces in flight and keeps the rows in feature order.
|
|
69
|
+
const rows = await inOrder(touching, async (f) => {
|
|
70
|
+
try {
|
|
71
|
+
if (!f.archived) {
|
|
72
|
+
const { state, notice } = await verificationState(req.docsDir, f, { fleet: req.fleet });
|
|
73
|
+
return { kind: "read", feature: f, state, notice };
|
|
74
|
+
}
|
|
75
|
+
const shipped = await readSnapshotChecklist(f.dir);
|
|
76
|
+
const { state, notice } = await verificationState(req.docsDir, f, { fleet: req.fleet, shipped });
|
|
77
|
+
return { kind: "read", feature: f, state, notice, shipped };
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
return { kind: "unreadable", finding: unreadableSubject("feature", f.id, err) };
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
const features = [];
|
|
84
|
+
const findings = [];
|
|
85
|
+
for (const row of rows) {
|
|
86
|
+
if (row.kind === "unreadable") {
|
|
87
|
+
findings.push(row.finding);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
features.push({
|
|
91
|
+
id: row.feature.id,
|
|
92
|
+
...row.state,
|
|
93
|
+
...(row.shipped === undefined ? {} : { archived: true, checklistAtArchive: row.shipped }),
|
|
94
|
+
});
|
|
95
|
+
findings.push(...featureFindings(row, req.service, since?.ref));
|
|
96
|
+
}
|
|
97
|
+
return { features, findings };
|
|
98
|
+
}
|
|
99
|
+
function featureFindings(row, service, since) {
|
|
100
|
+
const { feature, state, notice } = row;
|
|
101
|
+
if (state.verdict === "verified")
|
|
102
|
+
return [];
|
|
103
|
+
if (state.verdict === "attested") {
|
|
104
|
+
// attestedNotice's own words — the one notice verify, list and status all
|
|
105
|
+
// show, converted to a Finding rather than re-derived. The code string
|
|
106
|
+
// (`verify.scenario-attested`) is spelled literally at its one emit site,
|
|
107
|
+
// core/verify/record.ts, where the drift guard collects it.
|
|
108
|
+
return notice === null
|
|
109
|
+
? []
|
|
110
|
+
: [
|
|
111
|
+
{
|
|
112
|
+
severity: notice.severity,
|
|
113
|
+
code: notice.code,
|
|
114
|
+
subject: feature.id,
|
|
115
|
+
message: notice.message,
|
|
116
|
+
...(notice.claims === undefined ? {} : { details: notice.claims }),
|
|
117
|
+
},
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
const verify = `\`loam verify ${feature.id} --json\``;
|
|
121
|
+
const open = state.unconfirmed + state.unanswered;
|
|
122
|
+
const claimsOpen = `${open} of ${state.claims} claim(s) on ${feature.id} are open (${state.unconfirmed} unconfirmed, ${state.unanswered} unanswered)`;
|
|
123
|
+
const message = () => {
|
|
124
|
+
// A row `--since` added. Its record is frozen history: `loam verify` reads
|
|
125
|
+
// it back and refuses to re-record it (commands/verify/verify.ts), so the
|
|
126
|
+
// in-flight remedies below — derive, answer, re-derive — would send a
|
|
127
|
+
// deploy pipeline to a command that cannot run. What it CAN be told is
|
|
128
|
+
// that this deploy carries the feature unchecked, and the one way to
|
|
129
|
+
// reopen it. An archived record is `stale` only against the checklist its
|
|
130
|
+
// archive captured — the feature had moved under it before it shipped.
|
|
131
|
+
if (feature.archived) {
|
|
132
|
+
const shipped = `${feature.id} touches '${service}' and was archived after ${since ?? "the --since ref"}`;
|
|
133
|
+
const reopen = `Its record is frozen history: ${verify} reads it back, and \`loam unarchive ${feature.id}\` re-opens the feature if its claims must be answered before this deploy.`;
|
|
134
|
+
if (state.state === "absent")
|
|
135
|
+
return `${shipped} with no verification record — nothing was checked before it shipped. ${reopen}`;
|
|
136
|
+
// The file that failed may be one service's `verification/<svc>.yaml`
|
|
137
|
+
// as well as the one-file record; `loam verify` names which.
|
|
138
|
+
if (state.state === "unreadable")
|
|
139
|
+
return `${shipped} with a verification record that does not read as a record — ${verify} names the file that failed. ${reopen}`;
|
|
140
|
+
if (state.state === "stale") {
|
|
141
|
+
return `${shipped}, and it had moved after its record was written — the record answers a checklist that was no longer the one it asked when it was archived, so what shipped was not what was checked. ${reopen}`;
|
|
142
|
+
}
|
|
143
|
+
return state.claims === 0
|
|
144
|
+
? `${shipped} with a record that answers no claims at all. ${reopen}`
|
|
145
|
+
: `${shipped}, and ${claimsOpen}. ${reopen}`;
|
|
146
|
+
}
|
|
147
|
+
switch (state.state) {
|
|
148
|
+
case "absent":
|
|
149
|
+
return `${feature.id} touches '${service}' and has no verification record — nothing has been checked. Derive the checklist and answer it: ${verify}.`;
|
|
150
|
+
case "unreadable":
|
|
151
|
+
return `${feature.id}'s verification record does not read as a record — ${verify} names the file that failed and its safe repair (never delete a file other services' attestations may be in); nothing will overwrite it while it is unreadable.`;
|
|
152
|
+
case "stale":
|
|
153
|
+
return `${feature.id} moved after its record was written — the answers answer a checklist that is no longer the one being asked. Re-derive and re-answer: ${verify}.`;
|
|
154
|
+
case "recorded":
|
|
155
|
+
return state.claims === 0
|
|
156
|
+
? `${feature.id}'s record answers no claims at all — nothing was asked, so nothing was checked. ${verify} re-derives the checklist.`
|
|
157
|
+
: `${claimsOpen} — close them with evidence: ${verify}.`;
|
|
158
|
+
default: {
|
|
159
|
+
// A fifth record state must land here as a build failure, not fall
|
|
160
|
+
// through into some rung nobody decided (verificationStatus holds the
|
|
161
|
+
// same guard for the same reason).
|
|
162
|
+
const unreachable = state.state;
|
|
163
|
+
throw new Error(`gate: no wording for verification state '${String(unreachable)}'`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
return [
|
|
168
|
+
{
|
|
169
|
+
severity: "warn",
|
|
170
|
+
code: "gate.feature-unverified",
|
|
171
|
+
subject: feature.id,
|
|
172
|
+
message: message(),
|
|
173
|
+
},
|
|
174
|
+
];
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=verification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verification.js","sourceRoot":"","sources":["../../../src/core/gate/verification.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Check 3 of `loam gate`: the verification records of every active feature\n * touching the gated service, read through `verificationState`'s own graded\n * verdicts — never a re-derivation of \"verified\" (that module's header is the\n * contract). Split from `./checks.ts` when the four checks outgrew the line\n * limit; this is the one check with a per-feature phase of its own, so it is\n * the seam.\n *\n * Without `--since` it reads IN-FLIGHT features only, so a feature leaves the\n * check the moment it is archived — and archive reads no verification record,\n * deliberately (verify never gates the merge). Under `--strict` that made\n * archiving the cheapest way past this check's warning, on a draft service\n * and on a vouched one alike when the feature changed only a contract\n * (`content_digest` covers the spec bodies, not openapi.yaml/asyncapi.yaml, so\n * freshness cannot catch it either). `--since <ref>` closes it without any\n * deployment state: every feature archived after the docs commit the pipeline last\n * deployed from is graded too, by the same `verificationState`, under the\n * same code, its row marked `archived: true` — \"archived after\" meaning its\n * archive directory was absent at the ref OR differs from what it held there,\n * since a feature unarchived, edited and archived again ships again from the\n * same path. Its record is frozen, but not ungraded: it is held to the\n * checklist `loam archive` captured as the feature merged\n * (`readSnapshotChecklist`), so a record that had stopped answering the\n * feature before it shipped is `stale` — archiving it no longer reads it\n * `verified` again. An archive that captured none (an older loam) is read as\n * frozen history, as before, and the row says so.\n *\n * Report, never fail: every finding here is a warning, by the item's own\n * design — a deploy gate that hard-failed on unverified work would teach\n * everyone that the cheapest way past it is an empty record.\n */\nimport { inOrder } from \"../kernel/concurrency.js\";\nimport { verificationState } from \"../status/verification.js\";\nimport { readSnapshotChecklist } from \"../staging/snapshot/manifest.js\";\nimport { listFeatures } from \"../repo/repo.js\";\nimport { featurePaths } from \"../repo/paths.js\";\nimport { compareIds, type FeatureEntry } from \"../repo/entries.js\";\nimport type { Finding } from \"../vocabulary/report.js\";\nimport type { VerificationState } from \"../status/report.js\";\nimport type { VerifyNotice } from \"../verify/record.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\nimport type { RawServiceId } from \"../kernel/ids/service.js\";\nimport { unreadableSubject, type GateFeature, type GateSince } from \"./report.js\";\n\n/**\n * One graded feature. `shipped` is set only on an archived row: the checklist\n * digest its archive captured, or null when it captured none.\n */\ninterface ReadRow {\n kind: \"read\";\n feature: FeatureEntry;\n state: VerificationState;\n notice: VerifyNotice | null;\n shipped?: string | null;\n}\n\ntype VerificationRow = ReadRow | { kind: \"unreadable\"; finding: Finding };\n\nexport interface VerificationCheckRequest {\n docsDir: DocsDir;\n service: RawServiceId;\n fleet: FleetContext;\n since?: GateSince;\n}\n\nexport async function verificationCheck(\n req: VerificationCheckRequest,\n): Promise<{ features: GateFeature[]; findings: Finding[] }> {\n const { since } = req;\n const all = await listFeatures(req.docsDir, { includeArchived: since !== undefined }, req.fleet);\n // \"Touching\" = carries a specs/<svc>/ delta — the same definition\n // `status --service` answers with. A feature whose C4 delta merely draws an\n // edge into the service is deliberately out: counting it needs a delta parse\n // per active feature, and it can be added additively if a fleet asks. An\n // archived feature keeps its specs/ under features/archive/, so the one\n // definition answers for both sides. \"Archived after the ref\" is \"its\n // archive directory was not there at the ref, or is not what it was there\";\n // a feature whose directory was there UNCHANGED shipped in an earlier\n // deploy and is not this one's to answer for (`GateSince`).\n const touching = all\n .filter((f) => f.services.includes(req.service))\n .filter((f) => !f.archived || (since !== undefined && !since.shippedAtRef.has(f.dirName)))\n .sort((a, b) => compareIds(a.id, b.id) || compareIds(a.dirName, b.dirName));\n // COST ACCEPTED: each touching feature with a record derives its checklist,\n // which parses its delta. That is the per-feature cost\n // core/status/fleet/fleet.ts refuses for the WHOLE fleet; a deploy-time\n // command scoped to one service pays it for that service's features only —\n // with the invocation's context threaded through `verificationState` into\n // the derivation, so its enumerations are memo hits (one fleet walk per\n // run, not one per feature) and the batch prefetch below genuinely seeds\n // the delta parses. The prefetch is an accelerator only: a host that cannot\n // batch degrades to per-feature parses with identical findings.\n // An archived feature never derives a checklist (its record is frozen, see\n // `verificationState`, and held to the one its archive captured), so\n // prefetching its delta would parse for nobody.\n await req.fleet.prefetchLikeC4(\n touching.filter((f) => !f.archived && f.has.delta).map((f) => featurePaths(f.dir).delta),\n );\n // inOrder caps the workspaces in flight and keeps the rows in feature order.\n const rows = await inOrder(touching, async (f): Promise<VerificationRow> => {\n try {\n if (!f.archived) {\n const { state, notice } = await verificationState(req.docsDir, f, { fleet: req.fleet });\n return { kind: \"read\", feature: f, state, notice };\n }\n const shipped = await readSnapshotChecklist(f.dir);\n const { state, notice } = await verificationState(req.docsDir, f, { fleet: req.fleet, shipped });\n return { kind: \"read\", feature: f, state, notice, shipped };\n } catch (err) {\n return { kind: \"unreadable\", finding: unreadableSubject(\"feature\", f.id, err) };\n }\n });\n const features: GateFeature[] = [];\n const findings: Finding[] = [];\n for (const row of rows) {\n if (row.kind === \"unreadable\") {\n findings.push(row.finding);\n continue;\n }\n features.push({\n id: row.feature.id,\n ...row.state,\n ...(row.shipped === undefined ? {} : { archived: true, checklistAtArchive: row.shipped }),\n });\n findings.push(...featureFindings(row, req.service, since?.ref));\n }\n return { features, findings };\n}\n\nfunction featureFindings(\n row: ReadRow,\n service: string,\n since: string | undefined,\n): Finding[] {\n const { feature, state, notice } = row;\n if (state.verdict === \"verified\") return [];\n if (state.verdict === \"attested\") {\n // attestedNotice's own words — the one notice verify, list and status all\n // show, converted to a Finding rather than re-derived. The code string\n // (`verify.scenario-attested`) is spelled literally at its one emit site,\n // core/verify/record.ts, where the drift guard collects it.\n return notice === null\n ? []\n : [\n {\n severity: notice.severity,\n code: notice.code,\n subject: feature.id,\n message: notice.message,\n ...(notice.claims === undefined ? {} : { details: notice.claims }),\n },\n ];\n }\n const verify = `\\`loam verify ${feature.id} --json\\``;\n const open = state.unconfirmed + state.unanswered;\n const claimsOpen = `${open} of ${state.claims} claim(s) on ${feature.id} are open (${state.unconfirmed} unconfirmed, ${state.unanswered} unanswered)`;\n const message = (): string => {\n // A row `--since` added. Its record is frozen history: `loam verify` reads\n // it back and refuses to re-record it (commands/verify/verify.ts), so the\n // in-flight remedies below — derive, answer, re-derive — would send a\n // deploy pipeline to a command that cannot run. What it CAN be told is\n // that this deploy carries the feature unchecked, and the one way to\n // reopen it. An archived record is `stale` only against the checklist its\n // archive captured — the feature had moved under it before it shipped.\n if (feature.archived) {\n const shipped = `${feature.id} touches '${service}' and was archived after ${since ?? \"the --since ref\"}`;\n const reopen = `Its record is frozen history: ${verify} reads it back, and \\`loam unarchive ${feature.id}\\` re-opens the feature if its claims must be answered before this deploy.`;\n if (state.state === \"absent\") return `${shipped} with no verification record — nothing was checked before it shipped. ${reopen}`;\n // The file that failed may be one service's `verification/<svc>.yaml`\n // as well as the one-file record; `loam verify` names which.\n if (state.state === \"unreadable\") return `${shipped} with a verification record that does not read as a record — ${verify} names the file that failed. ${reopen}`;\n if (state.state === \"stale\") {\n return `${shipped}, and it had moved after its record was written — the record answers a checklist that was no longer the one it asked when it was archived, so what shipped was not what was checked. ${reopen}`;\n }\n return state.claims === 0\n ? `${shipped} with a record that answers no claims at all. ${reopen}`\n : `${shipped}, and ${claimsOpen}. ${reopen}`;\n }\n switch (state.state) {\n case \"absent\":\n return `${feature.id} touches '${service}' and has no verification record — nothing has been checked. Derive the checklist and answer it: ${verify}.`;\n case \"unreadable\":\n return `${feature.id}'s verification record does not read as a record — ${verify} names the file that failed and its safe repair (never delete a file other services' attestations may be in); nothing will overwrite it while it is unreadable.`;\n case \"stale\":\n return `${feature.id} moved after its record was written — the answers answer a checklist that is no longer the one being asked. Re-derive and re-answer: ${verify}.`;\n case \"recorded\":\n return state.claims === 0\n ? `${feature.id}'s record answers no claims at all — nothing was asked, so nothing was checked. ${verify} re-derives the checklist.`\n : `${claimsOpen} — close them with evidence: ${verify}.`;\n default: {\n // A fifth record state must land here as a build failure, not fall\n // through into some rung nobody decided (verificationStatus holds the\n // same guard for the same reason).\n const unreachable: never = state.state;\n throw new Error(`gate: no wording for verification state '${String(unreachable)}'`);\n }\n }\n };\n return [\n {\n severity: \"warn\",\n code: \"gate.feature-unverified\",\n subject: feature.id,\n message: message(),\n },\n ];\n}\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The scenario-identity digest — ONE recipe with three consumers, deliberately
|
|
3
|
+
* in one module: `verify/checklist.ts` folds it into `scenario.tested` claim
|
|
4
|
+
* ids and claim digests, and `./stamp.ts` stamps the same hex as the
|
|
5
|
+
* `@loam-digest-…` tag on every generated scenario, which is what a cucumber
|
|
6
|
+
* report carries and what `verify --results` matches on. A second spelling of
|
|
7
|
+
* the hash would silently stop every scenario claim from being answerable by a
|
|
8
|
+
* run — which is why this lives beside the stamper rather than inside either
|
|
9
|
+
* consumer.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash } from "node:crypto";
|
|
12
|
+
/**
|
|
13
|
+
* The full sha256 of a scenario's body — its lines joined and edge-trimmed,
|
|
14
|
+
* exactly as `serializeRequirements` frames them. The BODY, not the title,
|
|
15
|
+
* because rewriting the Given/When/Then under an unchanged heading is new text
|
|
16
|
+
* nobody answered for, and the promise — rewording a scenario renames its
|
|
17
|
+
* claim — has to hold for the words that actually specify the behaviour.
|
|
18
|
+
*
|
|
19
|
+
* `scenario.tested` claim ids fold in a prefix of this hex, a claim's `digest`
|
|
20
|
+
* and the `@loam-digest-<16hex>` tag `loam gherkin` stamps both take another
|
|
21
|
+
* (`verify/checklist.ts` owns those lengths, `./stamp.ts` its own) — so the
|
|
22
|
+
* claim, the stamp and the report `--results` reads can never disagree about
|
|
23
|
+
* what a scenario says.
|
|
24
|
+
*
|
|
25
|
+
* The identity is (SERVICE, AXIS, body), and both salts are there for the same
|
|
26
|
+
* reason: a digest that spans two namespaces lets one green run answer a
|
|
27
|
+
* question nobody ran a test for.
|
|
28
|
+
*
|
|
29
|
+
* - The AXIS salt keeps `spec.md` and `arch.spec.md` apart. Without it a green
|
|
30
|
+
* BUSINESS run answered the arch claim too — an integration test nobody wrote
|
|
31
|
+
* read as run.
|
|
32
|
+
* - The SERVICE salt keeps two repositories apart. Different services can word
|
|
33
|
+
* "the service returns 404 for an unknown id" identically; unsalted, those
|
|
34
|
+
* scenarios share one digest and one repository's green run can appear to
|
|
35
|
+
* confirm claims from suites that never ran each other's tests.
|
|
36
|
+
*
|
|
37
|
+
* The service salt is what makes that case CORRECT rather than merely refused:
|
|
38
|
+
* `contestedDigests` could only decline to answer a shared digest, which left a
|
|
39
|
+
* fleet with ordinary repeated wording holding claims nothing could ever
|
|
40
|
+
* answer.
|
|
41
|
+
*
|
|
42
|
+
* Both salts renamed every claim id and every stamped tag on the day they
|
|
43
|
+
* landed, and both readings are legible rather than silent: an existing
|
|
44
|
+
* `verification.yaml` answers a checklist digest that is no longer derived and
|
|
45
|
+
* reports STALE, and an existing generated `.feature` carries digests the
|
|
46
|
+
* living spec no longer computes and reports `gherkin.stale` beside the
|
|
47
|
+
* `gherkin.missing` for the new ones. One `loam gherkin` and one re-record
|
|
48
|
+
* clear both.
|
|
49
|
+
*/
|
|
50
|
+
export function scenarioBodyHash(service, lines, axis = "business") {
|
|
51
|
+
// NUL-separated like claimId's tuples (verify/checklist.ts), and for its
|
|
52
|
+
// reason: no body can spell the salt in front of it, so the namespaces stay
|
|
53
|
+
// disjoint. Spelled as an escape and never as a raw NUL in the literal — a
|
|
54
|
+
// raw one makes this file read as `data` to `file(1)` and invisible to
|
|
55
|
+
// `grep`.
|
|
56
|
+
const body = lines.join("\n").trim();
|
|
57
|
+
const onAxis = axis === "arch" ? `arch.spec.md\u0000${body}` : body;
|
|
58
|
+
return createHash("sha256").update(`${service}\u0000${onAxis}`).digest("hex");
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=digest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"digest.js","sourceRoot":"","sources":["../../../src/core/gherkin/digest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAe,EACf,KAAe,EACf,IAAI,GAAiB,UAAU;IAE/B,yEAAyE;IACzE,4EAA4E;IAC5E,2EAA2E;IAC3E,uEAAuE;IACvE,UAAU;IACV,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpE,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,SAAS,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChF,CAAC","sourcesContent":["/**\n * The scenario-identity digest — ONE recipe with three consumers, deliberately\n * in one module: `verify/checklist.ts` folds it into `scenario.tested` claim\n * ids and claim digests, and `./stamp.ts` stamps the same hex as the\n * `@loam-digest-…` tag on every generated scenario, which is what a cucumber\n * report carries and what `verify --results` matches on. A second spelling of\n * the hash would silently stop every scenario claim from being answerable by a\n * run — which is why this lives beside the stamper rather than inside either\n * consumer.\n */\nimport { createHash } from \"node:crypto\";\n\n/** The axis a scenario's words live on: `spec.md` or `arch.spec.md`. */\nexport type ScenarioAxis = \"business\" | \"arch\";\n\n/**\n * The full sha256 of a scenario's body — its lines joined and edge-trimmed,\n * exactly as `serializeRequirements` frames them. The BODY, not the title,\n * because rewriting the Given/When/Then under an unchanged heading is new text\n * nobody answered for, and the promise — rewording a scenario renames its\n * claim — has to hold for the words that actually specify the behaviour.\n *\n * `scenario.tested` claim ids fold in a prefix of this hex, a claim's `digest`\n * and the `@loam-digest-<16hex>` tag `loam gherkin` stamps both take another\n * (`verify/checklist.ts` owns those lengths, `./stamp.ts` its own) — so the\n * claim, the stamp and the report `--results` reads can never disagree about\n * what a scenario says.\n *\n * The identity is (SERVICE, AXIS, body), and both salts are there for the same\n * reason: a digest that spans two namespaces lets one green run answer a\n * question nobody ran a test for.\n *\n * - The AXIS salt keeps `spec.md` and `arch.spec.md` apart. Without it a green\n * BUSINESS run answered the arch claim too — an integration test nobody wrote\n * read as run.\n * - The SERVICE salt keeps two repositories apart. Different services can word\n * \"the service returns 404 for an unknown id\" identically; unsalted, those\n * scenarios share one digest and one repository's green run can appear to\n * confirm claims from suites that never ran each other's tests.\n *\n * The service salt is what makes that case CORRECT rather than merely refused:\n * `contestedDigests` could only decline to answer a shared digest, which left a\n * fleet with ordinary repeated wording holding claims nothing could ever\n * answer.\n *\n * Both salts renamed every claim id and every stamped tag on the day they\n * landed, and both readings are legible rather than silent: an existing\n * `verification.yaml` answers a checklist digest that is no longer derived and\n * reports STALE, and an existing generated `.feature` carries digests the\n * living spec no longer computes and reports `gherkin.stale` beside the\n * `gherkin.missing` for the new ones. One `loam gherkin` and one re-record\n * clear both.\n */\nexport function scenarioBodyHash(\n service: string,\n lines: string[],\n axis: ScenarioAxis = \"business\",\n): string {\n // NUL-separated like claimId's tuples (verify/checklist.ts), and for its\n // reason: no body can spell the salt in front of it, so the namespaces stay\n // disjoint. Spelled as an escape and never as a raw NUL in the literal — a\n // raw one makes this file read as `data` to `file(1)` and invisible to\n // `grep`.\n const body = lines.join(\"\\n\").trim();\n const onAxis = axis === \"arch\" ? `arch.spec.md\\u0000${body}` : body;\n return createHash(\"sha256\").update(`${service}\\u0000${onAxis}`).digest(\"hex\");\n}\n"]}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A requirement set as a `.feature` file: what gets written where, and what the
|
|
3
|
+
* text says.
|
|
4
|
+
*
|
|
5
|
+
* The plan is separate from the render because the two answer to different
|
|
6
|
+
* owners — where a suite lands is the service repository's layout question
|
|
7
|
+
* (`./stamp.ts` owns the root), while what a scenario reads like is the
|
|
8
|
+
* requirement's. Every emitted scenario carries the digest tag the claim
|
|
9
|
+
* checklist matches on, which is why nothing here may reword a scenario body.
|
|
10
|
+
*/
|
|
11
|
+
import {} from "../document/spec.js";
|
|
12
|
+
import { scenarioGherkin } from "../vocabulary/steps.js";
|
|
13
|
+
import {} from "../repo/paths.js";
|
|
14
|
+
import {} from "./digest.js";
|
|
15
|
+
import { gherkinStampLine, scenarioDigest, scenarioDigestTag } from "./stamp.js";
|
|
16
|
+
/** The axis label the machine contract speaks. */
|
|
17
|
+
export function axisLabel(axis) {
|
|
18
|
+
return axis.key === "archSpec" ? "arch" : "business";
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A requirement name as a file name: lowercase, every non-letter/digit run one
|
|
22
|
+
* hyphen, edges trimmed.
|
|
23
|
+
*
|
|
24
|
+
* The keep-set is `\p{L}\p{N}`, not `[a-z0-9]`, because an ASCII-only slug is
|
|
25
|
+
* not a slug of a non-Latin fleet — it is the empty string. Every requirement
|
|
26
|
+
* written in Chinese, Japanese, Korean, Greek, Cyrillic or Hebrew slugged to
|
|
27
|
+
* nothing, fell back to `requirement`, and the whole service's suite came out
|
|
28
|
+
* as `requirement.feature`, `requirement-2.feature`, … : file names that name
|
|
29
|
+
* nothing, in the one place the mapping is supposed to be legible. So letters
|
|
30
|
+
* of every script survive as themselves.
|
|
31
|
+
*
|
|
32
|
+
* Accents are folded rather than kept, and that is the reason for NFKD first:
|
|
33
|
+
* decomposing splits `é` into `e` + a combining acute, and dropping the
|
|
34
|
+
* combining marks (`\p{M}`) leaves `e`. Without the fold `émojis` and `emojis`
|
|
35
|
+
* would be two files that look identical in a directory listing — and on a
|
|
36
|
+
* filesystem that normalises names (APFS, and HFS+ before it) they would be one
|
|
37
|
+
* file, silently, with the second emission overwriting the first.
|
|
38
|
+
*
|
|
39
|
+
* A name this still leaves empty (all punctuation or emoji) falls back to
|
|
40
|
+
* "requirement" and lets the collision counter number it. Runs collapse to a
|
|
41
|
+
* SINGLE hyphen, which is what keeps the `arch--` prefix an axis marker no
|
|
42
|
+
* business slug can spell.
|
|
43
|
+
*/
|
|
44
|
+
export function slugOf(name) {
|
|
45
|
+
const s = name
|
|
46
|
+
.normalize("NFKD")
|
|
47
|
+
.replace(/\p{M}+/gu, "")
|
|
48
|
+
.toLowerCase()
|
|
49
|
+
.replace(/[^\p{L}\p{N}]+/gu, "-")
|
|
50
|
+
.replace(/^-+|-+$/g, "");
|
|
51
|
+
return s.length > 0 ? s : "requirement";
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The emission plan for one scope: one `.feature` per requirement.
|
|
55
|
+
*
|
|
56
|
+
* File naming is the mapping's contract, so it is spelled here once:
|
|
57
|
+
* `<slug>.feature` for the business axis, `arch--<slug>.feature` for the
|
|
58
|
+
* architecture axis — flat and diffable, and collision-proof across axes
|
|
59
|
+
* because slugs collapse punctuation runs to a single hyphen, so no business
|
|
60
|
+
* slug can ever begin `arch--`. Two requirements slugging identically are
|
|
61
|
+
* disambiguated in document order: the first keeps the bare slug, later ones
|
|
62
|
+
* take `-2`, `-3`, … (counting up past any name that already owns the suffix).
|
|
63
|
+
*
|
|
64
|
+
* Tags ride the `Feature:` line and are inherited by every scenario in the
|
|
65
|
+
* file: `@<FEAT>` in feature mode (living emissions carry no feature tag),
|
|
66
|
+
* `@architecture` on the arch axis.
|
|
67
|
+
*
|
|
68
|
+
* `opts.service` is the suite's owner and salts every digest stamp — the same
|
|
69
|
+
* service `loam verify` files the matching claims under. Required, not
|
|
70
|
+
* defaulted: an emission that guessed it would stamp tags no claim matches.
|
|
71
|
+
*/
|
|
72
|
+
export function planEmission(byAxis, opts) {
|
|
73
|
+
const used = new Set();
|
|
74
|
+
const out = [];
|
|
75
|
+
for (const { axis, reqs } of byAxis) {
|
|
76
|
+
for (const r of reqs) {
|
|
77
|
+
const base = (axis.key === "archSpec" ? "arch--" : "") + slugOf(r.name);
|
|
78
|
+
let fileName = `${base}.feature`;
|
|
79
|
+
for (let n = 2; used.has(fileName); n += 1)
|
|
80
|
+
fileName = `${base}-${n}.feature`;
|
|
81
|
+
used.add(fileName);
|
|
82
|
+
const tags = [
|
|
83
|
+
...(opts.featureTag === undefined ? [] : [`@${opts.featureTag}`]),
|
|
84
|
+
...(axis.key === "archSpec" ? ["@architecture"] : []),
|
|
85
|
+
];
|
|
86
|
+
const { content, digests, stepless, malformedExamples, strandedBlocks } = renderFeature(r, { tags, version: opts.version }, opts.service, axisLabel(axis));
|
|
87
|
+
out.push({ fileName, axis, requirement: r, digests, stepless, malformedExamples, strandedBlocks, content });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
export function renderFeature(r, stamp, service, axis = "business") {
|
|
93
|
+
const { tags, version } = stamp;
|
|
94
|
+
const lines = [gherkinStampLine(version)];
|
|
95
|
+
if (tags.length > 0)
|
|
96
|
+
lines.push(tags.join(" "));
|
|
97
|
+
lines.push(`Feature: ${r.name}`);
|
|
98
|
+
const text = r.text.join("\n").trim();
|
|
99
|
+
if (text.length > 0) {
|
|
100
|
+
lines.push("");
|
|
101
|
+
for (const l of text.split("\n"))
|
|
102
|
+
lines.push(l.length > 0 ? ` ${l}` : "");
|
|
103
|
+
}
|
|
104
|
+
const digests = [];
|
|
105
|
+
const stepless = [];
|
|
106
|
+
const malformedExamples = [];
|
|
107
|
+
const strandedBlocks = [];
|
|
108
|
+
for (const s of r.scenarios) {
|
|
109
|
+
// The digest hashes the WHOLE body, table rows included, so a changed cell
|
|
110
|
+
// is a changed scenario: `gherkin.stale` fires on an edited case exactly as
|
|
111
|
+
// it does on an edited step, and the claim it answers moves with it. It is
|
|
112
|
+
// also why a change to THIS renderer moves no digest: the hash is over the
|
|
113
|
+
// markdown source, so a suite generated before a grammar change keeps its
|
|
114
|
+
// stamps and grades `gherkin.current` until somebody regenerates it.
|
|
115
|
+
const digest = scenarioDigest(service, s.lines, axis);
|
|
116
|
+
digests.push(digest);
|
|
117
|
+
const { description, steps, examples, malformedExamples: broken, strandedBlocks: stranded } = scenarioGherkin(s.lines);
|
|
118
|
+
if (steps.length === 0)
|
|
119
|
+
stepless.push(s.name);
|
|
120
|
+
if (broken)
|
|
121
|
+
malformedExamples.push(s.name);
|
|
122
|
+
if (stranded)
|
|
123
|
+
strandedBlocks.push(s.name);
|
|
124
|
+
// The keyword is the whole difference between one case and twenty: cucumber
|
|
125
|
+
// expands an outline into one report element per row, each carrying this
|
|
126
|
+
// scenario's tag, and `runnerAnswers` confirms the claim only when every
|
|
127
|
+
// one of them passed.
|
|
128
|
+
lines.push("", ` ${scenarioDigestTag(digest)}`, ` ${examples === null ? "Scenario" : "Scenario Outline"}: ${s.name}`);
|
|
129
|
+
for (const d of description)
|
|
130
|
+
lines.push(` ${d}`);
|
|
131
|
+
for (const st of steps) {
|
|
132
|
+
lines.push(` ${st.text}`);
|
|
133
|
+
// Gherkin puts a step's argument UNDER the step, indented past it, and
|
|
134
|
+
// permits at most one of each kind. Docstring first, so a step carrying
|
|
135
|
+
// both reads request-then-expectation.
|
|
136
|
+
if (st.docstring !== undefined) {
|
|
137
|
+
lines.push(` """${st.docstring.contentType ?? ""}`);
|
|
138
|
+
// A payload containing its own `"""` would close the block early and
|
|
139
|
+
// silently move the rest of the request body into the step list.
|
|
140
|
+
for (const l of st.docstring.lines)
|
|
141
|
+
lines.push(l.length === 0 ? "" : ` ${l.replace(/"""/g, '\\"\\"\\"')}`);
|
|
142
|
+
lines.push(' """');
|
|
143
|
+
}
|
|
144
|
+
if (st.table !== undefined)
|
|
145
|
+
for (const row of st.table)
|
|
146
|
+
lines.push(` ${tableRow(row, st.table)}`);
|
|
147
|
+
}
|
|
148
|
+
if (examples !== null) {
|
|
149
|
+
lines.push("", " Examples:");
|
|
150
|
+
for (const row of [examples.header, ...examples.rows])
|
|
151
|
+
lines.push(` ${tableRow(row, [examples.header, ...examples.rows])}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return { content: lines.join("\n") + "\n", digests, stepless, malformedExamples, strandedBlocks };
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* One table row — an `Examples` case or a step's data table — with columns
|
|
158
|
+
* padded to the widest cell in that table.
|
|
159
|
+
*
|
|
160
|
+
* Padding is cosmetic to cucumber and deliberate here: these files are read in
|
|
161
|
+
* review as often as they are run, and an unaligned twenty-row matrix is where
|
|
162
|
+
* a wrong cell hides. Deterministic to the byte, like everything else the
|
|
163
|
+
* emitter writes — the widths come from the table alone.
|
|
164
|
+
*
|
|
165
|
+
* ESCAPING IS NOT COSMETIC. Gherkin's table grammar ends a cell at `|`, so a
|
|
166
|
+
* cell containing one silently becomes two cells and every row after it
|
|
167
|
+
* disagrees with the header; `\` and a literal newline are the same class. The
|
|
168
|
+
* escapes go on before the padding is measured, because the emitted width is
|
|
169
|
+
* the escaped width — measuring the raw cell produced columns that drifted by
|
|
170
|
+
* one character per escape.
|
|
171
|
+
*/
|
|
172
|
+
function tableRow(row, all) {
|
|
173
|
+
const esc = (c) => c.replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\n/g, "\\n");
|
|
174
|
+
const widths = row.map((_, i) => Math.max(...all.map((r) => esc(r[i] ?? "").length)));
|
|
175
|
+
return `| ${row.map((c, i) => esc(c).padEnd(widths[i])).join(" | ")} |`;
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=emit.js.map
|