@ybotok/loam 0.2.0-alpha.1 → 0.2.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3448 -0
- package/COMPARISON.md +91 -3
- package/CONTRIBUTING.md +37 -0
- package/MIGRATING-from-OpenSpec.md +47 -23
- package/QUICKSTART.md +189 -12
- package/README.md +274 -65
- package/ROADMAP.md +572 -31
- package/SCHEMA.md +1709 -155
- package/WORKFLOW.md +298 -72
- package/dist/cli.js +26 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +5 -10
- package/dist/commands/adopt/adopt.js.map +1 -1
- package/dist/commands/adopt/render.js +50 -9
- package/dist/commands/adopt/render.js.map +1 -1
- package/dist/commands/archive/archive.js +16 -19
- package/dist/commands/archive/archive.js.map +1 -1
- package/dist/commands/archive/closing.js +42 -0
- package/dist/commands/archive/closing.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +36 -42
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/consumers.js +56 -0
- package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +77 -43
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/document/head.js +151 -0
- package/dist/commands/archive/plan/document/head.js.map +1 -0
- package/dist/commands/archive/plan/document/links.js +284 -0
- package/dist/commands/archive/plan/document/links.js.map +1 -0
- package/dist/commands/archive/plan/document/run.js +136 -0
- package/dist/commands/archive/plan/document/run.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +21 -19
- package/dist/commands/archive/plan/gate.js.map +1 -1
- package/dist/commands/archive/plan/landscape.js +167 -30
- package/dist/commands/archive/plan/landscape.js.map +1 -1
- package/dist/commands/archive/plan/model/extending.js +85 -0
- package/dist/commands/archive/plan/model/extending.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +14 -19
- package/dist/commands/archive/plan/refusal.js.map +1 -1
- package/dist/commands/archive/plan/specs.js +137 -56
- package/dist/commands/archive/plan/specs.js.map +1 -1
- package/dist/commands/archive/plan/state.js +3 -0
- package/dist/commands/archive/plan/state.js.map +1 -1
- package/dist/commands/archive/run.js +134 -30
- package/dist/commands/archive/run.js.map +1 -1
- package/dist/commands/archive/shipped.js +49 -0
- package/dist/commands/archive/shipped.js.map +1 -0
- package/dist/commands/context/context.js +85 -18
- package/dist/commands/context/context.js.map +1 -1
- package/dist/commands/context/print.js +29 -7
- package/dist/commands/context/print.js.map +1 -1
- package/dist/commands/delta/delta.js +102 -14
- package/dist/commands/delta/delta.js.map +1 -1
- package/dist/commands/delta/print.js +17 -1
- package/dist/commands/delta/print.js.map +1 -1
- package/dist/commands/dependencies.js +3 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +20 -27
- package/dist/commands/diff/diff.js.map +1 -1
- package/dist/commands/doctor.js +60 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +89 -13
- package/dist/commands/explain/explain.js.map +1 -1
- package/dist/commands/explore.js +16 -10
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +45 -8
- package/dist/commands/gate/gate.js.map +1 -1
- package/dist/commands/gate/print.js +15 -3
- package/dist/commands/gate/print.js.map +1 -1
- package/dist/commands/gherkin/commit.js +13 -54
- package/dist/commands/gherkin/commit.js.map +1 -1
- package/dist/commands/gherkin/gherkin.js +36 -20
- package/dist/commands/gherkin/gherkin.js.map +1 -1
- package/dist/commands/gherkin/reconcile.js +10 -13
- package/dist/commands/gherkin/reconcile.js.map +1 -1
- package/dist/commands/init/first-hour.js +44 -0
- package/dist/commands/init/first-hour.js.map +1 -1
- package/dist/commands/init/init.js +18 -22
- package/dist/commands/init/init.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +4 -6
- package/dist/commands/list/campaign/campaign.js.map +1 -1
- package/dist/commands/list/json.js +5 -7
- package/dist/commands/list/json.js.map +1 -1
- package/dist/commands/list/list.js +44 -29
- package/dist/commands/list/list.js.map +1 -1
- package/dist/commands/list/print.js +52 -9
- package/dist/commands/list/print.js.map +1 -1
- package/dist/commands/list/suites/suites.js +140 -0
- package/dist/commands/list/suites/suites.js.map +1 -0
- package/dist/commands/list/views.js +37 -34
- package/dist/commands/list/views.js.map +1 -1
- package/dist/commands/mcp/dispatch.js +91 -36
- package/dist/commands/mcp/dispatch.js.map +1 -1
- package/dist/commands/mcp/mcp.js +56 -15
- package/dist/commands/mcp/mcp.js.map +1 -1
- package/dist/commands/mcp/serve.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/active.js +27 -22
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/target.js +2 -2
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/error.js +7 -8
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
- package/dist/commands/new/capability-template.js +118 -0
- package/dist/commands/new/capability-template.js.map +1 -0
- package/dist/commands/new/commit.js +8 -22
- package/dist/commands/new/commit.js.map +1 -1
- package/dist/commands/new/modifies.js +206 -0
- package/dist/commands/new/modifies.js.map +1 -0
- package/dist/commands/new/new.js +59 -14
- package/dist/commands/new/new.js.map +1 -1
- package/dist/commands/new/templates.js +48 -124
- package/dist/commands/new/templates.js.map +1 -1
- package/dist/commands/open.js +3 -7
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/policy/gate.js +27 -0
- package/dist/commands/policy/gate.js.map +1 -1
- package/dist/commands/rebase/plan.js +2 -2
- package/dist/commands/rebase/plan.js.map +1 -1
- package/dist/commands/rebase/rebase.js +60 -35
- package/dist/commands/rebase/rebase.js.map +1 -1
- package/dist/commands/seed/commit.js +55 -26
- package/dist/commands/seed/commit.js.map +1 -1
- package/dist/commands/seed/plan.js +158 -13
- package/dist/commands/seed/plan.js.map +1 -1
- package/dist/commands/seed/seed.js +13 -11
- package/dist/commands/seed/seed.js.map +1 -1
- package/dist/commands/show/feature.js +9 -5
- package/dist/commands/show/feature.js.map +1 -1
- package/dist/commands/show/introduced.js +157 -0
- package/dist/commands/show/introduced.js.map +1 -0
- package/dist/commands/show/marks.js +35 -6
- package/dist/commands/show/marks.js.map +1 -1
- package/dist/commands/show/service.js +41 -33
- package/dist/commands/show/service.js.map +1 -1
- package/dist/commands/show/show.js +17 -7
- package/dist/commands/show/show.js.map +1 -1
- package/dist/commands/status/fleet-next.js +90 -0
- package/dist/commands/status/fleet-next.js.map +1 -0
- package/dist/commands/status/json.js +2 -0
- package/dist/commands/status/json.js.map +1 -1
- package/dist/commands/status/print.js +89 -37
- package/dist/commands/status/print.js.map +1 -1
- package/dist/commands/status/status.js +3 -7
- package/dist/commands/status/status.js.map +1 -1
- package/dist/commands/steps/steps.js +103 -23
- package/dist/commands/steps/steps.js.map +1 -1
- package/dist/commands/subsystem/edit.js +7 -7
- package/dist/commands/subsystem/edit.js.map +1 -1
- package/dist/commands/subsystem/move.js +106 -46
- package/dist/commands/subsystem/move.js.map +1 -1
- package/dist/commands/subsystem/query.js +2 -4
- package/dist/commands/subsystem/query.js.map +1 -1
- package/dist/commands/subsystem/subsystem.js +4 -7
- package/dist/commands/subsystem/subsystem.js.map +1 -1
- package/dist/commands/subsystem/sync.js +289 -74
- package/dist/commands/subsystem/sync.js.map +1 -1
- package/dist/commands/subsystem/txn/exclude.js +132 -0
- package/dist/commands/subsystem/txn/exclude.js.map +1 -0
- package/dist/commands/subsystem/txn/links.js +128 -0
- package/dist/commands/subsystem/txn/links.js.map +1 -0
- package/dist/commands/subsystem/txn/report.js +174 -0
- package/dist/commands/subsystem/txn/report.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +147 -45
- package/dist/commands/subsystem/txn/txn.js.map +1 -1
- package/dist/commands/subsystem/txn/views.js +200 -21
- package/dist/commands/subsystem/txn/views.js.map +1 -1
- package/dist/commands/tasks/actions.js +107 -0
- package/dist/commands/tasks/actions.js.map +1 -0
- package/dist/commands/tasks/render.js +253 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +119 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +42 -26
- package/dist/commands/unarchive/manifest.js.map +1 -1
- package/dist/commands/unarchive/restore.js +83 -33
- package/dist/commands/unarchive/restore.js.map +1 -1
- package/dist/commands/unarchive/unarchive.js +22 -30
- package/dist/commands/unarchive/unarchive.js.map +1 -1
- package/dist/commands/validate/arch-coverage.js +78 -27
- package/dist/commands/validate/arch-coverage.js.map +1 -1
- package/dist/commands/validate/checks/fleet-shape.js +34 -126
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
- package/dist/commands/validate/checks/health-deps.js +9 -6
- package/dist/commands/validate/checks/health-deps.js.map +1 -1
- package/dist/commands/validate/checks/introduced.js +102 -0
- package/dist/commands/validate/checks/introduced.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +18 -8
- package/dist/commands/validate/checks/requirements.js.map +1 -1
- package/dist/commands/validate/checks/sources.js +11 -2
- package/dist/commands/validate/checks/sources.js.map +1 -1
- package/dist/commands/validate/coverage/covers-after.js +105 -0
- package/dist/commands/validate/coverage/covers-after.js.map +1 -0
- package/dist/commands/validate/feature.js +26 -20
- package/dist/commands/validate/feature.js.map +1 -1
- package/dist/commands/validate/fleet/census.js +37 -13
- package/dist/commands/validate/fleet/census.js.map +1 -1
- package/dist/commands/validate/fleet/landscape.js +144 -126
- package/dist/commands/validate/fleet/landscape.js.map +1 -1
- package/dist/commands/validate/fleet/load.js +66 -0
- package/dist/commands/validate/fleet/load.js.map +1 -1
- package/dist/commands/validate/fleet/map/attest.js +98 -0
- package/dist/commands/validate/fleet/map/attest.js.map +1 -0
- package/dist/commands/validate/fleet/map/bindings.js +107 -0
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
- package/dist/commands/validate/fleet/map/consumers.js +244 -0
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
- package/dist/commands/validate/fleet/map/isolation.js +116 -0
- package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
- package/dist/commands/validate/fleet/map/usecases.js +54 -0
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +44 -14
- package/dist/commands/validate/fleet/obligations.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/print.js +10 -2
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -1
- package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +50 -15
- package/dist/commands/validate/fleet/views/ids.js.map +1 -1
- package/dist/commands/validate/fleet/views/projects.js +278 -0
- package/dist/commands/validate/fleet/views/projects.js.map +1 -0
- package/dist/commands/validate/fleet/views/root-documents.js +83 -0
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +40 -47
- package/dist/commands/validate/fleet/views/stale.js.map +1 -1
- package/dist/commands/validate/links/corpus.js +1 -4
- package/dist/commands/validate/links/corpus.js.map +1 -1
- package/dist/commands/validate/links/glossary.js.map +1 -1
- package/dist/commands/validate/render/repeats.js +63 -0
- package/dist/commands/validate/render/repeats.js.map +1 -0
- package/dist/commands/validate/render/rollups.js +115 -0
- package/dist/commands/validate/render/rollups.js.map +1 -0
- package/dist/commands/validate/render/text.js +199 -0
- package/dist/commands/validate/render/text.js.map +1 -0
- package/dist/commands/validate/report.js +36 -160
- package/dist/commands/validate/report.js.map +1 -1
- package/dist/commands/validate/scope.js +113 -0
- package/dist/commands/validate/scope.js.map +1 -0
- package/dist/commands/validate/service/api.js +21 -107
- package/dist/commands/validate/service/api.js.map +1 -1
- package/dist/commands/validate/service/contracts/generated.js +134 -0
- package/dist/commands/validate/service/contracts/generated.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +36 -14
- package/dist/commands/validate/service/events/events.js.map +1 -1
- package/dist/commands/validate/service/events/message-producers.js +1 -1
- package/dist/commands/validate/service/events/message-producers.js.map +1 -1
- package/dist/commands/validate/service/evidence-pins.js +56 -10
- package/dist/commands/validate/service/evidence-pins.js.map +1 -1
- package/dist/commands/validate/service/model/diverged.js +226 -0
- package/dist/commands/validate/service/model/diverged.js.map +1 -0
- package/dist/commands/validate/service/model/grade.js +163 -0
- package/dist/commands/validate/service/model/grade.js.map +1 -0
- package/dist/commands/validate/service/service.js +121 -61
- package/dist/commands/validate/service/service.js.map +1 -1
- package/dist/commands/validate/service/specs.js +88 -28
- package/dist/commands/validate/service/specs.js.map +1 -1
- package/dist/commands/validate/service/spine.js +38 -3
- package/dist/commands/validate/service/spine.js.map +1 -1
- package/dist/commands/validate/service/usecases/tags.js +113 -0
- package/dist/commands/validate/service/usecases/tags.js.map +1 -0
- package/dist/commands/validate/service/usecases/usecases.js +209 -0
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/validate.js +85 -60
- package/dist/commands/validate/validate.js.map +1 -1
- package/dist/commands/verify/cross/diff.js +2 -6
- package/dist/commands/verify/cross/diff.js.map +1 -1
- package/dist/commands/verify/evidence/contract.js +1 -1
- package/dist/commands/verify/evidence/contract.js.map +1 -1
- package/dist/commands/verify/evidence/read.js +12 -3
- package/dist/commands/verify/evidence/read.js.map +1 -1
- package/dist/commands/verify/frozen.js +45 -23
- package/dist/commands/verify/frozen.js.map +1 -1
- package/dist/commands/verify/record.js +69 -17
- package/dist/commands/verify/record.js.map +1 -1
- package/dist/commands/verify/report.js +27 -44
- package/dist/commands/verify/report.js.map +1 -1
- package/dist/commands/verify/results.js +112 -30
- package/dist/commands/verify/results.js.map +1 -1
- package/dist/commands/verify/verify.js +55 -52
- package/dist/commands/verify/verify.js.map +1 -1
- package/dist/commands/vouch/pack/pack.js +2 -2
- package/dist/commands/vouch/pack/pack.js.map +1 -1
- package/dist/commands/vouch/pack/print.js +1 -6
- package/dist/commands/vouch/pack/print.js.map +1 -1
- package/dist/commands/vouch/pack/sections.js +1 -2
- package/dist/commands/vouch/pack/sections.js.map +1 -1
- package/dist/commands/vouch/run.js +26 -81
- package/dist/commands/vouch/run.js.map +1 -1
- package/dist/commands/vouch/sample/plan.js +20 -34
- package/dist/commands/vouch/sample/plan.js.map +1 -1
- package/dist/commands/vouch/vet/verify.js +39 -7
- package/dist/commands/vouch/vet/verify.js.map +1 -1
- package/dist/commands/vouch/vouch.js +10 -17
- package/dist/commands/vouch/vouch.js.map +1 -1
- package/dist/core/agent/agents-md/command-map.js +81 -106
- package/dist/core/agent/agents-md/command-map.js.map +1 -1
- package/dist/core/agent/agents-md/map/explain.js +21 -9
- package/dist/core/agent/agents-md/map/explain.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/context.js +17 -8
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
- package/dist/core/agent/agents-md/map/mcp.js +10 -7
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
- package/dist/core/agent/agents-md/map/status.js +24 -8
- package/dist/core/agent/agents-md/map/status.js.map +1 -1
- package/dist/core/agent/agents-md/map/subsystem.js +80 -8
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
- package/dist/core/agent/agents-md/map/usecases.js +88 -10
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
- package/dist/core/agent/agents-md/refusals.js +49 -22
- package/dist/core/agent/agents-md/refusals.js.map +1 -1
- package/dist/core/agent/agents-md.js +39 -6
- package/dist/core/agent/agents-md.js.map +1 -1
- package/dist/core/agent/agents-stamp.js +10 -0
- package/dist/core/agent/agents-stamp.js.map +1 -1
- package/dist/core/agent/protocol.js +1 -1
- package/dist/core/agent/protocol.js.map +1 -1
- package/dist/core/agent/scaffold.js +10 -15
- package/dist/core/agent/scaffold.js.map +1 -1
- package/dist/core/agent/support/report.js +46 -5
- package/dist/core/agent/support/report.js.map +1 -1
- package/dist/core/agent/tools/dialects.js +1 -0
- package/dist/core/agent/tools/dialects.js.map +1 -1
- package/dist/core/agent/tools/registry.js +41 -76
- package/dist/core/agent/tools/registry.js.map +1 -1
- package/dist/core/agent/workflows/adopt.js +158 -11
- package/dist/core/agent/workflows/adopt.js.map +1 -1
- package/dist/core/agent/workflows/check.js +78 -39
- package/dist/core/agent/workflows/check.js.map +1 -1
- package/dist/core/agent/workflows/closing.js +88 -27
- package/dist/core/agent/workflows/closing.js.map +1 -1
- package/dist/core/agent/workflows/feature.js +128 -13
- package/dist/core/agent/workflows/feature.js.map +1 -1
- package/dist/core/agent/workflows/implement.js +96 -13
- package/dist/core/agent/workflows/implement.js.map +1 -1
- package/dist/core/agent/workflows/reference/authoring.js +106 -4
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
- package/dist/core/agent/workflows/reference/codes.js +8 -6
- package/dist/core/agent/workflows/reference/codes.js.map +1 -1
- package/dist/core/agent/workflows/reference/done-check.js +37 -15
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
- package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +6 -3
- package/dist/core/agent/workflows/reference/reference.js.map +1 -1
- package/dist/core/agent/workflows/reference/spine.js +68 -27
- package/dist/core/agent/workflows/reference/spine.js.map +1 -1
- package/dist/core/asyncapi/baseline/plan.js +14 -81
- package/dist/core/asyncapi/baseline/plan.js.map +1 -1
- package/dist/core/asyncapi/digest.js +30 -25
- package/dist/core/asyncapi/digest.js.map +1 -1
- package/dist/core/asyncapi/merge/components.js +5 -4
- package/dist/core/asyncapi/merge/components.js.map +1 -1
- package/dist/core/asyncapi/merge/error.js +7 -2
- package/dist/core/asyncapi/merge/error.js.map +1 -1
- package/dist/core/asyncapi/merge/markers.js +32 -50
- package/dist/core/asyncapi/merge/markers.js.map +1 -1
- package/dist/core/asyncapi/merge/merge.js +33 -53
- package/dist/core/asyncapi/merge/merge.js.map +1 -1
- package/dist/core/asyncapi/merge/pin.js +12 -36
- package/dist/core/asyncapi/merge/pin.js.map +1 -1
- package/dist/core/asyncapi/model.js.map +1 -1
- package/dist/core/asyncapi/read.js +36 -12
- package/dist/core/asyncapi/read.js.map +1 -1
- package/dist/core/brief/brief.js +96 -36
- package/dist/core/brief/brief.js.map +1 -1
- package/dist/core/brief/checks.js +138 -3
- package/dist/core/brief/checks.js.map +1 -1
- package/dist/core/brief/landscape.js +209 -130
- package/dist/core/brief/landscape.js.map +1 -1
- package/dist/core/brief/map/extend.js +84 -0
- package/dist/core/brief/map/extend.js.map +1 -0
- package/dist/core/brief/map/owed.js +266 -0
- package/dist/core/brief/map/owed.js.map +1 -0
- package/dist/core/brief/targets.js +109 -31
- package/dist/core/brief/targets.js.map +1 -1
- package/dist/core/brief/unchecked.js +14 -3
- package/dist/core/brief/unchecked.js.map +1 -1
- package/dist/core/c4/arch.js +90 -182
- package/dist/core/c4/arch.js.map +1 -1
- package/dist/core/c4/direction/direction.js +114 -0
- package/dist/core/c4/direction/direction.js.map +1 -0
- package/dist/core/c4/likec4.js +169 -14
- package/dist/core/c4/likec4.js.map +1 -1
- package/dist/core/c4/locate/unlocated.js +150 -0
- package/dist/core/c4/locate/unlocated.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +160 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -1
- package/dist/core/c4/parsed/values.js +54 -1
- package/dist/core/c4/parsed/values.js.map +1 -1
- package/dist/core/c4/parsed/view-ids.js +39 -1
- package/dist/core/c4/parsed/view-ids.js.map +1 -1
- package/dist/core/c4/prefetch/fleet.js +134 -0
- package/dist/core/c4/prefetch/fleet.js.map +1 -0
- package/dist/core/c4/project/architecture.js +123 -7
- package/dist/core/c4/project/architecture.js.map +1 -1
- package/dist/core/c4/project/batch.js +140 -0
- package/dist/core/c4/project/batch.js.map +1 -0
- package/dist/core/c4/project/documents.js +43 -12
- package/dist/core/c4/project/documents.js.map +1 -1
- package/dist/core/c4/project/load.js +79 -43
- package/dist/core/c4/project/load.js.map +1 -1
- package/dist/core/c4/project/staged.js +277 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/attested.js +0 -0
- package/dist/core/c4/resolve/attested.js.map +1 -0
- package/dist/core/c4/resolve/external.js +51 -0
- package/dist/core/c4/resolve/external.js.map +1 -0
- package/dist/core/c4/resolve/service.js +78 -17
- package/dist/core/c4/resolve/service.js.map +1 -1
- package/dist/core/c4/resolve/steps.js +290 -0
- package/dist/core/c4/resolve/steps.js.map +1 -0
- package/dist/core/c4/resolve/systems.js +154 -0
- package/dist/core/c4/resolve/systems.js.map +1 -0
- package/dist/core/c4/root-project/exclude.js +352 -0
- package/dist/core/c4/root-project/exclude.js.map +1 -0
- package/dist/core/c4/seed/template.js +65 -1
- package/dist/core/c4/seed/template.js.map +1 -1
- package/dist/core/c4/service-model/created/models.js +96 -0
- package/dist/core/c4/service-model/created/models.js.map +1 -0
- package/dist/core/c4/service-model/documents.js +47 -0
- package/dist/core/c4/service-model/documents.js.map +1 -0
- package/dist/core/c4/service-model/fleet/extending.js +82 -0
- package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
- package/dist/core/c4/service-model/load.js +165 -0
- package/dist/core/c4/service-model/load.js.map +1 -0
- package/dist/core/c4/service-model/renderer.js +128 -0
- package/dist/core/c4/service-model/renderer.js.map +1 -0
- package/dist/core/c4/service-model/shape.js +106 -0
- package/dist/core/c4/service-model/shape.js.map +1 -0
- package/dist/core/c4/service-model/slice.js +188 -0
- package/dist/core/c4/service-model/slice.js.map +1 -0
- package/dist/core/c4/source-mask.js +297 -10
- package/dist/core/c4/source-mask.js.map +1 -1
- package/dist/core/c4/source-scan.js +222 -141
- package/dist/core/c4/source-scan.js.map +1 -1
- package/dist/core/c4/splice/authored-source.js +79 -13
- package/dist/core/c4/splice/authored-source.js.map +1 -1
- package/dist/core/c4/splice/contract.js +20 -0
- package/dist/core/c4/splice/contract.js.map +1 -1
- package/dist/core/c4/splice/delta-blocks.js +20 -20
- package/dist/core/c4/splice/delta-blocks.js.map +1 -1
- package/dist/core/c4/splice/identity/declared.js +87 -0
- package/dist/core/c4/splice/identity/declared.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +37 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -1
- package/dist/core/c4/splice/identity/existing.js +80 -0
- package/dist/core/c4/splice/identity/existing.js.map +1 -0
- package/dist/core/c4/splice/identity/interior.js +80 -0
- package/dist/core/c4/splice/identity/interior.js.map +1 -0
- package/dist/core/c4/splice/identity/owner.js +50 -0
- package/dist/core/c4/splice/identity/owner.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +182 -114
- package/dist/core/c4/splice/landscape-merge.js.map +1 -1
- package/dist/core/c4/splice/model/merge.js +151 -0
- package/dist/core/c4/splice/model/merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +160 -56
- package/dist/core/c4/splice/placement.js.map +1 -1
- package/dist/core/c4/splice/text/spot.js +131 -0
- package/dist/core/c4/splice/text/spot.js.map +1 -0
- package/dist/core/c4/workspace.js +13 -19
- package/dist/core/c4/workspace.js.map +1 -1
- package/dist/core/capabilities/capabilities.js +6 -6
- package/dist/core/capabilities/capabilities.js.map +1 -1
- package/dist/core/capabilities/delta/doc.js +7 -10
- package/dist/core/capabilities/delta/doc.js.map +1 -1
- package/dist/core/capabilities/delta/uncovered.js +2 -2
- package/dist/core/capabilities/delta/uncovered.js.map +1 -1
- package/dist/core/capabilities/findings.js +18 -22
- package/dist/core/capabilities/findings.js.map +1 -1
- package/dist/core/capabilities/realizes/findings.js +12 -19
- package/dist/core/capabilities/realizes/findings.js.map +1 -1
- package/dist/core/capabilities/realizes/join.js +0 -20
- package/dist/core/capabilities/realizes/join.js.map +1 -1
- package/dist/core/capabilities/rollup.js +6 -0
- package/dist/core/capabilities/rollup.js.map +1 -1
- package/dist/core/capabilities/tree.js +6 -28
- package/dist/core/capabilities/tree.js.map +1 -1
- package/dist/core/capabilities/usecase-join.js +3 -13
- package/dist/core/capabilities/usecase-join.js.map +1 -1
- package/dist/core/coherence/authoring/scaffold.js +11 -3
- package/dist/core/coherence/authoring/scaffold.js.map +1 -1
- package/dist/core/coherence/authoring/sentinels.js +2 -1
- package/dist/core/coherence/authoring/sentinels.js.map +1 -1
- package/dist/core/coherence/calls/called.js +52 -0
- package/dist/core/coherence/calls/called.js.map +1 -0
- package/dist/core/coherence/coherence.js +103 -22
- package/dist/core/coherence/coherence.js.map +1 -1
- package/dist/core/coherence/consumed/operations.js +70 -0
- package/dist/core/coherence/consumed/operations.js.map +1 -0
- package/dist/core/coherence/consumed/refusal.js +38 -0
- package/dist/core/coherence/consumed/refusal.js.map +1 -0
- package/dist/core/coherence/covers/health.js +85 -0
- package/dist/core/coherence/covers/health.js.map +1 -0
- package/dist/core/coherence/declared.js +60 -34
- package/dist/core/coherence/declared.js.map +1 -1
- package/dist/core/coherence/events/declared.js +44 -59
- package/dist/core/coherence/events/declared.js.map +1 -1
- package/dist/core/coherence/events/events.js +147 -16
- package/dist/core/coherence/events/events.js.map +1 -1
- package/dist/core/coherence/events/grades.js +31 -8
- package/dist/core/coherence/events/grades.js.map +1 -1
- package/dist/core/coherence/events/lookups.js +28 -87
- package/dist/core/coherence/events/lookups.js.map +1 -1
- package/dist/core/coherence/events/produced.js +100 -0
- package/dist/core/coherence/events/produced.js.map +1 -0
- package/dist/core/coherence/lookups.js +18 -78
- package/dist/core/coherence/lookups.js.map +1 -1
- package/dist/core/coherence/retired/archived.js +285 -0
- package/dist/core/coherence/retired/archived.js.map +1 -0
- package/dist/core/coherence/retired/event-pair.js +62 -0
- package/dist/core/coherence/retired/event-pair.js.map +1 -0
- package/dist/core/coherence/retired/merged.js +79 -0
- package/dist/core/coherence/retired/merged.js.map +1 -0
- package/dist/core/coherence/retired/retirement.js +49 -0
- package/dist/core/coherence/retired/retirement.js.map +1 -0
- package/dist/core/coherence/retired/revival/arrivals.js +131 -0
- package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
- package/dist/core/coherence/retired/revival/revived.js +297 -0
- package/dist/core/coherence/retired/revival/revived.js.map +1 -0
- package/dist/core/consumers/after.js +113 -0
- package/dist/core/consumers/after.js.map +1 -0
- package/dist/core/consumers/consumers.js +296 -0
- package/dist/core/consumers/consumers.js.map +1 -0
- package/dist/core/consumers/current.js +211 -0
- package/dist/core/consumers/current.js.map +1 -0
- package/dist/core/consumers/scan.js +46 -0
- package/dist/core/consumers/scan.js.map +1 -0
- package/dist/core/consumers/state.js +27 -0
- package/dist/core/consumers/state.js.map +1 -0
- package/dist/core/delta/delta.js +51 -6
- package/dist/core/delta/delta.js.map +1 -1
- package/dist/core/dependencies/fanin.js +2 -2
- package/dist/core/dependencies/fanin.js.map +1 -1
- package/dist/core/deployment/delta.js +191 -0
- package/dist/core/deployment/delta.js.map +1 -0
- package/dist/core/deployment/objects.js +145 -0
- package/dist/core/deployment/objects.js.map +1 -0
- package/dist/core/diff/base-git.js +94 -12
- package/dist/core/diff/base-git.js.map +1 -1
- package/dist/core/diff/base-state.js +49 -21
- package/dist/core/diff/base-state.js.map +1 -1
- package/dist/core/diff/joins.js +136 -0
- package/dist/core/diff/joins.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +22 -6
- package/dist/core/diff/scope/changed-paths.js.map +1 -1
- package/dist/core/diff/scope/edges.js +82 -0
- package/dist/core/diff/scope/edges.js.map +1 -0
- package/dist/core/diff/semantic.js +100 -31
- package/dist/core/diff/semantic.js.map +1 -1
- package/dist/core/docs.js +31 -22
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +34 -18
- package/dist/core/doctor/agents.js.map +1 -1
- package/dist/core/doctor/config.js +7 -3
- package/dist/core/doctor/config.js.map +1 -1
- package/dist/core/doctor/doctor.js +91 -11
- package/dist/core/doctor/doctor.js.map +1 -1
- package/dist/core/doctor/report.js.map +1 -1
- package/dist/core/doctor/reports/scan.js +242 -0
- package/dist/core/doctor/reports/scan.js.map +1 -0
- package/dist/core/document/apply.js +158 -11
- package/dist/core/document/apply.js.map +1 -1
- package/dist/core/document/frontmatter.js +55 -0
- package/dist/core/document/frontmatter.js.map +1 -1
- package/dist/core/document/parse.js +29 -6
- package/dist/core/document/parse.js.map +1 -1
- package/dist/core/document/scenarios.js +17 -0
- package/dist/core/document/scenarios.js.map +1 -1
- package/dist/core/document/spec.js +4 -11
- package/dist/core/document/spec.js.map +1 -1
- package/dist/core/envelope/config.js +10 -0
- package/dist/core/envelope/config.js.map +1 -1
- package/dist/core/envelope/json.js +34 -0
- package/dist/core/envelope/json.js.map +1 -1
- package/dist/core/explain/families.js +26 -21
- package/dist/core/explain/families.js.map +1 -1
- package/dist/core/explain/lookup.js +14 -1
- package/dist/core/explain/lookup.js.map +1 -1
- package/dist/core/explain/refusals.js +5 -5
- package/dist/core/explain/refusals.js.map +1 -1
- package/dist/core/explain/terms/documents.js +227 -0
- package/dist/core/explain/terms/documents.js.map +1 -0
- package/dist/core/explain/terms/done-check.js +144 -0
- package/dist/core/explain/terms/done-check.js.map +1 -0
- package/dist/core/explain/terms/entry.js +14 -0
- package/dist/core/explain/terms/entry.js.map +1 -0
- package/dist/core/explain/terms/stages.js +71 -0
- package/dist/core/explain/terms/stages.js.map +1 -0
- package/dist/core/explain/terms/tasks.js +97 -0
- package/dist/core/explain/terms/tasks.js.map +1 -0
- package/dist/core/explain/terms.js +68 -109
- package/dist/core/explain/terms.js.map +1 -1
- package/dist/core/explore/explore.js +40 -10
- package/dist/core/explore/explore.js.map +1 -1
- package/dist/core/fleet-context.js +81 -95
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +11 -4
- package/dist/core/gate/checks.js.map +1 -1
- package/dist/core/gate/partners.js +69 -28
- package/dist/core/gate/partners.js.map +1 -1
- package/dist/core/gate/report.js.map +1 -1
- package/dist/core/gate/verification.js +75 -12
- package/dist/core/gate/verification.js.map +1 -1
- package/dist/core/gherkin/stale.js +13 -37
- package/dist/core/gherkin/stale.js.map +1 -1
- package/dist/core/glossary/delta.js +10 -7
- package/dist/core/glossary/delta.js.map +1 -1
- package/dist/core/glossary/tree.js +6 -19
- package/dist/core/glossary/tree.js.map +1 -1
- package/dist/core/kernel/concurrency.js +19 -0
- package/dist/core/kernel/concurrency.js.map +1 -1
- package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
- package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
- package/dist/core/kernel/path-safety.js +38 -0
- package/dist/core/kernel/path-safety.js.map +1 -1
- package/dist/core/kernel/records.js +11 -0
- package/dist/core/kernel/records.js.map +1 -1
- package/dist/core/links/backlinks.js +1 -3
- package/dist/core/links/backlinks.js.map +1 -1
- package/dist/core/links/corpus.js +51 -37
- package/dist/core/links/corpus.js.map +1 -1
- package/dist/core/links/findings.js.map +1 -1
- package/dist/core/links/parse.js +38 -9
- package/dist/core/links/parse.js.map +1 -1
- package/dist/core/mcp/argv.js +101 -0
- package/dist/core/mcp/argv.js.map +1 -1
- package/dist/core/mcp/author-tools.js +2 -1
- package/dist/core/mcp/author-tools.js.map +1 -1
- package/dist/core/mcp/protocol.js +2 -2
- package/dist/core/mcp/protocol.js.map +1 -1
- package/dist/core/mcp/tools.js +43 -33
- package/dist/core/mcp/tools.js.map +1 -1
- package/dist/core/openapi/baseline/gate.js +53 -12
- package/dist/core/openapi/baseline/gate.js.map +1 -1
- package/dist/core/openapi/baseline/plan.js +40 -10
- package/dist/core/openapi/baseline/plan.js.map +1 -1
- package/dist/core/openapi/baseline/record.js +0 -1
- package/dist/core/openapi/baseline/record.js.map +1 -1
- package/dist/core/openapi/contract-text.js +33 -0
- package/dist/core/openapi/contract-text.js.map +1 -0
- package/dist/core/openapi/contract-tree.js +301 -0
- package/dist/core/openapi/contract-tree.js.map +1 -0
- package/dist/core/openapi/depth.js +38 -24
- package/dist/core/openapi/depth.js.map +1 -1
- package/dist/core/openapi/digest.js +52 -2
- package/dist/core/openapi/digest.js.map +1 -1
- package/dist/core/openapi/doc.js +12 -4
- package/dist/core/openapi/doc.js.map +1 -1
- package/dist/core/openapi/merge/components.js +25 -60
- package/dist/core/openapi/merge/components.js.map +1 -1
- package/dist/core/openapi/merge/error.js +3 -13
- package/dist/core/openapi/merge/error.js.map +1 -1
- package/dist/core/openapi/merge/markers.js +26 -30
- package/dist/core/openapi/merge/markers.js.map +1 -1
- package/dist/core/openapi/merge/merge.js +28 -52
- package/dist/core/openapi/merge/merge.js.map +1 -1
- package/dist/core/openapi/merge/pin.js +17 -35
- package/dist/core/openapi/merge/pin.js.map +1 -1
- package/dist/core/openspec/decide/verdict.js.map +1 -1
- package/dist/core/openspec/inventory.js +4 -5
- package/dist/core/openspec/inventory.js.map +1 -1
- package/dist/core/openspec/model/mapping.js +30 -28
- package/dist/core/openspec/model/mapping.js.map +1 -1
- package/dist/core/openspec/model/model.js +12 -7
- package/dist/core/openspec/model/model.js.map +1 -1
- package/dist/core/openspec/scan/changes.js +10 -4
- package/dist/core/openspec/scan/changes.js.map +1 -1
- package/dist/core/openspec/scan/config.js +7 -16
- package/dist/core/openspec/scan/config.js.map +1 -1
- package/dist/core/openspec/scan/shape.js +63 -19
- package/dist/core/openspec/scan/shape.js.map +1 -1
- package/dist/core/openspec/scan/walk.js +21 -38
- package/dist/core/openspec/scan/walk.js.map +1 -1
- package/dist/core/pack/living.js +43 -4
- package/dist/core/pack/living.js.map +1 -1
- package/dist/core/pack/pack.js +50 -6
- package/dist/core/pack/pack.js.map +1 -1
- package/dist/core/projection/arch-slice.js +2 -2
- package/dist/core/projection/arch-slice.js.map +1 -1
- package/dist/core/projection/introduced.js +14 -0
- package/dist/core/projection/introduced.js.map +1 -0
- package/dist/core/provenance/findings.js +48 -12
- package/dist/core/provenance/findings.js.map +1 -1
- package/dist/core/provenance/git.js +33 -57
- package/dist/core/provenance/git.js.map +1 -1
- package/dist/core/provenance/gitq/moves.js +71 -114
- package/dist/core/provenance/gitq/moves.js.map +1 -1
- package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
- package/dist/core/provenance/sources.js +23 -6
- package/dist/core/provenance/sources.js.map +1 -1
- package/dist/core/provenance/stamp.js +5 -17
- package/dist/core/provenance/stamp.js.map +1 -1
- package/dist/core/repo/authored/paths.js +18 -0
- package/dist/core/repo/authored/paths.js.map +1 -1
- package/dist/core/repo/entries.js.map +1 -1
- package/dist/core/repo/paths.js +92 -6
- package/dist/core/repo/paths.js.map +1 -1
- package/dist/core/repo/repo.js +74 -14
- package/dist/core/repo/repo.js.map +1 -1
- package/dist/core/repo/tree/find.js +12 -3
- package/dist/core/repo/tree/find.js.map +1 -1
- package/dist/core/repo/tree/fs.js +27 -1
- package/dist/core/repo/tree/fs.js.map +1 -1
- package/dist/core/repo/tree/render/body.js +258 -0
- package/dist/core/repo/tree/render/body.js.map +1 -0
- package/dist/core/repo/tree/render/projects.js +182 -0
- package/dist/core/repo/tree/render/projects.js.map +1 -0
- package/dist/core/repo/tree/render/service/header.js +125 -0
- package/dist/core/repo/tree/render/service/header.js.map +1 -0
- package/dist/core/repo/tree/render/service/peers.js +28 -0
- package/dist/core/repo/tree/render/service/peers.js.map +1 -0
- package/dist/core/repo/tree/render/service/view-id.js +67 -0
- package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
- package/dist/core/repo/tree/render/service/views.js +78 -0
- package/dist/core/repo/tree/render/service/views.js.map +1 -0
- package/dist/core/repo/tree/render/stale.js +42 -0
- package/dist/core/repo/tree/render/stale.js.map +1 -0
- package/dist/core/repo/tree/render/text.js +84 -0
- package/dist/core/repo/tree/render/text.js.map +1 -0
- package/dist/core/repo/tree/render/views.js +293 -0
- package/dist/core/repo/tree/render/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +53 -32
- package/dist/core/repo/tree/walk.js.map +1 -1
- package/dist/core/results.js +47 -12
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +121 -13
- package/dist/core/scaffold/landscape.js.map +1 -1
- package/dist/core/scaffold/legacy.js +271 -0
- package/dist/core/scaffold/legacy.js.map +1 -0
- package/dist/core/staging/commit.js +26 -15
- package/dist/core/staging/commit.js.map +1 -1
- package/dist/core/staging/lock.js +74 -12
- package/dist/core/staging/lock.js.map +1 -1
- package/dist/core/staging/recovery/intent.js +2 -5
- package/dist/core/staging/recovery/intent.js.map +1 -1
- package/dist/core/staging/recovery/recover.js +84 -6
- package/dist/core/staging/recovery/recover.js.map +1 -1
- package/dist/core/staging/snapshot/manifest.js +188 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +39 -45
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +24 -14
- package/dist/core/staging/txn/forward.js.map +1 -1
- package/dist/core/staging/writes.js.map +1 -1
- package/dist/core/status/actions/execution.js +11 -0
- package/dist/core/status/actions/execution.js.map +1 -1
- package/dist/core/status/contracts.js +39 -15
- package/dist/core/status/contracts.js.map +1 -1
- package/dist/core/status/feature/artifacts.js +33 -8
- package/dist/core/status/feature/artifacts.js.map +1 -1
- package/dist/core/status/feature/feature.js +24 -17
- package/dist/core/status/feature/feature.js.map +1 -1
- package/dist/core/status/feature/next.js +20 -7
- package/dist/core/status/feature/next.js.map +1 -1
- package/dist/core/status/feature/words.js +96 -0
- package/dist/core/status/feature/words.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +43 -14
- package/dist/core/status/fleet/fleet.js.map +1 -1
- package/dist/core/status/fleet/next.js +153 -58
- package/dist/core/status/fleet/next.js.map +1 -1
- package/dist/core/status/report.js.map +1 -1
- package/dist/core/status/scan.js.map +1 -1
- package/dist/core/status/verification.js +30 -15
- package/dist/core/status/verification.js.map +1 -1
- package/dist/core/tasks/packet.js +199 -0
- package/dist/core/tasks/packet.js.map +1 -0
- package/dist/core/tasks/record.js +43 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/sources.js +181 -0
- package/dist/core/tasks/sources.js.map +1 -0
- package/dist/core/tasks/stamps.js +76 -0
- package/dist/core/tasks/stamps.js.map +1 -0
- package/dist/core/tasks/unit.js +0 -0
- package/dist/core/tasks/unit.js.map +1 -0
- package/dist/core/usecases/capability.js +11 -14
- package/dist/core/usecases/capability.js.map +1 -1
- package/dist/core/usecases/delta/claims.js +31 -7
- package/dist/core/usecases/delta/claims.js.map +1 -1
- package/dist/core/usecases/delta/flows.js +5 -7
- package/dist/core/usecases/delta/flows.js.map +1 -1
- package/dist/core/usecases/delta/modified.js +315 -0
- package/dist/core/usecases/delta/modified.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +32 -191
- package/dist/core/usecases/delta/overlay.js.map +1 -1
- package/dist/core/usecases/fleet.js +195 -36
- package/dist/core/usecases/fleet.js.map +1 -1
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/capability-tag.js +8 -9
- package/dist/core/usecases/grade/capability-tag.js.map +1 -0
- package/dist/core/usecases/grade/feature.js +88 -0
- package/dist/core/usecases/grade/feature.js.map +1 -0
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/requirement-tag.js +3 -4
- package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/steps.js +102 -33
- package/dist/core/usecases/grade/steps.js.map +1 -0
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/usecases.js +23 -10
- package/dist/core/usecases/grade/usecases.js.map +1 -0
- package/dist/core/usecases/operations.js +26 -14
- package/dist/core/usecases/operations.js.map +1 -1
- package/dist/core/usecases/place.js.map +1 -1
- package/dist/core/usecases/service/exclude.js +119 -0
- package/dist/core/usecases/service/exclude.js.map +1 -0
- package/dist/core/usecases/service/flows.js +164 -0
- package/dist/core/usecases/service/flows.js.map +1 -0
- package/dist/core/usecases/suites/participants.js +83 -0
- package/dist/core/usecases/suites/participants.js.map +1 -0
- package/dist/core/usecases/suites/suites.js +45 -0
- package/dist/core/usecases/suites/suites.js.map +1 -0
- package/dist/core/verify/answers.js +12 -5
- package/dist/core/verify/answers.js.map +1 -1
- package/dist/core/verify/build.js +102 -82
- package/dist/core/verify/build.js.map +1 -1
- package/dist/core/verify/checklist.js +70 -12
- package/dist/core/verify/checklist.js.map +1 -1
- package/dist/core/verify/location.js +67 -0
- package/dist/core/verify/location.js.map +1 -0
- package/dist/core/verify/pins/lint.js +3 -2
- package/dist/core/verify/pins/lint.js.map +1 -1
- package/dist/core/verify/pins/pin.js +1 -1
- package/dist/core/verify/pins/pin.js.map +1 -1
- package/dist/core/verify/read/file.js +224 -0
- package/dist/core/verify/read/file.js.map +1 -0
- package/dist/core/verify/{file.js → read/shape.js} +16 -104
- package/dist/core/verify/read/shape.js.map +1 -0
- package/dist/core/verify/read/union.js +105 -0
- package/dist/core/verify/read/union.js.map +1 -0
- package/dist/core/verify/record.js +35 -12
- package/dist/core/verify/record.js.map +1 -1
- package/dist/core/verify/store/commit.js +40 -30
- package/dist/core/verify/store/commit.js.map +1 -1
- package/dist/core/verify/store/render.js +8 -4
- package/dist/core/verify/store/render.js.map +1 -1
- package/dist/core/vocabulary/issue.js +4 -0
- package/dist/core/vocabulary/issue.js.map +1 -1
- package/dist/core/vocabulary/maturity.js +75 -4
- package/dist/core/vocabulary/maturity.js.map +1 -1
- package/dist/core/vocabulary/report.js +16 -1
- package/dist/core/vocabulary/report.js.map +1 -1
- package/examples/README.md +54 -11
- package/examples/docs/architecture/landscape.likec4 +62 -6
- package/examples/docs/architecture/services.likec4 +70 -0
- package/examples/docs/architecture/subsystems.likec4 +7 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +16 -7
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +4 -1
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
- package/examples/docs/likec4.config.json +0 -1
- package/examples/docs/services/checkout-web/model.likec4 +39 -56
- package/examples/docs/services/order-service/arch.spec.md +13 -6
- package/examples/docs/services/order-service/asyncapi.yaml +3 -2
- package/examples/docs/services/order-service/model.likec4 +58 -70
- package/examples/docs/services/payment-service/arch.spec.md +7 -4
- package/examples/docs/services/payment-service/model.likec4 +38 -37
- package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
- package/examples/docs/services/platform/identity-service/model.likec4 +35 -37
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
- package/examples/docs/services/platform/notification-service/health.yaml +8 -3
- package/examples/docs/services/platform/notification-service/model.likec4 +43 -64
- package/package.json +1 -1
- package/dist/commands/validate/checks/vocabulary.js +0 -31
- package/dist/commands/validate/checks/vocabulary.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/capability-tag.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/steps.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/usecases.js.map +0 -1
- package/dist/core/agent/agents-md/artifacts.js +0 -220
- package/dist/core/agent/agents-md/artifacts.js.map +0 -1
- package/dist/core/agent/agents-md/cycle.js +0 -165
- package/dist/core/agent/agents-md/cycle.js.map +0 -1
- package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
- package/dist/core/agent/agents-md/spine.js +0 -40
- package/dist/core/agent/agents-md/spine.js.map +0 -1
- package/dist/core/coherence/events/merged.js +0 -40
- package/dist/core/coherence/events/merged.js.map +0 -1
- package/dist/core/diff/current-state.js +0 -96
- package/dist/core/diff/current-state.js.map +0 -1
- package/dist/core/diff/victims.js +0 -247
- package/dist/core/diff/victims.js.map +0 -1
- package/dist/core/repo/tree/views.js +0 -172
- package/dist/core/repo/tree/views.js.map +0 -1
- package/dist/core/staging/snapshot.js.map +0 -1
- package/dist/core/verify/file.js.map +0 -1
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { fail, repoPath, reportNoConfig } from "../../core/envelope/json.js";
|
|
1
|
+
import { configOrRefuse, fail, repoPath } from "../../core/envelope/json.js";
|
|
3
2
|
import { missingFeatureMessage, resolveFeature } from "../../core/repo/repo.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import {} from "../../core/staging/interrupted.js";
|
|
4
|
+
import { LOCK_WAIT_MS } from "../../core/staging/lock.js";
|
|
5
|
+
import { openCommitWindow } from "../../core/staging/recovery/recover.js";
|
|
7
6
|
import { docsRepoReady } from "../policy/gate.js";
|
|
8
7
|
import { featureChecklist } from "../../core/verify/checklist.js";
|
|
9
|
-
import { readVerificationState } from "../../core/verify/file.js";
|
|
10
|
-
import { verificationPath } from "../../core/verify/record.js";
|
|
8
|
+
import { readVerificationState } from "../../core/verify/read/file.js";
|
|
11
9
|
import { report } from "./report.js";
|
|
12
10
|
import { reportFrozen } from "./frozen.js";
|
|
13
11
|
import { record } from "./record.js";
|
|
@@ -17,21 +15,18 @@ export function registerVerify(program) {
|
|
|
17
15
|
program
|
|
18
16
|
.command("verify")
|
|
19
17
|
.argument("<featureId>", "feature id, e.g. FEAT-101")
|
|
20
|
-
.description("Check a
|
|
18
|
+
.description("Check a feature against its own promises: derive the claims, record the answers with evidence")
|
|
21
19
|
.option("--record <file>", "record a JSON answer set against the current checklist")
|
|
22
|
-
.option("--results <file>", "answer the scenario.tested claims mechanically from a cucumber JSON
|
|
20
|
+
.option("--results <file>", "answer the scenario.tested claims mechanically from a test report: cucumber JSON, or loam's runner-neutral loamScenarioReport JSON for any other runner")
|
|
23
21
|
.option("--contract-results <file>", "answer the api.exposes claims mechanically from an API contract-test report (loam's generic contract-results JSON)")
|
|
24
22
|
.option("--diff-answers <files...>", "cross-examine two independent answer sets against the current checklist (reads only, writes nothing)")
|
|
25
23
|
.option("--service <id>", "record only this service's claims, bound to the current repository commit")
|
|
26
24
|
.option("--json", "emit the machine contract instead of the human view")
|
|
27
25
|
.action(async (featureId, opts) => {
|
|
28
26
|
const json = opts.json === true;
|
|
29
|
-
const
|
|
30
|
-
if (
|
|
31
|
-
reportNoConfig(json, loaded);
|
|
27
|
+
const config = await configOrRefuse(json);
|
|
28
|
+
if (config === null)
|
|
32
29
|
return;
|
|
33
|
-
}
|
|
34
|
-
const config = loaded.config;
|
|
35
30
|
const { docsDir } = config;
|
|
36
31
|
const recording = opts.record !== undefined || opts.results !== undefined || opts.contractResults !== undefined;
|
|
37
32
|
// --diff-answers is a third READ form (see the WRITING/READING split
|
|
@@ -96,35 +91,23 @@ export function registerVerify(program) {
|
|
|
96
91
|
// recorders for different services of one feature are both supposed to
|
|
97
92
|
// land: the second waits out the first's sub-second window and merges
|
|
98
93
|
// over what it left. Reading stays lock-free — it writes nothing.
|
|
94
|
+
//
|
|
95
|
+
// A journal under the lock means the last writer never finished. The
|
|
96
|
+
// record's own authoritative read is about to happen; reading it over
|
|
97
|
+
// a half-commit would merge against bytes no run ever produced — the
|
|
98
|
+
// last docs-repo writer that could still silently treat a half-commit
|
|
99
|
+
// as healthy. That refusal must release the lock like every other path
|
|
100
|
+
// out, and once did not; `openCommitWindow` releases it before it answers.
|
|
99
101
|
let releaseLock = null;
|
|
100
102
|
let recovered = null;
|
|
101
103
|
if (recording) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return fail(json, "docs-busy", err.message);
|
|
108
|
-
throw err;
|
|
109
|
-
}
|
|
104
|
+
const opened = await openCommitWindow(docsDir, LOCK_WAIT_MS);
|
|
105
|
+
if (!opened.ok)
|
|
106
|
+
return fail(json, opened.code, opened.message);
|
|
107
|
+
releaseLock = opened.release;
|
|
108
|
+
recovered = opened.recovered;
|
|
110
109
|
}
|
|
111
110
|
try {
|
|
112
|
-
// A journal under the lock means the last writer never finished. The
|
|
113
|
-
// record's own authoritative read is about to happen; reading it over
|
|
114
|
-
// a half-commit would merge against bytes no run ever produced — the
|
|
115
|
-
// last docs-repo writer that could still silently treat a half-commit
|
|
116
|
-
// as healthy. INSIDE the try: this refusal must release the lock like
|
|
117
|
-
// every other path out, and once did not.
|
|
118
|
-
if (recording) {
|
|
119
|
-
try {
|
|
120
|
-
recovered = await recoverInterruptedCommit(docsDir);
|
|
121
|
-
}
|
|
122
|
-
catch (err) {
|
|
123
|
-
if (!(err instanceof InterruptedCommitError))
|
|
124
|
-
throw err;
|
|
125
|
-
return fail(json, "commit-interrupted", err.message);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
111
|
// Archived features resolve too: a shipped feature's verification is worth
|
|
129
112
|
// reading back, and it travelled into the archive with everything else.
|
|
130
113
|
const feature = await resolveFeature(docsDir, featureId, "include");
|
|
@@ -151,17 +134,31 @@ export function registerVerify(program) {
|
|
|
151
134
|
await diffAnswers({ docsDir, featureDir: feature.dir, json }, await featureChecklist(docsDir, feature.dir, feature.id), diffFiles, { lens: opts.service });
|
|
152
135
|
return;
|
|
153
136
|
}
|
|
154
|
-
// Before anything else: a
|
|
137
|
+
// Before anything else: a record file that exists but will not read
|
|
155
138
|
// is a refusal, not an absence. It holds somebody's answers and — in a
|
|
156
139
|
// fleet — other repositories' attestations; treating it as "not verified"
|
|
157
140
|
// let the next --record silently overwrite all of it, and made the read
|
|
158
141
|
// view say "no record" about a file sitting right there.
|
|
159
|
-
|
|
142
|
+
//
|
|
143
|
+
// The path is the one FILE that failed, and the advice is that file's:
|
|
144
|
+
// the record is several files now, and the recipe that is safe for a
|
|
145
|
+
// service's own attestation file (delete it, record that service again)
|
|
146
|
+
// is the one that erases a fleet's evidence when the file is the shared
|
|
147
|
+
// one-file record — which is what this refusal used to tell everyone,
|
|
148
|
+
// and what a miscounted record's "record again" looped back into.
|
|
149
|
+
//
|
|
150
|
+
// An in-flight feature's checklist is derived FIRST, because which of
|
|
151
|
+
// those files count depends on it: a record kept as per-service files
|
|
152
|
+
// answers the question being asked now, and only the caller knows what
|
|
153
|
+
// that is (`core/verify/read/union.ts`). Read without it, a service
|
|
154
|
+
// that recorded the current checklist could lose a same-day tie to one
|
|
155
|
+
// that recorded an older one, and this view called the whole record
|
|
156
|
+
// stale. An archived feature derives nothing — see below.
|
|
157
|
+
const checklist = feature.archived ? null : await featureChecklist(docsDir, feature.dir, feature.id);
|
|
158
|
+
const existing = await readVerificationState(feature.dir, checklist?.digest);
|
|
160
159
|
if (existing.state === "unreadable") {
|
|
161
|
-
return fail(json, "record-unreadable", `${repoPath(docsDir,
|
|
162
|
-
|
|
163
|
-
? "Record the answers again rather than editing the counts: a summary made to agree by hand still says nothing about what was checked."
|
|
164
|
-
: "It is plain YAML — repair it by hand, or delete it and record again. loam will not overwrite a record it could not read."));
|
|
160
|
+
return fail(json, "record-unreadable", `${repoPath(docsDir, existing.path)} exists but cannot be read as a verification record: ${existing.reason}. ` +
|
|
161
|
+
`${existing.advice} loam will not overwrite a record it could not read.`);
|
|
165
162
|
}
|
|
166
163
|
const recorded = existing.state === "ok" ? existing.verification : null;
|
|
167
164
|
// But an archived feature never gets a re-derived checklist — see the
|
|
@@ -169,15 +166,16 @@ export function registerVerify(program) {
|
|
|
169
166
|
// alike: the code is `invalid-option` rather than `answers-mismatch`
|
|
170
167
|
// because the answers were never compared to anything — there is no
|
|
171
168
|
// current checklist to answer, so the wrong thing here is the option,
|
|
172
|
-
// not the answer set.
|
|
173
|
-
|
|
169
|
+
// not the answer set. (`checklist` is null exactly when the feature is
|
|
170
|
+
// archived — the test is spelled on it so the compiler knows the
|
|
171
|
+
// in-flight path below has one.)
|
|
172
|
+
if (checklist === null) {
|
|
174
173
|
if (recording) {
|
|
175
174
|
return fail(json, "invalid-option", `${feature.id} is archived — its verification is history now. \`loam unarchive ${feature.id}\` first if the answers really need to change.`);
|
|
176
175
|
}
|
|
177
176
|
reportFrozen({ docsDir, featureDir: feature.dir, json }, feature.id, recorded);
|
|
178
177
|
return;
|
|
179
178
|
}
|
|
180
|
-
const checklist = await featureChecklist(docsDir, feature.dir, feature.id);
|
|
181
179
|
if (recording) {
|
|
182
180
|
// Standing in a service repo, `--service` is what the repo already
|
|
183
181
|
// says: omitting it must not fall back to the legacy all-at-once form,
|
|
@@ -191,10 +189,18 @@ export function registerVerify(program) {
|
|
|
191
189
|
// subdirectory, `--results` had to live in it, and `git rev-parse` ran
|
|
192
190
|
// there — a submodule or nested checkout under it would have named
|
|
193
191
|
// somebody else's commit on this repository's attestation.
|
|
192
|
+
//
|
|
193
|
+
// `config.service` and not `opts.service ?? config.service`, though
|
|
194
|
+
// the two are the same value: the binding refusal above lets a
|
|
195
|
+
// recording `--service` through only when it EQUALS the configured
|
|
196
|
+
// service. Taking the configured one keeps its brand — loam.json's
|
|
197
|
+
// reader validated it against the id grammar — and that brand is
|
|
198
|
+
// what `serviceRecordPath` demands before it joins the id into a
|
|
199
|
+
// file name. The raw flag never reaches the join.
|
|
194
200
|
await record({ docsDir, featureDir: feature.dir, json, recovered }, checklist, {
|
|
195
|
-
service:
|
|
201
|
+
service: config.service,
|
|
196
202
|
repoDir: config.root ?? process.cwd(),
|
|
197
|
-
previous: existing.state === "ok" ? { verification: existing.verification,
|
|
203
|
+
previous: existing.state === "ok" ? { verification: existing.verification, files: existing.files } : null,
|
|
198
204
|
}, opts);
|
|
199
205
|
return;
|
|
200
206
|
}
|
|
@@ -211,7 +217,4 @@ export function registerVerify(program) {
|
|
|
211
217
|
}
|
|
212
218
|
});
|
|
213
219
|
}
|
|
214
|
-
/* ------------------------------------------------------------------ */
|
|
215
|
-
/* Reading */
|
|
216
|
-
/* ------------------------------------------------------------------ */
|
|
217
220
|
//# sourceMappingURL=verify.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../src/commands/verify/verify.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Command } from \"commander\";\nimport { loadConfig } from \"../../core/envelope/config.js\";\nimport { fail, repoPath, reportNoConfig } from \"../../core/envelope/json.js\";\nimport { missingFeatureMessage, resolveFeature } from \"../../core/repo/repo.js\";\nimport { type CommitRecovery, InterruptedCommitError } from \"../../core/staging/interrupted.js\";\nimport { acquireDocsLockWaiting, DocsBusyError, LOCK_WAIT_MS } from \"../../core/staging/lock.js\";\nimport { recoverInterruptedCommit } from \"../../core/staging/recovery/recover.js\";\nimport { docsRepoReady } from \"../policy/gate.js\";\nimport { featureChecklist } from \"../../core/verify/checklist.js\";\nimport { readVerificationState } from \"../../core/verify/file.js\";\nimport { verificationPath } from \"../../core/verify/record.js\";\nimport { report } from \"./report.js\";\nimport { reportFrozen } from \"./frozen.js\";\nimport { record } from \"./record.js\";\nimport { type VerifyOptions } from \"./record.js\";\nimport { diffAnswers, type AnswerFiles } from \"./cross/diff.js\";\n\n\nexport function registerVerify(program: Command): void {\n program\n .command(\"verify\")\n .argument(\"<featureId>\", \"feature id, e.g. FEAT-101\")\n .description(\"Check a shipped feature against its own promises: derive the claims, record the answers\")\n .option(\"--record <file>\", \"record a JSON answer set against the current checklist\")\n .option(\n \"--results <file>\",\n \"answer the scenario.tested claims mechanically from a cucumber JSON test report\",\n )\n .option(\n \"--contract-results <file>\",\n \"answer the api.exposes claims mechanically from an API contract-test report (loam's generic contract-results JSON)\",\n )\n .option(\n \"--diff-answers <files...>\",\n \"cross-examine two independent answer sets against the current checklist (reads only, writes nothing)\",\n )\n .option(\n \"--service <id>\",\n \"record only this service's claims, bound to the current repository commit\",\n )\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .action(async (featureId: string, opts: VerifyOptions) => {\n const json = opts.json === true;\n\n const loaded = await loadConfig();\n if (loaded.kind !== \"loaded\") {\n reportNoConfig(json, loaded);\n return;\n }\n const config = loaded.config;\n const { docsDir } = config;\n const recording =\n opts.record !== undefined || opts.results !== undefined || opts.contractResults !== undefined;\n\n // --diff-answers is a third READ form (see the WRITING/READING split\n // below): it validates two answer sets against the same checklist and\n // writes nothing, so combining it with any recording flag is a\n // contradiction refused up front — before the binding, before the lock —\n // rather than a mode silently picked between the two.\n let diffFiles: AnswerFiles | null = null;\n if (opts.diffAnswers !== undefined) {\n if (recording) {\n return fail(\n json,\n \"invalid-option\",\n \"--diff-answers is a read-only cross-examination: it validates both files and writes nothing, \" +\n \"so it cannot be combined with --record, --results or --contract-results. \" +\n \"Diff first, then record the answer set you stand behind.\",\n );\n }\n // Commander's variadic form consumes arguments until the next --flag,\n // so a featureId placed AFTER the flag arrives here as a third file —\n // this refusal is what turns that mistake into a sentence instead of a\n // diff of the wrong files.\n const [a, b] = opts.diffAnswers;\n if (opts.diffAnswers.length !== 2 || a === undefined || b === undefined) {\n return fail(\n json,\n \"invalid-option\",\n \"--diff-answers takes exactly two answer files: --diff-answers a.json b.json\",\n );\n }\n diffFiles = { a, b };\n }\n\n // WRITING is bound to the repository; READING is not. An attestation\n // pins claims to this repo's git HEAD and to file:line evidence inside\n // it, so writing (--record, --results or --contract-results) with\n // `--service X` may only run where loam.json says this repo IS X —\n // vouch's and gherkin's refusal, for vouch's reason: from anywhere\n // else, that repository is somebody else's. Reading takes\n // `--service` as a pure lens (which claims are checkout-web's, and what\n // has it said?) and needs no binding at all, because it writes nothing.\n if (recording && opts.service !== undefined) {\n if (config.service === undefined) {\n return fail(\n json,\n \"repository-unavailable\",\n `Cannot attest for '${opts.service}' from here: this is not a service repo — loam.json declares no \\`service\\`. ` +\n `A federated attestation binds the answers to this repository's git HEAD and to evidence inside it, so the repository has to say which service it is. ` +\n `Add \"service\": \"${opts.service}\" to loam.json, or record it from that service's own repo.`,\n );\n }\n if (config.service !== opts.service) {\n return fail(\n json,\n \"service-mismatch\",\n `This repository is configured as service '${config.service}', so it cannot attest claims for '${opts.service}'.`,\n );\n }\n }\n\n // Before the lock, because the lock is a file INSIDE the docs repo: a\n // `docsDir` pointing at nothing used to surface as the lock file's own\n // ENOENT — an `internal` where the read side of this same command names\n // the misconfiguration. \"docs\", not \"services\", in BOTH modes — and that\n // is a pinned contract, not looseness: the legacy all-at-once form\n // records against a features-only docs repo with no `services/` at all,\n // and it has always exited 0 there. The cost is real and accepted: a\n // typo'd `docsDir` pointing at some existing non-docs directory gets a\n // `.loam-lock` created and removed inside it. The gate above only\n // guarantees the directory exists.\n if (!docsRepoReady(json, docsDir, \"docs\")) return;\n\n // A record is a merge over the docs repo, so recording takes the docs\n // lock — the same one archive, unarchive and rebase hold — and takes it\n // HERE, before the feature is even resolved. Behind the lock, an archive\n // can rename this feature's directory into features/archive/ at any\n // moment; a feature resolved before the lock could have its record\n // written into the pre-move path, a file nothing will ever read again.\n // The waiting form rather than archive's refuse-fast one, because two\n // recorders for different services of one feature are both supposed to\n // land: the second waits out the first's sub-second window and merges\n // over what it left. Reading stays lock-free — it writes nothing.\n let releaseLock: (() => Promise<void>) | null = null;\n let recovered: CommitRecovery | null = null;\n if (recording) {\n try {\n releaseLock = await acquireDocsLockWaiting(docsDir, LOCK_WAIT_MS);\n } catch (err) {\n if (err instanceof DocsBusyError) return fail(json, \"docs-busy\", err.message);\n throw err;\n }\n }\n try {\n // A journal under the lock means the last writer never finished. The\n // record's own authoritative read is about to happen; reading it over\n // a half-commit would merge against bytes no run ever produced — the\n // last docs-repo writer that could still silently treat a half-commit\n // as healthy. INSIDE the try: this refusal must release the lock like\n // every other path out, and once did not.\n if (recording) {\n try {\n recovered = await recoverInterruptedCommit(docsDir);\n } catch (err) {\n if (!(err instanceof InterruptedCommitError)) throw err;\n return fail(json, \"commit-interrupted\", err.message);\n }\n }\n // Archived features resolve too: a shipped feature's verification is worth\n // reading back, and it travelled into the archive with everything else.\n const feature = await resolveFeature(docsDir, featureId, \"include\");\n if (!feature) {\n // repo.ts's sentence, not a second copy of it. Resolving with \"include\"\n // means the archived branch inside it cannot fire here — an archived\n // feature resolves — so the text is exactly what it was; what changes is\n // that a reworded miss message can no longer leave this one behind.\n return fail(json, \"unknown-target\", await missingFeatureMessage(docsDir, featureId));\n }\n\n // The cross-examination lens leaves BEFORE the record is read below:\n // it never consumes verification.yaml, and the moment a\n // cross-examination is most needed is exactly when the record on disk\n // is too damaged to read and somebody is about to re-record over it —\n // the record-unreadable refusal must not bar the one command that\n // would inform that re-recording. The archived refusal still applies,\n // with the recording branch's code and reason: there is no current\n // checklist to answer, so the wrong thing is the option, not the\n // answer sets.\n if (diffFiles !== null) {\n if (feature.archived) {\n return fail(\n json,\n \"invalid-option\",\n `${feature.id} is archived — there is no current checklist to answer, so there is nothing to cross-examine; its record is frozen history. \\`loam unarchive ${feature.id}\\` first if the claims really need re-answering.`,\n );\n }\n await diffAnswers(\n { docsDir, featureDir: feature.dir, json },\n await featureChecklist(docsDir, feature.dir, feature.id),\n diffFiles,\n { lens: opts.service },\n );\n return;\n }\n\n // Before anything else: a verification.yaml that exists but will not read\n // is a refusal, not an absence. It holds somebody's answers and — in a\n // fleet — other repositories' attestations; treating it as \"not verified\"\n // let the next --record silently overwrite all of it, and made the read\n // view say \"no record\" about a file sitting right there.\n const existing = await readVerificationState(feature.dir);\n if (existing.state === \"unreadable\") {\n return fail(\n json,\n \"record-unreadable\",\n `${repoPath(docsDir, verificationPath(feature.dir))} exists but cannot be read as a verification record: ${existing.reason}. ` +\n (existing.code === \"verify.record-miscounted\"\n ? \"Record the answers again rather than editing the counts: a summary made to agree by hand still says nothing about what was checked.\"\n : \"It is plain YAML — repair it by hand, or delete it and record again. loam will not overwrite a record it could not read.\"),\n );\n }\n const recorded = existing.state === \"ok\" ? existing.verification : null;\n\n // But an archived feature never gets a re-derived checklist — see the\n // header. Its record is frozen history, and --record / --results refuse\n // alike: the code is `invalid-option` rather than `answers-mismatch`\n // because the answers were never compared to anything — there is no\n // current checklist to answer, so the wrong thing here is the option,\n // not the answer set.\n if (feature.archived) {\n if (recording) {\n return fail(\n json,\n \"invalid-option\",\n `${feature.id} is archived — its verification is history now. \\`loam unarchive ${feature.id}\\` first if the answers really need to change.`,\n );\n }\n reportFrozen({ docsDir, featureDir: feature.dir, json }, feature.id, recorded);\n return;\n }\n\n const checklist = await featureChecklist(docsDir, feature.dir, feature.id);\n\n if (recording) {\n // Standing in a service repo, `--service` is what the repo already\n // says: omitting it must not fall back to the legacy all-at-once form,\n // which claims the whole fleet's checklist on this one repo's word.\n //\n // The repo root, not the cwd — `vouch`'s and `gherkin`'s reason. An\n // attestation names a commit and rests on evidence resolved inside\n // \"this repository\", and `config.root` is the directory loam.json was\n // actually found in. Off `process.cwd()`, running from a subdirectory\n // silently changed all three: evidence resolved against the\n // subdirectory, `--results` had to live in it, and `git rev-parse` ran\n // there — a submodule or nested checkout under it would have named\n // somebody else's commit on this repository's attestation.\n await record(\n { docsDir, featureDir: feature.dir, json, recovered },\n checklist,\n {\n service: opts.service ?? config.service,\n repoDir: config.root ?? process.cwd(),\n previous: existing.state === \"ok\" ? { verification: existing.verification, raw: existing.raw } : null,\n },\n opts,\n );\n return;\n }\n\n report({ docsDir, featureDir: feature.dir, json }, checklist, recorded, {\n lens: opts.service,\n bound: config.service,\n });\n } finally {\n // Released on every path out — a refusal that kept the lock would turn\n // one bad answer set into a wedged docs repo for everyone else.\n if (releaseLock !== null) await releaseLock();\n }\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* Reading */\n/* ------------------------------------------------------------------ */\n"]}
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../src/commands/verify/verify.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Command } from \"commander\";\nimport { configOrRefuse, fail, repoPath } from \"../../core/envelope/json.js\";\nimport { missingFeatureMessage, resolveFeature } from \"../../core/repo/repo.js\";\nimport { type CommitRecovery } from \"../../core/staging/interrupted.js\";\nimport { LOCK_WAIT_MS } from \"../../core/staging/lock.js\";\nimport { openCommitWindow } from \"../../core/staging/recovery/recover.js\";\nimport { docsRepoReady } from \"../policy/gate.js\";\nimport { featureChecklist } from \"../../core/verify/checklist.js\";\nimport { readVerificationState } from \"../../core/verify/read/file.js\";\nimport { report } from \"./report.js\";\nimport { reportFrozen } from \"./frozen.js\";\nimport { record } from \"./record.js\";\nimport { type VerifyOptions } from \"./record.js\";\nimport { diffAnswers, type AnswerFiles } from \"./cross/diff.js\";\n\n\nexport function registerVerify(program: Command): void {\n program\n .command(\"verify\")\n .argument(\"<featureId>\", \"feature id, e.g. FEAT-101\")\n .description(\"Check a feature against its own promises: derive the claims, record the answers with evidence\")\n .option(\"--record <file>\", \"record a JSON answer set against the current checklist\")\n .option(\n \"--results <file>\",\n \"answer the scenario.tested claims mechanically from a test report: cucumber JSON, or loam's runner-neutral loamScenarioReport JSON for any other runner\",\n )\n .option(\n \"--contract-results <file>\",\n \"answer the api.exposes claims mechanically from an API contract-test report (loam's generic contract-results JSON)\",\n )\n .option(\n \"--diff-answers <files...>\",\n \"cross-examine two independent answer sets against the current checklist (reads only, writes nothing)\",\n )\n .option(\n \"--service <id>\",\n \"record only this service's claims, bound to the current repository commit\",\n )\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .action(async (featureId: string, opts: VerifyOptions) => {\n const json = opts.json === true;\n\n const config = await configOrRefuse(json);\n if (config === null) return;\n const { docsDir } = config;\n const recording =\n opts.record !== undefined || opts.results !== undefined || opts.contractResults !== undefined;\n\n // --diff-answers is a third READ form (see the WRITING/READING split\n // below): it validates two answer sets against the same checklist and\n // writes nothing, so combining it with any recording flag is a\n // contradiction refused up front — before the binding, before the lock —\n // rather than a mode silently picked between the two.\n let diffFiles: AnswerFiles | null = null;\n if (opts.diffAnswers !== undefined) {\n if (recording) {\n return fail(\n json,\n \"invalid-option\",\n \"--diff-answers is a read-only cross-examination: it validates both files and writes nothing, \" +\n \"so it cannot be combined with --record, --results or --contract-results. \" +\n \"Diff first, then record the answer set you stand behind.\",\n );\n }\n // Commander's variadic form consumes arguments until the next --flag,\n // so a featureId placed AFTER the flag arrives here as a third file —\n // this refusal is what turns that mistake into a sentence instead of a\n // diff of the wrong files.\n const [a, b] = opts.diffAnswers;\n if (opts.diffAnswers.length !== 2 || a === undefined || b === undefined) {\n return fail(\n json,\n \"invalid-option\",\n \"--diff-answers takes exactly two answer files: --diff-answers a.json b.json\",\n );\n }\n diffFiles = { a, b };\n }\n\n // WRITING is bound to the repository; READING is not. An attestation\n // pins claims to this repo's git HEAD and to file:line evidence inside\n // it, so writing (--record, --results or --contract-results) with\n // `--service X` may only run where loam.json says this repo IS X —\n // vouch's and gherkin's refusal, for vouch's reason: from anywhere\n // else, that repository is somebody else's. Reading takes\n // `--service` as a pure lens (which claims are checkout-web's, and what\n // has it said?) and needs no binding at all, because it writes nothing.\n if (recording && opts.service !== undefined) {\n if (config.service === undefined) {\n return fail(\n json,\n \"repository-unavailable\",\n `Cannot attest for '${opts.service}' from here: this is not a service repo — loam.json declares no \\`service\\`. ` +\n `A federated attestation binds the answers to this repository's git HEAD and to evidence inside it, so the repository has to say which service it is. ` +\n `Add \"service\": \"${opts.service}\" to loam.json, or record it from that service's own repo.`,\n );\n }\n if (config.service !== opts.service) {\n return fail(\n json,\n \"service-mismatch\",\n `This repository is configured as service '${config.service}', so it cannot attest claims for '${opts.service}'.`,\n );\n }\n }\n\n // Before the lock, because the lock is a file INSIDE the docs repo: a\n // `docsDir` pointing at nothing used to surface as the lock file's own\n // ENOENT — an `internal` where the read side of this same command names\n // the misconfiguration. \"docs\", not \"services\", in BOTH modes — and that\n // is a pinned contract, not looseness: the legacy all-at-once form\n // records against a features-only docs repo with no `services/` at all,\n // and it has always exited 0 there. The cost is real and accepted: a\n // typo'd `docsDir` pointing at some existing non-docs directory gets a\n // `.loam-lock` created and removed inside it. The gate above only\n // guarantees the directory exists.\n if (!docsRepoReady(json, docsDir, \"docs\")) return;\n\n // A record is a merge over the docs repo, so recording takes the docs\n // lock — the same one archive, unarchive and rebase hold — and takes it\n // HERE, before the feature is even resolved. Behind the lock, an archive\n // can rename this feature's directory into features/archive/ at any\n // moment; a feature resolved before the lock could have its record\n // written into the pre-move path, a file nothing will ever read again.\n // The waiting form rather than archive's refuse-fast one, because two\n // recorders for different services of one feature are both supposed to\n // land: the second waits out the first's sub-second window and merges\n // over what it left. Reading stays lock-free — it writes nothing.\n //\n // A journal under the lock means the last writer never finished. The\n // record's own authoritative read is about to happen; reading it over\n // a half-commit would merge against bytes no run ever produced — the\n // last docs-repo writer that could still silently treat a half-commit\n // as healthy. That refusal must release the lock like every other path\n // out, and once did not; `openCommitWindow` releases it before it answers.\n let releaseLock: (() => Promise<void>) | null = null;\n let recovered: CommitRecovery | null = null;\n if (recording) {\n const opened = await openCommitWindow(docsDir, LOCK_WAIT_MS);\n if (!opened.ok) return fail(json, opened.code, opened.message);\n releaseLock = opened.release;\n recovered = opened.recovered;\n }\n try {\n // Archived features resolve too: a shipped feature's verification is worth\n // reading back, and it travelled into the archive with everything else.\n const feature = await resolveFeature(docsDir, featureId, \"include\");\n if (!feature) {\n // repo.ts's sentence, not a second copy of it. Resolving with \"include\"\n // means the archived branch inside it cannot fire here — an archived\n // feature resolves — so the text is exactly what it was; what changes is\n // that a reworded miss message can no longer leave this one behind.\n return fail(json, \"unknown-target\", await missingFeatureMessage(docsDir, featureId));\n }\n\n // The cross-examination lens leaves BEFORE the record is read below:\n // it never consumes verification.yaml, and the moment a\n // cross-examination is most needed is exactly when the record on disk\n // is too damaged to read and somebody is about to re-record over it —\n // the record-unreadable refusal must not bar the one command that\n // would inform that re-recording. The archived refusal still applies,\n // with the recording branch's code and reason: there is no current\n // checklist to answer, so the wrong thing is the option, not the\n // answer sets.\n if (diffFiles !== null) {\n if (feature.archived) {\n return fail(\n json,\n \"invalid-option\",\n `${feature.id} is archived — there is no current checklist to answer, so there is nothing to cross-examine; its record is frozen history. \\`loam unarchive ${feature.id}\\` first if the claims really need re-answering.`,\n );\n }\n await diffAnswers(\n { docsDir, featureDir: feature.dir, json },\n await featureChecklist(docsDir, feature.dir, feature.id),\n diffFiles,\n { lens: opts.service },\n );\n return;\n }\n\n // Before anything else: a record file that exists but will not read\n // is a refusal, not an absence. It holds somebody's answers and — in a\n // fleet — other repositories' attestations; treating it as \"not verified\"\n // let the next --record silently overwrite all of it, and made the read\n // view say \"no record\" about a file sitting right there.\n //\n // The path is the one FILE that failed, and the advice is that file's:\n // the record is several files now, and the recipe that is safe for a\n // service's own attestation file (delete it, record that service again)\n // is the one that erases a fleet's evidence when the file is the shared\n // one-file record — which is what this refusal used to tell everyone,\n // and what a miscounted record's \"record again\" looped back into.\n //\n // An in-flight feature's checklist is derived FIRST, because which of\n // those files count depends on it: a record kept as per-service files\n // answers the question being asked now, and only the caller knows what\n // that is (`core/verify/read/union.ts`). Read without it, a service\n // that recorded the current checklist could lose a same-day tie to one\n // that recorded an older one, and this view called the whole record\n // stale. An archived feature derives nothing — see below.\n const checklist = feature.archived ? null : await featureChecklist(docsDir, feature.dir, feature.id);\n const existing = await readVerificationState(feature.dir, checklist?.digest);\n if (existing.state === \"unreadable\") {\n return fail(\n json,\n \"record-unreadable\",\n `${repoPath(docsDir, existing.path)} exists but cannot be read as a verification record: ${existing.reason}. ` +\n `${existing.advice} loam will not overwrite a record it could not read.`,\n );\n }\n const recorded = existing.state === \"ok\" ? existing.verification : null;\n\n // But an archived feature never gets a re-derived checklist — see the\n // header. Its record is frozen history, and --record / --results refuse\n // alike: the code is `invalid-option` rather than `answers-mismatch`\n // because the answers were never compared to anything — there is no\n // current checklist to answer, so the wrong thing here is the option,\n // not the answer set. (`checklist` is null exactly when the feature is\n // archived — the test is spelled on it so the compiler knows the\n // in-flight path below has one.)\n if (checklist === null) {\n if (recording) {\n return fail(\n json,\n \"invalid-option\",\n `${feature.id} is archived — its verification is history now. \\`loam unarchive ${feature.id}\\` first if the answers really need to change.`,\n );\n }\n reportFrozen({ docsDir, featureDir: feature.dir, json }, feature.id, recorded);\n return;\n }\n\n if (recording) {\n // Standing in a service repo, `--service` is what the repo already\n // says: omitting it must not fall back to the legacy all-at-once form,\n // which claims the whole fleet's checklist on this one repo's word.\n //\n // The repo root, not the cwd — `vouch`'s and `gherkin`'s reason. An\n // attestation names a commit and rests on evidence resolved inside\n // \"this repository\", and `config.root` is the directory loam.json was\n // actually found in. Off `process.cwd()`, running from a subdirectory\n // silently changed all three: evidence resolved against the\n // subdirectory, `--results` had to live in it, and `git rev-parse` ran\n // there — a submodule or nested checkout under it would have named\n // somebody else's commit on this repository's attestation.\n //\n // `config.service` and not `opts.service ?? config.service`, though\n // the two are the same value: the binding refusal above lets a\n // recording `--service` through only when it EQUALS the configured\n // service. Taking the configured one keeps its brand — loam.json's\n // reader validated it against the id grammar — and that brand is\n // what `serviceRecordPath` demands before it joins the id into a\n // file name. The raw flag never reaches the join.\n await record(\n { docsDir, featureDir: feature.dir, json, recovered },\n checklist,\n {\n service: config.service,\n repoDir: config.root ?? process.cwd(),\n previous: existing.state === \"ok\" ? { verification: existing.verification, files: existing.files } : null,\n },\n opts,\n );\n return;\n }\n\n report({ docsDir, featureDir: feature.dir, json }, checklist, recorded, {\n lens: opts.service,\n bound: config.service,\n });\n } finally {\n // Released on every path out — a refusal that kept the lock would turn\n // one bad answer set into a wedged docs repo for everyone else.\n if (releaseLock !== null) await releaseLock();\n }\n });\n}\n"]}
|
|
@@ -39,10 +39,10 @@ import { join } from "node:path";
|
|
|
39
39
|
import { loadFile } from "../../../core/c4/likec4.js";
|
|
40
40
|
import { serviceResolver } from "../../../core/c4/resolve/service.js";
|
|
41
41
|
import { repoPath } from "../../../core/envelope/json.js";
|
|
42
|
-
import { parseFrontmatter, rawBody, stringField } from "../../../core/document/frontmatter.js";
|
|
42
|
+
import { contentDigest, parseFrontmatter, rawBody, stringField } from "../../../core/document/frontmatter.js";
|
|
43
43
|
import { sectionHeadings } from "../../../core/document/parse.js";
|
|
44
44
|
import { bodyDiffText, findVouchedAncestor } from "../../../core/provenance/gitq/vouched-ancestor.js";
|
|
45
|
-
import {
|
|
45
|
+
import { decodeSourceIndex, sourceDelta } from "../../../core/provenance/stamp.js";
|
|
46
46
|
import { landscapePath, servicePathsAt, SPEC_AXES, unfiledServicePaths } from "../../../core/repo/paths.js";
|
|
47
47
|
import { enumeratedServices } from "../../../core/repo/service-target.js";
|
|
48
48
|
import { COMMIT_INTENT } from "../../../core/staging/interrupted.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pack.js","sourceRoot":"","sources":["../../../../src/commands/vouch/pack/pack.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The re-vouch reading pack: everything `loam vouch --pack` computes and\n * nothing it prints. Three derivations per spec-axis file, all read-only and\n * all from stamps `loam vouch` already writes — (a) the body's diff from the\n * last commit whose version of the file hashes to the stamped\n * `content_digest`, (b) the source files that moved against the stamped\n * per-file index, (c) the sections whose text is identical to the vouched\n * ancestor's, which the person need not re-read. Nothing here writes, locks\n * or stamps; a \"pack\" in vouch's vocabulary is always the READING pack — the\n * context pack (`core/pack/`) is a different artifact for a different reader.\n *\n * Why this mode may relax vouch's unattended refusal: the vouch gates\n * (identity, TTY, `--yes`, the docs lock) all defend the WRITE — a\n * `status: verified` no person stood behind. The pack writes nothing and can\n * stamp nothing, so refusing it unattended would only stop agents from doing\n * the one thing they are supposed to do here: prepare the exact reading list\n * a HUMAN then works through before running the vouch itself, which keeps\n * every one of its gates. That is also why `--pack --yes` is refused at the\n * flag boundary (vouch.ts): the two flags point at opposite halves of the\n * act, and a pack that stamped would defeat the read it just prescribed.\n * Journal recovery is different in kind: it is not a gate but a read-side\n * NEED (run.ts rolls it forward \"before verification reads a byte\" precisely\n * because it changes files a reader has already read), and the pack cannot\n * perform it because recovery is itself a write — so `buildPack` detects the\n * pending journal and reports it instead. What survives unchanged is the\n * wrong-repo gate — the source delta resolves `sources` against the\n * service's own repo, so from anywhere else the paths are someone else's.\n *\n * The fail-closed doctrine, stated once for all three parts: when git cannot\n * answer — no repository, no history, the walk's cap passed, a decline\n * mid-walk — the body degrades to \"full read\", never to a guessed diff; and\n * an unanswerable question never shrinks the list, because \"nobody could\n * look\" is not \"nothing changed\". Only the axis's UNCHANGED list may licence\n * skipping a section, and it is only ever computed from a found ancestor or\n * a digest-equal body.\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { loadFile } from \"../../../core/c4/likec4.js\";\nimport { serviceResolver } from \"../../../core/c4/resolve/service.js\";\nimport { repoPath } from \"../../../core/envelope/json.js\";\nimport { parseFrontmatter, rawBody, stringField, type Frontmatter } from \"../../../core/document/frontmatter.js\";\nimport { sectionHeadings } from \"../../../core/document/parse.js\";\nimport type { DocsDir } from \"../../../core/kernel/ids/dirs.js\";\nimport { bodyDiffText, findVouchedAncestor } from \"../../../core/provenance/gitq/vouched-ancestor.js\";\nimport { contentDigest, decodeSourceIndex, sourceDelta } from \"../../../core/provenance/stamp.js\";\nimport { landscapePath, servicePathsAt, SPEC_AXES, unfiledServicePaths } from \"../../../core/repo/paths.js\";\nimport { enumeratedServices } from \"../../../core/repo/service-target.js\";\nimport { COMMIT_INTENT } from \"../../../core/staging/interrupted.js\";\nimport { NotUtf8Error, readUtf8 } from \"../../../core/staging/writes.js\";\nimport { landscapeEvidence } from \"../../../core/vocabulary/maturity.js\";\nimport { noLivingSpecMessage, verifySpec } from \"../vet/verify.js\";\nimport type { PackAxis, PackBody, PackLandscape, PackOutcome, PackRequest, PackSources } from \"./contract.js\";\nimport { forwardSample, priorScope, sectionDelta } from \"./sections.js\";\n\n/** One axis file off disk: its text and header, or the reason nobody could read it. */\ntype AxisRead =\n | { kind: \"read\"; raw: string; fm: Frontmatter }\n | { kind: \"unreadable\"; reason: string };\n\nasync function readAxis(path: string): Promise<AxisRead> {\n try {\n const raw = await readUtf8(path);\n return { kind: \"read\", raw, fm: parseFrontmatter(raw) };\n } catch (err) {\n if (!(err instanceof NotUtf8Error)) throw err;\n return { kind: \"unreadable\", reason: err.message };\n }\n}\n\nexport async function buildPack(req: PackRequest): Promise<PackOutcome> {\n // One enumeration answers both questions this function has: where the\n // service's files live (a filed service is not at the root join), and which\n // ids the landscape's resolver may bind to (the same `known` set every\n // other landscape reader passes). The two-line resolution below is\n // `locateServicePaths` (core/repo/service-target.ts) inlined — that helper\n // enumerates internally, and calling it here would walk the tree twice.\n const entries = await enumeratedServices(req.docsDir);\n const entry = entries.find((s) => s.id === req.service);\n const paths = entry === undefined ? unfiledServicePaths(req.docsDir, req.service) : servicePathsAt(entry.dir);\n if (!existsSync(paths.spec)) {\n // One sentence, from `vet/verify.ts`: these commands must not describe the\n // same absence differently, and the fix — adopt first — is the same fix.\n return { ok: false, code: \"unknown-target\", message: noLivingSpecMessage(paths.spec, req.service) };\n }\n const [specAxis, archAxis] = SPEC_AXES;\n const specRead = await readAxis(paths[specAxis.key]);\n\n // First vouch is a property of the REQUIRED axis: with neither digest\n // stamped on spec.md there is no prior read to diff against, so the pack is\n // the whole document, landscape claims first. A malformed or unreadable\n // header deliberately does NOT count as first-vouch — it cannot prove the\n // stamps absent, and claiming \"first vouch\" over a document that may carry\n // one would order the read around a guess.\n const firstVouch =\n specRead.kind === \"read\" &&\n !specRead.fm.malformed &&\n stringField(specRead.fm, \"content_digest\") === undefined &&\n stringField(specRead.fm, \"sources_digest\") === undefined;\n\n const spec = await packAxis(req, { path: paths[specAxis.key], file: specAxis.file, read: specRead });\n let archSpec: PackAxis | null = null;\n if (existsSync(paths[archAxis.key])) {\n const archRead = await readAxis(paths[archAxis.key]);\n archSpec = await packAxis(req, { path: paths[archAxis.key], file: archAxis.file, read: archRead });\n }\n const knownIds = new Set<string>(entries.map((s) => s.id));\n return {\n ok: true,\n report: {\n service: req.service,\n packMode: firstVouch ? \"first-vouch\" : \"re-vouch\",\n // One existsSync, the same one run.ts pays before verification reads a\n // byte: a predecessor's journal means the stamps just read may predate\n // the write it was killed inside. The pack cannot recover (a write) —\n // it warns, and the next journaled writer rolls the journal forward.\n pendingCommit: existsSync(join(req.docsDir, COMMIT_INTENT)),\n spec,\n archSpec,\n landscape: firstVouch ? await landscapeSlice(req.docsDir, req.service, knownIds) : null,\n },\n };\n}\n\n/** One spec-axis file's full share of the pack: body verdict, source verdict, stamp fields. */\nasync function packAxis(\n req: PackRequest,\n axis: { path: string; file: string; read: AxisRead },\n): Promise<PackAxis> {\n const rel = repoPath(req.docsDir, axis.path);\n // The source half rides on verifySpec — the vouch's own vetting, message\n // for message. The pack never refuses over sources: \"your re-vouch will\n // refuse, fix this first\" IS the worklist, so the refusal sentence travels\n // as the `unavailable` reason instead of an exit code.\n const vetted = await verifySpec({ service: req.service, repoDir: req.repoDir }, axis.path, axis.file);\n // What the digest recompute would NOT hash. Empty on a refusal because\n // nobody walked — never because there is nothing to say.\n const skipped = vetted.ok ? vetted.skipped : [];\n\n if (axis.read.kind === \"unreadable\") {\n // Per-axis containment: an undecodable file suspends THIS axis with the\n // decode error as both reasons — the sibling axis still gets its pack.\n return {\n path: rel,\n file: axis.file,\n body: { kind: \"full-read\", reason: axis.read.reason },\n sources: { kind: \"unavailable\", reason: vetted.ok ? axis.read.reason : vetted.message },\n skipped,\n };\n }\n const { raw, fm } = axis.read;\n const vouchedBy = stringField(fm, \"vouched_by\");\n const lastVerified = stringField(fm, \"last_verified\");\n const body = await bodyArm(req, { rel, raw, fm });\n const sources = sourcesArm(vetted, fm);\n const stampedScope = priorScope(fm, body.kind === \"unchanged\" ? rawBody(raw) : null);\n return {\n path: rel,\n file: axis.file,\n ...(vouchedBy === undefined ? {} : { vouchedBy }),\n ...(lastVerified === undefined ? {} : { lastVerified }),\n body,\n sources,\n skipped,\n // A full read is exactly where the heading listing IS the reading plan —\n // per axis, not per mode, so an arch.spec.md created after the last vouch\n // gets its plan inside a re-vouch pack. `rawBody` first so no frontmatter\n // line can ever masquerade as a section.\n ...(body.kind === \"full-read\" ? { headings: sectionHeadings(rawBody(raw)).map((h) => h.text) } : {}),\n // Only an UNCHANGED body can license naming what the last sampled vouch\n // read: the recompute needs the bytes that vouch was taken over, and a\n // digest-equal body is exactly those bytes. When the body has moved the\n // scope is still reported — it still means the document was not read in\n // full — with no covered list behind it. Reaching back to the vouched\n // ancestor for the older body would be more information; it would also\n // put a git walk behind a claim about what a person read, and the answer\n // when git cannot speak would have to be this same one.\n ...(stampedScope === null ? {} : { vouchScope: stampedScope }),\n ...(req.sample === undefined || !vetted.ok\n ? {}\n : { sample: forwardSample({ service: req.service, raw, sourcesDigest: vetted.digest, n: req.sample }) }),\n };\n}\n\n/** The body verdict: unchanged, a diff from the vouched ancestor, or an honest full read. */\nasync function bodyArm(\n req: PackRequest,\n doc: { rel: string; raw: string; fm: Frontmatter },\n): Promise<PackBody> {\n // Deliberately NOT branched on the report-level first-vouch mode: the mode\n // orders the read (landscape first), but each axis answers from its OWN\n // stamps. In the one corpus where they disagree — spec.md hand-reverted to\n // draft while arch.spec.md still carries a stamp — the stamped axis gets\n // its real diff rather than a false \"nobody has read this yet\".\n if (doc.fm.malformed) {\n return {\n kind: \"full-read\",\n reason: \"the frontmatter cannot be read as YAML, so whatever content_digest it carries is unreachable — fix the header, then read the whole file\",\n };\n }\n const stamped = stringField(doc.fm, \"content_digest\");\n if (stamped === undefined) {\n return {\n kind: \"full-read\",\n reason:\n stringField(doc.fm, \"sources_digest\") === undefined\n ? \"this file has never been vouched, so the whole of it is the read\"\n : \"the last vouch predates content_digest, so no vouched body exists to diff from — read the whole file\",\n };\n }\n // The cheap answer first, and without git: the digest recipe is byte-exact\n // over the working-tree file, so equality here IS \"no byte of the body\n // moved since the stamp\".\n if (contentDigest(doc.raw) === stamped) return { kind: \"unchanged\" };\n\n const ancestor = await findVouchedAncestor(req.docsDir, doc.rel, stamped);\n if (ancestor.kind !== \"found\") {\n return { kind: \"full-read\", reason: ancestor.kind === \"none\" ? ancestor.reason : ancestor.detail };\n }\n const diff = await bodyDiffText(req.docsDir, ancestor.commit, doc.rel);\n // An ancestor without a printable diff could still licence a section delta,\n // but a pack that says \"these sections changed, no diff shown\" invites\n // skipping the rest on this run's partial word — degrade the whole arm to\n // the full read instead; read more, never less.\n if (diff.kind === \"failed\") return { kind: \"full-read\", reason: diff.reason };\n return {\n kind: \"diff\",\n ancestorCommit: ancestor.commit,\n diff: diff.diff,\n sections: sectionDelta(rawBody(ancestor.text), rawBody(doc.raw)),\n };\n}\n\n/** The source verdict, from the vouch's own vetting plus the stamped digests. */\nfunction sourcesArm(vetted: Awaited<ReturnType<typeof verifySpec>>, fm: Frontmatter): PackSources {\n if (!vetted.ok) return { kind: \"unavailable\", reason: vetted.message };\n const stamped = stringField(fm, \"sources_digest\");\n if (stamped === undefined) return { kind: \"unvouched\" };\n if (vetted.digest === stamped) return { kind: \"unchanged\" };\n const index = decodeSourceIndex(stringField(fm, \"sources_files\"));\n const delta = sourceDelta(index, vetted.index);\n if (delta === null) return { kind: \"uncounted\", countThen: index.count ?? null, countNow: vetted.index.length };\n return { kind: \"delta\", ...delta };\n}\n\n/**\n * The fleet map's claims about the service — a first vouch reads these before\n * the spec, because the landscape is the one document making claims ABOUT the\n * service that the person is not the author of. Absence and unparseability\n * both come back as `silent`: per landscapeEvidence's own rule they prove\n * nothing about who calls the service, and the pack says so rather than\n * printing an empty edge list that reads as \"nobody does\".\n */\nasync function landscapeSlice(docsDir: DocsDir, service: string, known: Set<string>): Promise<PackLandscape> {\n const silent: PackLandscape = {\n kind: \"silent\",\n reason: `the fleet map says nothing about ${service} (absent or unparseable)`,\n };\n const path = landscapePath(docsDir);\n if (!existsSync(path)) return silent;\n let land: Awaited<ReturnType<typeof loadFile>>;\n try {\n land = await loadFile(path);\n } catch {\n // Unreadable is not \"no claims\" — but for a reading list both collapse to\n // the same honest sentence: the map cannot brief this read.\n return silent;\n }\n if (land.errors.length > 0) return silent;\n const svcOf = serviceResolver(land.elements, known);\n const evidence = landscapeEvidence({\n id: service,\n parses: true,\n relationships: land.relationships,\n elementIds: land.elements.map((e) => e.id),\n svcOf,\n });\n return { kind: \"edges\", inbound: evidence.inbound, outbound: evidence.outbound };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"pack.js","sourceRoot":"","sources":["../../../../src/commands/vouch/pack/pack.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The re-vouch reading pack: everything `loam vouch --pack` computes and\n * nothing it prints. Three derivations per spec-axis file, all read-only and\n * all from stamps `loam vouch` already writes — (a) the body's diff from the\n * last commit whose version of the file hashes to the stamped\n * `content_digest`, (b) the source files that moved against the stamped\n * per-file index, (c) the sections whose text is identical to the vouched\n * ancestor's, which the person need not re-read. Nothing here writes, locks\n * or stamps; a \"pack\" in vouch's vocabulary is always the READING pack — the\n * context pack (`core/pack/`) is a different artifact for a different reader.\n *\n * Why this mode may relax vouch's unattended refusal: the vouch gates\n * (identity, TTY, `--yes`, the docs lock) all defend the WRITE — a\n * `status: verified` no person stood behind. The pack writes nothing and can\n * stamp nothing, so refusing it unattended would only stop agents from doing\n * the one thing they are supposed to do here: prepare the exact reading list\n * a HUMAN then works through before running the vouch itself, which keeps\n * every one of its gates. That is also why `--pack --yes` is refused at the\n * flag boundary (vouch.ts): the two flags point at opposite halves of the\n * act, and a pack that stamped would defeat the read it just prescribed.\n * Journal recovery is different in kind: it is not a gate but a read-side\n * NEED (run.ts rolls it forward \"before verification reads a byte\" precisely\n * because it changes files a reader has already read), and the pack cannot\n * perform it because recovery is itself a write — so `buildPack` detects the\n * pending journal and reports it instead. What survives unchanged is the\n * wrong-repo gate — the source delta resolves `sources` against the\n * service's own repo, so from anywhere else the paths are someone else's.\n *\n * The fail-closed doctrine, stated once for all three parts: when git cannot\n * answer — no repository, no history, the walk's cap passed, a decline\n * mid-walk — the body degrades to \"full read\", never to a guessed diff; and\n * an unanswerable question never shrinks the list, because \"nobody could\n * look\" is not \"nothing changed\". Only the axis's UNCHANGED list may licence\n * skipping a section, and it is only ever computed from a found ancestor or\n * a digest-equal body.\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { loadFile } from \"../../../core/c4/likec4.js\";\nimport { serviceResolver } from \"../../../core/c4/resolve/service.js\";\nimport { repoPath } from \"../../../core/envelope/json.js\";\nimport { contentDigest, parseFrontmatter, rawBody, stringField, type Frontmatter } from \"../../../core/document/frontmatter.js\";\nimport { sectionHeadings } from \"../../../core/document/parse.js\";\nimport type { DocsDir } from \"../../../core/kernel/ids/dirs.js\";\nimport { bodyDiffText, findVouchedAncestor } from \"../../../core/provenance/gitq/vouched-ancestor.js\";\nimport { decodeSourceIndex, sourceDelta } from \"../../../core/provenance/stamp.js\";\nimport { landscapePath, servicePathsAt, SPEC_AXES, unfiledServicePaths } from \"../../../core/repo/paths.js\";\nimport { enumeratedServices } from \"../../../core/repo/service-target.js\";\nimport { COMMIT_INTENT } from \"../../../core/staging/interrupted.js\";\nimport { NotUtf8Error, readUtf8 } from \"../../../core/staging/writes.js\";\nimport { landscapeEvidence } from \"../../../core/vocabulary/maturity.js\";\nimport { noLivingSpecMessage, verifySpec } from \"../vet/verify.js\";\nimport type { PackAxis, PackBody, PackLandscape, PackOutcome, PackRequest, PackSources } from \"./contract.js\";\nimport { forwardSample, priorScope, sectionDelta } from \"./sections.js\";\n\n/** One axis file off disk: its text and header, or the reason nobody could read it. */\ntype AxisRead =\n | { kind: \"read\"; raw: string; fm: Frontmatter }\n | { kind: \"unreadable\"; reason: string };\n\nasync function readAxis(path: string): Promise<AxisRead> {\n try {\n const raw = await readUtf8(path);\n return { kind: \"read\", raw, fm: parseFrontmatter(raw) };\n } catch (err) {\n if (!(err instanceof NotUtf8Error)) throw err;\n return { kind: \"unreadable\", reason: err.message };\n }\n}\n\nexport async function buildPack(req: PackRequest): Promise<PackOutcome> {\n // One enumeration answers both questions this function has: where the\n // service's files live (a filed service is not at the root join), and which\n // ids the landscape's resolver may bind to (the same `known` set every\n // other landscape reader passes). The two-line resolution below is\n // `locateServicePaths` (core/repo/service-target.ts) inlined — that helper\n // enumerates internally, and calling it here would walk the tree twice.\n const entries = await enumeratedServices(req.docsDir);\n const entry = entries.find((s) => s.id === req.service);\n const paths = entry === undefined ? unfiledServicePaths(req.docsDir, req.service) : servicePathsAt(entry.dir);\n if (!existsSync(paths.spec)) {\n // One sentence, from `vet/verify.ts`: these commands must not describe the\n // same absence differently, and the fix — adopt first — is the same fix.\n return { ok: false, code: \"unknown-target\", message: noLivingSpecMessage(paths.spec, req.service) };\n }\n const [specAxis, archAxis] = SPEC_AXES;\n const specRead = await readAxis(paths[specAxis.key]);\n\n // First vouch is a property of the REQUIRED axis: with neither digest\n // stamped on spec.md there is no prior read to diff against, so the pack is\n // the whole document, landscape claims first. A malformed or unreadable\n // header deliberately does NOT count as first-vouch — it cannot prove the\n // stamps absent, and claiming \"first vouch\" over a document that may carry\n // one would order the read around a guess.\n const firstVouch =\n specRead.kind === \"read\" &&\n !specRead.fm.malformed &&\n stringField(specRead.fm, \"content_digest\") === undefined &&\n stringField(specRead.fm, \"sources_digest\") === undefined;\n\n const spec = await packAxis(req, { path: paths[specAxis.key], file: specAxis.file, read: specRead });\n let archSpec: PackAxis | null = null;\n if (existsSync(paths[archAxis.key])) {\n const archRead = await readAxis(paths[archAxis.key]);\n archSpec = await packAxis(req, { path: paths[archAxis.key], file: archAxis.file, read: archRead });\n }\n const knownIds = new Set<string>(entries.map((s) => s.id));\n return {\n ok: true,\n report: {\n service: req.service,\n packMode: firstVouch ? \"first-vouch\" : \"re-vouch\",\n // One existsSync, the same one run.ts pays before verification reads a\n // byte: a predecessor's journal means the stamps just read may predate\n // the write it was killed inside. The pack cannot recover (a write) —\n // it warns, and the next journaled writer rolls the journal forward.\n pendingCommit: existsSync(join(req.docsDir, COMMIT_INTENT)),\n spec,\n archSpec,\n landscape: firstVouch ? await landscapeSlice(req.docsDir, req.service, knownIds) : null,\n },\n };\n}\n\n/** One spec-axis file's full share of the pack: body verdict, source verdict, stamp fields. */\nasync function packAxis(\n req: PackRequest,\n axis: { path: string; file: string; read: AxisRead },\n): Promise<PackAxis> {\n const rel = repoPath(req.docsDir, axis.path);\n // The source half rides on verifySpec — the vouch's own vetting, message\n // for message. The pack never refuses over sources: \"your re-vouch will\n // refuse, fix this first\" IS the worklist, so the refusal sentence travels\n // as the `unavailable` reason instead of an exit code.\n const vetted = await verifySpec({ service: req.service, repoDir: req.repoDir }, axis.path, axis.file);\n // What the digest recompute would NOT hash. Empty on a refusal because\n // nobody walked — never because there is nothing to say.\n const skipped = vetted.ok ? vetted.skipped : [];\n\n if (axis.read.kind === \"unreadable\") {\n // Per-axis containment: an undecodable file suspends THIS axis with the\n // decode error as both reasons — the sibling axis still gets its pack.\n return {\n path: rel,\n file: axis.file,\n body: { kind: \"full-read\", reason: axis.read.reason },\n sources: { kind: \"unavailable\", reason: vetted.ok ? axis.read.reason : vetted.message },\n skipped,\n };\n }\n const { raw, fm } = axis.read;\n const vouchedBy = stringField(fm, \"vouched_by\");\n const lastVerified = stringField(fm, \"last_verified\");\n const body = await bodyArm(req, { rel, raw, fm });\n const sources = sourcesArm(vetted, fm);\n const stampedScope = priorScope(fm, body.kind === \"unchanged\" ? rawBody(raw) : null);\n return {\n path: rel,\n file: axis.file,\n ...(vouchedBy === undefined ? {} : { vouchedBy }),\n ...(lastVerified === undefined ? {} : { lastVerified }),\n body,\n sources,\n skipped,\n // A full read is exactly where the heading listing IS the reading plan —\n // per axis, not per mode, so an arch.spec.md created after the last vouch\n // gets its plan inside a re-vouch pack. `rawBody` first so no frontmatter\n // line can ever masquerade as a section.\n ...(body.kind === \"full-read\" ? { headings: sectionHeadings(rawBody(raw)).map((h) => h.text) } : {}),\n // Only an UNCHANGED body can license naming what the last sampled vouch\n // read: the recompute needs the bytes that vouch was taken over, and a\n // digest-equal body is exactly those bytes. When the body has moved the\n // scope is still reported — it still means the document was not read in\n // full — with no covered list behind it. Reaching back to the vouched\n // ancestor for the older body would be more information; it would also\n // put a git walk behind a claim about what a person read, and the answer\n // when git cannot speak would have to be this same one.\n ...(stampedScope === null ? {} : { vouchScope: stampedScope }),\n ...(req.sample === undefined || !vetted.ok\n ? {}\n : { sample: forwardSample({ service: req.service, raw, sourcesDigest: vetted.digest, n: req.sample }) }),\n };\n}\n\n/** The body verdict: unchanged, a diff from the vouched ancestor, or an honest full read. */\nasync function bodyArm(\n req: PackRequest,\n doc: { rel: string; raw: string; fm: Frontmatter },\n): Promise<PackBody> {\n // Deliberately NOT branched on the report-level first-vouch mode: the mode\n // orders the read (landscape first), but each axis answers from its OWN\n // stamps. In the one corpus where they disagree — spec.md hand-reverted to\n // draft while arch.spec.md still carries a stamp — the stamped axis gets\n // its real diff rather than a false \"nobody has read this yet\".\n if (doc.fm.malformed) {\n return {\n kind: \"full-read\",\n reason: \"the frontmatter cannot be read as YAML, so whatever content_digest it carries is unreachable — fix the header, then read the whole file\",\n };\n }\n const stamped = stringField(doc.fm, \"content_digest\");\n if (stamped === undefined) {\n return {\n kind: \"full-read\",\n reason:\n stringField(doc.fm, \"sources_digest\") === undefined\n ? \"this file has never been vouched, so the whole of it is the read\"\n : \"the last vouch predates content_digest, so no vouched body exists to diff from — read the whole file\",\n };\n }\n // The cheap answer first, and without git: the digest recipe is byte-exact\n // over the working-tree file, so equality here IS \"no byte of the body\n // moved since the stamp\".\n if (contentDigest(doc.raw) === stamped) return { kind: \"unchanged\" };\n\n const ancestor = await findVouchedAncestor(req.docsDir, doc.rel, stamped);\n if (ancestor.kind !== \"found\") {\n return { kind: \"full-read\", reason: ancestor.kind === \"none\" ? ancestor.reason : ancestor.detail };\n }\n const diff = await bodyDiffText(req.docsDir, ancestor.commit, doc.rel);\n // An ancestor without a printable diff could still licence a section delta,\n // but a pack that says \"these sections changed, no diff shown\" invites\n // skipping the rest on this run's partial word — degrade the whole arm to\n // the full read instead; read more, never less.\n if (diff.kind === \"failed\") return { kind: \"full-read\", reason: diff.reason };\n return {\n kind: \"diff\",\n ancestorCommit: ancestor.commit,\n diff: diff.diff,\n sections: sectionDelta(rawBody(ancestor.text), rawBody(doc.raw)),\n };\n}\n\n/** The source verdict, from the vouch's own vetting plus the stamped digests. */\nfunction sourcesArm(vetted: Awaited<ReturnType<typeof verifySpec>>, fm: Frontmatter): PackSources {\n if (!vetted.ok) return { kind: \"unavailable\", reason: vetted.message };\n const stamped = stringField(fm, \"sources_digest\");\n if (stamped === undefined) return { kind: \"unvouched\" };\n if (vetted.digest === stamped) return { kind: \"unchanged\" };\n const index = decodeSourceIndex(stringField(fm, \"sources_files\"));\n const delta = sourceDelta(index, vetted.index);\n if (delta === null) return { kind: \"uncounted\", countThen: index.count ?? null, countNow: vetted.index.length };\n return { kind: \"delta\", ...delta };\n}\n\n/**\n * The fleet map's claims about the service — a first vouch reads these before\n * the spec, because the landscape is the one document making claims ABOUT the\n * service that the person is not the author of. Absence and unparseability\n * both come back as `silent`: per landscapeEvidence's own rule they prove\n * nothing about who calls the service, and the pack says so rather than\n * printing an empty edge list that reads as \"nobody does\".\n */\nasync function landscapeSlice(docsDir: DocsDir, service: string, known: Set<string>): Promise<PackLandscape> {\n const silent: PackLandscape = {\n kind: \"silent\",\n reason: `the fleet map says nothing about ${service} (absent or unparseable)`,\n };\n const path = landscapePath(docsDir);\n if (!existsSync(path)) return silent;\n let land: Awaited<ReturnType<typeof loadFile>>;\n try {\n land = await loadFile(path);\n } catch {\n // Unreadable is not \"no claims\" — but for a reading list both collapse to\n // the same honest sentence: the map cannot brief this read.\n return silent;\n }\n if (land.errors.length > 0) return silent;\n const svcOf = serviceResolver(land.elements, known);\n const evidence = landscapeEvidence({\n id: service,\n parses: true,\n relationships: land.relationships,\n elementIds: land.elements.map((e) => e.id),\n svcOf,\n });\n return { kind: \"edges\", inbound: evidence.inbound, outbound: evidence.outbound };\n}\n"]}
|
|
@@ -13,12 +13,7 @@ import { emitJson, fail } from "../../../core/envelope/json.js";
|
|
|
13
13
|
import { plural } from "../../policy/format.js";
|
|
14
14
|
import { buildPack } from "./pack.js";
|
|
15
15
|
export async function runPack(req) {
|
|
16
|
-
const outcome = await buildPack(
|
|
17
|
-
docsDir: req.docsDir,
|
|
18
|
-
service: req.service,
|
|
19
|
-
repoDir: req.repoDir,
|
|
20
|
-
...(req.sample === undefined ? {} : { sample: req.sample }),
|
|
21
|
-
});
|
|
16
|
+
const outcome = await buildPack(req);
|
|
22
17
|
if (!outcome.ok)
|
|
23
18
|
return fail(req.json, outcome.code, outcome.message);
|
|
24
19
|
if (req.json) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print.js","sourceRoot":"","sources":["../../../../src/commands/vouch/pack/print.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The reading pack's two renderings — the human view in the proposal's order\n * (per axis: the body diff, then the source worklist, then the sections\n * already covered; first vouch: the fleet map's claims, then everything), and\n * the `--json` envelope. `runPack` is the whole command surface of\n * `--pack`: vouch.ts hands over here as soon as the flag combination is\n * legal, so the write path's machinery — identity, prompt, lock, journal —\n * never loads for a run that cannot write. Exit 0 covers every computed pack\n * INCLUDING full-read fallbacks (\"read everything\" is an answer, not a\n * failure); only refusals exit 1.\n */\nimport { emitJson, fail } from \"../../../core/envelope/json.js\";\nimport type { DocsDir } from \"../../../core/kernel/ids/dirs.js\";\nimport type { PathableService } from \"../../../core/kernel/ids/service.js\";\nimport type { LandscapeEdge } from \"../../../core/vocabulary/maturity.js\";\nimport { plural } from \"../../policy/format.js\";\nimport type { PackAxis, PackReport } from \"./contract.js\";\nimport type { PackSample } from \"./sections.js\";\nimport { buildPack } from \"./pack.js\";\n\nexport interface RunPackRequest {\n docsDir: DocsDir;\n service: PathableService;\n repoDir: string;\n json: boolean;\n /** `--sample <n>`: print the reading list for a SAMPLED vouch rather than the whole one. */\n sample?: number;\n}\n\nexport async function runPack(req: RunPackRequest): Promise<void> {\n const outcome = await buildPack({\n docsDir: req.docsDir,\n service: req.service,\n repoDir: req.repoDir,\n ...(req.sample === undefined ? {} : { sample: req.sample }),\n });\n if (!outcome.ok) return fail(req.json, outcome.code, outcome.message);\n if (req.json) {\n emitJson(packPayload(outcome.report));\n return;\n }\n printPack(outcome.report);\n}\n\n/** The additive `--json` shape: `mode: \"pack\"` beside the write path's stamp payload. */\nfunction packPayload(report: PackReport): Record<string, unknown> {\n return {\n command: \"vouch\",\n mode: \"pack\",\n service: report.service,\n packMode: report.packMode,\n pendingCommit: report.pendingCommit,\n spec: axisPayload(report.spec),\n archSpec: report.archSpec === null ? null : axisPayload(report.archSpec),\n ...(report.landscape === null ? {} : { landscape: report.landscape }),\n };\n}\n\n/** One axis, stamp fields under their frontmatter spellings. */\nfunction axisPayload(axis: PackAxis): Record<string, unknown> {\n return {\n path: axis.path,\n file: axis.file,\n ...(axis.vouchedBy === undefined ? {} : { vouched_by: axis.vouchedBy }),\n ...(axis.lastVerified === undefined ? {} : { last_verified: axis.lastVerified }),\n body: axis.body,\n sources: axis.sources,\n skipped: axis.skipped,\n ...(axis.headings === undefined ? {} : { headings: axis.headings }),\n ...(axis.vouchScope === undefined ? {} : { vouchScope: axis.vouchScope }),\n ...(axis.sample === undefined ? {} : { sample: axis.sample }),\n };\n}\n\nfunction printPack(report: PackReport): void {\n // Before anything else: a pack computed over a half-committed docs repo may\n // be describing bytes the next journaled writer will replace, and a person\n // must know that before they spend a read on it.\n if (report.pendingCommit) {\n console.log(\n \"⚠ an interrupted docs-repo commit is pending — what is on disk (this pack included) may \" +\n \"predate it. Any journaled docs-repo writer (`loam vouch`, `loam archive`) rolls it \" +\n \"forward on its next run; re-run --pack after.\\n\",\n );\n }\n if (report.packMode === \"first-vouch\") {\n console.log(`${report.service} first-vouch reading pack — the whole document is the read\\n`);\n printLandscape(report);\n } else {\n console.log(`${report.service} re-vouch reading pack\\n`);\n }\n for (const axis of [report.spec, ...(report.archSpec === null ? [] : [report.archSpec])]) {\n printAxis(axis);\n }\n console.log(\n `\\nWhen the read is done, a person runs \\`loam vouch --service ${report.service}\\` in the service's own repo — the pack stamps nothing.`,\n );\n}\n\n/** The fleet map's claims — first, because the spec's author did not write them. */\nfunction printLandscape(report: PackReport): void {\n if (report.landscape === null) return;\n if (report.landscape.kind === \"silent\") {\n console.log(` ${report.landscape.reason}\\n`);\n return;\n }\n const { inbound, outbound } = report.landscape;\n if (inbound.length === 0 && outbound.length === 0) {\n console.log(` the fleet map draws no edge touching ${report.service}\\n`);\n return;\n }\n console.log(\" what the fleet map says:\");\n for (const edge of inbound) console.log(` ${edgeLine(edge.service, report.service, edge)}`);\n for (const edge of outbound) console.log(` ${edgeLine(report.service, edge.service, edge)}`);\n console.log(\"\");\n}\n\nfunction edgeLine(from: string, to: string, edge: LandscapeEdge): string {\n const label = edge.op !== null ? ` (${edge.op})` : edge.title !== null ? ` — ${edge.title}` : \"\";\n return `${from} -> ${to}${label}`;\n}\n\n/** One axis in the proposal's order: (a) body, (b) source worklist, (c) already covered. */\nfunction printAxis(axis: PackAxis): void {\n console.log(`${axis.path}\\n`);\n printBody(axis);\n printSources(axis);\n printSkipped(axis);\n printSampledStamp(axis);\n printCovered(axis);\n // Under `--sample` the sampled list REPLACES the full heading listing —\n // printing both would make the list a person must not skip look like the\n // one they may. The diff above is never filtered: a sample narrows what the\n // stamp CLAIMS, never what a reader is shown.\n if (axis.sample !== undefined) {\n printSample(axis.sample);\n } else if (axis.headings !== undefined) {\n console.log(` sections to read (${axis.headings.length}):`);\n for (const heading of axis.headings) console.log(` ${heading}`);\n console.log(\"\");\n }\n}\n\n/**\n * The forward sample: exactly what the `--sample <n>` vouch after this pack\n * will stand behind. The consequences are named in one line rather than\n * restated at length — `sample/print.ts` says them in full at the prompt,\n * which is the screen where somebody is about to commit to them.\n */\nfunction printSample(sample: PackSample): void {\n if (sample.covers) {\n console.log(` sampled read: the sample reaches all ${sample.of} section(s) — the vouch after it is an ordinary full one.\\n`);\n return;\n }\n console.log(` sampled read — ${sample.headings.length} of ${sample.of} section(s), seed=${sample.seed}:`);\n console.log(\" the preamble above the first heading — always read, never part of the count\");\n for (const heading of sample.headings) console.log(` ${heading}`);\n console.log(\n `\\n Reading only these is what --sample means, and the stamp will say so: \\`vouch_scope: sampled ` +\n `${sample.headings.length}/${sample.of}\\`, then \\`sources.sampled-vouch\\` until somebody reads the whole document.\\n`,\n );\n}\n\n/**\n * The last vouch's own scope, printed BEFORE the covered list it disqualifies\n * — which sections that person actually read (`sections.ts`'s `priorScope`\n * recomputes them from the stamped seed), and which have now survived a vouch\n * without anybody looking. Where the read set cannot be recomputed, no\n * covered set is named at all: an unreproducible sample licenses nothing.\n */\nfunction printSampledStamp(axis: PackAxis): void {\n const scope = axis.vouchScope;\n if (scope === undefined) return;\n const whose = `${axis.vouchedBy === undefined ? \"\" : ` by ${axis.vouchedBy}`}${axis.lastVerified === undefined ? \"\" : ` on ${axis.lastVerified}`}`;\n console.log(\n scope.scope === null\n ? ` ⚠ the last vouch${whose} carries a vouch_scope this loam cannot read (\\`${scope.stamped}\\`) — graded as ` +\n \"SAMPLED, because an unreadable scope must never be taken for a full read.\"\n : ` ⚠ the last vouch${whose} was SAMPLED: ${scope.scope.sections} of ${scope.scope.of} section(s), ` +\n `seed=${scope.scope.seed}. \"Unchanged since then\" does not mean anybody read it.`,\n );\n if (scope.read === null) {\n console.log(\" which sections it read cannot be recomputed (the body moved, or the scope does not decode), so nothing here is covered.\\n\");\n return;\n }\n console.log(` read at that vouch (${scope.read.length}): ${scope.read.join(\" · \")}`);\n if (scope.unread !== null && scope.unread.length > 0) {\n console.log(` NEVER read by anyone (${scope.unread.length}) — this is the read:`);\n for (const heading of scope.unread) console.log(` ${heading}`);\n }\n console.log(\"\");\n}\n\nfunction printBody(axis: PackAxis): void {\n const since = axis.lastVerified === undefined ? \"the stamp\" : axis.lastVerified;\n switch (axis.body.kind) {\n case \"unchanged\":\n // The qualification is the whole point after a sampled vouch: the text\n // did not move, and most of it was still never read. Saying \"nothing to\n // re-read\" over that would be this feature's worst failure — a partial\n // read reported as a finished one — so the sentence stops at what it\n // can actually claim and hands off to the scope block below.\n console.log(\n axis.vouchScope === undefined\n ? ` body unchanged since ${since} — nothing of the document itself to re-read\\n`\n : ` body unchanged since ${since} — but that vouch was sampled, so \"unchanged\" is not \"read\"\\n`,\n );\n return;\n case \"full-read\":\n console.log(` full read: ${axis.body.reason}\\n`);\n return;\n case \"diff\": {\n // \"The file's diff\", not \"the body's\": a hand edit to the header after\n // the vouch rides along in git's hunks, and promising body-only would\n // make truthful noise read as a bug.\n console.log(\n ` body changed since ${since} — the file's diff from its last vouched state (${axis.body.ancestorCommit.slice(0, 12)}):\\n`,\n );\n console.log(axis.body.diff.trimEnd());\n const { changed, added, removed } = axis.body.sections;\n const summary = [\n ...(changed.length > 0 ? [`changed: ${changed.join(\", \")}`] : []),\n ...(added.length > 0 ? [`added: ${added.join(\", \")}`] : []),\n ...(removed.length > 0 ? [`removed: ${removed.join(\", \")}`] : []),\n ];\n if (summary.length > 0) console.log(`\\n sections ${summary.join(\"; \")}`);\n console.log(\"\");\n return;\n }\n }\n}\n\nfunction printSources(axis: PackAxis): void {\n switch (axis.sources.kind) {\n case \"unchanged\":\n console.log(\" sources unchanged since the stamp\\n\");\n return;\n case \"unvouched\":\n console.log(\" sources carry no sources_digest yet — the vouch will stamp one\\n\");\n return;\n case \"unavailable\":\n console.log(` sources — the re-vouch will refuse until this is fixed:\\n ${axis.sources.reason}\\n`);\n return;\n case \"uncounted\":\n console.log(\n ` sources changed — ${axis.sources.countThen === null ? \"an unknown number of\" : axis.sources.countThen} file(s) at the stamp, ` +\n `${axis.sources.countNow} now, and the stamp cannot name which moved: re-read the sources\\n`,\n );\n return;\n case \"delta\": {\n const { added, changed, removed } = axis.sources;\n const moved = added.length + changed.length + removed.length;\n // movedSources' one-column annotated layout, so a reader who knows the\n // stale finding's shape reads this without learning a second one.\n console.log(` sources — ${moved} path(s) moved since the stamp:`);\n for (const path of added) console.log(` added ${path}`);\n for (const path of changed) console.log(` changed ${path}`);\n for (const path of removed) console.log(` removed ${path}`);\n console.log(\"\");\n return;\n }\n }\n}\n\n/**\n * The hole in the promise, said BEFORE the stamp rather than only on\n * vouch.ts's post-stamp screen: paths under the listed sources the digest\n * will not hash. Same sentence as that screen, so the pre-vouch and\n * post-vouch descriptions of one hole cannot drift apart.\n */\nfunction printSkipped(axis: PackAxis): void {\n if (axis.skipped.length === 0) return;\n console.log(` ⚠ ${plural(axis.skipped.length, \"path\")} under those sources went unhashed — the vouch's digest says nothing about what is behind them:`);\n for (const skip of axis.skipped) console.log(` ${skip.path} — ${skip.reason}`);\n console.log(\"\");\n}\n\n/** (c): what the previous vouch already covers, so the read can stop where it should. */\nfunction printCovered(axis: PackAxis): void {\n if (axis.body.kind !== \"diff\" || axis.body.sections.unchanged.length === 0) return;\n const by = axis.vouchedBy === undefined ? \"\" : ` by ${axis.vouchedBy}`;\n const on = axis.lastVerified === undefined ? \"\" : ` on ${axis.lastVerified}`;\n // The licence to skip rests entirely on somebody having read the section\n // before. A sampled vouch did not read most of them, so after one this list\n // is only \"text that did not move\" — it is still worth printing (a reader\n // wants to know what is stable), but it must not be printed under a heading\n // that says a person covered it.\n console.log(\n axis.vouchScope === undefined\n ? ` unchanged — previously vouched${by}${on}:`\n : ` unchanged since the sampled vouch${by}${on} — text that did not move, NOT a covered list:`,\n );\n for (const heading of axis.body.sections.unchanged) console.log(` ${heading}`);\n console.log(\"\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"print.js","sourceRoot":"","sources":["../../../../src/commands/vouch/pack/print.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The reading pack's two renderings — the human view in the proposal's order\n * (per axis: the body diff, then the source worklist, then the sections\n * already covered; first vouch: the fleet map's claims, then everything), and\n * the `--json` envelope. `runPack` is the whole command surface of\n * `--pack`: vouch.ts hands over here as soon as the flag combination is\n * legal, so the write path's machinery — identity, prompt, lock, journal —\n * never loads for a run that cannot write. Exit 0 covers every computed pack\n * INCLUDING full-read fallbacks (\"read everything\" is an answer, not a\n * failure); only refusals exit 1.\n */\nimport { emitJson, fail } from \"../../../core/envelope/json.js\";\nimport type { LandscapeEdge } from \"../../../core/vocabulary/maturity.js\";\nimport { plural } from \"../../policy/format.js\";\nimport type { PackAxis, PackReport, PackRequest } from \"./contract.js\";\nimport type { PackSample } from \"./sections.js\";\nimport { buildPack } from \"./pack.js\";\n\n/** The pack's own request (`--sample <n>` included), plus the one rendering choice the command adds. */\nexport interface RunPackRequest extends PackRequest {\n json: boolean;\n}\n\nexport async function runPack(req: RunPackRequest): Promise<void> {\n const outcome = await buildPack(req);\n if (!outcome.ok) return fail(req.json, outcome.code, outcome.message);\n if (req.json) {\n emitJson(packPayload(outcome.report));\n return;\n }\n printPack(outcome.report);\n}\n\n/** The additive `--json` shape: `mode: \"pack\"` beside the write path's stamp payload. */\nfunction packPayload(report: PackReport): Record<string, unknown> {\n return {\n command: \"vouch\",\n mode: \"pack\",\n service: report.service,\n packMode: report.packMode,\n pendingCommit: report.pendingCommit,\n spec: axisPayload(report.spec),\n archSpec: report.archSpec === null ? null : axisPayload(report.archSpec),\n ...(report.landscape === null ? {} : { landscape: report.landscape }),\n };\n}\n\n/** One axis, stamp fields under their frontmatter spellings. */\nfunction axisPayload(axis: PackAxis): Record<string, unknown> {\n return {\n path: axis.path,\n file: axis.file,\n ...(axis.vouchedBy === undefined ? {} : { vouched_by: axis.vouchedBy }),\n ...(axis.lastVerified === undefined ? {} : { last_verified: axis.lastVerified }),\n body: axis.body,\n sources: axis.sources,\n skipped: axis.skipped,\n ...(axis.headings === undefined ? {} : { headings: axis.headings }),\n ...(axis.vouchScope === undefined ? {} : { vouchScope: axis.vouchScope }),\n ...(axis.sample === undefined ? {} : { sample: axis.sample }),\n };\n}\n\nfunction printPack(report: PackReport): void {\n // Before anything else: a pack computed over a half-committed docs repo may\n // be describing bytes the next journaled writer will replace, and a person\n // must know that before they spend a read on it.\n if (report.pendingCommit) {\n console.log(\n \"⚠ an interrupted docs-repo commit is pending — what is on disk (this pack included) may \" +\n \"predate it. Any journaled docs-repo writer (`loam vouch`, `loam archive`) rolls it \" +\n \"forward on its next run; re-run --pack after.\\n\",\n );\n }\n if (report.packMode === \"first-vouch\") {\n console.log(`${report.service} first-vouch reading pack — the whole document is the read\\n`);\n printLandscape(report);\n } else {\n console.log(`${report.service} re-vouch reading pack\\n`);\n }\n for (const axis of [report.spec, ...(report.archSpec === null ? [] : [report.archSpec])]) {\n printAxis(axis);\n }\n console.log(\n `\\nWhen the read is done, a person runs \\`loam vouch --service ${report.service}\\` in the service's own repo — the pack stamps nothing.`,\n );\n}\n\n/** The fleet map's claims — first, because the spec's author did not write them. */\nfunction printLandscape(report: PackReport): void {\n if (report.landscape === null) return;\n if (report.landscape.kind === \"silent\") {\n console.log(` ${report.landscape.reason}\\n`);\n return;\n }\n const { inbound, outbound } = report.landscape;\n if (inbound.length === 0 && outbound.length === 0) {\n console.log(` the fleet map draws no edge touching ${report.service}\\n`);\n return;\n }\n console.log(\" what the fleet map says:\");\n for (const edge of inbound) console.log(` ${edgeLine(edge.service, report.service, edge)}`);\n for (const edge of outbound) console.log(` ${edgeLine(report.service, edge.service, edge)}`);\n console.log(\"\");\n}\n\nfunction edgeLine(from: string, to: string, edge: LandscapeEdge): string {\n const label = edge.op !== null ? ` (${edge.op})` : edge.title !== null ? ` — ${edge.title}` : \"\";\n return `${from} -> ${to}${label}`;\n}\n\n/** One axis in the proposal's order: (a) body, (b) source worklist, (c) already covered. */\nfunction printAxis(axis: PackAxis): void {\n console.log(`${axis.path}\\n`);\n printBody(axis);\n printSources(axis);\n printSkipped(axis);\n printSampledStamp(axis);\n printCovered(axis);\n // Under `--sample` the sampled list REPLACES the full heading listing —\n // printing both would make the list a person must not skip look like the\n // one they may. The diff above is never filtered: a sample narrows what the\n // stamp CLAIMS, never what a reader is shown.\n if (axis.sample !== undefined) {\n printSample(axis.sample);\n } else if (axis.headings !== undefined) {\n console.log(` sections to read (${axis.headings.length}):`);\n for (const heading of axis.headings) console.log(` ${heading}`);\n console.log(\"\");\n }\n}\n\n/**\n * The forward sample: exactly what the `--sample <n>` vouch after this pack\n * will stand behind. The consequences are named in one line rather than\n * restated at length — `sample/print.ts` says them in full at the prompt,\n * which is the screen where somebody is about to commit to them.\n */\nfunction printSample(sample: PackSample): void {\n if (sample.covers) {\n console.log(` sampled read: the sample reaches all ${sample.of} section(s) — the vouch after it is an ordinary full one.\\n`);\n return;\n }\n console.log(` sampled read — ${sample.headings.length} of ${sample.of} section(s), seed=${sample.seed}:`);\n console.log(\" the preamble above the first heading — always read, never part of the count\");\n for (const heading of sample.headings) console.log(` ${heading}`);\n console.log(\n `\\n Reading only these is what --sample means, and the stamp will say so: \\`vouch_scope: sampled ` +\n `${sample.headings.length}/${sample.of}\\`, then \\`sources.sampled-vouch\\` until somebody reads the whole document.\\n`,\n );\n}\n\n/**\n * The last vouch's own scope, printed BEFORE the covered list it disqualifies\n * — which sections that person actually read (`sections.ts`'s `priorScope`\n * recomputes them from the stamped seed), and which have now survived a vouch\n * without anybody looking. Where the read set cannot be recomputed, no\n * covered set is named at all: an unreproducible sample licenses nothing.\n */\nfunction printSampledStamp(axis: PackAxis): void {\n const scope = axis.vouchScope;\n if (scope === undefined) return;\n const whose = `${axis.vouchedBy === undefined ? \"\" : ` by ${axis.vouchedBy}`}${axis.lastVerified === undefined ? \"\" : ` on ${axis.lastVerified}`}`;\n console.log(\n scope.scope === null\n ? ` ⚠ the last vouch${whose} carries a vouch_scope this loam cannot read (\\`${scope.stamped}\\`) — graded as ` +\n \"SAMPLED, because an unreadable scope must never be taken for a full read.\"\n : ` ⚠ the last vouch${whose} was SAMPLED: ${scope.scope.sections} of ${scope.scope.of} section(s), ` +\n `seed=${scope.scope.seed}. \"Unchanged since then\" does not mean anybody read it.`,\n );\n if (scope.read === null) {\n console.log(\" which sections it read cannot be recomputed (the body moved, or the scope does not decode), so nothing here is covered.\\n\");\n return;\n }\n console.log(` read at that vouch (${scope.read.length}): ${scope.read.join(\" · \")}`);\n if (scope.unread !== null && scope.unread.length > 0) {\n console.log(` NEVER read by anyone (${scope.unread.length}) — this is the read:`);\n for (const heading of scope.unread) console.log(` ${heading}`);\n }\n console.log(\"\");\n}\n\nfunction printBody(axis: PackAxis): void {\n const since = axis.lastVerified === undefined ? \"the stamp\" : axis.lastVerified;\n switch (axis.body.kind) {\n case \"unchanged\":\n // The qualification is the whole point after a sampled vouch: the text\n // did not move, and most of it was still never read. Saying \"nothing to\n // re-read\" over that would be this feature's worst failure — a partial\n // read reported as a finished one — so the sentence stops at what it\n // can actually claim and hands off to the scope block below.\n console.log(\n axis.vouchScope === undefined\n ? ` body unchanged since ${since} — nothing of the document itself to re-read\\n`\n : ` body unchanged since ${since} — but that vouch was sampled, so \"unchanged\" is not \"read\"\\n`,\n );\n return;\n case \"full-read\":\n console.log(` full read: ${axis.body.reason}\\n`);\n return;\n case \"diff\": {\n // \"The file's diff\", not \"the body's\": a hand edit to the header after\n // the vouch rides along in git's hunks, and promising body-only would\n // make truthful noise read as a bug.\n console.log(\n ` body changed since ${since} — the file's diff from its last vouched state (${axis.body.ancestorCommit.slice(0, 12)}):\\n`,\n );\n console.log(axis.body.diff.trimEnd());\n const { changed, added, removed } = axis.body.sections;\n const summary = [\n ...(changed.length > 0 ? [`changed: ${changed.join(\", \")}`] : []),\n ...(added.length > 0 ? [`added: ${added.join(\", \")}`] : []),\n ...(removed.length > 0 ? [`removed: ${removed.join(\", \")}`] : []),\n ];\n if (summary.length > 0) console.log(`\\n sections ${summary.join(\"; \")}`);\n console.log(\"\");\n return;\n }\n }\n}\n\nfunction printSources(axis: PackAxis): void {\n switch (axis.sources.kind) {\n case \"unchanged\":\n console.log(\" sources unchanged since the stamp\\n\");\n return;\n case \"unvouched\":\n console.log(\" sources carry no sources_digest yet — the vouch will stamp one\\n\");\n return;\n case \"unavailable\":\n console.log(` sources — the re-vouch will refuse until this is fixed:\\n ${axis.sources.reason}\\n`);\n return;\n case \"uncounted\":\n console.log(\n ` sources changed — ${axis.sources.countThen === null ? \"an unknown number of\" : axis.sources.countThen} file(s) at the stamp, ` +\n `${axis.sources.countNow} now, and the stamp cannot name which moved: re-read the sources\\n`,\n );\n return;\n case \"delta\": {\n const { added, changed, removed } = axis.sources;\n const moved = added.length + changed.length + removed.length;\n // movedSources' one-column annotated layout, so a reader who knows the\n // stale finding's shape reads this without learning a second one.\n console.log(` sources — ${moved} path(s) moved since the stamp:`);\n for (const path of added) console.log(` added ${path}`);\n for (const path of changed) console.log(` changed ${path}`);\n for (const path of removed) console.log(` removed ${path}`);\n console.log(\"\");\n return;\n }\n }\n}\n\n/**\n * The hole in the promise, said BEFORE the stamp rather than only on\n * vouch.ts's post-stamp screen: paths under the listed sources the digest\n * will not hash. Same sentence as that screen, so the pre-vouch and\n * post-vouch descriptions of one hole cannot drift apart.\n */\nfunction printSkipped(axis: PackAxis): void {\n if (axis.skipped.length === 0) return;\n console.log(` ⚠ ${plural(axis.skipped.length, \"path\")} under those sources went unhashed — the vouch's digest says nothing about what is behind them:`);\n for (const skip of axis.skipped) console.log(` ${skip.path} — ${skip.reason}`);\n console.log(\"\");\n}\n\n/** (c): what the previous vouch already covers, so the read can stop where it should. */\nfunction printCovered(axis: PackAxis): void {\n if (axis.body.kind !== \"diff\" || axis.body.sections.unchanged.length === 0) return;\n const by = axis.vouchedBy === undefined ? \"\" : ` by ${axis.vouchedBy}`;\n const on = axis.lastVerified === undefined ? \"\" : ` on ${axis.lastVerified}`;\n // The licence to skip rests entirely on somebody having read the section\n // before. A sampled vouch did not read most of them, so after one this list\n // is only \"text that did not move\" — it is still worth printing (a reader\n // wants to know what is stable), but it must not be printed under a heading\n // that says a person covered it.\n console.log(\n axis.vouchScope === undefined\n ? ` unchanged — previously vouched${by}${on}:`\n : ` unchanged since the sampled vouch${by}${on} — text that did not move, NOT a covered list:`,\n );\n for (const heading of axis.body.sections.unchanged) console.log(` ${heading}`);\n console.log(\"\");\n}\n"]}
|
|
@@ -17,11 +17,10 @@
|
|
|
17
17
|
* module can never disagree with the rest of loam about whether a `## ` line
|
|
18
18
|
* inside a code fence is structure.
|
|
19
19
|
*/
|
|
20
|
-
import { rawBody } from "../../../core/document/frontmatter.js";
|
|
20
|
+
import { contentDigest, rawBody } from "../../../core/document/frontmatter.js";
|
|
21
21
|
import { sectionHeadings } from "../../../core/document/parse.js";
|
|
22
22
|
import { splitSections } from "../../../core/provenance/sample/sections.js";
|
|
23
23
|
import { planSample, readVouchScope, sampledSections, scopeText } from "../../../core/provenance/sample/scope.js";
|
|
24
|
-
import { contentDigest } from "../../../core/provenance/stamp.js";
|
|
25
24
|
/** How the delta names the text above the first H2 — a section with no heading to call it by. */
|
|
26
25
|
const PREAMBLE_LABEL = "(before the first heading)";
|
|
27
26
|
/**
|