@ybotok/loam 0.1.0-beta.2 → 0.2.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2570 -61
- package/COMPARISON.md +80 -63
- package/CONTRIBUTING.md +84 -0
- package/MIGRATING-from-OpenSpec.md +213 -54
- package/QUICKSTART.md +125 -0
- package/README.md +450 -150
- package/ROADMAP.md +494 -0
- package/SCHEMA.md +2362 -245
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +701 -0
- package/dist/cli.js +113 -19
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +209 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +268 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +77 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +159 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +317 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +161 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +111 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +237 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +27 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +251 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/context/context.js +99 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +283 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +279 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +205 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +9 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +93 -0
- package/dist/commands/diff/diff.js.map +1 -0
- package/dist/commands/diff/print.js +38 -0
- package/dist/commands/diff/print.js.map +1 -0
- package/dist/commands/doctor.js +5 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +151 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +29 -24
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +115 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +54 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +146 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +246 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +149 -0
- package/dist/commands/gherkin/reconcile.js.map +1 -0
- package/dist/commands/gherkin/render.js +77 -0
- package/dist/commands/gherkin/render.js.map +1 -0
- package/dist/commands/init/example.js +204 -0
- package/dist/commands/init/example.js.map +1 -0
- package/dist/commands/init/first-hour.js +28 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +146 -71
- package/dist/commands/init/init.js.map +1 -0
- package/dist/commands/init/mcp.js +131 -0
- package/dist/commands/init/mcp.js.map +1 -0
- package/dist/commands/init/options.js +78 -0
- package/dist/commands/init/options.js.map +1 -0
- package/dist/commands/instructions.js +82 -14
- package/dist/commands/instructions.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +65 -0
- package/dist/commands/list/campaign/campaign.js.map +1 -0
- package/dist/commands/list/campaign/owners.js +65 -0
- package/dist/commands/list/campaign/owners.js.map +1 -0
- package/dist/commands/list/json.js +157 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +343 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +301 -0
- package/dist/commands/list/print.js.map +1 -0
- package/dist/commands/list/review.js +120 -0
- package/dist/commands/list/review.js.map +1 -0
- package/dist/commands/list/views.js +105 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +183 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +34 -0
- package/dist/commands/mcp/mcp.js.map +1 -0
- package/dist/commands/mcp/serve.js +55 -0
- package/dist/commands/mcp/serve.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/active.js +170 -0
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
- package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/living.js +62 -0
- package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/target.js +219 -0
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +19 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/read.js +49 -0
- package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
- package/dist/commands/migrate-openspec/print.js +89 -0
- package/dist/commands/migrate-openspec/print.js.map +1 -0
- package/dist/commands/new/commit.js +76 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/new.js +283 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +355 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +203 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/policy/format.js +152 -0
- package/dist/commands/policy/format.js.map +1 -0
- package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
- package/dist/commands/policy/gate.js.map +1 -0
- package/dist/commands/rebase/edit.js +106 -0
- package/dist/commands/rebase/edit.js.map +1 -0
- package/dist/commands/rebase/living.js +185 -0
- package/dist/commands/rebase/living.js.map +1 -0
- package/dist/commands/rebase/plan.js +245 -0
- package/dist/commands/rebase/plan.js.map +1 -0
- package/dist/commands/rebase/rebase.js +275 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +192 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +133 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +172 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +178 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/marks.js +24 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/{show.js → show/service.js} +63 -152
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +77 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/json.js +45 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +157 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +119 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +189 -0
- package/dist/commands/steps/steps.js.map +1 -0
- package/dist/commands/subsystem/edit.js +192 -0
- package/dist/commands/subsystem/edit.js.map +1 -0
- package/dist/commands/subsystem/move.js +265 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +115 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +101 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +103 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +94 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +70 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +160 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +67 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +194 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +296 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +55 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +254 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +76 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/checks/vocabulary.js +31 -0
- package/dist/commands/validate/checks/vocabulary.js.map +1 -0
- package/dist/commands/validate/feature.js +216 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +69 -0
- package/dist/commands/validate/fleet/census.js.map +1 -0
- package/dist/commands/validate/fleet/kind-tags.js +39 -0
- package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
- package/dist/commands/validate/fleet/landscape.js +353 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +52 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +236 -0
- package/dist/commands/validate/fleet/obligations.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/print.js +63 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/place.js +13 -0
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/steps.js +197 -0
- package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
- package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +40 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +59 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +92 -0
- package/dist/commands/validate/links/corpus.js.map +1 -0
- package/dist/commands/validate/links/glossary.js +75 -0
- package/dist/commands/validate/links/glossary.js.map +1 -0
- package/dist/commands/validate/report.js +269 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/service/api.js +338 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +219 -0
- package/dist/commands/validate/service/events/events.js.map +1 -0
- package/dist/commands/validate/service/events/message-producers.js +77 -0
- package/dist/commands/validate/service/events/message-producers.js.map +1 -0
- package/dist/commands/validate/service/evidence-pins.js +131 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/service.js +250 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +219 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +113 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/validate.js +338 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +182 -0
- package/dist/commands/verify/cross/diff.js.map +1 -0
- package/dist/commands/verify/evidence/contract.js +32 -0
- package/dist/commands/verify/evidence/contract.js.map +1 -0
- package/dist/commands/verify/evidence/pins.js +52 -0
- package/dist/commands/verify/evidence/pins.js.map +1 -0
- package/dist/commands/verify/evidence/read.js +72 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +241 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +226 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +223 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +246 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +217 -0
- package/dist/commands/verify/verify.js.map +1 -0
- package/dist/commands/vouch/contract.js +11 -0
- package/dist/commands/vouch/contract.js.map +1 -0
- package/dist/commands/vouch/pack/contract.js +2 -0
- package/dist/commands/vouch/pack/contract.js.map +1 -0
- package/dist/commands/vouch/pack/pack.js +266 -0
- package/dist/commands/vouch/pack/pack.js.map +1 -0
- package/dist/commands/vouch/pack/print.js +271 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +142 -0
- package/dist/commands/vouch/pack/sections.js.map +1 -0
- package/dist/commands/vouch/prompt/confirm.js +46 -0
- package/dist/commands/vouch/prompt/confirm.js.map +1 -0
- package/dist/commands/vouch/report.js +101 -0
- package/dist/commands/vouch/report.js.map +1 -0
- package/dist/commands/vouch/run.js +285 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +125 -0
- package/dist/commands/vouch/sample/plan.js.map +1 -0
- package/dist/commands/vouch/sample/print.js +109 -0
- package/dist/commands/vouch/sample/print.js.map +1 -0
- package/dist/commands/vouch/vet/verify.js +123 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +176 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/artifacts.js +220 -0
- package/dist/core/agent/agents-md/artifacts.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +324 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/cycle.js +165 -0
- package/dist/core/agent/agents-md/cycle.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +34 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +41 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +62 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +32 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +60 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +246 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
- package/dist/core/agent/agents-md/spine.js +40 -0
- package/dist/core/agent/agents-md/spine.js.map +1 -0
- package/dist/core/agent/agents-md.js +170 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/agent/agents-stamp.js +155 -0
- package/dist/core/agent/agents-stamp.js.map +1 -0
- package/dist/core/agent/contract.js +2 -0
- package/dist/core/agent/contract.js.map +1 -0
- package/dist/core/agent/protocol.js +193 -0
- package/dist/core/agent/protocol.js.map +1 -0
- package/dist/core/agent/scaffold.js +259 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +103 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +150 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +228 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +133 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +334 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +262 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +105 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +105 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +209 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +65 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +188 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +16 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +297 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +110 -0
- package/dist/core/asyncapi/baseline/plan.js.map +1 -0
- package/dist/core/asyncapi/baseline/surfaces.js +54 -0
- package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
- package/dist/core/asyncapi/depth.js +164 -0
- package/dist/core/asyncapi/depth.js.map +1 -0
- package/dist/core/asyncapi/digest.js +141 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +91 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +33 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +308 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +215 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +107 -0
- package/dist/core/asyncapi/merge/pin.js.map +1 -0
- package/dist/core/asyncapi/model.js +11 -0
- package/dist/core/asyncapi/model.js.map +1 -0
- package/dist/core/asyncapi/producers.js +50 -0
- package/dist/core/asyncapi/producers.js.map +1 -0
- package/dist/core/asyncapi/read.js +239 -0
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +225 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +250 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +194 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/targets.js +226 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +47 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +282 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/likec4.js +88 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +57 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +75 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/project/architecture.js +45 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/documents.js +58 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +183 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/resolve/service.js +113 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/seed/fleet-file.js +201 -0
- package/dist/core/c4/seed/fleet-file.js.map +1 -0
- package/dist/core/c4/seed/items.js +91 -0
- package/dist/core/c4/seed/items.js.map +1 -0
- package/dist/core/c4/seed/stamp.js +48 -0
- package/dist/core/c4/seed/stamp.js.map +1 -0
- package/dist/core/c4/seed/template.js +109 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/source-mask.js +82 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +227 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +101 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +10 -0
- package/dist/core/c4/splice/contract.js.map +1 -0
- package/dist/core/c4/splice/delta-blocks.js +126 -0
- package/dist/core/c4/splice/delta-blocks.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +36 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +269 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +194 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/workspace.js +172 -0
- package/dist/core/c4/workspace.js.map +1 -0
- package/dist/core/capabilities/authoring/notes.js +141 -0
- package/dist/core/capabilities/authoring/notes.js.map +1 -0
- package/dist/core/capabilities/capabilities.js +124 -0
- package/dist/core/capabilities/capabilities.js.map +1 -0
- package/dist/core/capabilities/delta/doc.js +50 -0
- package/dist/core/capabilities/delta/doc.js.map +1 -0
- package/dist/core/capabilities/delta/overlay.js +129 -0
- package/dist/core/capabilities/delta/overlay.js.map +1 -0
- package/dist/core/capabilities/delta/summary.js +57 -0
- package/dist/core/capabilities/delta/summary.js.map +1 -0
- package/dist/core/capabilities/delta/tree.js +43 -0
- package/dist/core/capabilities/delta/tree.js.map +1 -0
- package/dist/core/capabilities/delta/uncovered.js +222 -0
- package/dist/core/capabilities/delta/uncovered.js.map +1 -0
- package/dist/core/capabilities/findings.js +342 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +181 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +143 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +199 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +126 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +277 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +177 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +74 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/coherence.js +251 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/declared.js +269 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +206 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +204 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +166 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +122 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/merged.js +40 -0
- package/dist/core/coherence/events/merged.js.map +1 -0
- package/dist/core/coherence/living.js +198 -0
- package/dist/core/coherence/living.js.map +1 -0
- package/dist/core/coherence/lookups.js +155 -0
- package/dist/core/coherence/lookups.js.map +1 -0
- package/dist/core/coherence/pending.js +39 -0
- package/dist/core/coherence/pending.js.map +1 -0
- package/dist/core/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.js.map +1 -0
- package/dist/core/delta/claims.js +73 -0
- package/dist/core/delta/claims.js.map +1 -0
- package/dist/core/delta/delta.js +296 -0
- package/dist/core/delta/delta.js.map +1 -0
- package/dist/core/delta/document.js +177 -0
- package/dist/core/delta/document.js.map +1 -0
- package/dist/core/delta/scope.js +48 -0
- package/dist/core/delta/scope.js.map +1 -0
- package/dist/core/delta/select.js +237 -0
- package/dist/core/delta/select.js.map +1 -0
- package/dist/core/dependencies/dependencies.js +141 -0
- package/dist/core/dependencies/dependencies.js.map +1 -0
- package/dist/core/dependencies/facts.js +165 -0
- package/dist/core/dependencies/facts.js.map +1 -0
- package/dist/core/dependencies/fanin.js +88 -0
- package/dist/core/dependencies/fanin.js.map +1 -0
- package/dist/core/dependencies/graph.js +106 -0
- package/dist/core/dependencies/graph.js.map +1 -0
- package/dist/core/diff/base-git.js +148 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +209 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/current-state.js +96 -0
- package/dist/core/diff/current-state.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +188 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/semantic.js +243 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/diff/victims.js +247 -0
- package/dist/core/diff/victims.js.map +1 -0
- package/dist/core/docs.js +59 -55
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +222 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +135 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +275 -0
- package/dist/core/doctor/doctor.js.map +1 -0
- package/dist/core/doctor/report.js +13 -0
- package/dist/core/doctor/report.js.map +1 -0
- package/dist/core/doctor/residue.js +110 -0
- package/dist/core/doctor/residue.js.map +1 -0
- package/dist/core/document/apply.js +77 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
- package/dist/core/document/frontmatter.js.map +1 -0
- package/dist/core/document/grammar/directives.js +143 -0
- package/dist/core/document/grammar/directives.js.map +1 -0
- package/dist/core/document/parse.js +263 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +221 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +241 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +79 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +175 -0
- package/dist/core/envelope/json.js.map +1 -0
- package/dist/core/{version.js → envelope/version.js} +3 -3
- package/dist/core/envelope/version.js.map +1 -0
- package/dist/core/explain/families.js +175 -0
- package/dist/core/explain/families.js.map +1 -0
- package/dist/core/explain/fix-tables.js +178 -0
- package/dist/core/explain/fix-tables.js.map +1 -0
- package/dist/core/explain/lookup.js +181 -0
- package/dist/core/explain/lookup.js.map +1 -0
- package/dist/core/explain/refusals.js +49 -0
- package/dist/core/explain/refusals.js.map +1 -0
- package/dist/core/explain/terms.js +144 -0
- package/dist/core/explain/terms.js.map +1 -0
- package/dist/core/explore/describe.js +105 -0
- package/dist/core/explore/describe.js.map +1 -0
- package/dist/core/{explore.js → explore/explore.js} +50 -101
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +132 -77
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +201 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +205 -0
- package/dist/core/gate/partners.js.map +1 -0
- package/dist/core/gate/report.js +47 -0
- package/dist/core/gate/report.js.map +1 -0
- package/dist/core/gate/verification.js +113 -0
- package/dist/core/gate/verification.js.map +1 -0
- package/dist/core/gherkin/digest.js +60 -0
- package/dist/core/gherkin/digest.js.map +1 -0
- package/dist/core/gherkin/emit.js +177 -0
- package/dist/core/gherkin/emit.js.map +1 -0
- package/dist/core/gherkin/read.js +76 -0
- package/dist/core/gherkin/read.js.map +1 -0
- package/dist/core/gherkin/stale.js +234 -0
- package/dist/core/gherkin/stale.js.map +1 -0
- package/dist/core/gherkin/stamp.js +77 -0
- package/dist/core/gherkin/stamp.js.map +1 -0
- package/dist/core/gherkin/steps/catalogue.js +154 -0
- package/dist/core/gherkin/steps/catalogue.js.map +1 -0
- package/dist/core/gherkin/steps/inventory.js +98 -0
- package/dist/core/gherkin/steps/inventory.js.map +1 -0
- package/dist/core/gherkin/steps/phrase.js +72 -0
- package/dist/core/gherkin/steps/phrase.js.map +1 -0
- package/dist/core/glossary/delta.js +106 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +86 -0
- package/dist/core/glossary/tree.js.map +1 -0
- package/dist/core/kernel/concurrency.js.map +1 -0
- package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
- package/dist/core/kernel/document-bytes.js.map +1 -0
- package/dist/core/kernel/fences.js +42 -0
- package/dist/core/kernel/fences.js.map +1 -0
- package/dist/core/kernel/ids/capability.js +72 -0
- package/dist/core/kernel/ids/capability.js.map +1 -0
- package/dist/core/kernel/ids/dirs.js +33 -0
- package/dist/core/kernel/ids/dirs.js.map +1 -0
- package/dist/core/kernel/ids/feature.js +75 -0
- package/dist/core/kernel/ids/feature.js.map +1 -0
- package/dist/core/kernel/ids/service.js +156 -0
- package/dist/core/kernel/ids/service.js.map +1 -0
- package/dist/core/kernel/ids/subsystem.js +63 -0
- package/dist/core/kernel/ids/subsystem.js.map +1 -0
- package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +68 -0
- package/dist/core/links/backlinks.js.map +1 -0
- package/dist/core/links/case.js +74 -0
- package/dist/core/links/case.js.map +1 -0
- package/dist/core/links/corpus.js +104 -0
- package/dist/core/links/corpus.js.map +1 -0
- package/dist/core/links/findings.js +110 -0
- package/dist/core/links/findings.js.map +1 -0
- package/dist/core/links/parse.js +236 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +111 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +72 -0
- package/dist/core/mcp/author-tools.js.map +1 -0
- package/dist/core/mcp/framing.js +46 -0
- package/dist/core/mcp/framing.js.map +1 -0
- package/dist/core/mcp/protocol.js +280 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/tools.js +314 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/obligations/obligations.js +106 -0
- package/dist/core/obligations/obligations.js.map +1 -0
- package/dist/core/openapi/baseline/gate.js +166 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +112 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +175 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/depth.js +122 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +189 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +44 -106
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +234 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +26 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +208 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +256 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +128 -0
- package/dist/core/openapi/merge/pin.js.map +1 -0
- package/dist/core/openspec/decide/capabilities.js +244 -0
- package/dist/core/openspec/decide/capabilities.js.map +1 -0
- package/dist/core/openspec/decide/dispositions.js +63 -0
- package/dist/core/openspec/decide/dispositions.js.map +1 -0
- package/dist/core/openspec/decide/renames.js +179 -0
- package/dist/core/openspec/decide/renames.js.map +1 -0
- package/dist/core/openspec/decide/verdict.js +84 -0
- package/dist/core/openspec/decide/verdict.js.map +1 -0
- package/dist/core/openspec/inventory.js +221 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +76 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +65 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +235 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +200 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +260 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +133 -0
- package/dist/core/openspec/scan/walk.js.map +1 -0
- package/dist/core/openspec/scan/workspace.js +71 -0
- package/dist/core/openspec/scan/workspace.js.map +1 -0
- package/dist/core/owners/codeowners.js +141 -0
- package/dist/core/owners/codeowners.js.map +1 -0
- package/dist/core/pack/features.js +120 -0
- package/dist/core/pack/features.js.map +1 -0
- package/dist/core/pack/joins.js +112 -0
- package/dist/core/pack/joins.js.map +1 -0
- package/dist/core/pack/living.js +118 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +76 -0
- package/dist/core/pack/pack.js.map +1 -0
- package/dist/core/permissions/permissions.js +87 -0
- package/dist/core/permissions/permissions.js.map +1 -0
- package/dist/core/projection/api.js +84 -0
- package/dist/core/projection/api.js.map +1 -0
- package/dist/core/projection/arch-slice.js +63 -0
- package/dist/core/projection/arch-slice.js.map +1 -0
- package/dist/core/projection/events.js +34 -0
- package/dist/core/projection/events.js.map +1 -0
- package/dist/core/provenance/findings.js +208 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +225 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +182 -0
- package/dist/core/provenance/gitq/moves.js.map +1 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
- package/dist/core/provenance/sample/scope.js +238 -0
- package/dist/core/provenance/sample/scope.js.map +1 -0
- package/dist/core/provenance/sample/sections.js +61 -0
- package/dist/core/provenance/sample/sections.js.map +1 -0
- package/dist/core/provenance/sources.js +263 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +232 -0
- package/dist/core/provenance/stamp.js.map +1 -0
- package/dist/core/provenance/walk.js +157 -0
- package/dist/core/provenance/walk.js.map +1 -0
- package/dist/core/repo/authored/paths.js +192 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +236 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +248 -0
- package/dist/core/repo/repo.js.map +1 -0
- package/dist/core/repo/service-target.js +153 -0
- package/dist/core/repo/service-target.js.map +1 -0
- package/dist/core/repo/state.js +58 -0
- package/dist/core/repo/state.js.map +1 -0
- package/dist/core/repo/tree/find.js +52 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +64 -0
- package/dist/core/repo/tree/fs.js.map +1 -0
- package/dist/core/repo/tree/marker.js +61 -0
- package/dist/core/repo/tree/marker.js.map +1 -0
- package/dist/core/repo/tree/views.js +172 -0
- package/dist/core/repo/tree/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +234 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +99 -2
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +131 -0
- package/dist/core/scaffold/landscape.js.map +1 -0
- package/dist/core/scaffold/readme.js +84 -0
- package/dist/core/scaffold/readme.js.map +1 -0
- package/dist/core/staging/commit.js +241 -0
- package/dist/core/staging/commit.js.map +1 -0
- package/dist/core/staging/interrupted.js +96 -0
- package/dist/core/staging/interrupted.js.map +1 -0
- package/dist/core/staging/lock.js +206 -0
- package/dist/core/staging/lock.js.map +1 -0
- package/dist/core/staging/recovery/finding.js +35 -0
- package/dist/core/staging/recovery/finding.js.map +1 -0
- package/dist/core/staging/recovery/intent.js +98 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +126 -0
- package/dist/core/staging/recovery/recover.js.map +1 -0
- package/dist/core/staging/recovery/residue.js +62 -0
- package/dist/core/staging/recovery/residue.js.map +1 -0
- package/dist/core/staging/snapshot.js +202 -0
- package/dist/core/staging/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +171 -0
- package/dist/core/staging/txn/forward.js.map +1 -0
- package/dist/core/staging/txn/journal.js +139 -0
- package/dist/core/staging/txn/journal.js.map +1 -0
- package/dist/core/staging/txn/transaction.js +75 -0
- package/dist/core/staging/txn/transaction.js.map +1 -0
- package/dist/core/staging/writes.js +113 -0
- package/dist/core/staging/writes.js.map +1 -0
- package/dist/core/status/actions/execution.js +49 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +102 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +171 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +207 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +150 -0
- package/dist/core/status/feature/next.js.map +1 -0
- package/dist/core/status/feature/state.js +21 -0
- package/dist/core/status/feature/state.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +187 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +207 -0
- package/dist/core/status/fleet/next.js.map +1 -0
- package/dist/core/status/interrupted.js +97 -0
- package/dist/core/status/interrupted.js.map +1 -0
- package/dist/core/status/report.js +31 -0
- package/dist/core/status/report.js.map +1 -0
- package/dist/core/status/scan.js +41 -0
- package/dist/core/status/scan.js.map +1 -0
- package/dist/core/status/verification.js +201 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/usecases/capability.js +169 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +116 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +103 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +235 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +137 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/operations.js +111 -0
- package/dist/core/usecases/operations.js.map +1 -0
- package/dist/core/usecases/place.js +44 -0
- package/dist/core/usecases/place.js.map +1 -0
- package/dist/core/usecases/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +173 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +150 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +201 -0
- package/dist/core/verify/checklist.js.map +1 -0
- package/dist/core/verify/claims/identity.js +61 -0
- package/dist/core/verify/claims/identity.js.map +1 -0
- package/dist/core/verify/cross/diff.js +97 -0
- package/dist/core/verify/cross/diff.js.map +1 -0
- package/dist/core/verify/evidence/contract.js +169 -0
- package/dist/core/verify/evidence/contract.js.map +1 -0
- package/dist/core/verify/file.js +257 -0
- package/dist/core/verify/file.js.map +1 -0
- package/dist/core/verify/pins/lint.js +157 -0
- package/dist/core/verify/pins/lint.js.map +1 -0
- package/dist/core/verify/pins/pin.js +95 -0
- package/dist/core/verify/pins/pin.js.map +1 -0
- package/dist/core/verify/record.js +142 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +89 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +57 -0
- package/dist/core/verify/store/render.js.map +1 -0
- package/dist/core/vocabulary/health.js +91 -0
- package/dist/core/vocabulary/health.js.map +1 -0
- package/dist/core/vocabulary/issue.js +55 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +145 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/{report.js → vocabulary/report.js} +30 -2
- package/dist/core/vocabulary/report.js.map +1 -0
- package/dist/core/vocabulary/steps.js +266 -0
- package/dist/core/vocabulary/steps.js.map +1 -0
- package/dist/core/workspace/discover.js +239 -0
- package/dist/core/workspace/discover.js.map +1 -0
- package/dist/core/workspace/render.js +52 -0
- package/dist/core/workspace/render.js.map +1 -0
- package/examples/README.md +189 -0
- package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
- package/examples/docs/architecture/capabilities.yaml +31 -0
- package/examples/docs/architecture/landscape.likec4 +280 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/subsystems.likec4 +11 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
- package/examples/docs/capabilities/checkout/spec.md +55 -0
- package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
- package/examples/docs/capabilities/order-notifications/spec.md +43 -0
- package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
- package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
- package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
- package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
- package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
- package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
- package/examples/docs/glossary/order.md +15 -0
- package/examples/docs/glossary/payments/authorization.md +14 -0
- package/examples/docs/likec4.config.json +9 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +109 -0
- package/examples/docs/services/checkout-web/spec.md +91 -0
- package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
- package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
- package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
- package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
- package/examples/docs/services/order-service/arch.spec.md +127 -0
- package/examples/docs/services/order-service/asyncapi.yaml +108 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +138 -0
- package/examples/docs/services/order-service/openapi.yaml +257 -0
- package/examples/docs/services/order-service/runbook.md +62 -0
- package/examples/docs/services/order-service/spec.md +134 -0
- package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
- package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
- package/examples/docs/services/payment-service/arch.spec.md +73 -0
- package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
- package/examples/docs/services/payment-service/health.yaml +39 -0
- package/examples/docs/services/payment-service/model.likec4 +67 -0
- package/examples/docs/services/payment-service/openapi.yaml +151 -0
- package/examples/docs/services/payment-service/runbook.md +37 -0
- package/examples/docs/services/payment-service/spec.md +88 -0
- package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
- package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
- package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
- package/examples/docs/services/platform/identity-service/runbook.md +95 -0
- package/examples/docs/services/platform/identity-service/spec.md +119 -0
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
- package/examples/docs/services/platform/notification-service/health.yaml +35 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
- package/examples/docs/services/platform/notification-service/runbook.md +48 -0
- package/examples/docs/services/platform/notification-service/spec.md +112 -0
- package/examples/docs/services/platform/subsystem.yaml +2 -0
- package/examples/fleet.yaml +57 -0
- package/package.json +19 -6
- package/dist/commands/adopt.js +0 -240
- package/dist/commands/adopt.js.map +0 -1
- package/dist/commands/archive.js +0 -1313
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/delta.js +0 -388
- package/dist/commands/delta.js.map +0 -1
- package/dist/commands/docs-repo-gate.js.map +0 -1
- package/dist/commands/format.js +0 -17
- package/dist/commands/format.js.map +0 -1
- package/dist/commands/gherkin.js +0 -309
- package/dist/commands/gherkin.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/list.js +0 -291
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/migrate-openspec.js +0 -950
- package/dist/commands/migrate-openspec.js.map +0 -1
- package/dist/commands/new.js +0 -413
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/rebase.js +0 -356
- package/dist/commands/rebase.js.map +0 -1
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/status.js +0 -254
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unarchive.js.map +0 -1
- package/dist/commands/validate.js +0 -1591
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/verify.js +0 -775
- package/dist/commands/verify.js.map +0 -1
- package/dist/commands/vouch.js +0 -343
- package/dist/commands/vouch.js.map +0 -1
- package/dist/core/agent.js +0 -2065
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agents-stamp.js +0 -68
- package/dist/core/agents-stamp.js.map +0 -1
- package/dist/core/arch.js +0 -130
- package/dist/core/arch.js.map +0 -1
- package/dist/core/brief.js +0 -733
- package/dist/core/brief.js.map +0 -1
- package/dist/core/coherence.js +0 -577
- package/dist/core/coherence.js.map +0 -1
- package/dist/core/concurrency.js.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/delta.js +0 -476
- package/dist/core/delta.js.map +0 -1
- package/dist/core/dependencies.js +0 -356
- package/dist/core/dependencies.js.map +0 -1
- package/dist/core/doctor.js +0 -559
- package/dist/core/doctor.js.map +0 -1
- package/dist/core/document-bytes.js.map +0 -1
- package/dist/core/explore.js.map +0 -1
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/gherkin.js +0 -463
- package/dist/core/gherkin.js.map +0 -1
- package/dist/core/health.js +0 -67
- package/dist/core/health.js.map +0 -1
- package/dist/core/ids.js +0 -122
- package/dist/core/ids.js.map +0 -1
- package/dist/core/issue.js +0 -9
- package/dist/core/issue.js.map +0 -1
- package/dist/core/json.js +0 -74
- package/dist/core/json.js.map +0 -1
- package/dist/core/likec4.js +0 -479
- package/dist/core/likec4.js.map +0 -1
- package/dist/core/maturity.js +0 -66
- package/dist/core/maturity.js.map +0 -1
- package/dist/core/openapi-merge.js +0 -552
- package/dist/core/openapi-merge.js.map +0 -1
- package/dist/core/openapi.js.map +0 -1
- package/dist/core/openspec-inventory.js +0 -1440
- package/dist/core/openspec-inventory.js.map +0 -1
- package/dist/core/path-safety.js.map +0 -1
- package/dist/core/provenance.js +0 -720
- package/dist/core/provenance.js.map +0 -1
- package/dist/core/records.js.map +0 -1
- package/dist/core/repo.js +0 -436
- package/dist/core/repo.js.map +0 -1
- package/dist/core/report.js.map +0 -1
- package/dist/core/spec.js +0 -481
- package/dist/core/spec.js.map +0 -1
- package/dist/core/staging.js +0 -890
- package/dist/core/staging.js.map +0 -1
- package/dist/core/status.js +0 -1104
- package/dist/core/status.js.map +0 -1
- package/dist/core/steps.js +0 -72
- package/dist/core/steps.js.map +0 -1
- package/dist/core/verify.js +0 -807
- package/dist/core/verify.js.map +0 -1
- package/dist/core/version.js.map +0 -1
- /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
- /package/dist/core/{records.js → kernel/records.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../../src/commands/verify/cross/diff.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `loam verify <FEAT> --diff-answers a.json b.json` — the command surface of\n * the cross-examination lens.\n *\n * A third read form beside the report and frozen views: it takes no lock,\n * needs no service binding, and writes nothing. The payload deliberately\n * carries NO `verified`, `verdict` or `attested` key — their absence is the\n * doctrine made structural (`core/verify/cross/diff.ts` holds the\n * reasoning): this surface ranks review, it grades nothing.\n *\n * Both files validate through the same `checkAnswers` the record path uses,\n * against the same scoped checklist, with `runnerOwned` unset: under a diff\n * both agents answer everything in scope, `scenario.tested` included — that\n * is the attested channel, and this command records nothing. If a future\n * wave ever makes scenario claims runner-only even without `--results`,\n * blind agents can no longer answer them and this command starts refusing;\n * `checkAnswers`' own `runnerOwned` note carries the same warning where that\n * editor will see it.\n */\nimport { createHash } from \"node:crypto\";\nimport { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { emitJson, fail, repoPath } from \"../../../core/envelope/json.js\";\nimport { isRecord } from \"../../../core/kernel/records.js\";\nimport { checkAnswers, type Answer, type AnswerRefusal } from \"../../../core/verify/answers.js\";\nimport { type Checklist, type Claim } from \"../../../core/verify/checklist.js\";\nimport { crossExamine, disjointNotice, type CrossAnswer } from \"../../../core/verify/cross/diff.js\";\nimport { plural } from \"../../policy/format.js\";\nimport { type VerifyTarget } from \"../report.js\";\n\n/**\n * The two files, named for the order they were given: `a` is the first and\n * every refusal about it says \"first answer set\". One record rather than two\n * loose strings because they are never asked about separately, and because a\n * transposed pair is exactly the mistake a positional form invites.\n */\nexport interface AnswerFiles {\n a: string;\n b: string;\n}\n\ntype SideRead =\n | { ok: true; answers: Answer[]; digest: string }\n | { ok: false; code: AnswerRefusal; message: string };\n\n/**\n * Everything a side is validated against: the lens-scoped claims, the whole\n * checklist behind them (what the honest off-lens diagnosis is written from),\n * and the lens itself. One record because the three are never asked about\n * separately — a scoped array without its checklist is how the false \"not on\n * the checklist\" diagnosis happened.\n */\ninterface DiffScope {\n scoped: Claim[];\n checklist: Checklist;\n lens?: string;\n}\n\n/**\n * The honest half of a lens-narrowed mismatch. `checkAnswers` is handed only\n * the scoped claims, so an answer naming another service's claim — which IS\n * on the feature's checklist — would otherwise be called \"not on the\n * checklist\": the same false diagnosis `runnerOwned` exists to prevent on the\n * recording path. When the stray ids are real claims the lens filtered out,\n * say that, and say what the lens narrowed.\n */\nfunction offLensNote(scope: DiffScope, raw: unknown): string {\n if (scope.lens === undefined) return \"\";\n const entries = Array.isArray(raw)\n ? raw\n : isRecord(raw) && Array.isArray(raw[\"answers\"])\n ? (raw[\"answers\"] as unknown[])\n : [];\n const scoped = new Set(scope.scoped.map((c) => c.id));\n const onChecklist = new Set(scope.checklist.claims.map((c) => c.id));\n const foreign = [\n ...new Set(\n entries\n .filter(isRecord)\n .map((entry) => entry[\"id\"])\n .filter((id): id is string => typeof id === \"string\" && onChecklist.has(id) && !scoped.has(id)),\n ),\n ];\n if (foreign.length === 0) return \"\";\n return (\n ` (${foreign.join(\", \")}: on the ${scope.checklist.feature} checklist but owned by another service — ` +\n `--service ${scope.lens} narrowed the comparison to ${scope.scoped.length} of ${scope.checklist.claims.length} claims)`\n );\n}\n\n/**\n * Read, digest and validate ONE answer set. Fail-closed on purpose at every\n * step: an unreadable or malformed file is a refusal naming which file and\n * why — never a silently empty side, which would grade as \"no disagreement\"\n * about claims nobody compared.\n */\nasync function readSide(scope: DiffScope, file: string, side: \"first\" | \"second\"): Promise<SideRead> {\n const label = `${side} answer set (${file})`;\n let bytes: Buffer;\n try {\n // cwd-relative deliberately — record.ts's reason for the same choice: the\n // answer sets are the caller's hand-offs, not repository artifacts, and\n // nothing on any record will ever point at them.\n bytes = await readFile(resolve(process.cwd(), file));\n } catch (err) {\n return {\n ok: false,\n code: \"answers-unreadable\",\n message: `${label}: cannot read: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n let raw: unknown;\n try {\n raw = JSON.parse(bytes.toString(\"utf8\"));\n } catch (err) {\n return {\n ok: false,\n code: \"answers-unreadable\",\n message: `${label}: not JSON: ${err instanceof Error ? err.message : String(err)}`,\n };\n }\n const context = { feature: scope.checklist.feature, ...(scope.lens === undefined ? {} : { service: scope.lens }) };\n const checked = checkAnswers(scope.scoped, raw, undefined, context);\n if (!checked.ok) {\n return { ok: false, code: checked.code, message: `${label}: ${checked.message}${offLensNote(scope, raw)}` };\n }\n // The digest is over the exact bytes read — the same reviewer-checkable\n // promise `reportLine` makes for consumed reports: `shasum -a 256 <file>`\n // answers whether the diff in hand read the file in hand.\n return { ok: true, answers: checked.answers, digest: createHash(\"sha256\").update(bytes).digest(\"hex\") };\n}\n\nfunction sideLine(answer: CrossAnswer): string {\n if (answer.verdict === \"confirmed\") return `confirmed (${answer.evidence.join(\", \")})`;\n return `unconfirmed${answer.note === undefined ? \"\" : ` — ${answer.note}`}`;\n}\n\nexport async function diffAnswers(\n target: VerifyTarget,\n checklist: Checklist,\n files: AnswerFiles,\n scope: { lens?: string },\n): Promise<void> {\n const { docsDir, featureDir, json } = target;\n const lens = scope.lens;\n // The same lens the read view applies (report.ts): the claims that\n // service's code answers, no repository binding asked for — a diff writes\n // nothing, so there is nothing to bind.\n const scoped = lens === undefined ? checklist.claims : checklist.claims.filter((c) => c.subject === lens);\n // record.ts's refusal, mirrored: a lens that owns nothing here is almost\n // always a typo'd service id, and validating two files against an empty\n // claim set would call every honest answer off-checklist instead of naming\n // the real mistake.\n if (lens !== undefined && scoped.length === 0) {\n return fail(\n json,\n \"unknown-service\",\n `The current ${checklist.feature} checklist has no claims owned by service '${lens}'.`,\n );\n }\n const diffScope: DiffScope = { scoped, checklist, ...(lens === undefined ? {} : { lens }) };\n\n // Sequential on purpose — a short-circuit, not a race: readSide never\n // rejects, but when the first file refuses, the second is never read or\n // parsed, so the refusal a caller sees always names the earliest problem\n // and no work is spent on a file whose sibling already failed the run.\n const a = await readSide(diffScope, files.a, \"first\");\n if (!a.ok) return fail(json, a.code, a.message);\n const b = await readSide(diffScope, files.b, \"second\");\n if (!b.ok) return fail(json, b.code, b.message);\n\n const cross = crossExamine(scoped, a.answers, b.answers);\n const notice = disjointNotice(cross.rows);\n\n if (json) {\n emitJson({\n command: \"verify\",\n feature: checklist.feature,\n path: repoPath(docsDir, featureDir),\n digest: checklist.digest,\n // Named only when narrowed — report.ts's rule: a consumer must never\n // mistake one service's cross-examination for the feature's.\n ...(lens === undefined ? {} : { service: lens, checklistClaims: checklist.claims.length }),\n files: {\n a: { path: files.a, digest: a.digest },\n b: { path: files.b, digest: b.digest },\n },\n summary: cross.summary,\n claims: cross.rows,\n disagreements: cross.disagreements,\n ...(notice === null ? {} : { notices: [notice] }),\n });\n return;\n }\n\n const scopeNote =\n lens === undefined ? \"\" : ` owned by ${lens} (of ${plural(checklist.claims.length, \"claim\")} on the checklist)`;\n console.log(\n `${checklist.feature} — cross-examination over ${plural(cross.rows.length, \"claim\")}${scopeNote} (${files.a} vs ${files.b})\\n`,\n );\n if (cross.rows.length === 0) {\n // Only the whole-checklist form can get here: a lens that owns nothing\n // refused `unknown-service` above.\n console.log(\" Nothing to cross-examine: this feature's delta, specs and openapi promise nothing yet.\");\n return;\n }\n for (const row of cross.rows) {\n if (row.code === \"cross.disagree\") {\n console.log(` ✗ cross.disagree ${row.id} [${row.subject}] ${row.claim}`);\n console.log(` a: ${sideLine(row.a)}`);\n console.log(` b: ${sideLine(row.b)}`);\n } else if (row.code === \"cross.agree-unconfirmed\") {\n console.log(` = ${row.id} [${row.subject}] ${row.claim} (both unconfirmed)`);\n } else {\n console.log(` = ${row.id} [${row.subject}] ${row.claim}${row.evidenceDisjoint === true ? \" (disjoint evidence)\" : \"\"}`);\n }\n }\n console.log(\"\");\n if (notice !== null) console.log(` ⚠ ${notice.code}: ${notice.message}`);\n console.log(\n ` ${cross.summary.agreeConfirmed} agree-confirmed, ${cross.summary.agreeUnconfirmed} agree-unconfirmed, ${cross.summary.disagree} disagree.`,\n );\n console.log(\"\\n Agreement is not verification — nothing was written and no verdict changed.\");\n console.log(\" Read the disagreements first, then the disjoint-evidence agreements.\");\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `--contract-results` consumed: the file read and pinned through the shared
|
|
3
|
+
* plumbing in `./read.ts`, then graded by the format reader in
|
|
4
|
+
* `core/verify/evidence/contract.ts`. Mirrors what `../results.ts` is for the
|
|
5
|
+
* cucumber report — the command-side half that touches the filesystem, kept
|
|
6
|
+
* apart from the core half that only ever judges a parsed document.
|
|
7
|
+
*/
|
|
8
|
+
import { readContractReport } from "../../../core/verify/evidence/contract.js";
|
|
9
|
+
import {} from "../../../core/verify/record.js";
|
|
10
|
+
import { readReportArtifact } from "./read.js";
|
|
11
|
+
export async function readContractResults(spelled, repoDir) {
|
|
12
|
+
const artifact = await readReportArtifact(spelled, repoDir, "contract-test report");
|
|
13
|
+
if (!artifact.ok)
|
|
14
|
+
return artifact;
|
|
15
|
+
const parsed = readContractReport(artifact.doc, spelled);
|
|
16
|
+
if (!parsed.ok)
|
|
17
|
+
return { ok: false, code: "answers-unreadable", message: parsed.message };
|
|
18
|
+
return {
|
|
19
|
+
ok: true,
|
|
20
|
+
runs: parsed.runs,
|
|
21
|
+
report: {
|
|
22
|
+
path: artifact.spelled,
|
|
23
|
+
digest: artifact.digest,
|
|
24
|
+
mtime: artifact.mtime,
|
|
25
|
+
// Distinct operationIds, not entries: the pin says how much of an API
|
|
26
|
+
// the file speaks about, and a re-run is not a second operation.
|
|
27
|
+
operations: new Set(parsed.runs.map((r) => r.operationId)).size,
|
|
28
|
+
format: "generic",
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../../src/commands/verify/evidence/contract.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,kBAAkB,EAAoB,MAAM,2CAA2C,CAAC;AACjG,OAAO,EAA+B,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAM/C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAe,EACf,OAA2B;IAE3B,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,sBAAsB,CAAC,CAAC;IACpF,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,OAAO,QAAQ,CAAC;IAClC,MAAM,MAAM,GAAG,kBAAkB,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACzD,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IAC1F,OAAO;QACL,EAAE,EAAE,IAAI;QACR,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ,CAAC,OAAO;YACtB,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,sEAAsE;YACtE,iEAAiE;YACjE,UAAU,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI;YAC/D,MAAM,EAAE,SAAS;SAClB;KACF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * `--contract-results` consumed: the file read and pinned through the shared\n * plumbing in `./read.ts`, then graded by the format reader in\n * `core/verify/evidence/contract.ts`. Mirrors what `../results.ts` is for the\n * cucumber report — the command-side half that touches the filesystem, kept\n * apart from the core half that only ever judges a parsed document.\n */\nimport { readContractReport, type ContractRun } from \"../../../core/verify/evidence/contract.js\";\nimport { type ConsumedContractReport } from \"../../../core/verify/record.js\";\nimport { readReportArtifact } from \"./read.js\";\n\nexport type ContractResultsRead =\n | { ok: true; report: ConsumedContractReport; runs: ContractRun[] }\n | { ok: false; code: \"answers-unreadable\"; message: string };\n\nexport async function readContractResults(\n spelled: string,\n repoDir: string | undefined,\n): Promise<ContractResultsRead> {\n const artifact = await readReportArtifact(spelled, repoDir, \"contract-test report\");\n if (!artifact.ok) return artifact;\n const parsed = readContractReport(artifact.doc, spelled);\n if (!parsed.ok) return { ok: false, code: \"answers-unreadable\", message: parsed.message };\n return {\n ok: true,\n runs: parsed.runs,\n report: {\n path: artifact.spelled,\n digest: artifact.digest,\n mtime: artifact.mtime,\n // Distinct operationIds, not entries: the pin says how much of an API\n // the file speaks about, and a re-run is not a second operation.\n operations: new Set(parsed.runs.map((r) => r.operationId)).size,\n format: \"generic\",\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The record path's half of evidence pins: attaching what the evidence
|
|
3
|
+
* validation computed onto the answers being recorded, and saying — once,
|
|
4
|
+
* while the agent is still in the loop — when a cited blob does not contain
|
|
5
|
+
* the string its claim asserts.
|
|
6
|
+
*
|
|
7
|
+
* It lives in `evidence/` beside the report readers because it is the same
|
|
8
|
+
* subject (what a federated confirmation rests on), and because `record.ts`
|
|
9
|
+
* sits against the line limit: the notice's wording and the attach loop are a
|
|
10
|
+
* seam of their own, not lines seventeen-through-forty of the record flow.
|
|
11
|
+
*/
|
|
12
|
+
import {} from "../../../core/verify/answers.js";
|
|
13
|
+
import {} from "../../../core/verify/checklist.js";
|
|
14
|
+
import {} from "../../../core/verify/pins/pin.js";
|
|
15
|
+
import {} from "../../../core/verify/record.js";
|
|
16
|
+
import { plural } from "../../policy/format.js";
|
|
17
|
+
/** Claim id → the literal the claim asserts, for the kinds that assert one. */
|
|
18
|
+
export function claimTokens(claims) {
|
|
19
|
+
return new Map(claims.flatMap((c) => (c.token === undefined ? [] : [[c.id, c.token]])));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Stamp the computed pins onto the answers they were computed from, and build
|
|
23
|
+
* the one record-time notice. The notice is verdict-neutral and gates nothing
|
|
24
|
+
* — verify has never gated — but it fires HERE rather than only at the next
|
|
25
|
+
* `loam validate` because record time is the anti-fabrication moment: the
|
|
26
|
+
* agent whose evidence does not spell the claim is still in the loop to
|
|
27
|
+
* re-read it. The validate-side `evidence.token-missing` finding describes the
|
|
28
|
+
* same fact later and continuously, in a different repository's run; neither
|
|
29
|
+
* surface is derivable from the other's.
|
|
30
|
+
*/
|
|
31
|
+
export function pinAnswers(answers, evidence, commit) {
|
|
32
|
+
const pinned = answers.map((answer) => {
|
|
33
|
+
const pins = evidence.pins.get(answer.id);
|
|
34
|
+
return pins === undefined ? answer : { ...answer, evidence_pins: pins };
|
|
35
|
+
});
|
|
36
|
+
if (evidence.tokenMisses.length === 0)
|
|
37
|
+
return { answers: pinned, notice: null };
|
|
38
|
+
const cited = evidence.tokenMisses.map((m) => `${m.id} ${m.evidence} (token '${m.token}')`);
|
|
39
|
+
return {
|
|
40
|
+
answers: pinned,
|
|
41
|
+
notice: {
|
|
42
|
+
code: "verify.evidence-token-missing",
|
|
43
|
+
severity: "warn",
|
|
44
|
+
message: `${plural(evidence.tokenMisses.length, "confirmed citation")} whose file at ${commit.slice(0, 12)} does not contain ` +
|
|
45
|
+
`the literal string the claim asserts: ${cited.join("; ")}. ` +
|
|
46
|
+
"Read that evidence before trusting it — a pin records what was cited, not that the claim is true. " +
|
|
47
|
+
"The answer stands as given; nothing gates on this.",
|
|
48
|
+
claims: [...new Set(evidence.tokenMisses.map((m) => m.id))],
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=pins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pins.js","sourceRoot":"","sources":["../../../../src/commands/verify/evidence/pins.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAe,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAc,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAAoB,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAqB,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAgBhD,+EAA+E;AAC/E,MAAM,UAAU,WAAW,CAAC,MAAwB;IAClD,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACnG,CAAC;AAeD;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CAAC,OAAiB,EAAE,QAAsB,EAAE,MAAc;IAClF,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1C,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;IAC1E,CAAC,CAAC,CAAC;IACH,IAAI,QAAQ,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAChF,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,YAAY,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAC5F,OAAO;QACL,OAAO,EAAE,MAAM;QACf,MAAM,EAAE;YACN,IAAI,EAAE,+BAA+B;YACrC,QAAQ,EAAE,MAAM;YAChB,OAAO,EACL,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,kBAAkB,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,oBAAoB;gBACrH,yCAAyC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;gBAC7D,oGAAoG;gBACpG,oDAAoD;YACtD,MAAM,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;SAC5D;KACF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The record path's half of evidence pins: attaching what the evidence\n * validation computed onto the answers being recorded, and saying — once,\n * while the agent is still in the loop — when a cited blob does not contain\n * the string its claim asserts.\n *\n * It lives in `evidence/` beside the report readers because it is the same\n * subject (what a federated confirmation rests on), and because `record.ts`\n * sits against the line limit: the notice's wording and the attach loop are a\n * seam of their own, not lines seventeen-through-forty of the record flow.\n */\nimport { type Answer } from \"../../../core/verify/answers.js\";\nimport { type Claim } from \"../../../core/verify/checklist.js\";\nimport { type EvidencePin } from \"../../../core/verify/pins/pin.js\";\nimport { type VerifyNotice } from \"../../../core/verify/record.js\";\nimport { plural } from \"../../policy/format.js\";\n\n/**\n * One citation whose committed blob does not contain the claim's token —\n * collected by `validateServiceEvidence` in the same pass that builds the pin,\n * where the blob is already in hand. The type lives here rather than in\n * `../results.ts` so this package never imports its parent back (the package\n * graph's acyclicity is a checked obligation, not a taste).\n */\nexport interface TokenMiss {\n id: string;\n /** The `path:line` citation whose blob was scanned. */\n evidence: string;\n token: string;\n}\n\n/** Claim id → the literal the claim asserts, for the kinds that assert one. */\nexport function claimTokens(claims: readonly Claim[]): ReadonlyMap<string, string> {\n return new Map(claims.flatMap((c) => (c.token === undefined ? [] : [[c.id, c.token] as const])));\n}\n\n/** The validation's pin and token-miss halves together — they come from one pass. */\nexport interface EvidencePins {\n /** Claim id → one pin per file:line citation, in evidence order. */\n pins: ReadonlyMap<string, EvidencePin[]>;\n tokenMisses: TokenMiss[];\n}\n\nexport interface PinnedAnswers {\n answers: Answer[];\n /** The record-time token warning, or null when every scanned blob held its token. */\n notice: VerifyNotice | null;\n}\n\n/**\n * Stamp the computed pins onto the answers they were computed from, and build\n * the one record-time notice. The notice is verdict-neutral and gates nothing\n * — verify has never gated — but it fires HERE rather than only at the next\n * `loam validate` because record time is the anti-fabrication moment: the\n * agent whose evidence does not spell the claim is still in the loop to\n * re-read it. The validate-side `evidence.token-missing` finding describes the\n * same fact later and continuously, in a different repository's run; neither\n * surface is derivable from the other's.\n */\nexport function pinAnswers(answers: Answer[], evidence: EvidencePins, commit: string): PinnedAnswers {\n const pinned = answers.map((answer) => {\n const pins = evidence.pins.get(answer.id);\n return pins === undefined ? answer : { ...answer, evidence_pins: pins };\n });\n if (evidence.tokenMisses.length === 0) return { answers: pinned, notice: null };\n const cited = evidence.tokenMisses.map((m) => `${m.id} ${m.evidence} (token '${m.token}')`);\n return {\n answers: pinned,\n notice: {\n code: \"verify.evidence-token-missing\",\n severity: \"warn\",\n message:\n `${plural(evidence.tokenMisses.length, \"confirmed citation\")} whose file at ${commit.slice(0, 12)} does not contain ` +\n `the literal string the claim asserts: ${cited.join(\"; \")}. ` +\n \"Read that evidence before trusting it — a pin records what was cited, not that the claim is true. \" +\n \"The answer stands as given; nothing gates on this.\",\n claims: [...new Set(evidence.tokenMisses.map((m) => m.id))],\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A report file as an artifact: resolved, read, digested, parsed — the
|
|
3
|
+
* plumbing `--results` and `--contract-results` share, extracted from
|
|
4
|
+
* `../results.ts` when the contract path became its second consumer. One
|
|
5
|
+
* spelling on purpose: the two flags must agree byte-for-byte about what "the
|
|
6
|
+
* file loam read" means, because both pins end up on the same record making
|
|
7
|
+
* the same promise.
|
|
8
|
+
*
|
|
9
|
+
* `repoDir` is set in federated mode, and there the report must be a file
|
|
10
|
+
* INSIDE the repository being attested, resolved by the same rules as evidence
|
|
11
|
+
* (`portablePathOf` then `resolveInside`): an attestation says "at this
|
|
12
|
+
* commit, in this repository", and a report living somewhere else answers for
|
|
13
|
+
* a run nobody standing here can find. The legacy all-at-once form binds to no
|
|
14
|
+
* repository at all, so it takes the path as spelled — its looser contract,
|
|
15
|
+
* unchanged.
|
|
16
|
+
*
|
|
17
|
+
* Every refusal is `answers-unreadable` with the failing fact named — a path
|
|
18
|
+
* that is a directory arrives here as the read's own EISDIR, a file that is
|
|
19
|
+
* not UTF-8 is refused by name rather than parsed through U+FFFD substitution
|
|
20
|
+
* (JSON.parse's "unexpected token" over bytes nobody wrote is a message that
|
|
21
|
+
* sends the caller hunting a typo that is not there), and broken JSON carries
|
|
22
|
+
* the parser's message. Never `internal`: the file is the caller's, so the
|
|
23
|
+
* refusal must name the file.
|
|
24
|
+
*/
|
|
25
|
+
import { isUtf8 } from "node:buffer";
|
|
26
|
+
import { createHash } from "node:crypto";
|
|
27
|
+
import { readFile, stat } from "node:fs/promises";
|
|
28
|
+
import { resolve } from "node:path";
|
|
29
|
+
import { resolvePortableFileInside } from "../../../core/kernel/path-safety.js";
|
|
30
|
+
export async function readReportArtifact(spelled, repoDir, label) {
|
|
31
|
+
const refuse = (message) => ({ ok: false, code: "answers-unreadable", message });
|
|
32
|
+
let path;
|
|
33
|
+
if (repoDir === undefined) {
|
|
34
|
+
path = resolve(process.cwd(), spelled);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
try {
|
|
38
|
+
path = resolvePortableFileInside(repoDir, spelled, label);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
return refuse(`Cannot answer from ${spelled}: ${err instanceof Error ? err.message : String(err)}. ` +
|
|
42
|
+
"A federated attestation rests on a report inside the repository it attests — give the path relative to the repo root.");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
let bytes;
|
|
46
|
+
let mtime;
|
|
47
|
+
try {
|
|
48
|
+
bytes = await readFile(path);
|
|
49
|
+
mtime = (await stat(path)).mtime;
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
return refuse(`Cannot read ${spelled} as a ${label}: ${err instanceof Error ? err.message : String(err)}`);
|
|
53
|
+
}
|
|
54
|
+
if (!isUtf8(bytes)) {
|
|
55
|
+
return refuse(`Cannot read ${spelled} as a ${label}: the file is not valid UTF-8`);
|
|
56
|
+
}
|
|
57
|
+
let doc;
|
|
58
|
+
try {
|
|
59
|
+
doc = JSON.parse(bytes.toString("utf8"));
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
return refuse(`Cannot read ${spelled} as a ${label}: ${err instanceof Error ? err.message : String(err)}`);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
ok: true,
|
|
66
|
+
spelled,
|
|
67
|
+
digest: createHash("sha256").update(bytes).digest("hex"),
|
|
68
|
+
mtime: mtime.toISOString(),
|
|
69
|
+
doc,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../../../src/commands/verify/evidence/read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,yBAAyB,EAAE,MAAM,qCAAqC,CAAC;AAgBhF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAe,EACf,OAA2B,EAC3B,KAAa;IAEb,MAAM,MAAM,GAAG,CAAC,OAAe,EAAsB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7G,IAAI,IAAY,CAAC;IACjB,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,IAAI,GAAG,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QAC5D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,MAAM,CACX,sBAAsB,OAAO,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI;gBACpF,uHAAuH,CAC1H,CAAC;QACJ,CAAC;IACH,CAAC;IAED,IAAI,KAAa,CAAC;IAClB,IAAI,KAAW,CAAC;IAChB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7B,KAAK,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,MAAM,CAAC,eAAe,OAAO,SAAS,KAAK,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7G,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,MAAM,CAAC,eAAe,OAAO,SAAS,KAAK,+BAA+B,CAAC,CAAC;IACrF,CAAC;IACD,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,MAAM,CAAC,eAAe,OAAO,SAAS,KAAK,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7G,CAAC;IACD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,OAAO;QACP,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;QACxD,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE;QAC1B,GAAG;KACJ,CAAC;AACJ,CAAC","sourcesContent":["/**\n * A report file as an artifact: resolved, read, digested, parsed — the\n * plumbing `--results` and `--contract-results` share, extracted from\n * `../results.ts` when the contract path became its second consumer. One\n * spelling on purpose: the two flags must agree byte-for-byte about what \"the\n * file loam read\" means, because both pins end up on the same record making\n * the same promise.\n *\n * `repoDir` is set in federated mode, and there the report must be a file\n * INSIDE the repository being attested, resolved by the same rules as evidence\n * (`portablePathOf` then `resolveInside`): an attestation says \"at this\n * commit, in this repository\", and a report living somewhere else answers for\n * a run nobody standing here can find. The legacy all-at-once form binds to no\n * repository at all, so it takes the path as spelled — its looser contract,\n * unchanged.\n *\n * Every refusal is `answers-unreadable` with the failing fact named — a path\n * that is a directory arrives here as the read's own EISDIR, a file that is\n * not UTF-8 is refused by name rather than parsed through U+FFFD substitution\n * (JSON.parse's \"unexpected token\" over bytes nobody wrote is a message that\n * sends the caller hunting a typo that is not there), and broken JSON carries\n * the parser's message. Never `internal`: the file is the caller's, so the\n * refusal must name the file.\n */\nimport { isUtf8 } from \"node:buffer\";\nimport { createHash } from \"node:crypto\";\nimport { readFile, stat } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { resolvePortableFileInside } from \"../../../core/kernel/path-safety.js\";\n\nexport type ReportArtifactRead =\n | {\n ok: true;\n /** The path as the caller spelled it — what goes on the record. */\n spelled: string;\n /** Full sha256 of the exact bytes read. */\n digest: string;\n /** ISO-8601 mtime of the report file. */\n mtime: string;\n /** The parsed JSON document, for the format reader to grade. */\n doc: unknown;\n }\n | { ok: false; code: \"answers-unreadable\"; message: string };\n\nexport async function readReportArtifact(\n spelled: string,\n repoDir: string | undefined,\n label: string,\n): Promise<ReportArtifactRead> {\n const refuse = (message: string): ReportArtifactRead => ({ ok: false, code: \"answers-unreadable\", message });\n let path: string;\n if (repoDir === undefined) {\n path = resolve(process.cwd(), spelled);\n } else {\n try {\n path = resolvePortableFileInside(repoDir, spelled, label);\n } catch (err) {\n return refuse(\n `Cannot answer from ${spelled}: ${err instanceof Error ? err.message : String(err)}. ` +\n \"A federated attestation rests on a report inside the repository it attests — give the path relative to the repo root.\",\n );\n }\n }\n\n let bytes: Buffer;\n let mtime: Date;\n try {\n bytes = await readFile(path);\n mtime = (await stat(path)).mtime;\n } catch (err) {\n return refuse(`Cannot read ${spelled} as a ${label}: ${err instanceof Error ? err.message : String(err)}`);\n }\n if (!isUtf8(bytes)) {\n return refuse(`Cannot read ${spelled} as a ${label}: the file is not valid UTF-8`);\n }\n let doc: unknown;\n try {\n doc = JSON.parse(bytes.toString(\"utf8\"));\n } catch (err) {\n return refuse(`Cannot read ${spelled} as a ${label}: ${err instanceof Error ? err.message : String(err)}`);\n }\n return {\n ok: true,\n spelled,\n digest: createHash(\"sha256\").update(bytes).digest(\"hex\"),\n mtime: mtime.toISOString(),\n doc,\n };\n}\n"]}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An archived feature's record, read back and never recomputed.
|
|
3
|
+
*
|
|
4
|
+
* A frozen record is history: the checklist it answered no longer exists in
|
|
5
|
+
* `features/`, so there is nothing to re-derive it from and re-deriving it would
|
|
6
|
+
* be an opinion about a feature nobody can change. Everything here reads the
|
|
7
|
+
* recorded claims, which is also why the shared marks (`answeredMark`), the
|
|
8
|
+
* contested-claim notices and the report-pin lines live beside it: the read
|
|
9
|
+
* and record views print the same facts about the same claims, in one voice.
|
|
10
|
+
*/
|
|
11
|
+
import { emitJson, repoPath } from "../../core/envelope/json.js";
|
|
12
|
+
import { contestedDigests } from "../../core/results.js";
|
|
13
|
+
import {} from "../../core/verify/checklist.js";
|
|
14
|
+
import { contestedOperations } from "../../core/verify/evidence/contract.js";
|
|
15
|
+
import { attestedNotice, openClaimsNotice, tallyRecord, verificationPath, verificationVerdict, } from "../../core/verify/record.js";
|
|
16
|
+
import { plural } from "../policy/format.js";
|
|
17
|
+
import {} from "./report.js";
|
|
18
|
+
export function reportFrozen(target, featureId, v) {
|
|
19
|
+
const { docsDir, featureDir, json } = target;
|
|
20
|
+
const tally = v === null ? null : tallyRecord(v);
|
|
21
|
+
const verdict = tally === null ? "unverified" : verificationVerdict(tally);
|
|
22
|
+
// The open-claims line rides into the frozen view too: a feature archived on
|
|
23
|
+
// a partial record must keep saying so after it ships, not only before. No
|
|
24
|
+
// record stays bare — the prose already says nothing was recorded.
|
|
25
|
+
const open = tally === null ? null : openClaimsNotice(tally, featureId);
|
|
26
|
+
const notices = [...(v === null ? [] : noticesFor(v.claims, featureId)), ...(open === null ? [] : [open])];
|
|
27
|
+
if (json) {
|
|
28
|
+
emitJson({
|
|
29
|
+
command: "verify",
|
|
30
|
+
feature: featureId,
|
|
31
|
+
path: repoPath(docsDir, featureDir),
|
|
32
|
+
frozen: true,
|
|
33
|
+
verified: verdict === "verified",
|
|
34
|
+
verdict,
|
|
35
|
+
attested: tally?.attested ?? 0,
|
|
36
|
+
summary: v === null ? null : v.summary,
|
|
37
|
+
recorded: v === null
|
|
38
|
+
? null
|
|
39
|
+
: {
|
|
40
|
+
path: repoPath(docsDir, verificationPath(featureDir)),
|
|
41
|
+
recorded: v.recorded,
|
|
42
|
+
checklist: v.checklist,
|
|
43
|
+
...(v.attestations === undefined ? {} : { attestations: v.attestations }),
|
|
44
|
+
...(v.report === undefined ? {} : { report: v.report }),
|
|
45
|
+
...(v.contractReport === undefined ? {} : { contractReport: v.contractReport }),
|
|
46
|
+
},
|
|
47
|
+
claims: v === null ? [] : v.claims,
|
|
48
|
+
...(notices.length === 0 ? {} : { notices }),
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (v === null) {
|
|
53
|
+
console.log(`${featureId} is archived and has no verification record — nothing was recorded before it shipped.`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
console.log(`${featureId} — verification recorded ${v.recorded}, frozen at archive (${repoPath(docsDir, featureDir)})\n`);
|
|
57
|
+
for (const c of v.claims) {
|
|
58
|
+
// `subject` is absent in records written before schema 2 — an old record
|
|
59
|
+
// must read as itself, not gain a service it never named.
|
|
60
|
+
const subject = c.subject === undefined ? "" : ` [${c.subject}]`;
|
|
61
|
+
console.log(` ${MARK[c.verdict]} ${c.id}${subject} ${c.claim}${answeredMark(c)}`);
|
|
62
|
+
for (const e of c.evidence)
|
|
63
|
+
console.log(` ${e}`);
|
|
64
|
+
if (c.note !== undefined)
|
|
65
|
+
console.log(` note: ${c.note}`);
|
|
66
|
+
}
|
|
67
|
+
const counts = tallyRecord(v);
|
|
68
|
+
console.log(`\n Recorded ${v.recorded} — ${counts.confirmed} confirmed, ${counts.unconfirmed} unconfirmed.`);
|
|
69
|
+
console.log(" This checklist is frozen at record time: the feature is archived and its claims are not re-derived.");
|
|
70
|
+
for (const attestation of v.attestations ?? []) {
|
|
71
|
+
console.log(` Attested by ${attestation.service} at ${attestation.commit.slice(0, 12)} (${attestation.recorded}).`);
|
|
72
|
+
if (attestation.report !== undefined)
|
|
73
|
+
console.log(` from ${reportLine(attestation.report)}`);
|
|
74
|
+
if (attestation.contractReport !== undefined) {
|
|
75
|
+
console.log(` from ${contractReportLine(attestation.contractReport)}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (v.report !== undefined)
|
|
79
|
+
console.log(` Answered from ${reportLine(v.report)}.`);
|
|
80
|
+
if (v.contractReport !== undefined)
|
|
81
|
+
console.log(` Contract report read: ${contractReportLine(v.contractReport)}.`);
|
|
82
|
+
for (const notice of notices)
|
|
83
|
+
console.log(` ⚠ ${notice.code}: ${notice.message}`);
|
|
84
|
+
}
|
|
85
|
+
export const MARK = { confirmed: "✓", unconfirmed: "✗", unanswered: "?" };
|
|
86
|
+
/**
|
|
87
|
+
* Who answered, where that changes what the verdict means. `[runner]` is a
|
|
88
|
+
* digest-matched green run; `[contract]` is an operationId-matched green
|
|
89
|
+
* contract-test run — mechanical too, and marked so the record's provenance is
|
|
90
|
+
* readable per line, not only in `contractReport:`; `[attested]` is a scenario
|
|
91
|
+
* claim confirmed on somebody's word — the same ✓, a weaker fact, and it must
|
|
92
|
+
* be visible on the line itself and not only in the summary. The attested test
|
|
93
|
+
* runs FIRST and uses `attestedClaims`' own predicate (a confirmed scenario
|
|
94
|
+
* claim not answered by the runner), so the mark can never disagree with the
|
|
95
|
+
* tally: a scenario claim carrying `answered_by: external-runner` — a hand
|
|
96
|
+
* edit, or a future loam; the reader accepts any string on purpose — COUNTS as
|
|
97
|
+
* attested, and printing `[contract]` two lines above a notice saying "an
|
|
98
|
+
* agent's word" would be the mark calling the tally a liar. Everything else is
|
|
99
|
+
* unmarked: an agent's answer about a service existing or an operation being
|
|
100
|
+
* exposed is exactly what the checklist asks for.
|
|
101
|
+
*/
|
|
102
|
+
export function answeredMark(c) {
|
|
103
|
+
if (c.answered_by === "runner")
|
|
104
|
+
return " [runner]";
|
|
105
|
+
if (c.kind === "scenario.tested") {
|
|
106
|
+
return c.verdict === "confirmed" ? " [attested]" : "";
|
|
107
|
+
}
|
|
108
|
+
return c.answered_by === "external-runner" ? " [contract]" : "";
|
|
109
|
+
}
|
|
110
|
+
/** Everything a verify surface has to say about a set of answers beyond the counts. */
|
|
111
|
+
export function noticesFor(claims, feature) {
|
|
112
|
+
const attested = attestedNotice(claims, feature);
|
|
113
|
+
return attested === null ? [] : [attested];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* `verify.checklist-forked` — two services answered DIFFERENT versions of this
|
|
117
|
+
* feature{@link ServiceAttestation}'s question set.
|
|
118
|
+
*
|
|
119
|
+
* The record carries one top-level `checklist` digest, so before attestations
|
|
120
|
+
* carried their own the file could not represent this at all: a service that
|
|
121
|
+
* attested last week against a delta since rewritten wrote the same digest as
|
|
122
|
+
* one that attested this morning, and the record-level staleness check flagged
|
|
123
|
+
* both or neither. It could never say WHICH answers went stale, which is the
|
|
124
|
+
* only question a reader has.
|
|
125
|
+
*
|
|
126
|
+
* A warn, and only ever a warn: a fork is normal mid-rollout — services attest
|
|
127
|
+
* as they finish, and a feature legitimately changes between the first and the
|
|
128
|
+
* last. What it must not do is stay invisible. Attestations with no `checklist`
|
|
129
|
+
* field are excluded rather than counted as a third version: they make no claim
|
|
130
|
+
* about what they answered, and reading silence as disagreement would fire this
|
|
131
|
+
* on every record written before the field existed.
|
|
132
|
+
*/
|
|
133
|
+
export function forkedChecklistNotices(recorded, current) {
|
|
134
|
+
const stated = (recorded?.attestations ?? []).filter((a) => a.checklist !== undefined);
|
|
135
|
+
// Measured against the CURRENT checklist, not pairwise between attestations.
|
|
136
|
+
// The pairwise reading answers the wrong question: three services that all
|
|
137
|
+
// attested against a since-rewritten delta agree with each other perfectly
|
|
138
|
+
// and are all stale, which pairwise calls clean. What a reader needs is
|
|
139
|
+
// WHICH services answered something other than what is being asked now.
|
|
140
|
+
const behind = stated.filter((a) => a.checklist !== current);
|
|
141
|
+
if (behind.length === 0)
|
|
142
|
+
return [];
|
|
143
|
+
const byVersion = [...new Set(behind.map((a) => a.checklist))]
|
|
144
|
+
.sort()
|
|
145
|
+
.map((v) => `${v} (${behind.filter((a) => a.checklist === v).map((a) => a.service).sort().join(", ")})`);
|
|
146
|
+
return [
|
|
147
|
+
{
|
|
148
|
+
code: "verify.checklist-forked",
|
|
149
|
+
severity: "warn",
|
|
150
|
+
message: `${plural(behind.length, "service")} answered a different version of this feature's question set ` +
|
|
151
|
+
`than the one it now asks (${current}): ${byVersion.join("; ")}. ` +
|
|
152
|
+
"The feature changed after they recorded, so their answers are not about the questions being asked now. " +
|
|
153
|
+
"Re-record them from their own repositories (`loam verify <FEAT> --service <id> --record`), " +
|
|
154
|
+
"or accept the split knowingly — nothing gates on it.",
|
|
155
|
+
},
|
|
156
|
+
];
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* The claims one report could not attribute: a scenario digest — and therefore
|
|
160
|
+
* an `@loam-digest-…` tag — that more than one service claims.
|
|
161
|
+
*
|
|
162
|
+
* This is now a GUARD rather than a diagnosis of ordinary authoring. Until the
|
|
163
|
+
* digest was salted by service, two services wording a scenario identically
|
|
164
|
+
* really did share one tag, and this is what stopped one repository's green run
|
|
165
|
+
* from confirming the other's claim. `scenarioBodyHash` folds the owning
|
|
166
|
+
* service into the hash, so a claim's digest is computed from the same service
|
|
167
|
+
* the claim is filed under and two subjects cannot share one short of a
|
|
168
|
+
* truncated-sha256 collision. It stays because the invariant is worth asserting
|
|
169
|
+
* where it is relied on: if this ever fires, a digest is answering for two
|
|
170
|
+
* services and no report can say which, so nothing here may confirm.
|
|
171
|
+
*
|
|
172
|
+
* Derived from claims rather than from a report, so the read view raises it too
|
|
173
|
+
* — the collision exists the moment the checklist does, and learning about it
|
|
174
|
+
* from a `--results` run that already happened is learning too late.
|
|
175
|
+
*/
|
|
176
|
+
export function contestedNotices(claims) {
|
|
177
|
+
const contested = contestedDigests(claims);
|
|
178
|
+
if (contested.size === 0)
|
|
179
|
+
return [];
|
|
180
|
+
const shared = [...contested].map(([digest, services]) => `${digest} (${services.join(", ")})`);
|
|
181
|
+
return [
|
|
182
|
+
{
|
|
183
|
+
code: "verify.digest-contested",
|
|
184
|
+
severity: "warn",
|
|
185
|
+
message: `${plural(contested.size, "scenario digest")} claimed by more than one service: ${shared.join("; ")}. ` +
|
|
186
|
+
"The digest is salted by service, so this is a hash collision, not shared wording — but one report still " +
|
|
187
|
+
"cannot say whose suite ran them, so a shared --results run leaves them unconfirmed. " +
|
|
188
|
+
"Record each service's claims from its own repository with --service.",
|
|
189
|
+
claims: claims.filter((c) => c.digest !== undefined && contested.has(c.digest)).map((c) => c.id),
|
|
190
|
+
},
|
|
191
|
+
];
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* The digest-contested rule's twin on the contract axis: operationIds that
|
|
195
|
+
* more than one service on this checklist exposes, which one report can
|
|
196
|
+
* therefore never attribute (`contestedOperations`, the module that also
|
|
197
|
+
* leaves those claims unconfirmed). Raised where the contract report is
|
|
198
|
+
* consumed, so the record path says WHY the claims came back unconfirmed
|
|
199
|
+
* instead of leaving two bare ✗ lines to be misread as failures.
|
|
200
|
+
*/
|
|
201
|
+
export function contestedOperationNotices(claims) {
|
|
202
|
+
const contested = contestedOperations(claims);
|
|
203
|
+
if (contested.size === 0)
|
|
204
|
+
return [];
|
|
205
|
+
const shared = [...contested].map(([operation, services]) => `${operation} (${services.join(", ")})`);
|
|
206
|
+
return [
|
|
207
|
+
{
|
|
208
|
+
code: "verify.operation-contested",
|
|
209
|
+
severity: "warn",
|
|
210
|
+
message: `${plural(contested.size, "operationId")} exposed by more than one service on this checklist: ${shared.join("; ")}. ` +
|
|
211
|
+
"A contract report entry names no service, so a shared --contract-results run cannot say whose suite exercised them and leaves them unconfirmed. " +
|
|
212
|
+
"Record each service's claims from its own repository with --service.",
|
|
213
|
+
claims: claims.filter((c) => c.operation !== undefined && contested.has(c.operation)).map((c) => c.id),
|
|
214
|
+
},
|
|
215
|
+
];
|
|
216
|
+
}
|
|
217
|
+
/** The report a `--results` run consumed, as one line a reviewer can check by hand. */
|
|
218
|
+
export function reportLine(r) {
|
|
219
|
+
return `${r.path} (sha256 ${r.digest.slice(0, 12)}…, ${plural(r.scenarios, "tagged scenario")}, written ${r.mtime})`;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* The contract report a `--contract-results` run consumed — the same line for
|
|
223
|
+
* the same promise, counting operations where the cucumber one counts tagged
|
|
224
|
+
* scenarios. A separate function rather than a parameter on `reportLine`
|
|
225
|
+
* because the two pins are different shapes, and a merged formatter would need
|
|
226
|
+
* exactly the switching flag that near-duplicates are kept apart to avoid.
|
|
227
|
+
*/
|
|
228
|
+
export function contractReportLine(r) {
|
|
229
|
+
return `${r.path} (sha256 ${r.digest.slice(0, 12)}…, ${plural(r.operations, "operation")}, written ${r.mtime})`;
|
|
230
|
+
}
|
|
231
|
+
/* ------------------------------------------------------------------ */
|
|
232
|
+
/* Recording */
|
|
233
|
+
/* ------------------------------------------------------------------ */
|
|
234
|
+
/**
|
|
235
|
+
* `repoDir` is the repository an attestation is ABOUT: the commit it names, the
|
|
236
|
+
* tree its evidence must resolve inside, and where a `--results` report has to
|
|
237
|
+
* live. It is threaded rather than read here because it comes from
|
|
238
|
+
* `config.root`, and a `process.cwd()` in this function was the whole bug —
|
|
239
|
+
* from a subdirectory, "this repo" quietly became that subdirectory.
|
|
240
|
+
*/
|
|
241
|
+
//# sourceMappingURL=frozen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frozen.js","sourceRoot":"","sources":["../../../src/commands/verify/frozen.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * An archived feature's record, read back and never recomputed.\n *\n * A frozen record is history: the checklist it answered no longer exists in\n * `features/`, so there is nothing to re-derive it from and re-deriving it would\n * be an opinion about a feature nobody can change. Everything here reads the\n * recorded claims, which is also why the shared marks (`answeredMark`), the\n * contested-claim notices and the report-pin lines live beside it: the read\n * and record views print the same facts about the same claims, in one voice.\n */\nimport { emitJson, repoPath } from \"../../core/envelope/json.js\";\nimport { contestedDigests } from \"../../core/results.js\";\nimport { type Claim } from \"../../core/verify/checklist.js\";\nimport { contestedOperations } from \"../../core/verify/evidence/contract.js\";\nimport {\n attestedNotice,\n openClaimsNotice,\n tallyRecord,\n type AnsweredClaim,\n type ConsumedContractReport,\n type ConsumedReport,\n type Verification,\n type VerifyNotice,\n verificationPath,\n verificationVerdict,\n} from \"../../core/verify/record.js\";\nimport { plural } from \"../policy/format.js\";\nimport { type VerifyTarget } from \"./report.js\";\n\nexport function reportFrozen(\n target: VerifyTarget,\n featureId: string,\n v: Verification | null,\n): void {\n const { docsDir, featureDir, json } = target;\n const tally = v === null ? null : tallyRecord(v);\n const verdict = tally === null ? \"unverified\" : verificationVerdict(tally);\n // The open-claims line rides into the frozen view too: a feature archived on\n // a partial record must keep saying so after it ships, not only before. No\n // record stays bare — the prose already says nothing was recorded.\n const open = tally === null ? null : openClaimsNotice(tally, featureId);\n const notices = [...(v === null ? [] : noticesFor(v.claims, featureId)), ...(open === null ? [] : [open])];\n\n if (json) {\n emitJson({\n command: \"verify\",\n feature: featureId,\n path: repoPath(docsDir, featureDir),\n frozen: true,\n verified: verdict === \"verified\",\n verdict,\n attested: tally?.attested ?? 0,\n summary: v === null ? null : v.summary,\n recorded:\n v === null\n ? null\n : {\n path: repoPath(docsDir, verificationPath(featureDir)),\n recorded: v.recorded,\n checklist: v.checklist,\n ...(v.attestations === undefined ? {} : { attestations: v.attestations }),\n ...(v.report === undefined ? {} : { report: v.report }),\n ...(v.contractReport === undefined ? {} : { contractReport: v.contractReport }),\n },\n claims: v === null ? [] : v.claims,\n ...(notices.length === 0 ? {} : { notices }),\n });\n return;\n }\n\n if (v === null) {\n console.log(\n `${featureId} is archived and has no verification record — nothing was recorded before it shipped.`,\n );\n return;\n }\n\n console.log(\n `${featureId} — verification recorded ${v.recorded}, frozen at archive (${repoPath(docsDir, featureDir)})\\n`,\n );\n for (const c of v.claims) {\n // `subject` is absent in records written before schema 2 — an old record\n // must read as itself, not gain a service it never named.\n const subject = c.subject === undefined ? \"\" : ` [${c.subject}]`;\n console.log(` ${MARK[c.verdict]} ${c.id}${subject} ${c.claim}${answeredMark(c)}`);\n for (const e of c.evidence) console.log(` ${e}`);\n if (c.note !== undefined) console.log(` note: ${c.note}`);\n }\n const counts = tallyRecord(v);\n console.log(`\\n Recorded ${v.recorded} — ${counts.confirmed} confirmed, ${counts.unconfirmed} unconfirmed.`);\n console.log(\n \" This checklist is frozen at record time: the feature is archived and its claims are not re-derived.\",\n );\n for (const attestation of v.attestations ?? []) {\n console.log(\n ` Attested by ${attestation.service} at ${attestation.commit.slice(0, 12)} (${attestation.recorded}).`,\n );\n if (attestation.report !== undefined) console.log(` from ${reportLine(attestation.report)}`);\n if (attestation.contractReport !== undefined) {\n console.log(` from ${contractReportLine(attestation.contractReport)}`);\n }\n }\n if (v.report !== undefined) console.log(` Answered from ${reportLine(v.report)}.`);\n if (v.contractReport !== undefined) console.log(` Contract report read: ${contractReportLine(v.contractReport)}.`);\n for (const notice of notices) console.log(` ⚠ ${notice.code}: ${notice.message}`);\n}\n\nexport const MARK: Record<string, string> = { confirmed: \"✓\", unconfirmed: \"✗\", unanswered: \"?\" };\n\n/**\n * Who answered, where that changes what the verdict means. `[runner]` is a\n * digest-matched green run; `[contract]` is an operationId-matched green\n * contract-test run — mechanical too, and marked so the record's provenance is\n * readable per line, not only in `contractReport:`; `[attested]` is a scenario\n * claim confirmed on somebody's word — the same ✓, a weaker fact, and it must\n * be visible on the line itself and not only in the summary. The attested test\n * runs FIRST and uses `attestedClaims`' own predicate (a confirmed scenario\n * claim not answered by the runner), so the mark can never disagree with the\n * tally: a scenario claim carrying `answered_by: external-runner` — a hand\n * edit, or a future loam; the reader accepts any string on purpose — COUNTS as\n * attested, and printing `[contract]` two lines above a notice saying \"an\n * agent's word\" would be the mark calling the tally a liar. Everything else is\n * unmarked: an agent's answer about a service existing or an operation being\n * exposed is exactly what the checklist asks for.\n */\nexport function answeredMark(c: AnsweredClaim): string {\n if (c.answered_by === \"runner\") return \" [runner]\";\n if (c.kind === \"scenario.tested\") {\n return c.verdict === \"confirmed\" ? \" [attested]\" : \"\";\n }\n return c.answered_by === \"external-runner\" ? \" [contract]\" : \"\";\n}\n\n/** Everything a verify surface has to say about a set of answers beyond the counts. */\nexport function noticesFor(claims: readonly AnsweredClaim[], feature: string): VerifyNotice[] {\n const attested = attestedNotice(claims, feature);\n return attested === null ? [] : [attested];\n}\n\n/**\n * `verify.checklist-forked` — two services answered DIFFERENT versions of this\n * feature{@link ServiceAttestation}'s question set.\n *\n * The record carries one top-level `checklist` digest, so before attestations\n * carried their own the file could not represent this at all: a service that\n * attested last week against a delta since rewritten wrote the same digest as\n * one that attested this morning, and the record-level staleness check flagged\n * both or neither. It could never say WHICH answers went stale, which is the\n * only question a reader has.\n *\n * A warn, and only ever a warn: a fork is normal mid-rollout — services attest\n * as they finish, and a feature legitimately changes between the first and the\n * last. What it must not do is stay invisible. Attestations with no `checklist`\n * field are excluded rather than counted as a third version: they make no claim\n * about what they answered, and reading silence as disagreement would fire this\n * on every record written before the field existed.\n */\nexport function forkedChecklistNotices(\n recorded: Verification | null,\n current: string,\n): VerifyNotice[] {\n const stated = (recorded?.attestations ?? []).filter((a) => a.checklist !== undefined);\n // Measured against the CURRENT checklist, not pairwise between attestations.\n // The pairwise reading answers the wrong question: three services that all\n // attested against a since-rewritten delta agree with each other perfectly\n // and are all stale, which pairwise calls clean. What a reader needs is\n // WHICH services answered something other than what is being asked now.\n const behind = stated.filter((a) => a.checklist !== current);\n if (behind.length === 0) return [];\n const byVersion = [...new Set(behind.map((a) => a.checklist!))]\n .sort()\n .map((v) => `${v} (${behind.filter((a) => a.checklist === v).map((a) => a.service).sort().join(\", \")})`);\n return [\n {\n code: \"verify.checklist-forked\",\n severity: \"warn\",\n message:\n `${plural(behind.length, \"service\")} answered a different version of this feature's question set ` +\n `than the one it now asks (${current}): ${byVersion.join(\"; \")}. ` +\n \"The feature changed after they recorded, so their answers are not about the questions being asked now. \" +\n \"Re-record them from their own repositories (`loam verify <FEAT> --service <id> --record`), \" +\n \"or accept the split knowingly — nothing gates on it.\",\n },\n ];\n}\n\n/**\n * The claims one report could not attribute: a scenario digest — and therefore\n * an `@loam-digest-…` tag — that more than one service claims.\n *\n * This is now a GUARD rather than a diagnosis of ordinary authoring. Until the\n * digest was salted by service, two services wording a scenario identically\n * really did share one tag, and this is what stopped one repository's green run\n * from confirming the other's claim. `scenarioBodyHash` folds the owning\n * service into the hash, so a claim's digest is computed from the same service\n * the claim is filed under and two subjects cannot share one short of a\n * truncated-sha256 collision. It stays because the invariant is worth asserting\n * where it is relied on: if this ever fires, a digest is answering for two\n * services and no report can say which, so nothing here may confirm.\n *\n * Derived from claims rather than from a report, so the read view raises it too\n * — the collision exists the moment the checklist does, and learning about it\n * from a `--results` run that already happened is learning too late.\n */\nexport function contestedNotices(claims: readonly Claim[]): VerifyNotice[] {\n const contested = contestedDigests(claims);\n if (contested.size === 0) return [];\n const shared = [...contested].map(([digest, services]) => `${digest} (${services.join(\", \")})`);\n return [\n {\n code: \"verify.digest-contested\",\n severity: \"warn\",\n message:\n `${plural(contested.size, \"scenario digest\")} claimed by more than one service: ${shared.join(\"; \")}. ` +\n \"The digest is salted by service, so this is a hash collision, not shared wording — but one report still \" +\n \"cannot say whose suite ran them, so a shared --results run leaves them unconfirmed. \" +\n \"Record each service's claims from its own repository with --service.\",\n claims: claims.filter((c) => c.digest !== undefined && contested.has(c.digest)).map((c) => c.id),\n },\n ];\n}\n\n/**\n * The digest-contested rule's twin on the contract axis: operationIds that\n * more than one service on this checklist exposes, which one report can\n * therefore never attribute (`contestedOperations`, the module that also\n * leaves those claims unconfirmed). Raised where the contract report is\n * consumed, so the record path says WHY the claims came back unconfirmed\n * instead of leaving two bare ✗ lines to be misread as failures.\n */\nexport function contestedOperationNotices(claims: readonly Claim[]): VerifyNotice[] {\n const contested = contestedOperations(claims);\n if (contested.size === 0) return [];\n const shared = [...contested].map(([operation, services]) => `${operation} (${services.join(\", \")})`);\n return [\n {\n code: \"verify.operation-contested\",\n severity: \"warn\",\n message:\n `${plural(contested.size, \"operationId\")} exposed by more than one service on this checklist: ${shared.join(\"; \")}. ` +\n \"A contract report entry names no service, so a shared --contract-results run cannot say whose suite exercised them and leaves them unconfirmed. \" +\n \"Record each service's claims from its own repository with --service.\",\n claims: claims.filter((c) => c.operation !== undefined && contested.has(c.operation)).map((c) => c.id),\n },\n ];\n}\n\n/** The report a `--results` run consumed, as one line a reviewer can check by hand. */\nexport function reportLine(r: ConsumedReport): string {\n return `${r.path} (sha256 ${r.digest.slice(0, 12)}…, ${plural(r.scenarios, \"tagged scenario\")}, written ${r.mtime})`;\n}\n\n/**\n * The contract report a `--contract-results` run consumed — the same line for\n * the same promise, counting operations where the cucumber one counts tagged\n * scenarios. A separate function rather than a parameter on `reportLine`\n * because the two pins are different shapes, and a merged formatter would need\n * exactly the switching flag that near-duplicates are kept apart to avoid.\n */\nexport function contractReportLine(r: ConsumedContractReport): string {\n return `${r.path} (sha256 ${r.digest.slice(0, 12)}…, ${plural(r.operations, \"operation\")}, written ${r.mtime})`;\n}\n\n\n/* ------------------------------------------------------------------ */\n/* Recording */\n/* ------------------------------------------------------------------ */\n\n/**\n * `repoDir` is the repository an attestation is ABOUT: the commit it names, the\n * tree its evidence must resolve inside, and where a `--results` report has to\n * live. It is threaded rather than read here because it comes from\n * `config.root`, and a `process.cwd()` in this function was the whole bug —\n * from a subdirectory, \"this repo\" quietly became that subdirectory.\n */\n"]}
|