@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,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What gets written down, and how a set of answers counts up to a verdict.
|
|
3
|
+
*
|
|
4
|
+
* The shapes and the arithmetic are one module because they are one claim about
|
|
5
|
+
* the same numbers: `tallyRecord` recounts from the answers rather than reading
|
|
6
|
+
* the `summary` field back, so a record whose header disagrees with its own
|
|
7
|
+
* claims is caught rather than believed. A separate counter would be a second
|
|
8
|
+
* opinion, which is precisely what this file exists to prevent.
|
|
9
|
+
*
|
|
10
|
+
* `verified` is reserved for a checklist whose scenarios a RUN answered.
|
|
11
|
+
* Where an agent answered one instead — a legacy service whose suite is months
|
|
12
|
+
* away, which is the fleet loam exists for — the record marks it attested, and
|
|
13
|
+
* `attestedNotice` says so on every surface that reads the record.
|
|
14
|
+
*/
|
|
15
|
+
import {} from "./claims/identity.js";
|
|
16
|
+
import { ANSWERED_BY } from "./answers.js";
|
|
17
|
+
import {} from "./pins/pin.js";
|
|
18
|
+
/**
|
|
19
|
+
* The confirmed `scenario.tested` claims that no test run answered.
|
|
20
|
+
*
|
|
21
|
+
* A scenario claim's whole premise is that a run answers it — its digest IS the
|
|
22
|
+
* tag `loam gherkin` stamps, and `--results` matches the two mechanically. An
|
|
23
|
+
* agent may still answer one, because a legacy service has no runnable suite
|
|
24
|
+
* for months and that fleet is who loam is for; but the answer is somebody's
|
|
25
|
+
* word about a test, and it must not read as the run. A record written before
|
|
26
|
+
* `--results` existed carries no `answered_by` at all: unknown counts as agent
|
|
27
|
+
* here, because the alternative is to credit a run nobody can point at.
|
|
28
|
+
*/
|
|
29
|
+
export function attestedClaims(claims) {
|
|
30
|
+
return claims
|
|
31
|
+
.filter((c) => c.kind === "scenario.tested" && c.verdict === "confirmed" && c.answered_by !== "runner")
|
|
32
|
+
.map((c) => c.id);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Of the CONFIRMED answers, one count per `answered_by` value. Anything that is not a runner spelling
|
|
36
|
+
* counts as the agent's word — a record too old to carry the field says nothing, and crediting a run
|
|
37
|
+
* nobody can point at is the error that matters. Never derive it by subtracting {@link attestedClaims}
|
|
38
|
+
* from the confirmed total: that count is `scenario.tested` ALONE, so the fleet scorecard filed every
|
|
39
|
+
* other kind an agent confirmed under a runner that never ran.
|
|
40
|
+
*/
|
|
41
|
+
export function confirmedProvenance(claims) {
|
|
42
|
+
const done = claims.filter((c) => c.verdict === "confirmed");
|
|
43
|
+
const by = (who) => done.filter((c) => c.answered_by === who).length;
|
|
44
|
+
const ran = { runner: by("runner"), "external-runner": by("external-runner") };
|
|
45
|
+
return { ...ran, agent: done.length - ran.runner - ran["external-runner"] };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The confirmed split as the per-feature human views print it — `13 runner · 6 agent`, empty
|
|
49
|
+
* buckets left out. `loam status <FEAT>` and `list`'s verification column print it beside the
|
|
50
|
+
* verdict because the verdict turns on the scenario claims alone ({@link verificationVerdict}), so
|
|
51
|
+
* `verified 19/19 confirmed` read as nineteen runs over a record where six were an agent's word —
|
|
52
|
+
* the split `--json` and the fleet scorecard already carried. The scorecard keeps all three keys
|
|
53
|
+
* for its stable-shape reason (validate's scorecard/print.ts); a one-feature line has no shape to
|
|
54
|
+
* keep, and a column of zeros is width the reader pays for nothing.
|
|
55
|
+
*/
|
|
56
|
+
export function answeredSplit(answered) {
|
|
57
|
+
return ANSWERED_BY.filter((who) => answered[who] > 0)
|
|
58
|
+
.map((who) => `${answered[who]} ${who}`)
|
|
59
|
+
.join(" · ");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* `unanswered` is the count the answers themselves cannot show: a federated
|
|
63
|
+
* record holds only what somebody answered, and the claims still owed to other
|
|
64
|
+
* repositories exist on the checklist, not in `claims[]`. Read views that carry
|
|
65
|
+
* an `unanswered` status inside the list pass 0 and are counted in place.
|
|
66
|
+
*/
|
|
67
|
+
export function tallyAnswers(claims, unanswered = 0) {
|
|
68
|
+
const of = (verdict) => claims.filter((c) => c.verdict === verdict).length;
|
|
69
|
+
return {
|
|
70
|
+
claims: claims.length + unanswered,
|
|
71
|
+
confirmed: of("confirmed"),
|
|
72
|
+
unconfirmed: of("unconfirmed"),
|
|
73
|
+
unanswered: of("unanswered") + unanswered,
|
|
74
|
+
attested: attestedClaims(claims).length,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The record's own answers, recounted. Never `v.summary`: the summary is what
|
|
79
|
+
* whoever wrote the file said the answers add up to, and every reader that
|
|
80
|
+
* believed it reported a record full of unconfirmed claims as fully confirmed.
|
|
81
|
+
* `readVerificationState` refuses a record whose summary contradicts this, so a
|
|
82
|
+
* caller holding a Verification may use either — and should use this one.
|
|
83
|
+
*/
|
|
84
|
+
export function tallyRecord(v) {
|
|
85
|
+
return tallyAnswers(v.claims, v.summary.unanswered ?? 0);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The recorded rows that may answer a checklist, keyed by claim id — the one
|
|
89
|
+
* spelling of the attestation-scoping rule. A legacy (no `schema`) record is
|
|
90
|
+
* all-at-once, so every row answers. In a federated record a row only counts
|
|
91
|
+
* where an attestation from the claim's OWN subject (per `claims`, the live
|
|
92
|
+
* checklist) listed it, so one repository cannot answer another's claims by
|
|
93
|
+
* writing their ids into its own attestation. `verify`'s read view and `loam
|
|
94
|
+
* tasks` each used to carry a copy, the second labelled "a deliberate mirror"
|
|
95
|
+
* because core could not import the command module the first lived in; the
|
|
96
|
+
* rule lives here now and both import it.
|
|
97
|
+
*/
|
|
98
|
+
export function countedAnswers(claims, recorded) {
|
|
99
|
+
const subjects = new Map(claims.map((claim) => [claim.id, claim.subject]));
|
|
100
|
+
const attested = recorded.schema !== 2
|
|
101
|
+
? null
|
|
102
|
+
: new Set((recorded.attestations ?? []).flatMap((a) => a.claims.filter((id) => subjects.get(id) === a.service)));
|
|
103
|
+
return new Map(recorded.claims.filter((c) => attested === null || attested.has(c.id)).map((c) => [c.id, c]));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Three states, because two were a lie. `verified` is the strong claim — every
|
|
107
|
+
* question answered, every answer confirmed, and every scenario answered by a
|
|
108
|
+
* digest-matched green run. `attested` is the same completeness resting, for at
|
|
109
|
+
* least one scenario, on an agent's word. `unverified` is everything else:
|
|
110
|
+
* nothing recorded, a record gone stale, a claim unanswered or unconfirmed, or
|
|
111
|
+
* a checklist that asks nothing at all.
|
|
112
|
+
*/
|
|
113
|
+
export const VERIFICATION_VERDICTS = ["verified", "attested", "unverified"];
|
|
114
|
+
export function verificationVerdict(t, stale = false) {
|
|
115
|
+
if (stale || t.claims === 0 || t.confirmed !== t.claims)
|
|
116
|
+
return "unverified";
|
|
117
|
+
return t.attested > 0 ? "attested" : "verified";
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The one notice `verify`, `list` and `status` all show: this record's scenario
|
|
121
|
+
* claims were confirmed without a run.
|
|
122
|
+
*
|
|
123
|
+
* It is a warning and it gates nothing — verify has never gated, and a service
|
|
124
|
+
* with no suite yet has to be able to ship. What it must never do is read the
|
|
125
|
+
* same as a green run.
|
|
126
|
+
*/
|
|
127
|
+
export function attestedNotice(claims, feature) {
|
|
128
|
+
const ids = attestedClaims(claims);
|
|
129
|
+
if (ids.length === 0)
|
|
130
|
+
return null;
|
|
131
|
+
return {
|
|
132
|
+
code: "verify.scenario-attested",
|
|
133
|
+
severity: "warn",
|
|
134
|
+
message: `${ids.length} scenario claim(s) are confirmed on an agent's word, not on a test run: ${ids.join(", ")}. ` +
|
|
135
|
+
`Answer them mechanically once the suite runs: \`loam verify ${feature} --results <report.json>\` — ` +
|
|
136
|
+
"a cucumber JSON report, or loam's runner-neutral loamScenarioReport shape for any other runner.",
|
|
137
|
+
claims: ids,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The one-line honesty summary of a record that leaves claims open: partial is
|
|
142
|
+
* not a clean result, and the counts alone did not say so — `summary` carries
|
|
143
|
+
* them on every surface, and a reader skimming for the ⚠ lines shipped a
|
|
144
|
+
* half-answered record as done anyway. Null when nothing is open, and the
|
|
145
|
+
* callers fire it only when a record EXISTS: a feature with no record already
|
|
146
|
+
* says "Not verified", and calling that "not a clean result" would conflate
|
|
147
|
+
* not-started with partial. A pure-attested record (all confirmed, some on an
|
|
148
|
+
* agent's word) never reaches the message either — its counts are closed, and
|
|
149
|
+
* `attestedNotice` above owns that honesty; two notices about one fact is the
|
|
150
|
+
* double-reporting this file's notices exist to prevent.
|
|
151
|
+
*/
|
|
152
|
+
export function openClaimsNotice(tally, feature) {
|
|
153
|
+
const open = tally.unconfirmed + tally.unanswered;
|
|
154
|
+
if (open === 0)
|
|
155
|
+
return null;
|
|
156
|
+
return {
|
|
157
|
+
code: "verify.claims-open",
|
|
158
|
+
severity: "warn",
|
|
159
|
+
message: `not a clean result: of ${tally.claims} claim(s), ${tally.confirmed} confirmed` +
|
|
160
|
+
(tally.attested > 0 ? ` (${tally.attested} on an agent's word)` : "") +
|
|
161
|
+
`, ${tally.unconfirmed} unconfirmed, ${tally.unanswered} unanswered — ` +
|
|
162
|
+
`treat ${feature} as unverified until every claim is answered and confirmed.`,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.js","sourceRoot":"","sources":["../../../src/core/verify/record.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What gets written down, and how a set of answers counts up to a verdict.\n *\n * The shapes and the arithmetic are one module because they are one claim about\n * the same numbers: `tallyRecord` recounts from the answers rather than reading\n * the `summary` field back, so a record whose header disagrees with its own\n * claims is caught rather than believed. A separate counter would be a second\n * opinion, which is precisely what this file exists to prevent.\n *\n * `verified` is reserved for a checklist whose scenarios a RUN answered.\n * Where an agent answered one instead — a legacy service whose suite is months\n * away, which is the fleet loam exists for — the record marks it attested, and\n * `attestedNotice` says so on every surface that reads the record.\n */\nimport { type ClaimKind } from \"./claims/identity.js\";\nimport { ANSWERED_BY, type AnsweredBy, type Verdict } from \"./answers.js\";\nimport { type EvidencePin } from \"./pins/pin.js\";\n\nexport interface RecordedClaim {\n id: string;\n kind: ClaimKind;\n /** Present in federated records; omitted by legacy records written before schema 2. */\n subject?: string;\n claim: string;\n verdict: Verdict;\n /** Who answered — absent only in records written before `--results` existed. */\n answered_by?: AnsweredBy;\n evidence: string[];\n note?: string;\n /**\n * One pin per file:line citation of a federated agent-confirmed answer: the\n * cited file's normalized sha256 at the attested commit, the cited line's\n * text, and the claim's token where it asserts one. A pin records which\n * text was cited at that commit so `loam validate`, run later in the\n * service's own repo, can convict drift; it does not prove the claim true —\n * a faithful pin of the wrong line is still a wrong answer. Absent on\n * runner-answered claims (their evidence names a report entry, not a file)\n * and on every record written before pins existed.\n */\n evidence_pins?: EvidencePin[];\n}\n\n/**\n * The test report a `--results` run consumed.\n *\n * Nothing can prove a JSON file came from executing a particular commit — a\n * report is bytes, and bytes are writable. What loam can do is stop leaving the\n * question open: it records exactly which file it read (inside the attesting\n * repository, resolved by the same path rules as evidence), the sha256 of the\n * bytes it read, the file's own mtime and how many digest-tagged scenarios it\n * carried. A reviewer holding the repository can tell whether this is that\n * file; before this, `answered_by: runner` named nothing at all.\n */\nexport interface ConsumedReport {\n /** As it was passed to `--results` — repo-relative in a federated record. */\n path: string;\n /** Full sha256 of the bytes read, so `shasum -a 256 <path>` answers the question. */\n digest: string;\n /** ISO-8601 mtime of the report file — when the run that wrote it finished. */\n mtime: string;\n /** How many digest-tagged scenarios the report carried. */\n scenarios: number;\n}\n\n/**\n * The contract-test report a `--contract-results` run consumed — the same pin,\n * the same honesty, for the report that answers `api.exposes` claims by\n * operationId. Nothing here proves the file came from executing the attested\n * commit either; the digest identifies WHICH file was consumed, and the\n * federated form binds a committed one to the commit exactly as `report:` is.\n */\nexport interface ConsumedContractReport {\n /** As it was passed to `--contract-results` — repo-relative in a federated record. */\n path: string;\n /** Full sha256 of the bytes read. */\n digest: string;\n /** ISO-8601 mtime of the report file. */\n mtime: string;\n /** How many distinct operationIds the report's entries name. */\n operations: number;\n /**\n * Which accepted shape the report was read as — `\"generic\"` for the\n * documented `loamContractReport: 1` shape, the only one v1 accepts. loam\n * always writes it, but the READ shape keeps it optional: no reader\n * dereferences it, so a hand-written pin without it stays a readable record\n * (`isConsumedContractReport` in ./read/shape.ts says why) — and it is a string\n * rather than a closed union so a format a NEWER loam learned to read stays\n * readable here too.\n */\n format?: string;\n}\n\n/**\n * Both mechanical answer sheets one recording run may consume, together\n * because they are validated together (`validateServiceEvidence` binds each to\n * the attested commit) and filed together (on the record all-at-once, inside\n * the service's attestation federated). Two loose optional parameters made the\n * inconsistent pair representable at every call site.\n */\nexport interface ConsumedReports {\n results?: ConsumedReport;\n contract?: ConsumedContractReport;\n}\n\n/** A service repository's commit-bound contribution to a federated record. */\nexport interface ServiceAttestation {\n service: string;\n commit: string;\n recorded: string;\n /** Claim ids this commit answered. Kept explicit so stale answers can be pruned safely. */\n claims: string[];\n /**\n * The checklist digest THIS attestation answered.\n *\n * The record carries one `checklist` for the whole file, which is the right\n * field for the all-at-once form and an incomplete one for a federated\n * record: two services attesting a week apart across a changed delta write\n * the same top-level digest, and nothing in the file can say they answered\n * different questions. With this, `verify.checklist-forked` can.\n *\n * Optional forever. An attestation written before this field existed carries\n * no claim about which checklist it answered, and inventing one from the\n * record-level digest would be asserting exactly the thing that cannot be\n * known — the `evidence.unpinned` precedent, one axis over.\n */\n checklist?: string;\n /**\n * The docs-repo commit the checklist was computed from, when the docs repo is\n * a git repository with a committed HEAD.\n *\n * `commit` pins the SERVICE repo — the code the evidence points into.\n * Nothing pinned the side the QUESTION came from, so a reader could not tell\n * a re-record against an unchanged feature from one against a rewritten\n * delta. Absent whenever git cannot answer: a docs repo is not required to be\n * a git checkout, and a missing pin is not a defect.\n */\n docsCommit?: string;\n /** The report that answered this service's scenario claims, when `--results` did. */\n report?: ConsumedReport;\n /** The report that answered this service's api.exposes claims, when `--contract-results` did. */\n contractReport?: ConsumedContractReport;\n}\n\nexport interface Verification {\n /** Federated, partial records use schema 2. Absent means the original all-at-once format. */\n schema?: 2;\n feature: string;\n /** The day the answers were recorded. */\n recorded: string;\n /** The checklist digest they answer — how a later reader spots a record gone stale. */\n checklist: string;\n summary: { claims: number; confirmed: number; unconfirmed: number; unanswered?: number };\n claims: RecordedClaim[];\n /** The all-at-once form's consumed report; the federated form files it per attestation. */\n report?: ConsumedReport;\n /** The all-at-once form's consumed contract report — filed per attestation when federated. */\n contractReport?: ConsumedContractReport;\n attestations?: ServiceAttestation[];\n}\n\n/**\n * Anything carrying an answer, whichever surface holds it: a recorded claim, or\n * the read view's per-claim status. Structural on purpose — the same questions\n * are asked of both, and neither should have to convert into the other to be\n * counted.\n */\nexport interface AnsweredClaim {\n id: string;\n kind: string;\n verdict: string;\n answered_by?: string;\n}\n\n/**\n * The confirmed `scenario.tested` claims that no test run answered.\n *\n * A scenario claim's whole premise is that a run answers it — its digest IS the\n * tag `loam gherkin` stamps, and `--results` matches the two mechanically. An\n * agent may still answer one, because a legacy service has no runnable suite\n * for months and that fleet is who loam is for; but the answer is somebody's\n * word about a test, and it must not read as the run. A record written before\n * `--results` existed carries no `answered_by` at all: unknown counts as agent\n * here, because the alternative is to credit a run nobody can point at.\n */\nexport function attestedClaims(claims: readonly AnsweredClaim[]): string[] {\n return claims\n .filter((c) => c.kind === \"scenario.tested\" && c.verdict === \"confirmed\" && c.answered_by !== \"runner\")\n .map((c) => c.id);\n}\n\n/**\n * Of the CONFIRMED answers, one count per `answered_by` value. Anything that is not a runner spelling\n * counts as the agent's word — a record too old to carry the field says nothing, and crediting a run\n * nobody can point at is the error that matters. Never derive it by subtracting {@link attestedClaims}\n * from the confirmed total: that count is `scenario.tested` ALONE, so the fleet scorecard filed every\n * other kind an agent confirmed under a runner that never ran.\n */\nexport function confirmedProvenance(claims: readonly AnsweredClaim[]): Record<AnsweredBy, number> {\n const done = claims.filter((c) => c.verdict === \"confirmed\");\n const by = (who: AnsweredBy): number => done.filter((c) => c.answered_by === who).length;\n const ran = { runner: by(\"runner\"), \"external-runner\": by(\"external-runner\") };\n return { ...ran, agent: done.length - ran.runner - ran[\"external-runner\"] };\n}\n\n/**\n * The confirmed split as the per-feature human views print it — `13 runner · 6 agent`, empty\n * buckets left out. `loam status <FEAT>` and `list`'s verification column print it beside the\n * verdict because the verdict turns on the scenario claims alone ({@link verificationVerdict}), so\n * `verified 19/19 confirmed` read as nineteen runs over a record where six were an agent's word —\n * the split `--json` and the fleet scorecard already carried. The scorecard keeps all three keys\n * for its stable-shape reason (validate's scorecard/print.ts); a one-feature line has no shape to\n * keep, and a column of zeros is width the reader pays for nothing.\n */\nexport function answeredSplit(answered: Record<AnsweredBy, number>): string {\n return ANSWERED_BY.filter((who) => answered[who] > 0)\n .map((who) => `${answered[who]} ${who}`)\n .join(\" · \");\n}\n\n/** How a set of answers counts up — recounted from the answers, never read off a `summary`. */\nexport interface RecordTally {\n /** Questions asked: answered, plus the ones a federated record leaves for other repos. */\n claims: number;\n confirmed: number;\n unconfirmed: number;\n unanswered: number;\n /** Of the confirmed, the scenario claims on an agent's word. See {@link attestedClaims}. */\n attested: number;\n}\n\n/**\n * `unanswered` is the count the answers themselves cannot show: a federated\n * record holds only what somebody answered, and the claims still owed to other\n * repositories exist on the checklist, not in `claims[]`. Read views that carry\n * an `unanswered` status inside the list pass 0 and are counted in place.\n */\nexport function tallyAnswers(claims: readonly AnsweredClaim[], unanswered = 0): RecordTally {\n const of = (verdict: string): number => claims.filter((c) => c.verdict === verdict).length;\n return {\n claims: claims.length + unanswered,\n confirmed: of(\"confirmed\"),\n unconfirmed: of(\"unconfirmed\"),\n unanswered: of(\"unanswered\") + unanswered,\n attested: attestedClaims(claims).length,\n };\n}\n\n/**\n * The record's own answers, recounted. Never `v.summary`: the summary is what\n * whoever wrote the file said the answers add up to, and every reader that\n * believed it reported a record full of unconfirmed claims as fully confirmed.\n * `readVerificationState` refuses a record whose summary contradicts this, so a\n * caller holding a Verification may use either — and should use this one.\n */\nexport function tallyRecord(v: Verification): RecordTally {\n return tallyAnswers(v.claims, v.summary.unanswered ?? 0);\n}\n\n/**\n * The recorded rows that may answer a checklist, keyed by claim id — the one\n * spelling of the attestation-scoping rule. A legacy (no `schema`) record is\n * all-at-once, so every row answers. In a federated record a row only counts\n * where an attestation from the claim's OWN subject (per `claims`, the live\n * checklist) listed it, so one repository cannot answer another's claims by\n * writing their ids into its own attestation. `verify`'s read view and `loam\n * tasks` each used to carry a copy, the second labelled \"a deliberate mirror\"\n * because core could not import the command module the first lived in; the\n * rule lives here now and both import it.\n */\nexport function countedAnswers(\n claims: readonly { id: string; subject: string }[],\n recorded: Verification,\n): Map<string, RecordedClaim> {\n const subjects = new Map(claims.map((claim) => [claim.id, claim.subject]));\n const attested =\n recorded.schema !== 2\n ? null\n : new Set(\n (recorded.attestations ?? []).flatMap((a) => a.claims.filter((id) => subjects.get(id) === a.service)),\n );\n return new Map(recorded.claims.filter((c) => attested === null || attested.has(c.id)).map((c) => [c.id, c]));\n}\n\n/**\n * Three states, because two were a lie. `verified` is the strong claim — every\n * question answered, every answer confirmed, and every scenario answered by a\n * digest-matched green run. `attested` is the same completeness resting, for at\n * least one scenario, on an agent's word. `unverified` is everything else:\n * nothing recorded, a record gone stale, a claim unanswered or unconfirmed, or\n * a checklist that asks nothing at all.\n */\nexport const VERIFICATION_VERDICTS = [\"verified\", \"attested\", \"unverified\"] as const;\nexport type VerificationVerdict = (typeof VERIFICATION_VERDICTS)[number];\n\nexport function verificationVerdict(t: RecordTally, stale = false): VerificationVerdict {\n if (stale || t.claims === 0 || t.confirmed !== t.claims) return \"unverified\";\n return t.attested > 0 ? \"attested\" : \"verified\";\n}\n\n/** A finding a verify surface reports about a record. Stable code, prose that may change. */\nexport interface VerifyNotice {\n code: string;\n severity: \"warn\";\n message: string;\n /** The claims it is about, when it is about claims. */\n claims?: string[];\n}\n\n/**\n * The one notice `verify`, `list` and `status` all show: this record's scenario\n * claims were confirmed without a run.\n *\n * It is a warning and it gates nothing — verify has never gated, and a service\n * with no suite yet has to be able to ship. What it must never do is read the\n * same as a green run.\n */\nexport function attestedNotice(claims: readonly AnsweredClaim[], feature: string): VerifyNotice | null {\n const ids = attestedClaims(claims);\n if (ids.length === 0) return null;\n return {\n code: \"verify.scenario-attested\",\n severity: \"warn\",\n message:\n `${ids.length} scenario claim(s) are confirmed on an agent's word, not on a test run: ${ids.join(\", \")}. ` +\n `Answer them mechanically once the suite runs: \\`loam verify ${feature} --results <report.json>\\` — ` +\n \"a cucumber JSON report, or loam's runner-neutral loamScenarioReport shape for any other runner.\",\n claims: ids,\n };\n}\n\n/**\n * The one-line honesty summary of a record that leaves claims open: partial is\n * not a clean result, and the counts alone did not say so — `summary` carries\n * them on every surface, and a reader skimming for the ⚠ lines shipped a\n * half-answered record as done anyway. Null when nothing is open, and the\n * callers fire it only when a record EXISTS: a feature with no record already\n * says \"Not verified\", and calling that \"not a clean result\" would conflate\n * not-started with partial. A pure-attested record (all confirmed, some on an\n * agent's word) never reaches the message either — its counts are closed, and\n * `attestedNotice` above owns that honesty; two notices about one fact is the\n * double-reporting this file's notices exist to prevent.\n */\nexport function openClaimsNotice(tally: RecordTally, feature: string): VerifyNotice | null {\n const open = tally.unconfirmed + tally.unanswered;\n if (open === 0) return null;\n return {\n code: \"verify.claims-open\",\n severity: \"warn\",\n message:\n `not a clean result: of ${tally.claims} claim(s), ${tally.confirmed} confirmed` +\n (tally.attested > 0 ? ` (${tally.attested} on an agent's word)` : \"\") +\n `, ${tally.unconfirmed} unconfirmed, ${tally.unanswered} unanswered — ` +\n `treat ${feature} as unverified until every claim is answered and confirmed.`,\n };\n}\n"]}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The verification record's commit: staged beside the target, compared against
|
|
3
|
+
* the byte pre-image the merge consumed, swapped in by one rename(2) per file.
|
|
4
|
+
* A write is one file, or two: a service's own `verification/<svc>.yaml`, and
|
|
5
|
+
* — once nothing in it counts any more — the removal of the one-file record it
|
|
6
|
+
* supersedes. Never another service's file: those are not this run's to touch.
|
|
7
|
+
*
|
|
8
|
+
* The record used to go down as a plain `writeFile`, which cost three ways at
|
|
9
|
+
* once: two `--record` runs read the same pre-image and the last writer
|
|
10
|
+
* silently discarded the other service's attestation; a process killed
|
|
11
|
+
* mid-write left the ONLY copy truncated, unreadable, and blocking every later
|
|
12
|
+
* record; and an edit that landed between the read and the write was buried
|
|
13
|
+
* under bytes computed from a document that no longer existed. The docs lock
|
|
14
|
+
* (taken by `loam verify` before its authoritative read) closes the first;
|
|
15
|
+
* this module closes the other two, and backstops the lock itself for a writer
|
|
16
|
+
* that never took it.
|
|
17
|
+
*
|
|
18
|
+
* A sub-package of core/verify rather than a sixth file in it, and a consumer
|
|
19
|
+
* of core/staging's primitives rather than a re-implementation: `stageWrites`
|
|
20
|
+
* and `swapStaged` already do temp-beside-target, whole-content compare-and-set
|
|
21
|
+
* and same-directory rename — vouch commits through exactly this shape.
|
|
22
|
+
*/
|
|
23
|
+
import { message, rollbackMessage, rollbackStaged, stageWrites, StagingRaceError, swapStaged } from "../../staging/commit.js";
|
|
24
|
+
import { repoPath } from "../../envelope/json.js";
|
|
25
|
+
import {} from "../../staging/writes.js";
|
|
26
|
+
import { renderVerification } from "./render.js";
|
|
27
|
+
import {} from "../record.js";
|
|
28
|
+
/**
|
|
29
|
+
* Writes land in the order given, so a caller puts what must survive a kill
|
|
30
|
+
* FIRST: a service's own file before the one-file record it supersedes, so a
|
|
31
|
+
* process killed between the two renames leaves a record that still reads
|
|
32
|
+
* whole — the new file counted, the old one superseded by it — rather than one
|
|
33
|
+
* with the old file gone and nothing in its place.
|
|
34
|
+
*/
|
|
35
|
+
export async function commitVerification(writes, docsDir) {
|
|
36
|
+
const planned = writes.map((w) => w.record === null
|
|
37
|
+
? { path: w.path, content: null }
|
|
38
|
+
: w.preImage === null
|
|
39
|
+
? { path: w.path, content: renderVerification(w.record), exclusive: true }
|
|
40
|
+
: { path: w.path, content: renderVerification(w.record) });
|
|
41
|
+
// Staging touches the filesystem — a read-only feature directory, a full
|
|
42
|
+
// disk, a pre-image that will not read. None of that is a bug in loam, and
|
|
43
|
+
// letting it escape as `internal` sends the reader looking for one (archive
|
|
44
|
+
// draws the same line around its own `stageWrites`). Nothing was written.
|
|
45
|
+
let staged;
|
|
46
|
+
try {
|
|
47
|
+
staged = await stageWrites(planned);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
return { ok: false, code: "merge-failed", message: `${message(err)} — nothing was recorded; the record is as the last writer left it` };
|
|
51
|
+
}
|
|
52
|
+
for (const w of writes) {
|
|
53
|
+
const display = repoPath(docsDir, w.path);
|
|
54
|
+
// Joined by path, not by index — vouch's rule, for vouch's reason: one
|
|
55
|
+
// entry per planned write in order is true today and promised nowhere, and
|
|
56
|
+
// a compare-and-set over the wrong pair would vouch for bytes the merge
|
|
57
|
+
// never saw. A missing entry fails closed as a merge that never happened.
|
|
58
|
+
const s = staged.find((x) => x.write.path === w.path);
|
|
59
|
+
if (s === undefined) {
|
|
60
|
+
await rollbackStaged(staged);
|
|
61
|
+
return { ok: false, code: "merge-failed", message: `staging returned no entry for ${display} — nothing was recorded` };
|
|
62
|
+
}
|
|
63
|
+
// The compare the read promised: the file as staging found it must be the
|
|
64
|
+
// file the merge consumed. `swapStaged` re-checks against ITS read just
|
|
65
|
+
// before the rename, so together the two compares cover the whole window
|
|
66
|
+
// from the authoritative read to the swap.
|
|
67
|
+
const edited = w.preImage === null ? s.before !== null : s.before === null || !s.before.equals(w.preImage);
|
|
68
|
+
if (edited) {
|
|
69
|
+
await rollbackStaged(staged);
|
|
70
|
+
return { ok: false, code: "record-raced", message: racedMessage(display) };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
await swapStaged(staged);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
const failures = await rollbackStaged(staged);
|
|
78
|
+
if (failures.length > 0) {
|
|
79
|
+
return {
|
|
80
|
+
ok: false,
|
|
81
|
+
code: "rollback-incomplete",
|
|
82
|
+
message: rollbackMessage(err, failures, "written"),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// EEXIST is the exclusive create losing its race — same fact as the CAS
|
|
86
|
+
// refusal, discovered by link(2) instead of by the compare.
|
|
87
|
+
if (err instanceof StagingRaceError || err.code === "EEXIST") {
|
|
88
|
+
const path = err instanceof StagingRaceError ? err.path : (writes.find((w) => w.preImage === null)?.path ?? writes[0].path);
|
|
89
|
+
return { ok: false, code: "record-raced", message: racedMessage(repoPath(docsDir, path)) };
|
|
90
|
+
}
|
|
91
|
+
return { ok: false, code: "merge-failed", message: `${message(err)} — nothing was recorded; the record is as the last writer left it` };
|
|
92
|
+
}
|
|
93
|
+
return { ok: true };
|
|
94
|
+
}
|
|
95
|
+
function racedMessage(display) {
|
|
96
|
+
return (`${display} changed while this record was being written — another writer or an editor landed between the read and the write. ` +
|
|
97
|
+
"Nothing was written and their bytes are untouched. Re-run: the merge is recomputed over the record as it now stands.");
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=commit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit.js","sourceRoot":"","sources":["../../../../src/core/verify/store/commit.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The verification record's commit: staged beside the target, compared against\n * the byte pre-image the merge consumed, swapped in by one rename(2) per file.\n * A write is one file, or two: a service's own `verification/<svc>.yaml`, and\n * — once nothing in it counts any more — the removal of the one-file record it\n * supersedes. Never another service's file: those are not this run's to touch.\n *\n * The record used to go down as a plain `writeFile`, which cost three ways at\n * once: two `--record` runs read the same pre-image and the last writer\n * silently discarded the other service's attestation; a process killed\n * mid-write left the ONLY copy truncated, unreadable, and blocking every later\n * record; and an edit that landed between the read and the write was buried\n * under bytes computed from a document that no longer existed. The docs lock\n * (taken by `loam verify` before its authoritative read) closes the first;\n * this module closes the other two, and backstops the lock itself for a writer\n * that never took it.\n *\n * A sub-package of core/verify rather than a sixth file in it, and a consumer\n * of core/staging's primitives rather than a re-implementation: `stageWrites`\n * and `swapStaged` already do temp-beside-target, whole-content compare-and-set\n * and same-directory rename — vouch commits through exactly this shape.\n */\nimport { message, rollbackMessage, rollbackStaged, stageWrites, StagingRaceError, swapStaged } from \"../../staging/commit.js\";\nimport { repoPath } from \"../../envelope/json.js\";\nimport { type PlannedWrite, type StagedWrite } from \"../../staging/writes.js\";\nimport { renderVerification } from \"./render.js\";\nimport { type Verification } from \"../record.js\";\n\n/**\n * `record-raced` re-runs cleanly: the merge is recomputed over whatever the\n * other writer left. The other two are staging's own vocabulary, with staging's\n * meanings — `merge-failed` trusts the repo, `rollback-incomplete` does not.\n */\nexport type VerificationCommit =\n | { ok: true }\n | { ok: false; code: \"record-raced\" | \"merge-failed\" | \"rollback-incomplete\"; message: string };\n\n/**\n * One file of the record this commit writes or removes.\n *\n * `preImage` is the exact bytes the caller's merge was computed from, or null\n * when the file was absent at the authoritative read — in which case the\n * commit may only CREATE it (link(2) refuses a file that appeared since), never\n * replace one it has not read. `record: null` removes the file, and only over\n * the bytes that read saw: a delete is a replace with nothing, and it is held\n * to the same compare.\n */\nexport interface RecordWrite {\n path: string;\n record: Verification | null;\n preImage: Buffer | null;\n}\n\n/**\n * Writes land in the order given, so a caller puts what must survive a kill\n * FIRST: a service's own file before the one-file record it supersedes, so a\n * process killed between the two renames leaves a record that still reads\n * whole — the new file counted, the old one superseded by it — rather than one\n * with the old file gone and nothing in its place.\n */\nexport async function commitVerification(writes: RecordWrite[], docsDir: string): Promise<VerificationCommit> {\n const planned = writes.map(\n (w): PlannedWrite =>\n w.record === null\n ? { path: w.path, content: null }\n : w.preImage === null\n ? { path: w.path, content: renderVerification(w.record), exclusive: true }\n : { path: w.path, content: renderVerification(w.record) },\n );\n // Staging touches the filesystem — a read-only feature directory, a full\n // disk, a pre-image that will not read. None of that is a bug in loam, and\n // letting it escape as `internal` sends the reader looking for one (archive\n // draws the same line around its own `stageWrites`). Nothing was written.\n let staged: StagedWrite[];\n try {\n staged = await stageWrites(planned);\n } catch (err) {\n return { ok: false, code: \"merge-failed\", message: `${message(err)} — nothing was recorded; the record is as the last writer left it` };\n }\n for (const w of writes) {\n const display = repoPath(docsDir, w.path);\n // Joined by path, not by index — vouch's rule, for vouch's reason: one\n // entry per planned write in order is true today and promised nowhere, and\n // a compare-and-set over the wrong pair would vouch for bytes the merge\n // never saw. A missing entry fails closed as a merge that never happened.\n const s = staged.find((x) => x.write.path === w.path);\n if (s === undefined) {\n await rollbackStaged(staged);\n return { ok: false, code: \"merge-failed\", message: `staging returned no entry for ${display} — nothing was recorded` };\n }\n // The compare the read promised: the file as staging found it must be the\n // file the merge consumed. `swapStaged` re-checks against ITS read just\n // before the rename, so together the two compares cover the whole window\n // from the authoritative read to the swap.\n const edited = w.preImage === null ? s.before !== null : s.before === null || !s.before.equals(w.preImage);\n if (edited) {\n await rollbackStaged(staged);\n return { ok: false, code: \"record-raced\", message: racedMessage(display) };\n }\n }\n try {\n await swapStaged(staged);\n } catch (err) {\n const failures = await rollbackStaged(staged);\n if (failures.length > 0) {\n return {\n ok: false,\n code: \"rollback-incomplete\",\n message: rollbackMessage(err, failures, \"written\"),\n };\n }\n // EEXIST is the exclusive create losing its race — same fact as the CAS\n // refusal, discovered by link(2) instead of by the compare.\n if (err instanceof StagingRaceError || (err as NodeJS.ErrnoException).code === \"EEXIST\") {\n const path = err instanceof StagingRaceError ? err.path : (writes.find((w) => w.preImage === null)?.path ?? writes[0]!.path);\n return { ok: false, code: \"record-raced\", message: racedMessage(repoPath(docsDir, path)) };\n }\n return { ok: false, code: \"merge-failed\", message: `${message(err)} — nothing was recorded; the record is as the last writer left it` };\n }\n return { ok: true };\n}\n\nfunction racedMessage(display: string): string {\n return (\n `${display} changed while this record was being written — another writer or an editor landed between the read and the write. ` +\n \"Nothing was written and their bytes are untouched. Re-run: the merge is recomputed over the record as it now stands.\"\n );\n}\n"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The record as bytes: the header and the YAML that `store/commit.ts` swaps
|
|
3
|
+
* into place. Moved here from `../file.ts` when the contract-report validation
|
|
4
|
+
* pushed that module over the line limit — and the seam is real, not
|
|
5
|
+
* arithmetic: reading was never the inverse of rendering (a record is
|
|
6
|
+
* re-graded on the way in, because anything may have edited it since), so the
|
|
7
|
+
* two were cohabiting rather than forming a codec, while the RENDER and the
|
|
8
|
+
* COMMIT genuinely are one concern — this module produces exactly the bytes
|
|
9
|
+
* whose atomic swap that one performs. The reading went on to a package of its
|
|
10
|
+
* own, `../read/` (`file.ts` finds and grades the files, `shape.ts` says what a
|
|
11
|
+
* file must hold, `union.ts` adds the files up), and `../read/file.ts`'s header
|
|
12
|
+
* says where the render went.
|
|
13
|
+
*/
|
|
14
|
+
import { stringify } from "yaml";
|
|
15
|
+
import {} from "../record.js";
|
|
16
|
+
/**
|
|
17
|
+
* The record as a file. The header explains what the reader is looking at,
|
|
18
|
+
* because the whole point is that this is legible to someone who has never run
|
|
19
|
+
* loam — including the part loam cannot vouch for.
|
|
20
|
+
*/
|
|
21
|
+
export function renderVerification(v) {
|
|
22
|
+
const header = [
|
|
23
|
+
`# Verification record for ${v.feature} — written by \`loam verify ${v.feature}\` (--results / --contract-results / --record).`,
|
|
24
|
+
"#",
|
|
25
|
+
"# Every claim below was derived mechanically from this feature's own artifacts:",
|
|
26
|
+
"# delta.likec4, specs/<svc>/spec.md, specs/<svc>/arch.spec.md and specs/<svc>/",
|
|
27
|
+
"# openapi.yaml. Each verdict names who answered it: `answered_by: runner` means a",
|
|
28
|
+
"# test report's digest-tagged scenarios answered it mechanically — cucumber JSON,",
|
|
29
|
+
"# or loam's own {\"loamScenarioReport\": 1, ...} shape that any runner adapts into;",
|
|
30
|
+
"# `answered_by: external-runner` means a contract-test report's operationId-matched",
|
|
31
|
+
"# entries did, and `contractReport:` records which file a --contract-results run",
|
|
32
|
+
"# read; `answered_by: agent` means somebody's word about the code, which loam did",
|
|
33
|
+
"# not check. Nothing gates on any of them.",
|
|
34
|
+
"#",
|
|
35
|
+
"# A `scenario.tested` claim confirmed by an agent is ATTESTED, not run: loam",
|
|
36
|
+
"# reports it as `verify.scenario-attested` and the feature does not count as",
|
|
37
|
+
"# verified until a report answers it. `report:` records the file a --results run",
|
|
38
|
+
"# read — its sha256 and mtime say WHICH file, not that it came from that commit;",
|
|
39
|
+
"# no digest can say that.",
|
|
40
|
+
"#",
|
|
41
|
+
"# `checklist` is a digest of the claim ids. If `loam verify` stops reporting the same",
|
|
42
|
+
"# one, the feature changed after this was recorded and these answers are stale.",
|
|
43
|
+
...(v.schema === 2
|
|
44
|
+
? [
|
|
45
|
+
"#",
|
|
46
|
+
"# Schema 2 is federated: each service entry under `attestations` binds its claim ids",
|
|
47
|
+
"# and file:line evidence to that repository's git commit. Each attesting service has a",
|
|
48
|
+
"# file of its own, verification/<svc>.yaml, and the record is the directory: claims",
|
|
49
|
+
"# another service owns are honestly unanswered in this file and answered in that",
|
|
50
|
+
"# service's own, and loam adds the files up when it reads them.",
|
|
51
|
+
"# `evidence_pins` records each cited file's sha256 (CRLF-normalized) and line text at",
|
|
52
|
+
"# the attested commit, so `loam validate` in that repo can convict drift later; a pin",
|
|
53
|
+
"# identifies what was cited — it does not prove the claim true.",
|
|
54
|
+
]
|
|
55
|
+
: []),
|
|
56
|
+
"",
|
|
57
|
+
].join("\n");
|
|
58
|
+
// lineWidth 0: never fold a claim onto a second line — these are grepped and diffed.
|
|
59
|
+
return header + stringify(v, { lineWidth: 0 });
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../../src/core/verify/store/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAqB,MAAM,cAAc,CAAC;AAEjD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,CAAe;IAChD,MAAM,MAAM,GAAG;QACb,6BAA6B,CAAC,CAAC,OAAO,+BAA+B,CAAC,CAAC,OAAO,iDAAiD;QAC/H,GAAG;QACH,iFAAiF;QACjF,gFAAgF;QAChF,mFAAmF;QACnF,mFAAmF;QACnF,qFAAqF;QACrF,qFAAqF;QACrF,kFAAkF;QAClF,mFAAmF;QACnF,4CAA4C;QAC5C,GAAG;QACH,8EAA8E;QAC9E,8EAA8E;QAC9E,kFAAkF;QAClF,kFAAkF;QAClF,2BAA2B;QAC3B,GAAG;QACH,uFAAuF;QACvF,iFAAiF;QACjF,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC;YAChB,CAAC,CAAC;gBACE,GAAG;gBACH,sFAAsF;gBACtF,wFAAwF;gBACxF,qFAAqF;gBACrF,kFAAkF;gBAClF,iEAAiE;gBACjE,uFAAuF;gBACvF,uFAAuF;gBACvF,iEAAiE;aAClE;YACH,CAAC,CAAC,EAAE,CAAC;QACP,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,qFAAqF;IACrF,OAAO,MAAM,GAAG,SAAS,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;AACjD,CAAC","sourcesContent":["/**\n * The record as bytes: the header and the YAML that `store/commit.ts` swaps\n * into place. Moved here from `../file.ts` when the contract-report validation\n * pushed that module over the line limit — and the seam is real, not\n * arithmetic: reading was never the inverse of rendering (a record is\n * re-graded on the way in, because anything may have edited it since), so the\n * two were cohabiting rather than forming a codec, while the RENDER and the\n * COMMIT genuinely are one concern — this module produces exactly the bytes\n * whose atomic swap that one performs. The reading went on to a package of its\n * own, `../read/` (`file.ts` finds and grades the files, `shape.ts` says what a\n * file must hold, `union.ts` adds the files up), and `../read/file.ts`'s header\n * says where the render went.\n */\nimport { stringify } from \"yaml\";\nimport { type Verification } from \"../record.js\";\n\n/**\n * The record as a file. The header explains what the reader is looking at,\n * because the whole point is that this is legible to someone who has never run\n * loam — including the part loam cannot vouch for.\n */\nexport function renderVerification(v: Verification): string {\n const header = [\n `# Verification record for ${v.feature} — written by \\`loam verify ${v.feature}\\` (--results / --contract-results / --record).`,\n \"#\",\n \"# Every claim below was derived mechanically from this feature's own artifacts:\",\n \"# delta.likec4, specs/<svc>/spec.md, specs/<svc>/arch.spec.md and specs/<svc>/\",\n \"# openapi.yaml. Each verdict names who answered it: `answered_by: runner` means a\",\n \"# test report's digest-tagged scenarios answered it mechanically — cucumber JSON,\",\n \"# or loam's own {\\\"loamScenarioReport\\\": 1, ...} shape that any runner adapts into;\",\n \"# `answered_by: external-runner` means a contract-test report's operationId-matched\",\n \"# entries did, and `contractReport:` records which file a --contract-results run\",\n \"# read; `answered_by: agent` means somebody's word about the code, which loam did\",\n \"# not check. Nothing gates on any of them.\",\n \"#\",\n \"# A `scenario.tested` claim confirmed by an agent is ATTESTED, not run: loam\",\n \"# reports it as `verify.scenario-attested` and the feature does not count as\",\n \"# verified until a report answers it. `report:` records the file a --results run\",\n \"# read — its sha256 and mtime say WHICH file, not that it came from that commit;\",\n \"# no digest can say that.\",\n \"#\",\n \"# `checklist` is a digest of the claim ids. If `loam verify` stops reporting the same\",\n \"# one, the feature changed after this was recorded and these answers are stale.\",\n ...(v.schema === 2\n ? [\n \"#\",\n \"# Schema 2 is federated: each service entry under `attestations` binds its claim ids\",\n \"# and file:line evidence to that repository's git commit. Each attesting service has a\",\n \"# file of its own, verification/<svc>.yaml, and the record is the directory: claims\",\n \"# another service owns are honestly unanswered in this file and answered in that\",\n \"# service's own, and loam adds the files up when it reads them.\",\n \"# `evidence_pins` records each cited file's sha256 (CRLF-normalized) and line text at\",\n \"# the attested commit, so `loam validate` in that repo can convict drift later; a pin\",\n \"# identifies what was cited — it does not prove the claim true.\",\n ]\n : []),\n \"\",\n ].join(\"\\n\");\n // lineWidth 0: never fold a claim onto a second line — these are grepped and diffed.\n return header + stringify(v, { lineWidth: 0 });\n}\n"]}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The minimal reader for `services/<svc>/health.yaml` — the moment that file
|
|
3
|
+
* stops being inert. loam reads exactly one KIND of thing out of it: ids. The
|
|
4
|
+
* alert and SLI ids, so the architecture spec axis can ask whether a
|
|
5
|
+
* requirement covers each one (`health.uncovered`); and the dependency ids,
|
|
6
|
+
* so the same axis can weigh and reconcile them against the service's own
|
|
7
|
+
* model — otherwise the file an on-call engineer reaches for first is free text
|
|
8
|
+
* as far as validation is concerned and can hold false operational claims under
|
|
9
|
+
* a green result. Queries, thresholds, checks, criticality — everything else
|
|
10
|
+
* stays authored prose that no check reads, the same stance `operationIds`
|
|
11
|
+
* takes on OpenAPI schemas.
|
|
12
|
+
*
|
|
13
|
+
* The recognized keys (documented in SCHEMA.md, and deliberately few):
|
|
14
|
+
*
|
|
15
|
+
* slis: a YAML sequence; each entry contributes its `name` (or `id`
|
|
16
|
+
* alerts: when there is no name), and a plain string entry is its own id.
|
|
17
|
+
* dependencies: a YAML sequence; each entry contributes its `id` (or
|
|
18
|
+
* `service`, or `name` — accepted inputs use all three forms),
|
|
19
|
+
* and a plain string entry is its own id.
|
|
20
|
+
*
|
|
21
|
+
* Tolerant about absence, honest about breakage: a health.yaml that is missing
|
|
22
|
+
* or declares nothing recognizable yields an empty set — and an empty set
|
|
23
|
+
* produces no findings, because an absent file must not manufacture
|
|
24
|
+
* obligations. A file that EXISTS but cannot be read is different evidence:
|
|
25
|
+
* its ids are unknown, not empty, so the `unreadable` flag travels alongside
|
|
26
|
+
* (parsers never diagnose — validate grades it as `health.invalid`). The old
|
|
27
|
+
* silent empty set turned every `Covers: alert:/sli:` entry of that service
|
|
28
|
+
* into a false `covers.unknown` "typo", when the truth was this file.
|
|
29
|
+
*/
|
|
30
|
+
import { existsSync } from "node:fs";
|
|
31
|
+
import { readFile } from "node:fs/promises";
|
|
32
|
+
import { parse } from "yaml";
|
|
33
|
+
const NO_HEALTH_IDS = { slis: [], alerts: [] };
|
|
34
|
+
export async function readHealth(healthPath) {
|
|
35
|
+
if (!existsSync(healthPath))
|
|
36
|
+
return { ids: NO_HEALTH_IDS, dependencies: [], unreadable: false };
|
|
37
|
+
let doc;
|
|
38
|
+
try {
|
|
39
|
+
doc = parse(await readFile(healthPath, "utf8"));
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
return {
|
|
43
|
+
ids: NO_HEALTH_IDS,
|
|
44
|
+
dependencies: [],
|
|
45
|
+
unreadable: true,
|
|
46
|
+
error: e instanceof Error ? e.message : String(e),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// An empty file parses to null: it declares nothing, and says so honestly.
|
|
50
|
+
// A scalar or sequence document declares nothing READABLE — flag it.
|
|
51
|
+
if (doc === null)
|
|
52
|
+
return { ids: NO_HEALTH_IDS, dependencies: [], unreadable: false };
|
|
53
|
+
if (typeof doc !== "object" || Array.isArray(doc)) {
|
|
54
|
+
return { ids: NO_HEALTH_IDS, dependencies: [], unreadable: true, error: "document is not a YAML mapping" };
|
|
55
|
+
}
|
|
56
|
+
const top = doc;
|
|
57
|
+
return {
|
|
58
|
+
ids: { slis: idsOf(top["slis"], NAME_KEYS), alerts: idsOf(top["alerts"], NAME_KEYS) },
|
|
59
|
+
dependencies: idsOf(top["dependencies"], DEPENDENCY_KEYS),
|
|
60
|
+
unreadable: false,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** slis/alerts entries answer to `name` first — the key SCHEMA.md teaches. */
|
|
64
|
+
const NAME_KEYS = ["name", "id"];
|
|
65
|
+
/**
|
|
66
|
+
* Dependency entries answer to `id` first, because it is the explicit
|
|
67
|
+
* identity; `service` and `name` are the spellings found in the wild.
|
|
68
|
+
* Tolerance in reading is not vocabulary — SCHEMA.md still teaches one.
|
|
69
|
+
*/
|
|
70
|
+
const DEPENDENCY_KEYS = ["id", "service", "name"];
|
|
71
|
+
/** The ids one sequence declares — first recognized key wins, deduped, document order. */
|
|
72
|
+
function idsOf(section, keys) {
|
|
73
|
+
if (!Array.isArray(section))
|
|
74
|
+
return [];
|
|
75
|
+
const out = new Set();
|
|
76
|
+
for (const entry of section) {
|
|
77
|
+
if (typeof entry === "string") {
|
|
78
|
+
if (entry.trim().length > 0)
|
|
79
|
+
out.add(entry.trim());
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry))
|
|
83
|
+
continue;
|
|
84
|
+
const rec = entry;
|
|
85
|
+
const id = keys.map((k) => rec[k]).find((v) => typeof v === "string" && v.trim().length > 0);
|
|
86
|
+
if (typeof id === "string")
|
|
87
|
+
out.add(id.trim());
|
|
88
|
+
}
|
|
89
|
+
return [...out];
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../../src/core/vocabulary/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAO7B,MAAM,aAAa,GAAc,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAa1D,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAkB;IACjD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,YAAY,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IAChG,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,KAAK,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO;YACL,GAAG,EAAE,aAAa;YAClB,YAAY,EAAE,EAAE;YAChB,UAAU,EAAE,IAAI;YAChB,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;SAClD,CAAC;IACJ,CAAC;IACD,2EAA2E;IAC3E,qEAAqE;IACrE,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,YAAY,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACrF,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClD,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,YAAY,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC;IAC7G,CAAC;IACD,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,OAAO;QACL,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,EAAE;QACrF,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,eAAe,CAAC;QACzD,UAAU,EAAE,KAAK;KAClB,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,IAAI,CAAU,CAAC;AAC1C;;;;GAIG;AACH,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,CAAU,CAAC;AAE3D,0FAA0F;AAC1F,SAAS,KAAK,CAAC,OAAgB,EAAE,IAAuB;IACtD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IACvC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;gBAAE,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YACnD,SAAS;QACX,CAAC;QACD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,SAAS;QAClF,MAAM,GAAG,GAAG,KAAgC,CAAC;QAC7C,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC7F,IAAI,OAAO,EAAE,KAAK,QAAQ;YAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;AAClB,CAAC","sourcesContent":["/**\n * The minimal reader for `services/<svc>/health.yaml` — the moment that file\n * stops being inert. loam reads exactly one KIND of thing out of it: ids. The\n * alert and SLI ids, so the architecture spec axis can ask whether a\n * requirement covers each one (`health.uncovered`); and the dependency ids,\n * so the same axis can weigh and reconcile them against the service's own\n * model — otherwise the file an on-call engineer reaches for first is free text\n * as far as validation is concerned and can hold false operational claims under\n * a green result. Queries, thresholds, checks, criticality — everything else\n * stays authored prose that no check reads, the same stance `operationIds`\n * takes on OpenAPI schemas.\n *\n * The recognized keys (documented in SCHEMA.md, and deliberately few):\n *\n * slis: a YAML sequence; each entry contributes its `name` (or `id`\n * alerts: when there is no name), and a plain string entry is its own id.\n * dependencies: a YAML sequence; each entry contributes its `id` (or\n * `service`, or `name` — accepted inputs use all three forms),\n * and a plain string entry is its own id.\n *\n * Tolerant about absence, honest about breakage: a health.yaml that is missing\n * or declares nothing recognizable yields an empty set — and an empty set\n * produces no findings, because an absent file must not manufacture\n * obligations. A file that EXISTS but cannot be read is different evidence:\n * its ids are unknown, not empty, so the `unreadable` flag travels alongside\n * (parsers never diagnose — validate grades it as `health.invalid`). The old\n * silent empty set turned every `Covers: alert:/sli:` entry of that service\n * into a false `covers.unknown` \"typo\", when the truth was this file.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { parse } from \"yaml\";\n\nexport interface HealthIds {\n slis: string[];\n alerts: string[];\n}\n\nconst NO_HEALTH_IDS: HealthIds = { slis: [], alerts: [] };\n\n/** The read of one health.yaml: its declared ids, and whether the file could be read at all. */\nexport interface HealthFile {\n ids: HealthIds;\n /** Ids of the `dependencies:` entries — empty when the file is missing, empty, or unreadable. */\n dependencies: string[];\n /** True when the file exists but is not a readable YAML mapping. Missing and empty files read as empty, not broken. */\n unreadable: boolean;\n /** The parser's own message, when there is one to quote back. */\n error?: string;\n}\n\nexport async function readHealth(healthPath: string): Promise<HealthFile> {\n if (!existsSync(healthPath)) return { ids: NO_HEALTH_IDS, dependencies: [], unreadable: false };\n let doc: unknown;\n try {\n doc = parse(await readFile(healthPath, \"utf8\"));\n } catch (e) {\n return {\n ids: NO_HEALTH_IDS,\n dependencies: [],\n unreadable: true,\n error: e instanceof Error ? e.message : String(e),\n };\n }\n // An empty file parses to null: it declares nothing, and says so honestly.\n // A scalar or sequence document declares nothing READABLE — flag it.\n if (doc === null) return { ids: NO_HEALTH_IDS, dependencies: [], unreadable: false };\n if (typeof doc !== \"object\" || Array.isArray(doc)) {\n return { ids: NO_HEALTH_IDS, dependencies: [], unreadable: true, error: \"document is not a YAML mapping\" };\n }\n const top = doc as Record<string, unknown>;\n return {\n ids: { slis: idsOf(top[\"slis\"], NAME_KEYS), alerts: idsOf(top[\"alerts\"], NAME_KEYS) },\n dependencies: idsOf(top[\"dependencies\"], DEPENDENCY_KEYS),\n unreadable: false,\n };\n}\n\n/** slis/alerts entries answer to `name` first — the key SCHEMA.md teaches. */\nconst NAME_KEYS = [\"name\", \"id\"] as const;\n/**\n * Dependency entries answer to `id` first, because it is the explicit\n * identity; `service` and `name` are the spellings found in the wild.\n * Tolerance in reading is not vocabulary — SCHEMA.md still teaches one.\n */\nconst DEPENDENCY_KEYS = [\"id\", \"service\", \"name\"] as const;\n\n/** The ids one sequence declares — first recognized key wins, deduped, document order. */\nfunction idsOf(section: unknown, keys: readonly string[]): string[] {\n if (!Array.isArray(section)) return [];\n const out = new Set<string>();\n for (const entry of section) {\n if (typeof entry === \"string\") {\n if (entry.trim().length > 0) out.add(entry.trim());\n continue;\n }\n if (entry === null || typeof entry !== \"object\" || Array.isArray(entry)) continue;\n const rec = entry as Record<string, unknown>;\n const id = keys.map((k) => rec[k]).find((v) => typeof v === \"string\" && v.trim().length > 0);\n if (typeof id === \"string\") out.add(id.trim());\n }\n return [...out];\n}\n"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A coherence breach: something that makes a feature unsafe to merge into the
|
|
3
|
+
* living docs. Shared by every check the archive gate runs.
|
|
4
|
+
*/
|
|
5
|
+
/** Whether `loam archive` refuses on this issue without `--approve`. */
|
|
6
|
+
export function gatesArchive(i) {
|
|
7
|
+
return i.gates ?? i.severity === "error";
|
|
8
|
+
}
|
|
9
|
+
/** One issue in the shared validation/status finding shape. */
|
|
10
|
+
export function issueFinding(i) {
|
|
11
|
+
return {
|
|
12
|
+
severity: i.severity,
|
|
13
|
+
code: i.code,
|
|
14
|
+
gates: gatesArchive(i),
|
|
15
|
+
...(i.subject === undefined ? {} : { subject: i.subject }),
|
|
16
|
+
...(i.locations === undefined ? {} : { locations: i.locations }),
|
|
17
|
+
...(i.details === undefined ? {} : { details: i.details }),
|
|
18
|
+
message: i.message,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Whether `--approve` can move this issue when it gates. A third axis beside
|
|
23
|
+
* severity and gating: severity answers "is the DOCUMENT valid", gating
|
|
24
|
+
* answers "is the MERGE safe", and this one answers whose call the refusal is
|
|
25
|
+
* — a human's or the grammar's. Almost every gating issue is a judgment about
|
|
26
|
+
* the feature, which is exactly the judgment `--approve` exists to override.
|
|
27
|
+
*
|
|
28
|
+
* The exceptions are the ones where approval could not change what happens.
|
|
29
|
+
* `c4.service-binding-invalid`: the binding IS the path the merge would write,
|
|
30
|
+
* so the fix is the name, never the flag. `glossary.term-exists`: the merge is
|
|
31
|
+
* a whole-file copy over an authored definition, so approving it is approving a
|
|
32
|
+
* deletion nobody described — and the alternative the message names (edit the
|
|
33
|
+
* living definition in the same change) costs one `git mv` and loses nothing.
|
|
34
|
+
* `usecase.flow-exists` is the same act one axis over: the merge would copy a
|
|
35
|
+
* feature's flow over a living one, and an ordered hop sequence is recorded
|
|
36
|
+
* nowhere else either. `usecase.flow-invalid` is the other kind of exception —
|
|
37
|
+
* not a deletion but a BLINDNESS: loam could not read the feature's flows
|
|
38
|
+
* against the map its own merge would leave, so it graded nothing, and
|
|
39
|
+
* `--approve` overrides loam's judgment about coherence and never its ability
|
|
40
|
+
* to read an axis. That is the same line `delta.likec4`'s unparseable case is
|
|
41
|
+
* refused on, one merge over.
|
|
42
|
+
*
|
|
43
|
+
* `archive` refuses these under the same `not-coherent` envelope and spells
|
|
44
|
+
* this verdict per issue as the additive `overridable` key, so a `--json`
|
|
45
|
+
* consumer branches on data rather than on a code list.
|
|
46
|
+
*/
|
|
47
|
+
const NEVER_OVERRIDABLE = new Set([
|
|
48
|
+
"c4.service-binding-invalid",
|
|
49
|
+
"glossary.term-exists",
|
|
50
|
+
"usecase.flow-exists",
|
|
51
|
+
"deployment.doc-exists",
|
|
52
|
+
"deployment.doc-invalid",
|
|
53
|
+
"deployment.doc-reserved",
|
|
54
|
+
"usecase.flow-invalid",
|
|
55
|
+
]);
|
|
56
|
+
export function approveOverrides(i) {
|
|
57
|
+
return !NEVER_OVERRIDABLE.has(i.code);
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=issue.js.map
|