@ybotok/loam 0.2.0-alpha.7 → 0.2.0-alpha.9
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 +1315 -1
- package/COMPARISON.md +91 -3
- package/CONTRIBUTING.md +37 -0
- package/MIGRATING-from-OpenSpec.md +40 -22
- package/QUICKSTART.md +181 -9
- package/README.md +256 -57
- package/ROADMAP.md +83 -7
- package/SCHEMA.md +569 -98
- package/WORKFLOW.md +272 -62
- 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/archive/archive.js +15 -18
- package/dist/commands/archive/archive.js.map +1 -1
- package/dist/commands/archive/plan/contracts/asyncapi.js +27 -41
- 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 +25 -42
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/verdict-lines.js +41 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +3 -7
- package/dist/commands/archive/plan/gate.js.map +1 -1
- package/dist/commands/archive/plan/landscape.js +4 -4
- package/dist/commands/archive/plan/landscape.js.map +1 -1
- package/dist/commands/archive/plan/refusal.js +8 -18
- package/dist/commands/archive/plan/refusal.js.map +1 -1
- package/dist/commands/archive/plan/specs.js +134 -25
- package/dist/commands/archive/plan/specs.js.map +1 -1
- package/dist/commands/archive/plan/state.js +1 -0
- package/dist/commands/archive/plan/state.js.map +1 -1
- package/dist/commands/archive/run.js +33 -11
- 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 +4 -7
- package/dist/commands/context/context.js.map +1 -1
- package/dist/commands/context/print.js +2 -2
- package/dist/commands/context/print.js.map +1 -1
- package/dist/commands/delta/delta.js +44 -12
- package/dist/commands/delta/delta.js.map +1 -1
- package/dist/commands/delta/print.js +1 -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/explore.js +4 -8
- 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 +0 -4
- package/dist/commands/list/json.js.map +1 -1
- package/dist/commands/list/list.js +38 -23
- package/dist/commands/list/list.js.map +1 -1
- package/dist/commands/list/print.js +38 -6
- 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 +28 -33
- 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 +21 -25
- package/dist/commands/seed/commit.js.map +1 -1
- package/dist/commands/seed/seed.js +6 -9
- package/dist/commands/seed/seed.js.map +1 -1
- package/dist/commands/show/show.js +3 -7
- package/dist/commands/show/show.js.map +1 -1
- package/dist/commands/status/print.js +13 -4
- 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 +3 -7
- package/dist/commands/steps/steps.js.map +1 -1
- package/dist/commands/subsystem/edit.js +3 -5
- package/dist/commands/subsystem/edit.js.map +1 -1
- package/dist/commands/subsystem/move.js +5 -8
- 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 +14 -41
- package/dist/commands/subsystem/sync.js.map +1 -1
- package/dist/commands/subsystem/txn/txn.js +17 -38
- package/dist/commands/subsystem/txn/txn.js.map +1 -1
- package/dist/commands/subsystem/txn/views.js +32 -5
- package/dist/commands/subsystem/txn/views.js.map +1 -1
- package/dist/commands/tasks/render.js +116 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +113 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +6 -9
- package/dist/commands/unarchive/manifest.js.map +1 -1
- package/dist/commands/unarchive/restore.js +17 -28
- 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 +6 -15
- package/dist/commands/validate/arch-coverage.js.map +1 -1
- package/dist/commands/validate/checks/fleet-shape.js +4 -49
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
- 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 +6 -2
- package/dist/commands/validate/checks/sources.js.map +1 -1
- package/dist/commands/validate/feature.js +23 -19
- package/dist/commands/validate/feature.js.map +1 -1
- package/dist/commands/validate/fleet/landscape.js +23 -23
- package/dist/commands/validate/fleet/landscape.js.map +1 -1
- package/dist/commands/validate/fleet/map/attest.js +6 -10
- package/dist/commands/validate/fleet/map/attest.js.map +1 -1
- package/dist/commands/validate/fleet/map/bindings.js +1 -3
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -1
- package/dist/commands/validate/fleet/map/usecases.js +5 -11
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -1
- package/dist/commands/validate/fleet/obligations.js +1 -5
- package/dist/commands/validate/fleet/obligations.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/print.js +5 -1
- 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/usecases.js +6 -4
- package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -1
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -1
- package/dist/commands/validate/fleet/views/root-documents.js +8 -28
- package/dist/commands/validate/fleet/views/root-documents.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/report.js +5 -4
- 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 +16 -104
- 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 +1 -1
- 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/service.js +16 -26
- package/dist/commands/validate/service/service.js.map +1 -1
- package/dist/commands/validate/service/specs.js +31 -38
- package/dist/commands/validate/service/specs.js.map +1 -1
- package/dist/commands/validate/service/spine.js +8 -11
- package/dist/commands/validate/service/spine.js.map +1 -1
- package/dist/commands/validate/service/usecases/usecases.js +3 -3
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -1
- package/dist/commands/validate/validate.js +44 -26
- 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 +54 -51
- 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 +56 -101
- package/dist/core/agent/agents-md/command-map.js.map +1 -1
- package/dist/core/agent/agents-md/map/explain.js +4 -3
- package/dist/core/agent/agents-md/map/explain.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/context.js +4 -3
- 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 +9 -3
- package/dist/core/agent/agents-md/map/status.js.map +1 -1
- package/dist/core/agent/agents-md/map/subsystem.js +4 -3
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
- package/dist/core/agent/agents-md/map/usecases.js +24 -6
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
- package/dist/core/agent/agents-md/refusals.js +32 -18
- package/dist/core/agent/agents-md/refusals.js.map +1 -1
- package/dist/core/agent/agents-md.js +9 -3
- 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/scaffold.js +10 -15
- package/dist/core/agent/scaffold.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 +5 -3
- package/dist/core/agent/workflows/adopt.js.map +1 -1
- package/dist/core/agent/workflows/check.js +20 -16
- package/dist/core/agent/workflows/check.js.map +1 -1
- package/dist/core/agent/workflows/closing.js +54 -21
- package/dist/core/agent/workflows/closing.js.map +1 -1
- package/dist/core/agent/workflows/feature.js +79 -11
- package/dist/core/agent/workflows/feature.js.map +1 -1
- package/dist/core/agent/workflows/implement.js +91 -13
- package/dist/core/agent/workflows/implement.js.map +1 -1
- package/dist/core/agent/workflows/reference/authoring.js +3 -1
- 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/reference.js.map +1 -1
- package/dist/core/agent/workflows/reference/spine.js +50 -18
- 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 +30 -50
- package/dist/core/asyncapi/merge/markers.js.map +1 -1
- package/dist/core/asyncapi/merge/merge.js +31 -53
- package/dist/core/asyncapi/merge/merge.js.map +1 -1
- package/dist/core/asyncapi/merge/pin.js +10 -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 +6 -18
- package/dist/core/brief/brief.js.map +1 -1
- package/dist/core/brief/landscape.js +8 -12
- package/dist/core/brief/landscape.js.map +1 -1
- package/dist/core/brief/map/extend.js +8 -5
- package/dist/core/brief/map/extend.js.map +1 -1
- package/dist/core/brief/map/owed.js +8 -26
- package/dist/core/brief/map/owed.js.map +1 -1
- package/dist/core/brief/targets.js +15 -5
- package/dist/core/brief/targets.js.map +1 -1
- package/dist/core/c4/likec4.js +147 -16
- 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/values.js +54 -1
- package/dist/core/c4/parsed/values.js.map +1 -1
- package/dist/core/c4/prefetch/fleet.js +1 -9
- package/dist/core/c4/prefetch/fleet.js.map +1 -1
- package/dist/core/c4/project/documents.js +31 -6
- package/dist/core/c4/project/documents.js.map +1 -1
- package/dist/core/c4/project/load.js +6 -17
- package/dist/core/c4/project/load.js.map +1 -1
- 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 +25 -1
- package/dist/core/c4/resolve/service.js.map +1 -1
- package/dist/core/c4/seed/template.js +15 -1
- package/dist/core/c4/seed/template.js.map +1 -1
- package/dist/core/c4/service-model/shape.js +2 -22
- package/dist/core/c4/service-model/shape.js.map +1 -1
- package/dist/core/c4/source-mask.js +288 -4
- package/dist/core/c4/source-mask.js.map +1 -1
- package/dist/core/c4/source-scan.js +203 -147
- package/dist/core/c4/source-scan.js.map +1 -1
- package/dist/core/c4/splice/authored-source.js +19 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -1
- package/dist/core/c4/splice/delta-blocks.js +5 -18
- package/dist/core/c4/splice/delta-blocks.js.map +1 -1
- package/dist/core/c4/splice/landscape-merge.js +13 -8
- package/dist/core/c4/splice/landscape-merge.js.map +1 -1
- package/dist/core/c4/splice/model/merge.js +10 -6
- package/dist/core/c4/splice/model/merge.js.map +1 -1
- package/dist/core/c4/splice/placement.js +108 -18
- package/dist/core/c4/splice/placement.js.map +1 -1
- package/dist/core/c4/workspace.js +13 -22
- 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/findings.js +15 -20
- 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/coherence.js +30 -16
- 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/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 +119 -8
- 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 +14 -82
- package/dist/core/coherence/events/lookups.js.map +1 -1
- 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 +1 -1
- package/dist/core/delta/delta.js.map +1 -1
- package/dist/core/deployment/delta.js +3 -6
- package/dist/core/deployment/delta.js.map +1 -1
- 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 +28 -16
- 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/doctor/agents.js +34 -18
- package/dist/core/doctor/agents.js.map +1 -1
- package/dist/core/doctor/report.js.map +1 -1
- package/dist/core/document/apply.js +10 -2
- 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 +17 -12
- package/dist/core/explain/families.js.map +1 -1
- package/dist/core/explain/refusals.js +3 -3
- package/dist/core/explain/refusals.js.map +1 -1
- package/dist/core/explain/terms.js +18 -9
- package/dist/core/explain/terms.js.map +1 -1
- package/dist/core/explore/explore.js +2 -7
- package/dist/core/explore/explore.js.map +1 -1
- package/dist/core/fleet-context.js +34 -95
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +5 -2
- package/dist/core/gate/checks.js.map +1 -1
- package/dist/core/gate/partners.js +4 -2
- 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/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/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 +5 -36
- package/dist/core/links/corpus.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 +22 -8
- 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 +56 -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 +26 -52
- package/dist/core/openapi/merge/merge.js.map +1 -1
- package/dist/core/openapi/merge/pin.js +15 -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 +2 -16
- package/dist/core/pack/living.js.map +1 -1
- 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/entries.js.map +1 -1
- package/dist/core/repo/repo.js +24 -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/walk.js +8 -30
- 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/staging/commit.js +10 -12
- 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 +60 -1
- package/dist/core/staging/recovery/recover.js.map +1 -1
- package/dist/core/staging/snapshot/manifest.js +152 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +10 -34
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/status/actions/execution.js +11 -0
- package/dist/core/status/actions/execution.js.map +1 -1
- package/dist/core/status/feature/artifacts.js +2 -2
- package/dist/core/status/feature/artifacts.js.map +1 -1
- package/dist/core/status/feature/feature.js +5 -11
- package/dist/core/status/feature/feature.js.map +1 -1
- package/dist/core/status/fleet/fleet.js +6 -2
- package/dist/core/status/fleet/fleet.js.map +1 -1
- package/dist/core/status/fleet/next.js +26 -3
- package/dist/core/status/fleet/next.js.map +1 -1
- package/dist/core/status/report.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 +174 -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/flows.js +5 -7
- package/dist/core/usecases/delta/flows.js.map +1 -1
- package/dist/core/usecases/fleet.js +178 -31
- package/dist/core/usecases/fleet.js.map +1 -1
- package/dist/core/usecases/operations.js +5 -4
- package/dist/core/usecases/operations.js.map +1 -1
- package/dist/core/usecases/service/flows.js +9 -6
- package/dist/core/usecases/service/flows.js.map +1 -1
- 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 +3 -0
- 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 +1 -0
- package/dist/core/vocabulary/issue.js.map +1 -1
- package/dist/core/vocabulary/maturity.js +12 -2
- package/dist/core/vocabulary/maturity.js.map +1 -1
- package/examples/README.md +21 -6
- package/examples/docs/architecture/landscape.likec4 +8 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +6 -2
- 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/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
- package/examples/docs/services/order-service/asyncapi.yaml +3 -2
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
- package/package.json +1 -1
- package/dist/commands/validate/checks/vocabulary.js +0 -16
- package/dist/commands/validate/checks/vocabulary.js.map +0 -1
- package/dist/core/agent/agents-md/artifacts.js +0 -221
- package/dist/core/agent/agents-md/artifacts.js.map +0 -1
- package/dist/core/agent/agents-md/cycle.js +0 -180
- 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 -256
- package/dist/core/diff/victims.js.map +0 -1
- package/dist/core/staging/snapshot.js.map +0 -1
- package/dist/core/verify/file.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"families.js","sourceRoot":"","sources":["../../../src/core/explain/families.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The family registry: `loam explain`'s content for the four code families no\n * fix table anywhere grades — `doctor.*`, `next.*`, `diff.*` and `gate.*`.\n *\n * WHY THIS IS NOT THE DUPLICATION fix-tables.ts FORBIDS. That module's header\n * argues against a second hand-maintained copy of the /loam-check prose, and\n * the argument is right: the tables ship in the binary, test/codes-drift.test.ts\n * holds every emitted finding code against them, and a registry restating them\n * would be free to trail the bytes `loam instructions loam-check` prints. None\n * of that applies here. These 65 codes have no fix-table row in any workflow\n * body — /loam-check grades DOCUMENTS, and these four families grade a\n * repository's wiring (`doctor`), a recommendation (`next`), a change between\n * two refs (`diff`) and a deploy question (`gate`). There is nothing to trail:\n * this registry is not a second copy, it is the only copy. The precedent is the\n * sibling module refusals.ts, a hand-written map that is the sole source for\n * the `ErrorCode` meanings for exactly the same reason — their prose lives in\n * doc comments, which are erased, so there is no runtime constant to read.\n *\n * What that costs, stated rather than hidden: nothing mechanical proves an\n * entry below still matches the message its emitter prints. Every meaning and\n * every fix here was written FROM the emitter — `doctor` findings carry a `fix`\n * field of their own (core/doctor/), a `next` step carries a `statement` and a\n * literal `command` (core/status/), the `DiffCode` union carries a doc comment\n * per member (core/diff/semantic.ts) — and the wording is theirs, not a\n * paraphrase invented here. Two guards catch the two failures that CAN be\n * caught: test/explain.test.ts asserts no code below is also answered by a fix\n * table (the two sources must never be able to disagree), and\n * test/agent-commands-runnable.test.ts parses every backticked `loam …` in this\n * file against the real program, so a fix naming a command loam does not have —\n * or a flag it does not declare — fails at gate time. A two-token span is a\n * NAME rather than an invocation there and is only checked for the command\n * existing, so a fix that means an invocation must carry its arguments.\n *\n * `severityNote` is the EMITTER's own word, not a fix table's parenthetical:\n * `doctor` grades blocker/warning, `diff` and `gate` grade ok/warn/error, and a\n * `next` step is graded not at all — it is a recommendation, so its note is\n * `step`. Where a code's severity depends on what was found (`doctor.docs-locked`,\n * `gate.partners-unknown`) the note says so in prose, the way the tables' own\n * long notes do (`warn here; error at archive plan time`).\n *\n * `openspec.*` and `mapping.*` — 49 codes — are deliberately NOT here, and the\n * reason is in test/explain.test.ts beside their backlog entries: they are the\n * only codes in the vocabulary whose subject is not a loam document at all.\n */\n\n/**\n * One code's answer. Structurally a `FindingEntry` (lookup.ts) minus `scope`,\n * which the family supplies — declared here rather than imported so this module\n * imports nothing at all and the package's file-level graph stays a tree.\n *\n * Every entry below is written on ONE line, however long that line runs, and\n * that is a deliberate concession to a counted limit rather than a style: 65\n * codes at four lines each is 260 lines of punctuation before a word of prose,\n * which does not fit the 400-line file limit — and src/core/explain/ is at its\n * five-file cap, so there is no second file to put the overflow in. The fields\n * stay named for the same reason a tuple was refused: `severityNote`, `meaning`\n * and `fix` say which column is which without counting commas.\n */\nexport interface FamilyEntry {\n /** The emitter's own severity word, or the prose a conditional one needs. */\n readonly severityNote: string;\n /** What the code is about, in the words the emitter already prints. */\n readonly meaning: string;\n /** What to do — for `next.*`, that the step's own `command` IS the action. */\n readonly fix: string;\n}\n\n/** One family: the invocation that emits it, and its codes. */\ninterface Family {\n /** The scope label, spelled as the fix tables spell theirs — the invocation that grades it. */\n readonly scope: string;\n readonly codes: Readonly<Record<string, FamilyEntry>>;\n}\n\n/**\n * `loam doctor` — the preflight. Every finding here already carries a `fix`\n * field in doctor's own report (core/doctor/doctor.ts, config.ts, agents.ts,\n * residue.ts); these rows say the same thing without a repository in front of\n * them, which is the whole difference between a report and a lookup.\n */\nconst DOCTOR: Family = {\n scope: \"loam doctor\",\n codes: {\n \"doctor.config-missing\": { severityNote: \"blocker\", meaning: \"No loam.json at or above the working directory, so nothing says which docs repo this checkout belongs to — every other command refuses with `no-config` until there is one.\", fix: \"Run `loam init --docs <dir>` in this repository; add `--create` when the docs repo does not exist yet.\" },\n \"doctor.config-invalid\": { severityNote: \"blocker\", meaning: \"A loam.json is there and `parseConfig` — the same loader every command uses — refuses it; the finding carries the parser's own words. doctor deliberately has no second validator: the one it used to carry accepted a config the commands rejected, and reported a healthy repo in which nothing could run.\", fix: \"Repair the file the finding names, or delete it and re-run `loam init`.\" },\n \"doctor.docs-missing\": { severityNote: \"blocker\", meaning: \"`docsDir` resolves to something that is missing or is not a directory — the docs repo was never cloned, or the path is wrong.\", fix: \"Fix `docsDir` in the loam.json the finding names, clone the docs repo to that path, or run `loam init --docs <dir> --create`.\" },\n \"doctor.services-missing\": { severityNote: \"blocker\", meaning: \"`docsDir` is a directory and holds no `services/`, so it is some other directory — most often the service repo itself, after a typo in the pointer.\", fix: \"Point `docsDir` at the shared docs repo, or run `loam init --docs <dir> --create` to scaffold one. Do not scaffold a second source of truth beside the real one.\" },\n \"doctor.docs-absolute\": { severityNote: \"warning\", meaning: \"`docsDir` is stored as an absolute path and loam.json is committed, so the pointer names a directory that exists on exactly one machine: it works for whoever ran `loam init` and for nobody who clones the repo afterwards.\", fix: \"Rewrite `docsDir` as a path relative to the loam.json holding it, such as `../docs`.\" },\n \"doctor.docs-unreadable\": { severityNote: \"warning\", meaning: \"The docs repo exists and this process cannot read it, so every command that reads the fleet will fail or report an empty one.\", fix: \"Grant read access to the directory the finding names — check ownership and mode.\" },\n \"doctor.docs-readonly\": { severityNote: \"warning\", meaning: \"The docs repo is readable and not writable: read-only commands work and the writing ones do not.\", fix: \"Grant write access if you need `loam new`, `loam adopt` or `loam archive`. A read-only checkout is a legitimate state for a reviewer, which is why this is a warning.\" },\n \"doctor.landscape-missing\": { severityNote: \"warning\", meaning: \"architecture/landscape.likec4 is missing, and it is the one artifact every cross-service check reads — nothing about who calls whom can be checked without it.\", fix: \"Create it with one element per service and an edge per call: `loam init --create` writes the empty map, and `loam seed --from fleet.yaml` templates one from stated facts.\" },\n \"doctor.landscape-unreadable\": { severityNote: \"blocker\", meaning: \"The landscape file exists and the read itself failed — permissions or an I/O error, carried verbatim in the message.\", fix: \"Check permissions on the path the finding names.\" },\n \"doctor.landscape-merge-conflict\": { severityNote: \"blocker\", meaning: \"The landscape still contains merge conflict markers, named by line. Checked BEFORE the parser on purpose: both sides of a conflict can be syntactically valid LikeC4, so the file sometimes parses and is still two halves of two different maps.\", fix: \"Resolve the conflict keeping BOTH services' elements and edges — the usual cause is several services adopted into one map in the same week — then re-run `loam doctor`.\" },\n \"doctor.landscape-invalid\": { severityNote: \"blocker\", meaning: \"The landscape exists, carries no conflict markers, and does not parse; the message quotes the first parser error with its line and counts the rest.\", fix: \"Fix the file — every fleet-wide check is blind until it parses.\" },\n \"doctor.likec4-config-missing\": { severityNote: \"warning\", meaning: \"The docs repo has no likec4.config.json, so the tree is not a loadable LikeC4 workspace: every service model and feature delta declares its own `specification` block, and a renderer pointed at the repo root merges them and reports every declaration as a duplicate. No loam check reads this file — the repo is only unrenderable, which is why it is a warning.\", fix: \"Write the project file the finding prints; it scopes the root project to architecture/, so `npx likec4 start` in the docs repo renders the fleet map. Then run `loam subsystem sync`: it writes one create-only likec4.config.json beside every service model, so each model renders from that same root as a project of its own — only a feature delta still renders from its own directory.\" },\n \"doctor.docs-locked\": { severityNote: \"warning while a live process holds it; blocker when its holder is dead or it names none\", meaning: \"A `.loam-lock` is present. Held by a running process it is a fact about right now. Held by a process that no longer exists on this host — or unreadable, so no holder can be named at all — nothing is ever going to release it, and every writing command refuses with `docs-busy` forever.\", fix: \"Wait and re-run while the holder is alive; nothing is read or written while it is held. Delete the lock file the finding names when its holder is dead or unnameable, then run `loam doctor` again for an interrupted commit underneath it.\" },\n \"doctor.commit-unreadable\": { severityNote: \"blocker\", meaning: \"A `.loam-commit` journal is present and cannot be read: a commit was interrupted and the one record of which files it had already written is unreadable.\", fix: \"Hand this to a human — compare the root's files against version control before running any loam command that writes there. Every journaled writer refuses with `commit-interrupted` while it is present.\" },\n \"doctor.commit-interrupted\": { severityNote: \"blocker\", meaning: \"A journaled writer — archive, unarchive, rebase, vouch, new, gherkin, or a recording verify — was killed mid-commit. The message names the host, pid and time, and every file or directory move that may be half-done. This is the surface that used to report a healthy repo over half-merged living docs.\", fix: \"Re-run the command the finding names: it recovers first, under the lock, rolling the staged bytes forward, and refuses rather than guessing if a file has been edited since. An interrupted `loam unarchive` is FINISHED, never undone — the merged text it was replacing is written down nowhere.\" },\n \"doctor.staging-temps\": { severityNote: \"warning\", meaning: \"Orphaned `.loam-*.tmp` scratch files from a killed writer, never linked into place — so nothing reads them and nothing depends on them. A journal's own recorded temps are excluded, because those are the durable copy its roll-forward recovery renames in. Litter, not damage.\", fix: \"The next journaled writer through that root removes its own; delete any that remain. They cost disk and nothing else.\" },\n \"doctor.inventory-unreadable\": { severityNote: \"warning\", meaning: \"The config and the docs repo are both fine and enumerating `services/` or `features/` threw, so doctor's fleet counts — and its verdict on the service binding — are about a fleet nobody could read.\", fix: \"Check that services/ and features/ under the docs repo are readable directories.\" },\n \"doctor.service-unbound\": { severityNote: \"warning\", meaning: \"loam.json declares no `service`, so nothing binds this checkout to one governed boundary and the service-repo checks have nothing to run against — `sources.stale`, a recording `loam verify`, `loam gherkin`. Deliberately not emitted inside the docs repo itself, where having no binding is the correct state rather than a gap.\", fix: \"Run `loam init --docs <dir> --service <id>` here.\" },\n \"doctor.service-unknown\": { severityNote: \"warning\", meaning: \"loam.json names a `service` the fleet has no services/<id>/ for — and the fleet WAS read, so this is a claim about a real inventory rather than one nobody could take.\", fix: \"Run `loam adopt --service <id>` to onboard it, or fix `service` in loam.json.\" },\n \"doctor.agent-files-missing\": { severityNote: \"warning\", meaning: \"Some of the command and skill files this loam lays down for the repo's recorded tools and profile are not here: the repo was initialized by an older loam, or they were deleted. An out-of-date command set costs entry points, never a refusal, which is why it is a warning.\", fix: \"Re-run `loam init --docs <dir> --tools <ids>` here. It creates absent files, refreshes only pointers whose current bytes still match their recorded digest, preserves every customized file, and keeps this repo's service binding.\" },\n \"doctor.agent-files-stale\": { severityNote: \"warning\", meaning: \"Command or skill files that ARE here carry no loam stamp, or one older than this binary, so the protocol and code tables they instruct an agent with may describe a loam that no longer exists. Staleness reads only the stamp; safe refresh is a separate digest check performed by init.\", fix: \"Re-run `loam init` to refresh a pointer only when its recorded digest still matches. Review a customized file against the current body yourself and update its stamp, or delete it so init can recreate it; your edits always outrank the template.\" },\n },\n};\n\n/**\n * `loam status` — both forms print `next[]`, and each entry carries a `code` to\n * branch on, one sentence, and the literal `command` to run. So the \"what to\n * do\" column is genuinely empty for this whole family: the step IS the action,\n * and each `fix` below names the step's own command rather than inventing a\n * second instruction beside it.\n */\nconst NEXT_STEPS: Family = {\n scope: \"loam status\",\n codes: {\n \"next.adopt-bound\": { severityNote: \"step\", meaning: \"The fleet form's first entry: this repository's loam.json says it is a service the fleet has no services/<id>/ for, so nothing about the boundary you are standing in is written down yet. Ahead of every other service's adoption work, because it is the only step that is about HERE.\", fix: \"The step IS the action: run its `command`, `loam adopt --service <id> --json`.\" },\n \"next.author-landscape\": { severityNote: \"step\", meaning: \"The first rung of the first-hour ladder, over a fleet with no services and no features: architecture/landscape.likec4 does not exist, or is still the scaffold's untouched map with no service drawn on it.\", fix: \"The step IS the action: run its `command` — `loam init --create` when the file is absent, `loam seed --from fleet.yaml` when it is the untouched scaffold. loam never guesses who calls whom.\" },\n \"next.bind-service\": { severityNote: \"step\", meaning: \"First-hour ladder: no service repository is bound to this fleet yet, so no command can ever run from a service's own checkout.\", fix: \"The step IS the action: run its `command`, `loam init --docs <path-to-this-docs-repo> --service <service-id>`, from a service's own repo, and commit the loam.json it writes.\" },\n \"next.adopt-first\": { severityNote: \"step\", meaning: \"First-hour ladder: services/ is empty, so nothing about any service is written down and nothing can be graded against anything.\", fix: \"The step IS the action: run its `command`, `loam adopt --service <service-id> --json`; the brief it prints walks an agent through writing the baseline docs as draft.\" },\n \"next.adopt\": { severityNote: \"step\", meaning: \"One service in the fleet has no spec.md — nothing about it is written down, so no feature can be graded against it. One entry per undocumented service.\", fix: \"The step IS the action: run its `command`, `loam adopt --service <id> --json`.\" },\n \"next.complete-service\": { severityNote: \"step\", meaning: \"Adoption does not end at spec.md: a service has one and no model.likec4, the state archive warns about and the fleet gate reports incomplete until something models it.\", fix: \"The step IS the action: run its `command`, `loam validate --service <id> --json`.\" },\n \"next.feature\": { severityNote: \"step\", meaning: \"One feature in flight that is not ready to ship, named with the stage it sits at and what it is missing — or, when it is blocked by another feature, the features it is waiting on.\", fix: \"The step IS the action: run its `command`, `loam status <FEAT-id> --json`, for that feature's own next list.\" },\n \"next.archive\": { severityNote: \"step\", meaning: \"In the fleet form, a feature that is authored and verified: ship it, and everything queued behind it is released. In a feature's own list it is always the last entry, saying the feature ships once everything above it is done.\", fix: \"The step IS the action: run its `command`, `loam archive <FEAT-id> --dry-run --json`; the dry run writes nothing and lists every file the merge would touch.\" },\n \"next.elided\": { severityNote: \"step\", meaning: \"The fleet list is capped, and this says how many steps of the same kinds it left out. The list is ordered most-unblocking first, so what was elided is the least urgent — a list nobody reads is not navigation.\", fix: \"The step IS the action: run its `command`, `loam list --json`, or work down the printed list and run status again.\" },\n \"next.fleet-clean\": { severityNote: \"step\", meaning: \"Services exist, nothing is in flight, and nothing is owed. Only that truthful case: over an EMPTY fleet the same sentence was vacuously true, and the first-hour ladder owns that repository now.\", fix: \"The step IS the action: run its `command`, `loam validate --all --json`, then start the next feature.\" },\n \"next.fleet-gate\": { severityNote: \"step\", meaning: \"The last entry of every fleet list, and always present: `status` grades nothing, so the least it can do is say where grading happens — `loam validate --all` is the gate this repository has to pass and the one CI runs.\", fix: \"The step IS the action: run its `command`, `loam validate --all --json`.\" },\n \"next.recover-commit\": { severityNote: \"step\", meaning: \"Always first, and never elided by the fleet form's cap: a journaled writer was killed mid-commit, so everything below this step is derived from files that may be half-written. Where the journal itself cannot be read, nothing below can be trusted until a human compares the living docs against version control.\", fix: \"The step IS the action: run its `command` — the interrupted command re-run, which recovers first under the lock, or `loam doctor --json` when the journal is unreadable and no loam command can repair it.\" },\n \"next.archived\": { severityNote: \"step\", meaning: \"The whole `next[]` for a feature that already shipped: it is archived, and its delta is folded into the living docs.\", fix: \"The step IS the action: run its `command`, `loam show <FEAT-id> --json`.\" },\n \"next.author-intent\": { severityNote: \"step\", meaning: \"The feature has no intent document — what it is for, in prose, before anything is derived from it.\", fix: \"The step IS the action: write the file the step names, then run its `command`, `loam validate <FEAT-id> --json`. The command never writes the artifact: loam does not author.\" },\n \"next.touch-service\": { severityNote: \"step\", meaning: \"The feature carries no per-service delta at all, so nothing says which governed boundaries it changes.\", fix: \"The step IS the action: run its `command`, `loam list services --json`, then add specs/<service>/spec.md for every service the feature changes.\" },\n \"next.author-spec\": { severityNote: \"step\", meaning: \"One service the feature touches has no requirement delta — the ADDED / MODIFIED / REMOVED requirements the feature makes to that service, each with a scenario.\", fix: \"The step IS the action: write the file the step names, then run its `command`, `loam delta <FEAT-id> --service <id> --json`, which projects the delta onto the living document.\" },\n \"next.author-openapi\": { severityNote: \"step\", meaning: \"Nothing gives one of the feature's services a living openapi.yaml, so this feature is the only thing that can write down its API surface. Deliberately not phrased as the service being absent from the living docs: a service adopted without a contract is the commoner case, and that wording sent readers looking for a directory that was right there.\", fix: \"The step IS the action: write the file the step names, then run its `command`, `loam delta <FEAT-id> --service <id> --json`.\" },\n \"next.author-scenarios\": { severityNote: \"step\", meaning: \"Requirements in one service's delta carry no `#### Scenario:`, so they generate no test and no verify claim — a promise that reaches neither the suite nor the done-check. One entry per service and never per requirement, because a delta with forty bare requirements would otherwise BE the payload.\", fix: \"The step IS the action: write a scenario under each bare requirement, then run its `command`, `loam delta <FEAT-id> --service <id> --json`.\" },\n \"next.rebase\": { severityNote: \"step\", meaning: \"The feature carries requirements or operations with no baseline pin, on any of the three axes; until they have one the merge cannot tell what it EDITS from what it merely quotes.\", fix: \"The step IS the action: run its `command`, `loam rebase <FEAT-id>`.\" },\n \"next.archive-first\": { severityNote: \"step\", meaning: \"The feature builds on other features still in flight, which have to archive before it can.\", fix: \"The step IS the action: run its `command`, `loam dependencies <FEAT-id> --json`.\" },\n \"next.fix-coherence\": { severityNote: \"step\", meaning: \"The feature has findings that stop it, named starting with the first. Everything EITHER gate refuses on is counted, so a warning marked as gating archive is in the tally even though `validate` grades the feature valid — which is why its exit code alone will not show you why archive refuses.\", fix: \"The step IS the action: run its `command`, `loam validate <FEAT-id> --json`.\" },\n \"next.generate-tests\": { severityNote: \"step\", meaning: \"The feature's delta for a service carries scenarios no test run has answered yet. `loam gherkin` writes the .feature files whose green run is the only thing that may answer a `scenario.tested` claim, and it writes into the service's own repository — so the step names which repo to run it in when that is not this one.\", fix: \"The step IS the action: run its `command`, `loam gherkin <FEAT-id> --service <id>`, from that service's own checkout.\" },\n \"next.verify\": { severityNote: \"step\", meaning: \"The done-check has not been started, or its record cannot be used. Five situations share this code because they share the work — nothing recorded, a verification.yaml that does not read as a record, a record the feature has moved out from under, a record that answers no claims at all, and a feature with nothing to derive a checklist from yet — and the step's own statement says which.\", fix: \"The step IS the action: run its `command`, `loam verify <FEAT-id> --json`, which derives the checklist and prints what it asks. A record nothing can read is repaired or deleted by hand: nothing overwrites it while it is unreadable.\" },\n \"next.verify-unconfirmed\": { severityNote: \"step\", meaning: \"Claims on the feature are open — unconfirmed or unanswered — and this repository is not one of the services that owes an answer, so the recording form is not a step anyone can take from here.\", fix: \"The step IS the action: run its `command`, `loam verify <FEAT-id> --json`. The open claims are closed from each affected service's own repository.\" },\n \"next.attest-service\": { severityNote: \"step\", meaning: \"Claims are open AND this repository is one of the services that owes an answer, so the recording form is nameable here: `--record --service` binds the answers to this repo's HEAD and refuses anywhere else.\", fix: \"The step IS the action: run its `command`, `loam verify <FEAT-id> --record answers.json --service <id>`, answering the claims filed under this service; the rest belong to their own repositories.\" },\n \"next.verify-attested\": { severityNote: \"step\", meaning: \"Every claim is answered and some scenario claims are confirmed on an agent's word rather than on a test run (`verify.scenario-attested`) — complete work resting on an assertion, which is what `ready` has always meant here.\", fix: \"The step IS the action: run its `command`, `loam verify <FEAT-id> --results <cucumber-report.json>`, and the record stops resting on an assertion.\" },\n },\n};\n\n/**\n * `loam diff` — what CHANGED between a base git ref of the docs repo and the\n * working tree, not what is WRONG with either. That is why most rows below have\n * no repair: the meanings are the `DiffCode` union's own doc comments\n * (core/diff/semantic.ts), and the two error rows are the only ones naming work.\n */\nconst DIFF: Family = {\n scope: \"loam diff --base <ref>\",\n codes: {\n \"diff.service-added\": { severityNote: \"ok\", meaning: \"A services/<id>/ directory exists now that did not exist at the base ref.\", fix: \"Nothing to fix: `loam diff` says what changed between two points of the living docs, never what is wrong with them. This is the class of the change, for a reviewer to read.\" },\n \"diff.service-removed\": { severityNote: \"warn\", meaning: \"A service present at the base ref is gone from the working tree; the finding names the directory it occupied.\", fix: \"A review question rather than a defect: nothing in the working tree describes that boundary any more. `loam validate --all` is what grades the fleet that is left.\" },\n \"diff.requirement-added\": { severityNote: \"ok\", meaning: \"A living requirement not present at base — by `Requirement-ID:` where one is authored, by heading otherwise, the same join `loam rebase` pins against.\", fix: \"Nothing to fix: this is the class of the change, for a reviewer to read.\" },\n \"diff.requirement-removed\": { severityNote: \"warn\", meaning: \"A requirement present at the base ref is no longer in the living spec under the same identity.\", fix: \"A review question. A requirement that CHANGED identity — a new `Requirement-ID:`, a renamed heading — reads here as a removal plus an addition, which is the join being honest about what it can see rather than guessing a rename.\" },\n \"diff.requirement-modified\": { severityNote: \"ok\", meaning: \"The same requirement identity is on both sides and its digest moved. A rebase pin never moves that digest, so this is a real edit to the requirement's text.\", fix: \"Nothing to fix: this is the class of the change, for a reviewer to read.\" },\n \"diff.op-added\": { severityNote: \"ok\", meaning: \"An operationId in the living contract that was absent at the base ref; the message names its method and path.\", fix: \"Nothing to fix: this is the class of the change, for a reviewer to read.\" },\n \"diff.op-removed\": { severityNote: \"warn\", meaning: \"A base operationId is gone from the living contract and no current landscape edge or living requirement names it — or, in the second wording this code also carries, whether one does could NOT be fully answered because some consumer documents were not scannable, and the details name them.\", fix: \"Read which of the two sentences it is. Nobody could be scanned is never nobody names it: the unreadable documents carry the run to exit 1 on their own, and the removal stays unreviewed until they can be read.\" },\n \"diff.op-removed-consumed\": { severityNote: \"error\", meaning: \"An operation was removed since the base ref and the current fleet still names it — a landscape edge, or a foreign service's living requirement. The details list the victims, and the finding sets `breaking`.\", fix: \"These joins break. Either restore the operation, or land the consumers' own deltas in the same change so nothing in the fleet is left calling something that is gone.\" },\n \"diff.op-deprecated\": { severityNote: \"warn\", meaning: \"`deprecated: true` was introduced on an operation since the base ref. The details name the current consumers, under one of three deliberately honest phrasings: some still name it, none does, or whether any does could not be fully answered.\", fix: \"Deprecation is a promise to the consumers the details name, and nothing is broken yet. Read which phrasing it is before treating a silent list as an empty one.\" },\n \"diff.message-added\": { severityNote: \"ok\", meaning: \"An AsyncAPI message name absent at the base ref.\", fix: \"Nothing to fix: this is the class of the change, for a reviewer to read.\" },\n \"diff.message-removed\": { severityNote: \"warn\", meaning: \"A base message is gone. The finding says which of three cases it is: another current service still declares the name, nothing currently consumes it, or whether anything does could not be fully answered because some consumer documents were not scannable.\", fix: \"Read which case it is. A name another service still declares is not orphaned, and an unanswerable scan is not an empty one — only positive evidence vouches here.\" },\n \"diff.message-removed-consumed\": { severityNote: \"error\", meaning: \"A message was removed since the base ref and the current fleet still consumes it — a `Consumes:` line, or a consumes edge. The details list the victims, and the finding sets `breaking`.\", fix: \"These joins break. Either restore the message, or land the consumers' own deltas in the same change.\" },\n \"diff.consumer-added\": { severityNote: \"ok\", meaning: \"A cross-service join appeared since base: another service's living requirements now name this service's operation or message. Filed on the PROVIDER — the service whose surface the join lands on.\", fix: \"Nothing to fix, and the change class most worth reading: a new consumer is a new obligation on this service's contract, and removing that operation later is what `diff.op-removed-consumed` will be about.\" },\n \"diff.consumer-removed\": { severityNote: \"ok\", meaning: \"A cross-service join present at the base ref is gone: a consumer's living requirements no longer name this service's operation or message.\", fix: \"Nothing to fix: this is the class of the change, for a reviewer to read.\" },\n },\n};\n\n/**\n * `loam gate` — the can-i-deploy question, a pure query over evidence other\n * commands already recorded. Nothing here re-derives a coherence plan, so every\n * repair below is somebody else's command.\n */\nconst GATE: Family = {\n scope: \"loam gate\",\n codes: {\n \"gate.partners-unknown\": { severityNote: \"warn when the map is absent; error when it exists and cannot be used\", meaning: \"The partner set for the gated service could not be derived from architecture/landscape.likec4 — it is absent, or it exists and does not parse. That means nobody could look, never that nothing joins this service. Absent is a warning because a repo before its first adopt legitimately has no map yet; a broken map is an error because `loam validate --all` fails that repo for the same file, and a deploy gate passing where the fleet gate fails would be the quieter of two contradictory verdicts.\", fix: \"Fix the landscape and re-run. `loam validate --all` diagnoses the file itself; this check only refuses the false silence.\" },\n \"gate.service-undocumented\": { severityNote: \"error\", meaning: \"The service being deployed sits below `documented` on the adoption ladder, so the docs cannot say what its joins even are and no recorded evidence can answer the deploy question. The details list what the next rung wants.\", fix: \"Author the baseline — `loam adopt --service <id>` briefs exactly what is missing — and this check passes once the required artifact set exists.\" },\n \"gate.partner-undocumented\": { severityNote: \"warn\", meaning: \"A service that joins the gated one has no services/<id>/ directory at all, or has one sitting below `documented`: its side of the join is not recorded, so the gate cannot see what that partner promises. An `#external` partner is exempt on purpose — somebody else's system is unrecorded by design.\", fix: \"Adopt the partner (`loam adopt --service <id>` briefs it), bind its landscape element to the right service with `metadata { service '<id>' }`, or tag it `#external` if it is not ours.\" },\n \"gate.feature-unverified\": { severityNote: \"warn\", meaning: \"An active feature touching the gated service is not verified: no record at all, a verification.yaml that does not read as a record, a record the feature moved out from under, a record answering no claims, or open claims counted in the message. A record that is merely `attested` is NOT reported under this code — it carries `verify.scenario-attested` instead, because complete work resting on an assertion is a different fact from work nobody checked.\", fix: \"Derive the checklist and answer every claim with evidence: `loam verify <FEAT-id> --json`. A record nothing can read is repaired or deleted by hand; nothing overwrites it while it is unreadable.\" },\n },\n};\n\n/** In listing order, though every consumer sorts by code — the order is documentation, not contract. */\nconst FAMILIES: readonly Family[] = [DOCTOR, NEXT_STEPS, DIFF, GATE];\n\n/** One family row, in the shape `FindingEntry` (lookup.ts) takes. */\nexport interface FamilyFinding extends FamilyEntry {\n readonly scope: string;\n}\n\n/**\n * The registry's answer for one subject, or null.\n *\n * Built per call over constants already in memory, never cached at module\n * level, for the reason lookup.ts's header gives: tests fork and chdir, and the\n * MCP server outlives many calls.\n */\nexport function familyFinding(subject: string): FamilyFinding | null {\n for (const family of FAMILIES) {\n const entry = family.codes[subject];\n if (entry !== undefined) return { scope: family.scope, ...entry };\n }\n return null;\n}\n\n/** Every code the registry answers, sorted — the same plain sort the code inventory uses. */\nexport function familyCodes(): string[] {\n return FAMILIES.flatMap((family) => Object.keys(family.codes)).sort();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"families.js","sourceRoot":"","sources":["../../../src/core/explain/families.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The family registry: `loam explain`'s content for the four code families no\n * fix table anywhere grades — `doctor.*`, `next.*`, `diff.*` and `gate.*`.\n *\n * WHY THIS IS NOT THE DUPLICATION fix-tables.ts FORBIDS. That module's header\n * argues against a second hand-maintained copy of the /loam-check prose, and\n * the argument is right: the tables ship in the binary, test/codes-drift.test.ts\n * holds every emitted finding code against them, and a registry restating them\n * would be free to trail the bytes `loam instructions loam-check` prints. None\n * of that applies here. These 67 codes have no fix-table row in any workflow\n * body — /loam-check grades DOCUMENTS, and these four families grade a\n * repository's wiring (`doctor`), a recommendation (`next`), a change between\n * two refs (`diff`) and a deploy question (`gate`). There is nothing to trail:\n * this registry is not a second copy, it is the only copy. The precedent is the\n * sibling module refusals.ts, a hand-written map that is the sole source for\n * the `ErrorCode` meanings for exactly the same reason — their prose lives in\n * doc comments, which are erased, so there is no runtime constant to read.\n *\n * What that costs, stated rather than hidden: nothing mechanical proves an\n * entry below still matches the message its emitter prints. Every meaning and\n * every fix here was written FROM the emitter — `doctor` findings carry a `fix`\n * field of their own (core/doctor/), a `next` step carries a `statement` and a\n * literal `command` (core/status/), the `DiffCode` union carries a doc comment\n * per member (core/diff/semantic.ts) — and the wording is theirs, not a\n * paraphrase invented here. Two guards catch the two failures that CAN be\n * caught: test/explain.test.ts asserts no code below is also answered by a fix\n * table (the two sources must never be able to disagree), and\n * test/agent-commands-runnable.test.ts parses every backticked `loam …` in this\n * file against the real program, so a fix naming a command loam does not have —\n * or a flag it does not declare — fails at gate time. A two-token span is a\n * NAME rather than an invocation there and is only checked for the command\n * existing, so a fix that means an invocation must carry its arguments.\n *\n * `severityNote` is the EMITTER's own word, not a fix table's parenthetical:\n * `doctor` grades blocker/warning, `diff` and `gate` grade ok/warn/error, and a\n * `next` step is graded not at all — it is a recommendation, so its note is\n * `step`. Where a code's severity depends on what was found (`doctor.docs-locked`,\n * `gate.partners-unknown`) the note says so in prose, the way the tables' own\n * long notes do (`warn here; error at archive plan time`).\n *\n * `openspec.*` and `mapping.*` — 49 codes — are deliberately NOT here, and the\n * reason is in test/explain.test.ts beside their backlog entries: they are the\n * only codes in the vocabulary whose subject is not a loam document at all.\n */\n\n/**\n * One code's answer. Structurally a `FindingEntry` (lookup.ts) minus `scope`,\n * which the family supplies — declared here rather than imported so this module\n * imports nothing at all and the package's file-level graph stays a tree.\n *\n * Every entry below is written on ONE line, however long that line runs, and\n * that is a deliberate concession to a counted limit rather than a style: 65\n * codes at four lines each is 260 lines of punctuation before a word of prose,\n * which does not fit the 400-line file limit — and src/core/explain/ is at its\n * five-file cap, so there is no second file to put the overflow in. The fields\n * stay named for the same reason a tuple was refused: `severityNote`, `meaning`\n * and `fix` say which column is which without counting commas.\n */\nexport interface FamilyEntry {\n /** The emitter's own severity word, or the prose a conditional one needs. */\n readonly severityNote: string;\n /** What the code is about, in the words the emitter already prints. */\n readonly meaning: string;\n /** What to do — for `next.*`, that the step's own `command` IS the action. */\n readonly fix: string;\n}\n\n/** One family: the invocation that emits it, and its codes. */\ninterface Family {\n /** The scope label, spelled as the fix tables spell theirs — the invocation that grades it. */\n readonly scope: string;\n readonly codes: Readonly<Record<string, FamilyEntry>>;\n}\n\n/**\n * `loam doctor` — the preflight. Every finding here already carries a `fix`\n * field in doctor's own report (core/doctor/doctor.ts, config.ts, agents.ts,\n * residue.ts); these rows say the same thing without a repository in front of\n * them, which is the whole difference between a report and a lookup.\n */\nconst DOCTOR: Family = {\n scope: \"loam doctor\",\n codes: {\n \"doctor.config-missing\": { severityNote: \"blocker\", meaning: \"No loam.json at or above the working directory, so nothing says which docs repo this checkout belongs to — every other command refuses with `no-config` until there is one.\", fix: \"Run `loam init --docs <dir>` in this repository; add `--create` when the docs repo does not exist yet.\" },\n \"doctor.config-invalid\": { severityNote: \"blocker\", meaning: \"A loam.json is there and `parseConfig` — the same loader every command uses — refuses it; the finding carries the parser's own words. doctor deliberately has no second validator: the one it used to carry accepted a config the commands rejected, and reported a healthy repo in which nothing could run.\", fix: \"Repair the file the finding names, or delete it and re-run `loam init`.\" },\n \"doctor.docs-missing\": { severityNote: \"blocker\", meaning: \"`docsDir` resolves to something that is missing or is not a directory — the docs repo was never cloned, or the path is wrong.\", fix: \"Fix `docsDir` in the loam.json the finding names, clone the docs repo to that path, or run `loam init --docs <dir> --create`.\" },\n \"doctor.services-missing\": { severityNote: \"blocker\", meaning: \"`docsDir` is a directory and holds no `services/`, so it is some other directory — most often the service repo itself, after a typo in the pointer.\", fix: \"Point `docsDir` at the shared docs repo, or run `loam init --docs <dir> --create` to scaffold one. Do not scaffold a second source of truth beside the real one.\" },\n \"doctor.docs-absolute\": { severityNote: \"warning\", meaning: \"`docsDir` is stored as an absolute path and loam.json is committed, so the pointer names a directory that exists on exactly one machine: it works for whoever ran `loam init` and for nobody who clones the repo afterwards.\", fix: \"Rewrite `docsDir` as a path relative to the loam.json holding it, such as `../docs`.\" },\n \"doctor.docs-unreadable\": { severityNote: \"warning\", meaning: \"The docs repo exists and this process cannot read it, so every command that reads the fleet will fail or report an empty one.\", fix: \"Grant read access to the directory the finding names — check ownership and mode.\" },\n \"doctor.docs-readonly\": { severityNote: \"warning\", meaning: \"The docs repo is readable and not writable: read-only commands work and the writing ones do not.\", fix: \"Grant write access if you need `loam new`, `loam adopt` or `loam archive`. A read-only checkout is a legitimate state for a reviewer, which is why this is a warning.\" },\n \"doctor.landscape-missing\": { severityNote: \"warning\", meaning: \"architecture/landscape.likec4 is missing, and it is the one artifact every cross-service check reads — nothing about who calls whom can be checked without it.\", fix: \"Create it with one element per service and an edge per call: `loam init --create` writes the empty map, and `loam seed --from fleet.yaml` templates one from stated facts.\" },\n \"doctor.landscape-unreadable\": { severityNote: \"blocker\", meaning: \"The landscape file exists and the read itself failed — permissions or an I/O error, carried verbatim in the message.\", fix: \"Check permissions on the path the finding names.\" },\n \"doctor.landscape-merge-conflict\": { severityNote: \"blocker\", meaning: \"The landscape still contains merge conflict markers, named by line. Checked BEFORE the parser on purpose: both sides of a conflict can be syntactically valid LikeC4, so the file sometimes parses and is still two halves of two different maps.\", fix: \"Resolve the conflict keeping BOTH services' elements and edges — the usual cause is several services adopted into one map in the same week — then re-run `loam doctor`.\" },\n \"doctor.landscape-invalid\": { severityNote: \"blocker\", meaning: \"The landscape exists, carries no conflict markers, and does not parse; the message quotes the first parser error with its line and counts the rest.\", fix: \"Fix the file — every fleet-wide check is blind until it parses.\" },\n \"doctor.likec4-config-missing\": { severityNote: \"warning\", meaning: \"The docs repo has no likec4.config.json, so the tree is not a loadable LikeC4 workspace: every service model and feature delta declares its own `specification` block, and a renderer pointed at the repo root merges them and reports every declaration as a duplicate. No loam check reads this file — the repo is only unrenderable, which is why it is a warning.\", fix: \"Write the project file the finding prints; it scopes the root project to architecture/, so `npx likec4 start` in the docs repo renders the fleet map. Then run `loam subsystem sync`: it writes one create-only likec4.config.json beside every service model, so each model renders from that same root as a project of its own — only a feature delta still renders from its own directory.\" },\n \"doctor.docs-locked\": { severityNote: \"warning while a live process holds it; blocker when its holder is dead or it names none\", meaning: \"A `.loam-lock` is present. Held by a running process it is a fact about right now. Held by a process that no longer exists on this host — or unreadable, so no holder can be named at all — nothing is ever going to release it, and every writing command refuses with `docs-busy` forever.\", fix: \"Wait and re-run while the holder is alive; nothing is read or written while it is held. Delete the lock file the finding names when its holder is dead or unnameable, then run `loam doctor` again for an interrupted commit underneath it.\" },\n \"doctor.commit-unreadable\": { severityNote: \"blocker\", meaning: \"A `.loam-commit` journal is present and cannot be read: a commit was interrupted and the one record of which files it had already written is unreadable.\", fix: \"Hand this to a human — compare the root's files against version control before running any loam command that writes there. Every journaled writer refuses with `commit-interrupted` while it is present.\" },\n \"doctor.commit-interrupted\": { severityNote: \"blocker\", meaning: \"A journaled writer — archive, unarchive, rebase, vouch, new, gherkin, or a recording verify — was killed mid-commit. The message names the host, pid and time, and every file or directory move that may be half-done. This is the surface that used to report a healthy repo over half-merged living docs.\", fix: \"Re-run the command the finding names: it recovers first, under the lock, rolling the staged bytes forward, and refuses rather than guessing if a file has been edited since. An interrupted `loam unarchive` is FINISHED, never undone — the merged text it was replacing is written down nowhere.\" },\n \"doctor.staging-temps\": { severityNote: \"warning\", meaning: \"Orphaned `.loam-*.tmp` scratch files from a killed writer, never linked into place — so nothing reads them and nothing depends on them. A journal's own recorded temps are excluded, because those are the durable copy its roll-forward recovery renames in. Litter, not damage.\", fix: \"The next journaled writer through that root removes its own; delete any that remain. They cost disk and nothing else.\" },\n \"doctor.inventory-unreadable\": { severityNote: \"warning\", meaning: \"The config and the docs repo are both fine and enumerating `services/` or `features/` threw, so doctor's fleet counts — and its verdict on the service binding — are about a fleet nobody could read.\", fix: \"Check that services/ and features/ under the docs repo are readable directories.\" },\n \"doctor.service-unbound\": { severityNote: \"warning\", meaning: \"loam.json declares no `service`, so nothing binds this checkout to one governed boundary and the service-repo checks have nothing to run against — `sources.stale`, a recording `loam verify`, `loam gherkin`. Deliberately not emitted inside the docs repo itself, where having no binding is the correct state rather than a gap.\", fix: \"Run `loam init --docs <dir> --service <id>` here.\" },\n \"doctor.service-unknown\": { severityNote: \"warning\", meaning: \"loam.json names a `service` the fleet has no services/<id>/ for — and the fleet WAS read, so this is a claim about a real inventory rather than one nobody could take.\", fix: \"Run `loam adopt --service <id>` to onboard it, or fix `service` in loam.json.\" },\n \"doctor.agent-files-missing\": { severityNote: \"warning\", meaning: \"Some of the command and skill files this loam lays down for the repo's recorded tools and profile are not here: the repo was initialized by an older loam, or they were deleted. An out-of-date command set costs entry points, never a refusal, which is why it is a warning.\", fix: \"Re-run `loam init --docs <dir> --tools <ids>` here. It creates absent files, refreshes only pointers whose current bytes still match their recorded digest, preserves every customized file, and keeps this repo's service binding.\" },\n \"doctor.agent-files-stale\": { severityNote: \"warning\", meaning: \"Command or skill files that ARE here differ from the body this binary writes and carry no loam stamp, or one older than this binary, so what they instruct an agent with may describe a loam that no longer exists. A file whose only difference is an older stamp is current and not reported; a customized body under a current stamp is not reported either, because the stamp records that somebody reviewed it. Safe refresh is a separate digest check performed by init.\", fix: \"Re-run `loam init` to refresh a pointer only when its recorded digest still matches. Review a customized file against the current body yourself and update its stamp, or delete it so init can recreate it; your edits always outrank the template.\" },\n },\n};\n\n/**\n * `loam status` — both forms print `next[]`, and each entry carries a `code` to\n * branch on, one sentence, and the literal `command` to run. So the \"what to\n * do\" column is genuinely empty for this whole family: the step IS the action,\n * and each `fix` below names the step's own command rather than inventing a\n * second instruction beside it.\n */\nconst NEXT_STEPS: Family = {\n scope: \"loam status\",\n codes: {\n \"next.adopt-bound\": { severityNote: \"step\", meaning: \"The fleet form's first entry: this repository's loam.json says it is a service the fleet has no services/<id>/ for, so nothing about the boundary you are standing in is written down yet. Ahead of every other service's adoption work, because it is the only step that is about HERE.\", fix: \"The step IS the action: run its `command`, `loam adopt --service <id> --json`.\" },\n \"next.author-landscape\": { severityNote: \"step\", meaning: \"The first rung of the first-hour ladder, over a fleet with no services and no features: architecture/landscape.likec4 does not exist, or is still the scaffold's untouched map with no service drawn on it.\", fix: \"The step IS the action: run its `command` — `loam init --create` when the file is absent, `loam seed --from fleet.yaml` when it is the untouched scaffold. loam never guesses who calls whom.\" },\n \"next.bind-service\": { severityNote: \"step\", meaning: \"First-hour ladder: no service repository is bound to this fleet yet, so no command can ever run from a service's own checkout.\", fix: \"The step IS the action: run its `command`, `loam init --docs <path-to-this-docs-repo> --service <service-id> --agent-profile service`, from a service's own repo, and commit the loam.json it writes. The service profile leaves loam-feature and loam-ship, which this docs repo keeps, out of the service checkout.\" },\n \"next.adopt-first\": { severityNote: \"step\", meaning: \"First-hour ladder: services/ is empty, so nothing about any service is written down and nothing can be graded against anything.\", fix: \"The step IS the action: run its `command`, `loam adopt --service <service-id> --json`; the brief it prints walks an agent through writing the baseline docs as draft.\" },\n \"next.adopt\": { severityNote: \"step\", meaning: \"One service in the fleet has no spec.md — nothing about it is written down, so no feature can be graded against it. One entry per undocumented service.\", fix: \"The step IS the action: run its `command`, `loam adopt --service <id> --json`.\" },\n \"next.complete-service\": { severityNote: \"step\", meaning: \"Adoption does not end at spec.md: a service has one and no model.likec4, the state archive warns about and the fleet gate reports incomplete until something models it.\", fix: \"The step IS the action: run its `command`, `loam validate --service <id> --json`.\" },\n \"next.revouch\": { severityNote: \"step\", meaning: \"A vouched service's spec.md or arch.spec.md changed after the person read it — `content.stale`, computable from the docs repo because it needs nothing but the document. `status: verified` still stands, so every fleet readout says vouched (stale) and this step keeps `next.fleet-clean` from saying nothing is owed. One entry per service, naming the documents that moved.\", fix: \"Not an agent's step: its `execution` is a human review. Prepare the reading list with `loam vouch --pack --service <id>`, then a person re-reads what moved and runs the step's `command`, `loam vouch --service <id>`, from that service's own repository. Never revert the document or touch `content_digest` to silence it.\" },\n \"next.feature\": { severityNote: \"step\", meaning: \"One feature in flight that is not ready to ship, named with the stage it sits at and what it is missing — or, when it is blocked by another feature, the features it is waiting on.\", fix: \"The step IS the action: run its `command`, `loam status <FEAT-id> --json`, for that feature's own next list.\" },\n \"next.archive\": { severityNote: \"step\", meaning: \"In the fleet form, a feature that is authored and verified: ship it, and everything queued behind it is released. In a feature's own list it is always the last entry, saying the feature ships once everything above it is done.\", fix: \"The step IS the action: run its `command`, `loam archive <FEAT-id> --dry-run --json`; the dry run writes nothing and lists every file the merge would touch.\" },\n \"next.elided\": { severityNote: \"step\", meaning: \"The fleet list is capped, and this says how many steps of the same kinds it left out. The list is ordered most-unblocking first, so what was elided is the least urgent — a list nobody reads is not navigation.\", fix: \"The step IS the action: run its `command`, `loam list --json`, or work down the printed list and run status again.\" },\n \"next.fleet-clean\": { severityNote: \"step\", meaning: \"Services exist, nothing is in flight, and nothing is owed. Only that truthful case: over an EMPTY fleet the same sentence was vacuously true, and the first-hour ladder owns that repository now.\", fix: \"The step IS the action: run its `command`, `loam validate --all --json`, then start the next feature.\" },\n \"next.fleet-gate\": { severityNote: \"step\", meaning: \"The last entry of every fleet list, and always present: `status` grades nothing, so the least it can do is say where grading happens — `loam validate --all` is the gate this repository has to pass and the one CI runs.\", fix: \"The step IS the action: run its `command`, `loam validate --all --json`.\" },\n \"next.recover-commit\": { severityNote: \"step\", meaning: \"Always first, and never elided by the fleet form's cap: a journaled writer was killed mid-commit, so everything below this step is derived from files that may be half-written. Where the journal itself cannot be read, nothing below can be trusted until a human compares the living docs against version control.\", fix: \"The step IS the action: run its `command` — the interrupted command re-run, which recovers first under the lock, or `loam doctor --json` when the journal is unreadable and no loam command can repair it.\" },\n \"next.archived\": { severityNote: \"step\", meaning: \"The whole `next[]` for a feature that already shipped: it is archived, and its delta is folded into the living docs.\", fix: \"The step IS the action: run its `command`, `loam show <FEAT-id> --json`.\" },\n \"next.author-intent\": { severityNote: \"step\", meaning: \"The feature has no intent document — what it is for, in prose, before anything is derived from it.\", fix: \"The step IS the action: write the file the step names, then run its `command`, `loam validate <FEAT-id> --json`. The command never writes the artifact: loam does not author.\" },\n \"next.touch-service\": { severityNote: \"step\", meaning: \"The feature carries no per-service delta at all, so nothing says which governed boundaries it changes.\", fix: \"The step IS the action: run its `command`, `loam list services --json`, then add specs/<service>/spec.md for every service the feature changes.\" },\n \"next.author-spec\": { severityNote: \"step\", meaning: \"One service the feature touches has no requirement delta — the ADDED / MODIFIED / REMOVED requirements the feature makes to that service, each with a scenario.\", fix: \"The step IS the action: write the file the step names, then run its `command`, `loam delta <FEAT-id> --service <id> --json`, which projects the delta onto the living document.\" },\n \"next.author-openapi\": { severityNote: \"step\", meaning: \"Nothing gives one of the feature's services a living openapi.yaml, so this feature is the only thing that can write down its API surface. Deliberately not phrased as the service being absent from the living docs: a service adopted without a contract is the commoner case, and that wording sent readers looking for a directory that was right there.\", fix: \"The step IS the action: write the file the step names, then run its `command`, `loam delta <FEAT-id> --service <id> --json`.\" },\n \"next.author-scenarios\": { severityNote: \"step\", meaning: \"Requirements in one service's delta carry no `#### Scenario:`, so they generate no test and no verify claim — a promise that reaches neither the suite nor the done-check. One entry per service and never per requirement, because a delta with forty bare requirements would otherwise BE the payload.\", fix: \"The step IS the action: write a scenario under each bare requirement, then run its `command`, `loam delta <FEAT-id> --service <id> --json`.\" },\n \"next.rebase\": { severityNote: \"step\", meaning: \"The feature carries requirements or operations with no baseline pin, on any of the three axes; until they have one the merge cannot tell what it EDITS from what it merely quotes.\", fix: \"The step IS the action: run its `command`, `loam rebase <FEAT-id>`.\" },\n \"next.archive-first\": { severityNote: \"step\", meaning: \"The feature builds on other features still in flight, which have to archive before it can.\", fix: \"The step IS the action: run its `command`, `loam dependencies <FEAT-id> --json`.\" },\n \"next.fix-coherence\": { severityNote: \"step\", meaning: \"The feature has findings that stop it, named starting with the first. Everything EITHER gate refuses on is counted, so a warning marked as gating archive is in the tally even though `validate` grades the feature valid — which is why its exit code alone will not show you why archive refuses.\", fix: \"The step IS the action: run its `command`, `loam validate <FEAT-id> --json`.\" },\n \"next.generate-tests\": { severityNote: \"step\", meaning: \"The feature's delta for a service carries scenarios no test run has answered yet. `loam gherkin` writes the .feature files whose green run is the only thing that may answer a `scenario.tested` claim, and it writes into the service's own repository — so the step names which repo to run it in when that is not this one.\", fix: \"The step IS the action: run its `command`, `loam gherkin <FEAT-id> --service <id>`, from that service's own checkout.\" },\n \"next.verify\": { severityNote: \"step\", meaning: \"The done-check has not been started, or its record cannot be used. Five situations share this code because they share the work — nothing recorded, a record file that does not read as a record, a record the feature has moved out from under, a record that answers no claims at all, and a feature with nothing to derive a checklist from yet — and the step's own statement says which.\", fix: \"The step IS the action: run its `command`, `loam verify <FEAT-id> --json`, which derives the checklist and prints what it asks. A record file nothing can read is repaired by hand or, when it is one service's own `verification/<svc>.yaml`, deleted and recorded again by that service; the one-file `verification.yaml` may hold other services' attestations and is restored from version control, never deleted. Nothing overwrites it while it is unreadable.\" },\n \"next.verify-unconfirmed\": { severityNote: \"step\", meaning: \"Claims on the feature are open — unconfirmed or unanswered — and this repository is not one of the services that owes an answer, so the recording form is not a step anyone can take from here.\", fix: \"The step IS the action: run its `command`, `loam verify <FEAT-id> --json`. The open claims are closed from each affected service's own repository.\" },\n \"next.attest-service\": { severityNote: \"step\", meaning: \"Claims are open AND this repository is one of the services that owes an answer, so the recording form is nameable here: `--record --service` binds the answers to this repo's HEAD and refuses anywhere else.\", fix: \"The step IS the action: run its `command`, `loam verify <FEAT-id> --record answers.json --service <id>`, answering the claims filed under this service; the rest belong to their own repositories.\" },\n \"next.verify-attested\": { severityNote: \"step\", meaning: \"Every claim is answered and some scenario claims are confirmed on an agent's word rather than on a test run (`verify.scenario-attested`) — complete work resting on an assertion, which is what `ready` has always meant here.\", fix: \"The step IS the action: run its `command`, `loam verify <FEAT-id> --results <report.json>` — a cucumber JSON report, or loam's runner-neutral `loamScenarioReport` shape for any other runner — and the record stops resting on an assertion.\" },\n },\n};\n\n/**\n * `loam diff` — what CHANGED between a base git ref of the docs repo and the\n * working tree, not what is WRONG with either. That is why most rows below have\n * no repair: the meanings are the `DiffCode` union's own doc comments\n * (core/diff/semantic.ts), and the two error rows are the only ones naming a\n * repair. The two `-modified` rows name work too, but not loam's: whether a\n * changed schema breaks its readers is the specialist diff's answer.\n */\nconst DIFF: Family = {\n scope: \"loam diff --base <ref>\",\n codes: {\n \"diff.service-added\": { severityNote: \"ok\", meaning: \"A services/<id>/ directory exists now that did not exist at the base ref.\", fix: \"Nothing to fix: `loam diff` says what changed between two points of the living docs, never what is wrong with them. This is the class of the change, for a reviewer to read.\" },\n \"diff.service-removed\": { severityNote: \"warn\", meaning: \"A service present at the base ref is gone from the working tree; the finding names the directory it occupied.\", fix: \"A review question rather than a defect: nothing in the working tree describes that boundary any more. `loam validate --all` is what grades the fleet that is left.\" },\n \"diff.requirement-added\": { severityNote: \"ok\", meaning: \"A living requirement not present at base — by `Requirement-ID:` where one is authored, by heading otherwise, the same join `loam rebase` pins against.\", fix: \"Nothing to fix: this is the class of the change, for a reviewer to read.\" },\n \"diff.requirement-removed\": { severityNote: \"warn\", meaning: \"A requirement present at the base ref is no longer in the living spec under the same identity.\", fix: \"A review question. A requirement that CHANGED identity — a new `Requirement-ID:`, a renamed heading — reads here as a removal plus an addition, which is the join being honest about what it can see rather than guessing a rename.\" },\n \"diff.requirement-modified\": { severityNote: \"ok\", meaning: \"The same requirement identity is on both sides and its digest moved. A rebase pin never moves that digest, so this is a real edit to the requirement's text.\", fix: \"Nothing to fix: this is the class of the change, for a reviewer to read.\" },\n \"diff.op-added\": { severityNote: \"ok\", meaning: \"An operationId in the living contract that was absent at the base ref; the message names its method and path.\", fix: \"Nothing to fix: this is the class of the change, for a reviewer to read.\" },\n \"diff.op-removed\": { severityNote: \"warn\", meaning: \"A base operationId is gone from the living contract and no current edge of the `architecture/` project, requirement or use-case hop names it — or, in the second wording this code also carries, whether one does could NOT be fully answered, and the details name the possible consumers nobody could check: a consumer document that was not scannable, or a landscape edge into this service drawn with no `metadata { op }`.\", fix: \"Read which of the two sentences it is. Nobody could be checked is never nobody names it: an unreadable document carries the run to exit 1 on its own, and an edge with no op is answered by putting the operation it calls on the edge (`spine.op-link-missing` names the same edge).\" },\n \"diff.op-removed-consumed\": { severityNote: \"error\", meaning: \"An operation was removed since the base ref and the current fleet still names it — an edge of the `architecture/` project, another service's requirement in spec.md or arch.spec.md (not one naming its own service's operation of the same id), or a use-case hop attributed to it: the consumers the archive gate refuses on too. The details list the victims, and the finding sets `breaking`.\", fix: \"These joins break. Either restore the operation, or land the consumers' own deltas in the same change so nothing in the fleet is left calling something that is gone.\" },\n \"diff.op-deprecated\": { severityNote: \"warn\", meaning: \"`deprecated: true` was introduced on an operation since the base ref. The details name the current consumers, under one of three deliberately honest phrasings: some still name it, none does, or whether any does could not be fully answered.\", fix: \"Deprecation is a promise to the consumers the details name, and nothing is broken yet. Read which phrasing it is before treating a silent list as an empty one.\" },\n \"diff.op-modified\": { severityNote: \"warn\", meaning: \"The same operationId is on both sides and the operation changed: its own definition, its method or path, or anything its internal `$ref`s reach — a field renamed in a shared `components` schema counts. The details name the authored consumers, the same scan `diff.op-deprecated` runs. loam does not read what a schema says, so it never grades whether the change is breaking.\", fix: \"Run `oasdiff breaking` on the two states of this contract to learn whether it breaks anyone; the details are who to tell. A warning on purpose: a new optional field and a renamed required one look identical from here.\" },\n \"diff.message-added\": { severityNote: \"ok\", meaning: \"An AsyncAPI message name absent at the base ref.\", fix: \"Nothing to fix: this is the class of the change, for a reviewer to read.\" },\n \"diff.message-removed\": { severityNote: \"warn\", meaning: \"A base message is gone. The finding says which of three cases it is: another current service still sends it (an `action: send` operation — a service that only receives it is a consumer) or an `#external` element still publishes it (a `publishes` edge from it in the `architecture/` project, the outside producer `spine.message-unproduced` accepts), nothing currently consumes it, or whether anything does could not be fully answered because some consumer documents were not scannable.\", fix: \"Read which case it is. A name another service still sends, or an `#external` element still publishes, is not orphaned, and an unanswerable scan is not an empty one — only positive evidence vouches here.\" },\n \"diff.message-removed-consumed\": { severityNote: \"error\", meaning: \"A message was removed since the base ref and the current fleet still consumes it — a `Consumes:` line in either spec file, a consumes edge of the `architecture/` project, or a use-case hop it backs. The details list the victims, and the finding sets `breaking`.\", fix: \"These joins break. Either restore the message, or land the consumers' own deltas in the same change.\" },\n \"diff.message-modified\": { severityNote: \"warn\", meaning: \"The same AsyncAPI message name is on both sides and its declaration, or anything its internal `$ref`s reach, changed — a payload field renamed counts. The details name the authored consumers: consumes-edges, `Consumes:` lines and the use-case hops they back. Content equality only: nothing inside the payload is ever joined on, and whether the change breaks a consumer is not graded.\", fix: \"Run `asyncapi diff` on the two states of this contract to learn whether it breaks anyone; the details are who to tell.\" },\n \"diff.consumer-added\": { severityNote: \"ok\", meaning: \"A cross-service join appeared since base: another service's living requirements — spec.md or arch.spec.md — now name this service's operation or message. A line naming an operation the consumer's own contract defines names its own, and is no join. Filed on the PROVIDER — the service whose surface the join lands on.\", fix: \"Nothing to fix, and the change class most worth reading: a new consumer is a new obligation on this service's contract, and removing that operation later is what `diff.op-removed-consumed` will be about.\" },\n \"diff.consumer-removed\": { severityNote: \"ok\", meaning: \"A cross-service join present at the base ref is gone: a consumer's living requirements no longer name this service's operation or message.\", fix: \"Nothing to fix: this is the class of the change, for a reviewer to read.\" },\n },\n};\n\n/**\n * `loam gate` — the can-i-deploy question, a pure query over evidence other\n * commands already recorded. Nothing here re-derives a coherence plan, so every\n * repair below is somebody else's command.\n */\nconst GATE: Family = {\n scope: \"loam gate\",\n codes: {\n \"gate.partners-unknown\": { severityNote: \"warn when the map is absent; error when it exists and cannot be used\", meaning: \"The partner set for the gated service could not be derived from architecture/landscape.likec4 — it is absent, or it exists and does not parse. That means nobody could look, never that nothing joins this service. Absent is a warning because a repo before its first adopt legitimately has no map yet; a broken map is an error because `loam validate --all` fails that repo for the same file, and a deploy gate passing where the fleet gate fails would be the quieter of two contradictory verdicts.\", fix: \"Fix the landscape and re-run. `loam validate --all` diagnoses the file itself; this check only refuses the false silence.\" },\n \"gate.service-undocumented\": { severityNote: \"error\", meaning: \"The service being deployed sits below `documented` on the adoption ladder, so the docs cannot say what its joins even are and no recorded evidence can answer the deploy question. The details list what the next rung wants.\", fix: \"Author the baseline — `loam adopt --service <id>` briefs exactly what is missing — and this check passes once the required artifact set exists.\" },\n \"gate.partner-undocumented\": { severityNote: \"warn\", meaning: \"A service that joins the gated one has no services/<id>/ directory at all, or has one sitting below `documented`: its side of the join is not recorded, so the gate cannot see what that partner promises. An `#external` partner is exempt on purpose — somebody else's system is unrecorded by design.\", fix: \"Adopt the partner (`loam adopt --service <id>` briefs it), bind its landscape element to the right service with `metadata { service '<id>' }`, or tag it `#external` if it is not ours.\" },\n \"gate.feature-unverified\": { severityNote: \"warn\", meaning: \"An active feature touching the gated service — or, under `--since <ref>`, one archived after that docs-repo ref (its `features/archive/` directory absent at the ref, or changed since: a feature unarchived and archived again ships again) — is not verified: no record at all, a record file that does not read as a record, a record the feature moved out from under (for an archived feature, one that no longer answered the checklist `loam archive` captured as it merged), a record answering no claims, or open claims counted in the message. A record that is merely `attested` is NOT reported under this code — it carries `verify.scenario-attested` instead, because complete work resting on an assertion is a different fact from work nobody checked. Without `--since` an archived feature is never read, so archiving one takes it out of this check.\", fix: \"Derive the checklist and answer every claim with evidence: `loam verify <FEAT-id> --json`. A record file nothing can read is repaired by hand or, when it is one service's own `verification/<svc>.yaml`, deleted and recorded again by that service; the one-file `verification.yaml` may hold other services' attestations and is restored from version control, never deleted. Nothing overwrites it while it is unreadable. An archived feature's record is frozen: `loam unarchive <FEAT-id>` re-opens it if its claims must be answered before the deploy.\" },\n },\n};\n\n/** In listing order, though every consumer sorts by code — the order is documentation, not contract. */\nconst FAMILIES: readonly Family[] = [DOCTOR, NEXT_STEPS, DIFF, GATE];\n\n/** One family row, in the shape `FindingEntry` (lookup.ts) takes. */\nexport interface FamilyFinding extends FamilyEntry {\n readonly scope: string;\n}\n\n/**\n * The registry's answer for one subject, or null.\n *\n * Built per call over constants already in memory, never cached at module\n * level, for the reason lookup.ts's header gives: tests fork and chdir, and the\n * MCP server outlives many calls.\n */\nexport function familyFinding(subject: string): FamilyFinding | null {\n for (const family of FAMILIES) {\n const entry = family.codes[subject];\n if (entry !== undefined) return { scope: family.scope, ...entry };\n }\n return null;\n}\n\n/** Every code the registry answers, sorted — the same plain sort the code inventory uses. */\nexport function familyCodes(): string[] {\n return FAMILIES.flatMap((family) => Object.keys(family.codes)).sort();\n}\n"]}
|
|
@@ -23,8 +23,8 @@ export const REFUSAL_MEANINGS = {
|
|
|
23
23
|
"service-mismatch": "A command that must run inside one service's own repository was told `--service` for a service this repository's loam.json does not declare: a recording `loam verify`, whose attestation must be bound to the code it is about; `loam gherkin`, whose .feature files land in that service's checkout; or `loam vouch`, whose `sources` resolve there. Run it from that service's own repo.",
|
|
24
24
|
"unknown-service": "Federated verify recording: the selected service is not one this feature's checklist (or the docs repo) knows, so there is nothing its attestation could bind to — fix the id.",
|
|
25
25
|
"repository-unavailable": "The repository this operation must be bound to (or read from) cannot be answered for — most commonly a writing `loam verify`, a `loam gherkin` or a `loam vouch` run where loam.json declares no `service` at all (the docs repo, usually), or a docs repo that cannot be enumerated — so the command refuses rather than guessing which service it is about.",
|
|
26
|
-
"record-federated": "`loam verify --record` without `--service` over a federated (schema 2) record — the all-at-once form would
|
|
27
|
-
"record-unreadable": "A verification.yaml exists but cannot be read
|
|
26
|
+
"record-federated": "`loam verify --record` without `--service` over a federated (schema 2) record — per-service files under `verification/`, or a one-file record carrying attestations — the all-at-once form would put one unattested answer set over other repositories' attestations, so it is refused naming the attestors; record per service instead.",
|
|
27
|
+
"record-unreadable": "A file of the verification record (`verification.yaml`, or one service's `verification/<svc>.yaml`) exists but cannot be read — broken YAML, git conflict markers, a summary contradicting its claims, or a per-service file holding anything but its own service's attestation. It is never overwritten and never reported as absent. The message names the file and the safe repair: a service's own file holds only that service's word, so it may be repaired, or deleted and recorded again from that service's repo; the one-file `verification.yaml` may hold other services' attestations, so it is repaired or restored from version control (after a merge, the copy on the branch you merged into), never deleted.",
|
|
28
28
|
"record-raced": "`loam verify --record` found the record changed between its locked read and the swap — an editor or a lock-ignoring writer landed first; nothing was written, and re-running merges over the record as it now stands.",
|
|
29
29
|
"gherkin-conflict": "`loam gherkin <FEAT>` would overwrite a `.feature` file owned by another feature still in flight — the whole emission refuses and names the owner; archive or coordinate with that feature first.",
|
|
30
30
|
"vouch-raced": "`loam vouch` found the spec changed between reading and stamping — another vouch or an edit landed first; nothing was written, so re-read and re-run.",
|
|
@@ -43,7 +43,7 @@ export const REFUSAL_MEANINGS = {
|
|
|
43
43
|
"seed-file-invalid": "`loam seed`'s fleet file is missing, unreadable, not YAML, the wrong shape, carries an illegal id — or no longer names every existing `services/<id>/` (that refusal lists the exact ids as `missingServices`); the message names the file and line, and editing the file and re-running succeeds.",
|
|
44
44
|
"seed-duplicate-service": "fleet.yaml declares one name twice — as two services, or as both a service and an external/subsystem; service ids, subsystem names and externals share one flat namespace, both declaration lines are named, and renaming one fixes it.",
|
|
45
45
|
"seed-unknown-subsystem": "A service's `subsystem:` in fleet.yaml names nothing `subsystems:` declares — the message carries a did-you-mean over the names the file really declares; add the subsystem or fix the spelling, then re-run.",
|
|
46
|
-
"seed-landscape-edited": "architecture/landscape.likec4 carries hand edits (the line-1 stamp's digest no longer matches) or was authored some other way, which includes anything written ABOVE the scaffold's stub — `loam seed` never overwrites human work and wrote nothing
|
|
46
|
+
"seed-landscape-edited": "architecture/landscape.likec4 carries hand edits (the line-1 stamp's digest no longer matches) or was authored some other way, which includes anything written ABOVE the scaffold's stub — `loam seed` never overwrites human work and wrote nothing. Seed runs once, before any operation is drawn: fleet.yaml cannot carry `metadata { op }`, publishes or consumes, so once the map holds them it grows without seed — `loam adopt --service <id>` for a new service, a feature's C4 delta for everything else. Folding the edits into fleet.yaml and deleting the file works only when every edit is a service, subsystem or plain call fleet.yaml can say.",
|
|
47
47
|
internal: "An unexpected throw — the one refusal with no stable meaning; it exists so a `--json` consumer still receives an envelope instead of a stack trace, and a repeatable `internal` is a loam defect worth reporting.",
|
|
48
48
|
};
|
|
49
49
|
//# sourceMappingURL=refusals.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refusals.js","sourceRoot":"","sources":["../../../src/core/explain/refusals.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,WAAW,EACT,gMAAgM;IAClM,gBAAgB,EACd,4MAA4M;IAC9M,gBAAgB,EACd,oJAAoJ;IACtJ,gBAAgB,EACd,qQAAqQ;IACvQ,gBAAgB,EACd,iNAAiN;IACnN,gBAAgB,EACd,4KAA4K;IAC9K,sBAAsB,EACpB,8LAA8L;IAChM,cAAc,EACZ,oOAAoO;IACtO,6BAA6B,EAC3B,yQAAyQ;IAC3Q,gBAAgB,EACd,gLAAgL;IAClL,cAAc,EACZ,yJAAyJ;IAC3J,qBAAqB,EACnB,qLAAqL;IACvL,gBAAgB,EACd,yLAAyL;IAC3L,kBAAkB,EAChB,oMAAoM;IACtM,gBAAgB,EACd,gMAAgM;IAClM,kBAAkB,EAChB,2NAA2N;IAC7N,oBAAoB,EAClB,sRAAsR;IACxR,gBAAgB,EACd,wIAAwI;IAC1I,oBAAoB,EAClB,wMAAwM;IAC1M,kBAAkB,EAChB,gNAAgN;IAClN,qBAAqB,EACnB,uLAAuL;IACzL,kBAAkB,EAChB,6XAA6X;IAC/X,iBAAiB,EACf,gLAAgL;IAClL,wBAAwB,EACtB,+VAA+V;IACjW,kBAAkB,EAChB,uNAAuN;IACzN,mBAAmB,EACjB,4KAA4K;IAC9K,cAAc,EACZ,uNAAuN;IACzN,kBAAkB,EAChB,mMAAmM;IACrM,aAAa,EACX,uJAAuJ;IACzJ,kBAAkB,EAChB,oJAAoJ;IACtJ,sBAAsB,EACpB,6LAA6L;IAC/L,gBAAgB,EACd,uGAAuG;IACzG,cAAc,EACZ,0MAA0M;IAC5M,kBAAkB,EAChB,wNAAwN;IAC1N,WAAW,EACT,wMAAwM;IAC1M,qBAAqB,EACnB,sOAAsO;IACxO,kBAAkB,EAChB,kOAAkO;IACpO,aAAa,EACX,+JAA+J;IACjK,YAAY,EACV,sNAAsN;IACxN,mBAAmB,EACjB,4NAA4N;IAC9N,mBAAmB,EACjB,oQAAoQ;IACtQ,mBAAmB,EACjB,oSAAoS;IACtS,wBAAwB,EACtB,yOAAyO;IAC3O,wBAAwB,EACtB,+MAA+M;IACjN,uBAAuB,EACrB,8VAA8V;IAChW,QAAQ,EACN,mNAAmN;CACzK,CAAC","sourcesContent":["/**\n * One sentence per envelope refusal code, for `loam explain`.\n *\n * This is the one deliberate restatement in the explain lookup, and the\n * compiler is its drift test: unlike the finding codes — whose prose ships in\n * the /loam-check fix tables and is PARSED at runtime (fix-tables.ts) — the\n * `ErrorCode` union's meanings live only in doc comments, which are erased,\n * so there is no runtime constant to read. `satisfies Record<ErrorCode,\n * string>` makes the pairing exhaustive both ways: a new union member cannot\n * ship without a row here (missing key fails typecheck), and a row for a\n * retired code fails the same way. What tsc cannot pin is accuracy — a\n * reworded doc comment can drift from its sentence — which is why each row\n * stays ONE sentence in the union's own voice (what happened, what it means,\n * whether re-running can work) rather than growing a paragraph of its own.\n */\nimport type { ErrorCode } from \"../envelope/json.js\";\n\nexport const REFUSAL_MEANINGS = {\n \"no-config\":\n \"No loam.json at or above the working directory — the repo is not wired to a fleet; run `loam init --docs <dir>` once per repository rather than letting a command guess where the fleet lives.\",\n \"config-invalid\":\n \"loam.json exists but cannot be loaded — repair the file (or delete it and re-run `loam init`); the code is distinct from `no-config` because running init over a corrupt config would silently rewrite it.\",\n \"unknown-target\":\n \"The name resolves to nothing this command can address — no such service, feature, workflow or subject; the message offers the closest known names.\",\n \"invalid-option\":\n \"The invocation itself is wrong — flags that contradict each other, a value that cannot be right, or a mistyped flag or command; nothing was read or written, and with `--json` anywhere in the arguments even commander's own usage errors arrive as this envelope.\",\n \"already-exists\":\n \"Refusing to create over something that already exists — a feature directory, a workspace file, a name already claimed in the subsystem namespace — because overwriting would destroy work nobody asked to lose.\",\n \"sources-absent\":\n \"`loam vouch` refuses to stamp a document that names no `sources` — with nothing tying the document to code, the staleness signal a vouch exists to power could never fire.\",\n \"sources-path-missing\":\n \"`loam vouch` refuses to stamp: a listed source does not exist in the service repo, or is a glob pattern (not supported) — the digest would cover a different file set than the author meant.\",\n \"not-coherent\":\n \"`loam archive` refuses: the feature has coherence issues, carried in `issues[]` with a per-issue `overridable` — fix the gating ones, or `--approve` the judgment calls; a refusal `--approve` cannot move says so in the message.\",\n \"living-outside-requirements\":\n \"`loam archive` refuses: the LIVING spec holds a requirement outside its `## Requirements` section, and the merge rewrites only that section, so the requirement would land in the file twice — the fix is in the living document, and `--approve` does not override it.\",\n \"archive-exists\":\n \"`loam archive` refuses: `features/archive/` already holds a directory for this feature — a destination collision, not a merge problem; move the old archive entry aside first.\",\n \"merge-failed\":\n \"The merge — or a journaled writer's one-file commit — could not be computed or was rolled back; the living docs are unchanged, and re-running can work.\",\n \"rollback-incomplete\":\n \"A failed write could not be fully undone: some files were not put back, and the message lists them — the one refusal that needs a human before anything else runs against the repo.\",\n \"feature-active\":\n \"`loam unarchive` refuses: a `features/` directory for this feature already exists outside the archive, so restoring would write over work in flight — remove or rename it, then re-run.\",\n \"snapshot-missing\":\n \"`loam unarchive` refuses: the archive carries no snapshot of what it overwrote (it predates snapshots, or was written by a different loam) — restore the living docs from version control instead.\",\n \"snapshot-stale\":\n \"`loam unarchive` refuses: the living docs changed after the archive, so restoring is no longer an undo — re-run with `--force` to restore anyway, deliberately discarding those later changes.\",\n \"snapshot-corrupt\":\n \"`loam unarchive` refuses: a snapshot pre-image no longer matches the digest the archive recorded for it, so restoring would write text nobody wrote — `--force` does not override this one; restore from version control.\",\n \"commit-interrupted\":\n \"A journaled writer (archive, unarchive, rebase, vouch, new, gherkin, a recording verify) was killed mid-commit and this run cannot repair the leftovers on its own — the docs may be half-written; run the command the message names, or `loam doctor` for the file-by-file account.\",\n \"restore-failed\":\n \"`loam unarchive` failed and everything was rolled back — nothing was restored, the living docs are unchanged, and re-running can work.\",\n \"answers-unreadable\":\n \"A recording `loam verify` could not read a user-named file — the answers JSON, or a cucumber/contract report — as what it claims to be; fail-closed: nothing was recorded, so fix the file and re-run.\",\n \"answers-mismatch\":\n \"The answer set does not answer the current checklist — an id not on it, a claim with no answer, or an entry for a claim a passed report already owns; re-derive the checklist and answer exactly what it asks.\",\n \"answers-unevidenced\":\n \"A `confirmed` answer carries no evidence — evidence is `file:line`, and a claim you cannot show is `unconfirmed` with a note saying why, which is a successful record, not a failure.\",\n \"service-mismatch\":\n \"A command that must run inside one service's own repository was told `--service` for a service this repository's loam.json does not declare: a recording `loam verify`, whose attestation must be bound to the code it is about; `loam gherkin`, whose .feature files land in that service's checkout; or `loam vouch`, whose `sources` resolve there. Run it from that service's own repo.\",\n \"unknown-service\":\n \"Federated verify recording: the selected service is not one this feature's checklist (or the docs repo) knows, so there is nothing its attestation could bind to — fix the id.\",\n \"repository-unavailable\":\n \"The repository this operation must be bound to (or read from) cannot be answered for — most commonly a writing `loam verify`, a `loam gherkin` or a `loam vouch` run where loam.json declares no `service` at all (the docs repo, usually), or a docs repo that cannot be enumerated — so the command refuses rather than guessing which service it is about.\",\n \"record-federated\":\n \"`loam verify --record` without `--service` over a federated (schema 2) record — the all-at-once form would erase other repositories' attestations, so it is refused naming the attestors; record per service instead.\",\n \"record-unreadable\":\n \"A verification.yaml exists but cannot be read as a record — it is never overwritten and never reported as absent; repair it by hand, or re-record from the service's repo.\",\n \"record-raced\":\n \"`loam verify --record` found the record changed between its locked read and the swap — an editor or a lock-ignoring writer landed first; nothing was written, and re-running merges over the record as it now stands.\",\n \"gherkin-conflict\":\n \"`loam gherkin <FEAT>` would overwrite a `.feature` file owned by another feature still in flight — the whole emission refuses and names the owner; archive or coordinate with that feature first.\",\n \"vouch-raced\":\n \"`loam vouch` found the spec changed between reading and stamping — another vouch or an edit landed first; nothing was written, so re-read and re-run.\",\n \"vouch-unattended\":\n \"`loam vouch` with nobody on the other end of stdin and no `--yes` — the stamp is a person's claim to have read the document, and nobody was asked.\",\n \"vouch-unattributable\":\n \"`loam vouch` could not learn who is vouching — git names no `user.email` here — and a stamp with nobody behind it records only that the word was written; set your git identity and re-run.\",\n \"vouch-declined\":\n \"`loam vouch` asked and the person said no — nothing was stamped; a successful refusal, not a failure.\",\n \"docs-missing\":\n \"`docsDir` in loam.json points at nothing — the docs repo was never cloned, or the path is wrong; a read command refuses rather than reporting an empty fleet, and `loam doctor` names the wiring to fix.\",\n \"services-missing\":\n \"`docsDir` is a directory but holds no `services/` — it is some other directory, most often the service repo itself after a typo; fix the pointer rather than scaffolding a second source of truth beside the real one.\",\n \"docs-busy\":\n \"Another loam writer holds the docs repo's advisory lock — nothing was read or written, and re-running once it finishes works; a lock nothing will ever release shows up in `loam doctor` as a blocker.\",\n \"subsystem-not-empty\":\n \"`loam subsystem` rm refuses a subsystem that still holds members — services or child subsystems, named in the message — because a destructive command never picks targets the caller did not name; move them out first, then re-run.\",\n \"move-uncommitted\":\n \"A subsystem move/rename refuses because git reports uncommitted or untracked paths under a directory being moved — the rename would sweep them into a move nobody reviewed; commit, `git stash -u`, or remove them, then re-run.\",\n \"move-failed\":\n \"A subsystem move/rename failed and was rolled back cleanly — every rename undone, the generated views file restored, the docs unchanged; re-running can work.\",\n \"no-members\":\n \"`loam open` found no service checkout bound to this docs repo under any scanned root — the workspace would hold only the docs repo; clone a bound checkout beside it, or point `--root` at where the checkouts live.\",\n \"binding-duplicate\":\n \"Two discovered repositories' committed loam.json files declare the same `service` for this docs repo — loam will not guess which checkout speaks for the service; narrow the scan with `--root`, or fix the stray binding.\",\n \"owners-unreadable\":\n \"`loam list --owners` could not use the named CODEOWNERS file — the path cannot be read, or a line does not parse as `pattern owner…` (the message names the line); fail-closed, because a half-read ownership file must never file a service under the wrong team.\",\n \"seed-file-invalid\":\n \"`loam seed`'s fleet file is missing, unreadable, not YAML, the wrong shape, carries an illegal id — or no longer names every existing `services/<id>/` (that refusal lists the exact ids as `missingServices`); the message names the file and line, and editing the file and re-running succeeds.\",\n \"seed-duplicate-service\":\n \"fleet.yaml declares one name twice — as two services, or as both a service and an external/subsystem; service ids, subsystem names and externals share one flat namespace, both declaration lines are named, and renaming one fixes it.\",\n \"seed-unknown-subsystem\":\n \"A service's `subsystem:` in fleet.yaml names nothing `subsystems:` declares — the message carries a did-you-mean over the names the file really declares; add the subsystem or fix the spelling, then re-run.\",\n \"seed-landscape-edited\":\n \"architecture/landscape.likec4 carries hand edits (the line-1 stamp's digest no longer matches) or was authored some other way, which includes anything written ABOVE the scaffold's stub — `loam seed` never overwrites human work and wrote nothing; fold the edits into fleet.yaml and delete the file, or keep the hand-authored map and stop using seed.\",\n internal:\n \"An unexpected throw — the one refusal with no stable meaning; it exists so a `--json` consumer still receives an envelope instead of a stack trace, and a repeatable `internal` is a loam defect worth reporting.\",\n} as const satisfies Record<ErrorCode, string>;\n"]}
|
|
1
|
+
{"version":3,"file":"refusals.js","sourceRoot":"","sources":["../../../src/core/explain/refusals.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,WAAW,EACT,gMAAgM;IAClM,gBAAgB,EACd,4MAA4M;IAC9M,gBAAgB,EACd,oJAAoJ;IACtJ,gBAAgB,EACd,qQAAqQ;IACvQ,gBAAgB,EACd,iNAAiN;IACnN,gBAAgB,EACd,4KAA4K;IAC9K,sBAAsB,EACpB,8LAA8L;IAChM,cAAc,EACZ,oOAAoO;IACtO,6BAA6B,EAC3B,yQAAyQ;IAC3Q,gBAAgB,EACd,gLAAgL;IAClL,cAAc,EACZ,yJAAyJ;IAC3J,qBAAqB,EACnB,qLAAqL;IACvL,gBAAgB,EACd,yLAAyL;IAC3L,kBAAkB,EAChB,oMAAoM;IACtM,gBAAgB,EACd,gMAAgM;IAClM,kBAAkB,EAChB,2NAA2N;IAC7N,oBAAoB,EAClB,sRAAsR;IACxR,gBAAgB,EACd,wIAAwI;IAC1I,oBAAoB,EAClB,wMAAwM;IAC1M,kBAAkB,EAChB,gNAAgN;IAClN,qBAAqB,EACnB,uLAAuL;IACzL,kBAAkB,EAChB,6XAA6X;IAC/X,iBAAiB,EACf,gLAAgL;IAClL,wBAAwB,EACtB,+VAA+V;IACjW,kBAAkB,EAChB,0UAA0U;IAC5U,mBAAmB,EACjB,+rBAA+rB;IACjsB,cAAc,EACZ,uNAAuN;IACzN,kBAAkB,EAChB,mMAAmM;IACrM,aAAa,EACX,uJAAuJ;IACzJ,kBAAkB,EAChB,oJAAoJ;IACtJ,sBAAsB,EACpB,6LAA6L;IAC/L,gBAAgB,EACd,uGAAuG;IACzG,cAAc,EACZ,0MAA0M;IAC5M,kBAAkB,EAChB,wNAAwN;IAC1N,WAAW,EACT,wMAAwM;IAC1M,qBAAqB,EACnB,sOAAsO;IACxO,kBAAkB,EAChB,kOAAkO;IACpO,aAAa,EACX,+JAA+J;IACjK,YAAY,EACV,sNAAsN;IACxN,mBAAmB,EACjB,4NAA4N;IAC9N,mBAAmB,EACjB,oQAAoQ;IACtQ,mBAAmB,EACjB,oSAAoS;IACtS,wBAAwB,EACtB,yOAAyO;IAC3O,wBAAwB,EACtB,+MAA+M;IACjN,uBAAuB,EACrB,ioBAAioB;IACnoB,QAAQ,EACN,mNAAmN;CACzK,CAAC","sourcesContent":["/**\n * One sentence per envelope refusal code, for `loam explain`.\n *\n * This is the one deliberate restatement in the explain lookup, and the\n * compiler is its drift test: unlike the finding codes — whose prose ships in\n * the /loam-check fix tables and is PARSED at runtime (fix-tables.ts) — the\n * `ErrorCode` union's meanings live only in doc comments, which are erased,\n * so there is no runtime constant to read. `satisfies Record<ErrorCode,\n * string>` makes the pairing exhaustive both ways: a new union member cannot\n * ship without a row here (missing key fails typecheck), and a row for a\n * retired code fails the same way. What tsc cannot pin is accuracy — a\n * reworded doc comment can drift from its sentence — which is why each row\n * stays ONE sentence in the union's own voice (what happened, what it means,\n * whether re-running can work) rather than growing a paragraph of its own.\n */\nimport type { ErrorCode } from \"../envelope/json.js\";\n\nexport const REFUSAL_MEANINGS = {\n \"no-config\":\n \"No loam.json at or above the working directory — the repo is not wired to a fleet; run `loam init --docs <dir>` once per repository rather than letting a command guess where the fleet lives.\",\n \"config-invalid\":\n \"loam.json exists but cannot be loaded — repair the file (or delete it and re-run `loam init`); the code is distinct from `no-config` because running init over a corrupt config would silently rewrite it.\",\n \"unknown-target\":\n \"The name resolves to nothing this command can address — no such service, feature, workflow or subject; the message offers the closest known names.\",\n \"invalid-option\":\n \"The invocation itself is wrong — flags that contradict each other, a value that cannot be right, or a mistyped flag or command; nothing was read or written, and with `--json` anywhere in the arguments even commander's own usage errors arrive as this envelope.\",\n \"already-exists\":\n \"Refusing to create over something that already exists — a feature directory, a workspace file, a name already claimed in the subsystem namespace — because overwriting would destroy work nobody asked to lose.\",\n \"sources-absent\":\n \"`loam vouch` refuses to stamp a document that names no `sources` — with nothing tying the document to code, the staleness signal a vouch exists to power could never fire.\",\n \"sources-path-missing\":\n \"`loam vouch` refuses to stamp: a listed source does not exist in the service repo, or is a glob pattern (not supported) — the digest would cover a different file set than the author meant.\",\n \"not-coherent\":\n \"`loam archive` refuses: the feature has coherence issues, carried in `issues[]` with a per-issue `overridable` — fix the gating ones, or `--approve` the judgment calls; a refusal `--approve` cannot move says so in the message.\",\n \"living-outside-requirements\":\n \"`loam archive` refuses: the LIVING spec holds a requirement outside its `## Requirements` section, and the merge rewrites only that section, so the requirement would land in the file twice — the fix is in the living document, and `--approve` does not override it.\",\n \"archive-exists\":\n \"`loam archive` refuses: `features/archive/` already holds a directory for this feature — a destination collision, not a merge problem; move the old archive entry aside first.\",\n \"merge-failed\":\n \"The merge — or a journaled writer's one-file commit — could not be computed or was rolled back; the living docs are unchanged, and re-running can work.\",\n \"rollback-incomplete\":\n \"A failed write could not be fully undone: some files were not put back, and the message lists them — the one refusal that needs a human before anything else runs against the repo.\",\n \"feature-active\":\n \"`loam unarchive` refuses: a `features/` directory for this feature already exists outside the archive, so restoring would write over work in flight — remove or rename it, then re-run.\",\n \"snapshot-missing\":\n \"`loam unarchive` refuses: the archive carries no snapshot of what it overwrote (it predates snapshots, or was written by a different loam) — restore the living docs from version control instead.\",\n \"snapshot-stale\":\n \"`loam unarchive` refuses: the living docs changed after the archive, so restoring is no longer an undo — re-run with `--force` to restore anyway, deliberately discarding those later changes.\",\n \"snapshot-corrupt\":\n \"`loam unarchive` refuses: a snapshot pre-image no longer matches the digest the archive recorded for it, so restoring would write text nobody wrote — `--force` does not override this one; restore from version control.\",\n \"commit-interrupted\":\n \"A journaled writer (archive, unarchive, rebase, vouch, new, gherkin, a recording verify) was killed mid-commit and this run cannot repair the leftovers on its own — the docs may be half-written; run the command the message names, or `loam doctor` for the file-by-file account.\",\n \"restore-failed\":\n \"`loam unarchive` failed and everything was rolled back — nothing was restored, the living docs are unchanged, and re-running can work.\",\n \"answers-unreadable\":\n \"A recording `loam verify` could not read a user-named file — the answers JSON, or a cucumber/contract report — as what it claims to be; fail-closed: nothing was recorded, so fix the file and re-run.\",\n \"answers-mismatch\":\n \"The answer set does not answer the current checklist — an id not on it, a claim with no answer, or an entry for a claim a passed report already owns; re-derive the checklist and answer exactly what it asks.\",\n \"answers-unevidenced\":\n \"A `confirmed` answer carries no evidence — evidence is `file:line`, and a claim you cannot show is `unconfirmed` with a note saying why, which is a successful record, not a failure.\",\n \"service-mismatch\":\n \"A command that must run inside one service's own repository was told `--service` for a service this repository's loam.json does not declare: a recording `loam verify`, whose attestation must be bound to the code it is about; `loam gherkin`, whose .feature files land in that service's checkout; or `loam vouch`, whose `sources` resolve there. Run it from that service's own repo.\",\n \"unknown-service\":\n \"Federated verify recording: the selected service is not one this feature's checklist (or the docs repo) knows, so there is nothing its attestation could bind to — fix the id.\",\n \"repository-unavailable\":\n \"The repository this operation must be bound to (or read from) cannot be answered for — most commonly a writing `loam verify`, a `loam gherkin` or a `loam vouch` run where loam.json declares no `service` at all (the docs repo, usually), or a docs repo that cannot be enumerated — so the command refuses rather than guessing which service it is about.\",\n \"record-federated\":\n \"`loam verify --record` without `--service` over a federated (schema 2) record — per-service files under `verification/`, or a one-file record carrying attestations — the all-at-once form would put one unattested answer set over other repositories' attestations, so it is refused naming the attestors; record per service instead.\",\n \"record-unreadable\":\n \"A file of the verification record (`verification.yaml`, or one service's `verification/<svc>.yaml`) exists but cannot be read — broken YAML, git conflict markers, a summary contradicting its claims, or a per-service file holding anything but its own service's attestation. It is never overwritten and never reported as absent. The message names the file and the safe repair: a service's own file holds only that service's word, so it may be repaired, or deleted and recorded again from that service's repo; the one-file `verification.yaml` may hold other services' attestations, so it is repaired or restored from version control (after a merge, the copy on the branch you merged into), never deleted.\",\n \"record-raced\":\n \"`loam verify --record` found the record changed between its locked read and the swap — an editor or a lock-ignoring writer landed first; nothing was written, and re-running merges over the record as it now stands.\",\n \"gherkin-conflict\":\n \"`loam gherkin <FEAT>` would overwrite a `.feature` file owned by another feature still in flight — the whole emission refuses and names the owner; archive or coordinate with that feature first.\",\n \"vouch-raced\":\n \"`loam vouch` found the spec changed between reading and stamping — another vouch or an edit landed first; nothing was written, so re-read and re-run.\",\n \"vouch-unattended\":\n \"`loam vouch` with nobody on the other end of stdin and no `--yes` — the stamp is a person's claim to have read the document, and nobody was asked.\",\n \"vouch-unattributable\":\n \"`loam vouch` could not learn who is vouching — git names no `user.email` here — and a stamp with nobody behind it records only that the word was written; set your git identity and re-run.\",\n \"vouch-declined\":\n \"`loam vouch` asked and the person said no — nothing was stamped; a successful refusal, not a failure.\",\n \"docs-missing\":\n \"`docsDir` in loam.json points at nothing — the docs repo was never cloned, or the path is wrong; a read command refuses rather than reporting an empty fleet, and `loam doctor` names the wiring to fix.\",\n \"services-missing\":\n \"`docsDir` is a directory but holds no `services/` — it is some other directory, most often the service repo itself after a typo; fix the pointer rather than scaffolding a second source of truth beside the real one.\",\n \"docs-busy\":\n \"Another loam writer holds the docs repo's advisory lock — nothing was read or written, and re-running once it finishes works; a lock nothing will ever release shows up in `loam doctor` as a blocker.\",\n \"subsystem-not-empty\":\n \"`loam subsystem` rm refuses a subsystem that still holds members — services or child subsystems, named in the message — because a destructive command never picks targets the caller did not name; move them out first, then re-run.\",\n \"move-uncommitted\":\n \"A subsystem move/rename refuses because git reports uncommitted or untracked paths under a directory being moved — the rename would sweep them into a move nobody reviewed; commit, `git stash -u`, or remove them, then re-run.\",\n \"move-failed\":\n \"A subsystem move/rename failed and was rolled back cleanly — every rename undone, the generated views file restored, the docs unchanged; re-running can work.\",\n \"no-members\":\n \"`loam open` found no service checkout bound to this docs repo under any scanned root — the workspace would hold only the docs repo; clone a bound checkout beside it, or point `--root` at where the checkouts live.\",\n \"binding-duplicate\":\n \"Two discovered repositories' committed loam.json files declare the same `service` for this docs repo — loam will not guess which checkout speaks for the service; narrow the scan with `--root`, or fix the stray binding.\",\n \"owners-unreadable\":\n \"`loam list --owners` could not use the named CODEOWNERS file — the path cannot be read, or a line does not parse as `pattern owner…` (the message names the line); fail-closed, because a half-read ownership file must never file a service under the wrong team.\",\n \"seed-file-invalid\":\n \"`loam seed`'s fleet file is missing, unreadable, not YAML, the wrong shape, carries an illegal id — or no longer names every existing `services/<id>/` (that refusal lists the exact ids as `missingServices`); the message names the file and line, and editing the file and re-running succeeds.\",\n \"seed-duplicate-service\":\n \"fleet.yaml declares one name twice — as two services, or as both a service and an external/subsystem; service ids, subsystem names and externals share one flat namespace, both declaration lines are named, and renaming one fixes it.\",\n \"seed-unknown-subsystem\":\n \"A service's `subsystem:` in fleet.yaml names nothing `subsystems:` declares — the message carries a did-you-mean over the names the file really declares; add the subsystem or fix the spelling, then re-run.\",\n \"seed-landscape-edited\":\n \"architecture/landscape.likec4 carries hand edits (the line-1 stamp's digest no longer matches) or was authored some other way, which includes anything written ABOVE the scaffold's stub — `loam seed` never overwrites human work and wrote nothing. Seed runs once, before any operation is drawn: fleet.yaml cannot carry `metadata { op }`, publishes or consumes, so once the map holds them it grows without seed — `loam adopt --service <id>` for a new service, a feature's C4 delta for everything else. Folding the edits into fleet.yaml and deleting the file works only when every edit is a service, subsystem or plain call fleet.yaml can say.\",\n internal:\n \"An unexpected throw — the one refusal with no stable meaning; it exists so a `--json` consumer still receives an envelope instead of a stack trace, and a repeatable `internal` is a loam defect worth reporting.\",\n} as const satisfies Record<ErrorCode, string>;\n"]}
|
|
@@ -16,16 +16,22 @@
|
|
|
16
16
|
* with them, and `vouch`'s pin went with the text rather than being reworded
|
|
17
17
|
* to something still in the file — the pairing is with whatever loam SHIPS as
|
|
18
18
|
* the teaching, not with one delivery of it.
|
|
19
|
+
*
|
|
20
|
+
* The converse failure is a source that ships NOWHERE, and it happened: once
|
|
21
|
+
* AGENTS.md became the one ORIENTATION literal (../agent/agents-md.ts), the old
|
|
22
|
+
* section constants this file still imported — the long cycle, the layout
|
|
23
|
+
* opening, the binding rule — were assembled into nothing, so the pins on them
|
|
24
|
+
* guarded prose no reader could see and the drift test passed vacuously. Those
|
|
25
|
+
* sources were deleted with the constants; a pin now names a page the binary
|
|
26
|
+
* prints or the AGENTS.md it writes, never a constant that merely compiles.
|
|
19
27
|
*/
|
|
20
|
-
import {
|
|
21
|
-
import { CYCLE } from "../agent/agents-md/cycle.js";
|
|
28
|
+
import { AGENTS_MD } from "../agent/agents-md.js";
|
|
22
29
|
import { REFUSALS } from "../agent/agents-md/refusals.js";
|
|
23
|
-
import { SPINE } from "../agent/agents-md/spine.js";
|
|
24
30
|
import { LOAM_AUTHORING } from "../agent/workflows/reference/authoring.js";
|
|
25
31
|
import { LOAM_DONE_CHECK } from "../agent/workflows/reference/done-check.js";
|
|
26
32
|
import { LOAM_SPINE } from "../agent/workflows/reference/spine.js";
|
|
27
33
|
/**
|
|
28
|
-
* The
|
|
34
|
+
* The shipped texts the pins point at, for the drift test and for anyone
|
|
29
35
|
* auditing a pairing.
|
|
30
36
|
*
|
|
31
37
|
* `REFUSALS` is still listed and still pinned against, and it is no longer a
|
|
@@ -34,11 +40,9 @@ import { LOAM_SPINE } from "../agent/workflows/reference/spine.js";
|
|
|
34
40
|
* delivery did.
|
|
35
41
|
*/
|
|
36
42
|
export const PIN_SOURCE_TEXT = {
|
|
37
|
-
|
|
43
|
+
AGENTS_MD,
|
|
38
44
|
SPINE_PAGE: LOAM_SPINE.body,
|
|
39
45
|
REFUSALS,
|
|
40
|
-
CYCLE,
|
|
41
|
-
ARTIFACTS,
|
|
42
46
|
AUTHORING: LOAM_AUTHORING.body,
|
|
43
47
|
DONE_CHECK: LOAM_DONE_CHECK.body,
|
|
44
48
|
};
|
|
@@ -104,8 +108,13 @@ export const TERMS = [
|
|
|
104
108
|
"`loam archive` folds the delta into the living state. The `delta.*` findings grade that algebra — whether the " +
|
|
105
109
|
"diff still applies to the living document it claims to change.",
|
|
106
110
|
pins: [
|
|
107
|
-
|
|
108
|
-
|
|
111
|
+
// Both used to pin the long layout opening, which stopped shipping when
|
|
112
|
+
// AGENTS.md was condensed; ORIENTATION's "What is where" teaches the same
|
|
113
|
+
// two facts in its own words. Re-paired on the clauses the two texts
|
|
114
|
+
// already share rather than by rewording either side, so `loam explain
|
|
115
|
+
// delta` prints exactly what it printed before.
|
|
116
|
+
{ source: "AGENTS_MD", phrase: "the complete current state" },
|
|
117
|
+
{ source: "AGENTS_MD", phrase: "reviewed as a diff" },
|
|
109
118
|
],
|
|
110
119
|
},
|
|
111
120
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terms.js","sourceRoot":"","sources":["../../../src/core/explain/terms.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The concept terms `loam explain` answers — the vocabulary wall an agent hits\n * in its first minute, before any docs repo exists to read.\n *\n * Each paragraph is authored HERE, but it is not free to drift: every entry\n * carries pin phrases lifted VERBATIM from the section that teaches the\n * concept, and test/explain.test.ts asserts each phrase appears both in the\n * paragraph and in its named source constant. Rewording that prose therefore\n * breaks the pairing loudly — the same discipline the compiler applies to\n * refusals.ts, done with a test because prose has no type. A pin phrase is\n * kept to one source LINE, because the sections wrap at ~80 columns and a\n * phrase spanning a wrap would never match.\n *\n * A source is no longer always an agents-md section. When the reference pages\n * were split out of the scaffolded AGENTS.md, the frontmatter teaching went\n * with them, and `vouch`'s pin went with the text rather than being reworded\n * to something still in the file — the pairing is with whatever loam SHIPS as\n * the teaching, not with one delivery of it.\n */\nimport { ARTIFACTS } from \"../agent/agents-md/artifacts.js\";\nimport { CYCLE } from \"../agent/agents-md/cycle.js\";\nimport { REFUSALS } from \"../agent/agents-md/refusals.js\";\nimport { SPINE } from \"../agent/agents-md/spine.js\";\nimport { LOAM_AUTHORING } from \"../agent/workflows/reference/authoring.js\";\nimport { LOAM_DONE_CHECK } from \"../agent/workflows/reference/done-check.js\";\nimport { LOAM_SPINE } from \"../agent/workflows/reference/spine.js\";\n\nexport type PinSource =\n | \"SPINE\"\n | \"SPINE_PAGE\"\n | \"REFUSALS\"\n | \"CYCLE\"\n | \"ARTIFACTS\"\n | \"AUTHORING\"\n | \"DONE_CHECK\";\n\n/**\n * The section constants the pins point at, for the drift test and for anyone\n * auditing a pairing.\n *\n * `REFUSALS` is still listed and still pinned against, and it is no longer a\n * section of AGENTS.md — it is the refusal half of the `loam-codes` page. The\n * constant is what a pin names, and the constant did not move; only its\n * delivery did.\n */\nexport const PIN_SOURCE_TEXT: Record<PinSource, string> = {\n SPINE,\n SPINE_PAGE: LOAM_SPINE.body,\n REFUSALS,\n CYCLE,\n ARTIFACTS,\n AUTHORING: LOAM_AUTHORING.body,\n DONE_CHECK: LOAM_DONE_CHECK.body,\n};\n\nexport interface TermPin {\n readonly source: PinSource;\n /** A verbatim single-line substring of both the paragraph and the source section. */\n readonly phrase: string;\n}\n\nexport interface TermEntry {\n readonly term: string;\n readonly aliases: readonly string[];\n /** The explanation. Its FIRST sentence doubles as the no-argument listing's summary. */\n readonly paragraph: string;\n readonly pins: readonly TermPin[];\n}\n\nexport const TERMS: readonly TermEntry[] = [\n {\n term: \"vouch\",\n aliases: [\"vouched\", \"vouching\"],\n paragraph:\n \"A vouch is the human promotion of a living document from draft to verified. \" +\n \"Promoting draft to verified is their call, not yours: a person runs `loam vouch --service <id>` in the service's own repo, \" +\n \"and the stamp records the date, who vouched (from git), and digests of both the source files and the document body — \" +\n \"which is what lets a later `loam validate` report `sources.stale` and `content.stale` when the code or the words move. \" +\n \"**`loam vouch` is not yours to run**, and it is built so that it cannot be. It refuses unattended runs (`vouch-unattended`), \" +\n \"records a no as `vouch-declined`, and refuses to stamp when git can name nobody (`vouch-unattributable`); \" +\n \"when your work leaves a document ready, hand back and say a vouch is owed.\",\n pins: [\n // Both phrases left AGENTS.md with the frontmatter teaching and are now\n // in `loam instructions loam-authoring`. Repaired by following the text,\n // not by rewording the paragraph to something still in the file: the\n // pairing exists so this paragraph and the teaching cannot drift, and\n // re-pinning to a different sentence would have quietly ended it.\n { source: \"AUTHORING\", phrase: \"Promoting draft to verified is their call, not yours\" },\n { source: \"AUTHORING\", phrase: \"**`loam vouch` is not yours to run**, and it is built so that it cannot be.\" },\n ],\n },\n {\n term: \"attested\",\n aliases: [\"attest\", \"attestation\"],\n paragraph:\n \"Attested is the verdict one rung below verified on the done-check's ladder. \" +\n \"Verified means somebody says the code was built and showed evidence — and for scenario claims that evidence is a \" +\n \"test runner's report, answered mechanically. Without a runnable suite your word can still answer them \" +\n \"(`loam verify <FEAT> --record` alone), but the record says who answered, and a feature whose \" +\n \"scenario claims rest on an agent's word is **attested**, not verified. Nothing gates on the difference; \" +\n \"pass `--results <report>` the moment a suite runs and the verdict moves on its own.\",\n pins: [\n { source: \"REFUSALS\", phrase: \"somebody says the code was built and showed evidence\" },\n // Left the cycle with the done-check teaching; repaired by following the\n // text, as `vouch`'s two were.\n { source: \"DONE_CHECK\", phrase: \"scenario claims rest on an agent's word is **attested**, not verified\" },\n ],\n },\n {\n term: \"spine\",\n aliases: [],\n paragraph:\n \"The spine is a family of exact joins, not one magic id. Its ids are the feature tag (`#FEAT-101`), the service \" +\n \"binding (`metadata { service }`), the synchronous operationId, the asynchronous message name, `Covers:` \" +\n \"architecture coverage, `Requires:` permissions and `Capability:` realization. Three artifacts describe one synchronous call — \" +\n \"a C4 edge, a requirement's `Operations:` line, the provider's openapi.yaml — joined by the operationId, and that \" +\n \"join is what `loam validate` checks. Spell it identically in all three places. The `spine.*` findings are exactly \" +\n \"these joins failing to resolve, and a mismatch is a broken contract between services, not a style problem.\",\n pins: [\n { source: \"SPINE_PAGE\", phrase: \"The spine is a family of exact joins, not one magic id\" },\n { source: \"SPINE_PAGE\", phrase: \"Spell it identically in all three places.\" },\n ],\n },\n {\n term: \"delta\",\n aliases: [\"deltas\"],\n paragraph:\n \"A delta is a feature's change, stated against the living docs rather than in them. \" +\n \"The living spec.md is the complete current state; a feature's copy is a diff against it, reviewed as a diff, with \" +\n \"requirements grouped under `## ADDED`, `## MODIFIED` or `## REMOVED Requirements`; delta.likec4 carries the \" +\n \"architecture change with every changed element tagged `#<FEAT>` (untagged elements are context, not changes); \" +\n \"and the contract deltas are complete documents whose baseline pins mark what is merely quoted. \" +\n \"`loam archive` folds the delta into the living state. The `delta.*` findings grade that algebra — whether the \" +\n \"diff still applies to the living document it claims to change.\",\n pins: [\n { source: \"ARTIFACTS\", phrase: \"is a diff against it, reviewed as a diff\" },\n { source: \"ARTIFACTS\", phrase: \"`loam archive` folds the delta into the living state.\" },\n ],\n },\n {\n term: \"axis\",\n aliases: [\"axes\"],\n paragraph:\n \"An axis is one language a service is described in, and loam's checks are joins BETWEEN axes rather than opinions within one. \" +\n \"The three: architecture — a C4 edge names the operation it calls; behaviour — a requirement declares the \" +\n \"operations it governs; contract — the provider's `openapi.yaml` defines it (asyncapi.yaml is the same axis for \" +\n \"events, and arch.spec.md is the behaviour axis for architectural obligations). A finding code's prefix names the \" +\n \"axes that disagree — `spec-api.op-undefined` is the behaviour axis joined against the contract axis — and the fix \" +\n \"is whichever side is wrong about the world.\",\n pins: [\n { source: \"SPINE_PAGE\", phrase: \"architecture — a C4 edge names the operation it calls\" },\n { source: \"SPINE_PAGE\", phrase: \"behaviour — a requirement declares the operations it governs\" },\n { source: \"SPINE_PAGE\", phrase: \"contract — the provider's `openapi.yaml` defines it\" },\n ],\n },\n {\n term: \"baseline\",\n aliases: [\"based-on\", \"baselines\"],\n paragraph:\n \"A baseline is the pin tying a delta to the living version it was written against. It rides as `Based-On:` under a \" +\n \"MODIFIED/REMOVED requirement and `x-loam-based-on` on a contract surface — written by `loam rebase <FEAT>`, never by \" +\n \"hand. It exists because a MODIFIED requirement carries its FULL new text, not a diff, so the merge REPLACES the \" +\n \"living text wholesale; the pin is what lets archive tell an edit from a quote and refuse a stale one \" +\n \"(`delta.baseline-stale`, `openapi.baseline-stale`) instead of silently reverting work that landed in between. \" +\n `**Restamping is not resolving.** A pin claims \"I read this version\". ` +\n \"Re-read the living text and fold in what you still mean before you re-pin.\",\n pins: [\n // Without the sentence-initial \"A\": the paragraph embeds the clause\n // mid-sentence, and a pin is a verbatim substring of BOTH sides.\n { source: \"SPINE_PAGE\", phrase: \"MODIFIED requirement carries its FULL new text, not a diff\" },\n { source: \"SPINE_PAGE\", phrase: `**Restamping is not resolving.** A pin claims \"I read this version\".` },\n ],\n },\n];\n"]}
|
|
1
|
+
{"version":3,"file":"terms.js","sourceRoot":"","sources":["../../../src/core/explain/terms.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The concept terms `loam explain` answers — the vocabulary wall an agent hits\n * in its first minute, before any docs repo exists to read.\n *\n * Each paragraph is authored HERE, but it is not free to drift: every entry\n * carries pin phrases lifted VERBATIM from the section that teaches the\n * concept, and test/explain.test.ts asserts each phrase appears both in the\n * paragraph and in its named source constant. Rewording that prose therefore\n * breaks the pairing loudly — the same discipline the compiler applies to\n * refusals.ts, done with a test because prose has no type. A pin phrase is\n * kept to one source LINE, because the sections wrap at ~80 columns and a\n * phrase spanning a wrap would never match.\n *\n * A source is no longer always an agents-md section. When the reference pages\n * were split out of the scaffolded AGENTS.md, the frontmatter teaching went\n * with them, and `vouch`'s pin went with the text rather than being reworded\n * to something still in the file — the pairing is with whatever loam SHIPS as\n * the teaching, not with one delivery of it.\n *\n * The converse failure is a source that ships NOWHERE, and it happened: once\n * AGENTS.md became the one ORIENTATION literal (../agent/agents-md.ts), the old\n * section constants this file still imported — the long cycle, the layout\n * opening, the binding rule — were assembled into nothing, so the pins on them\n * guarded prose no reader could see and the drift test passed vacuously. Those\n * sources were deleted with the constants; a pin now names a page the binary\n * prints or the AGENTS.md it writes, never a constant that merely compiles.\n */\nimport { AGENTS_MD } from \"../agent/agents-md.js\";\nimport { REFUSALS } from \"../agent/agents-md/refusals.js\";\nimport { LOAM_AUTHORING } from \"../agent/workflows/reference/authoring.js\";\nimport { LOAM_DONE_CHECK } from \"../agent/workflows/reference/done-check.js\";\nimport { LOAM_SPINE } from \"../agent/workflows/reference/spine.js\";\n\nexport type PinSource = \"AGENTS_MD\" | \"SPINE_PAGE\" | \"REFUSALS\" | \"AUTHORING\" | \"DONE_CHECK\";\n\n/**\n * The shipped texts the pins point at, for the drift test and for anyone\n * auditing a pairing.\n *\n * `REFUSALS` is still listed and still pinned against, and it is no longer a\n * section of AGENTS.md — it is the refusal half of the `loam-codes` page. The\n * constant is what a pin names, and the constant did not move; only its\n * delivery did.\n */\nexport const PIN_SOURCE_TEXT: Record<PinSource, string> = {\n AGENTS_MD,\n SPINE_PAGE: LOAM_SPINE.body,\n REFUSALS,\n AUTHORING: LOAM_AUTHORING.body,\n DONE_CHECK: LOAM_DONE_CHECK.body,\n};\n\nexport interface TermPin {\n readonly source: PinSource;\n /** A verbatim single-line substring of both the paragraph and the source section. */\n readonly phrase: string;\n}\n\nexport interface TermEntry {\n readonly term: string;\n readonly aliases: readonly string[];\n /** The explanation. Its FIRST sentence doubles as the no-argument listing's summary. */\n readonly paragraph: string;\n readonly pins: readonly TermPin[];\n}\n\nexport const TERMS: readonly TermEntry[] = [\n {\n term: \"vouch\",\n aliases: [\"vouched\", \"vouching\"],\n paragraph:\n \"A vouch is the human promotion of a living document from draft to verified. \" +\n \"Promoting draft to verified is their call, not yours: a person runs `loam vouch --service <id>` in the service's own repo, \" +\n \"and the stamp records the date, who vouched (from git), and digests of both the source files and the document body — \" +\n \"which is what lets a later `loam validate` report `sources.stale` and `content.stale` when the code or the words move. \" +\n \"**`loam vouch` is not yours to run**, and it is built so that it cannot be. It refuses unattended runs (`vouch-unattended`), \" +\n \"records a no as `vouch-declined`, and refuses to stamp when git can name nobody (`vouch-unattributable`); \" +\n \"when your work leaves a document ready, hand back and say a vouch is owed.\",\n pins: [\n // Both phrases left AGENTS.md with the frontmatter teaching and are now\n // in `loam instructions loam-authoring`. Repaired by following the text,\n // not by rewording the paragraph to something still in the file: the\n // pairing exists so this paragraph and the teaching cannot drift, and\n // re-pinning to a different sentence would have quietly ended it.\n { source: \"AUTHORING\", phrase: \"Promoting draft to verified is their call, not yours\" },\n { source: \"AUTHORING\", phrase: \"**`loam vouch` is not yours to run**, and it is built so that it cannot be.\" },\n ],\n },\n {\n term: \"attested\",\n aliases: [\"attest\", \"attestation\"],\n paragraph:\n \"Attested is the verdict one rung below verified on the done-check's ladder. \" +\n \"Verified means somebody says the code was built and showed evidence — and for scenario claims that evidence is a \" +\n \"test runner's report, answered mechanically. Without a runnable suite your word can still answer them \" +\n \"(`loam verify <FEAT> --record` alone), but the record says who answered, and a feature whose \" +\n \"scenario claims rest on an agent's word is **attested**, not verified. Nothing gates on the difference; \" +\n \"pass `--results <report>` the moment a suite runs and the verdict moves on its own.\",\n pins: [\n { source: \"REFUSALS\", phrase: \"somebody says the code was built and showed evidence\" },\n // Left the cycle with the done-check teaching; repaired by following the\n // text, as `vouch`'s two were.\n { source: \"DONE_CHECK\", phrase: \"scenario claims rest on an agent's word is **attested**, not verified\" },\n ],\n },\n {\n term: \"spine\",\n aliases: [],\n paragraph:\n \"The spine is a family of exact joins, not one magic id. Its ids are the feature tag (`#FEAT-101`), the service \" +\n \"binding (`metadata { service }`), the synchronous operationId, the asynchronous message name, `Covers:` \" +\n \"architecture coverage, `Requires:` permissions and `Capability:` realization. Three artifacts describe one synchronous call — \" +\n \"a C4 edge, a requirement's `Operations:` line, the provider's openapi.yaml — joined by the operationId, and that \" +\n \"join is what `loam validate` checks. Spell it identically in all three places. The `spine.*` findings are exactly \" +\n \"these joins failing to resolve, and a mismatch is a broken contract between services, not a style problem.\",\n pins: [\n { source: \"SPINE_PAGE\", phrase: \"The spine is a family of exact joins, not one magic id\" },\n { source: \"SPINE_PAGE\", phrase: \"Spell it identically in all three places.\" },\n ],\n },\n {\n term: \"delta\",\n aliases: [\"deltas\"],\n paragraph:\n \"A delta is a feature's change, stated against the living docs rather than in them. \" +\n \"The living spec.md is the complete current state; a feature's copy is a diff against it, reviewed as a diff, with \" +\n \"requirements grouped under `## ADDED`, `## MODIFIED` or `## REMOVED Requirements`; delta.likec4 carries the \" +\n \"architecture change with every changed element tagged `#<FEAT>` (untagged elements are context, not changes); \" +\n \"and the contract deltas are complete documents whose baseline pins mark what is merely quoted. \" +\n \"`loam archive` folds the delta into the living state. The `delta.*` findings grade that algebra — whether the \" +\n \"diff still applies to the living document it claims to change.\",\n pins: [\n // Both used to pin the long layout opening, which stopped shipping when\n // AGENTS.md was condensed; ORIENTATION's \"What is where\" teaches the same\n // two facts in its own words. Re-paired on the clauses the two texts\n // already share rather than by rewording either side, so `loam explain\n // delta` prints exactly what it printed before.\n { source: \"AGENTS_MD\", phrase: \"the complete current state\" },\n { source: \"AGENTS_MD\", phrase: \"reviewed as a diff\" },\n ],\n },\n {\n term: \"axis\",\n aliases: [\"axes\"],\n paragraph:\n \"An axis is one language a service is described in, and loam's checks are joins BETWEEN axes rather than opinions within one. \" +\n \"The three: architecture — a C4 edge names the operation it calls; behaviour — a requirement declares the \" +\n \"operations it governs; contract — the provider's `openapi.yaml` defines it (asyncapi.yaml is the same axis for \" +\n \"events, and arch.spec.md is the behaviour axis for architectural obligations). A finding code's prefix names the \" +\n \"axes that disagree — `spec-api.op-undefined` is the behaviour axis joined against the contract axis — and the fix \" +\n \"is whichever side is wrong about the world.\",\n pins: [\n { source: \"SPINE_PAGE\", phrase: \"architecture — a C4 edge names the operation it calls\" },\n { source: \"SPINE_PAGE\", phrase: \"behaviour — a requirement declares the operations it governs\" },\n { source: \"SPINE_PAGE\", phrase: \"contract — the provider's `openapi.yaml` defines it\" },\n ],\n },\n {\n term: \"baseline\",\n aliases: [\"based-on\", \"baselines\"],\n paragraph:\n \"A baseline is the pin tying a delta to the living version it was written against. It rides as `Based-On:` under a \" +\n \"MODIFIED/REMOVED requirement and `x-loam-based-on` on a contract surface — written by `loam rebase <FEAT>`, never by \" +\n \"hand. It exists because a MODIFIED requirement carries its FULL new text, not a diff, so the merge REPLACES the \" +\n \"living text wholesale; the pin is what lets archive tell an edit from a quote and refuse a stale one \" +\n \"(`delta.baseline-stale`, `openapi.baseline-stale`) instead of silently reverting work that landed in between. \" +\n `**Restamping is not resolving.** A pin claims \"I read this version\". ` +\n \"Re-read the living text and fold in what you still mean before you re-pin.\",\n pins: [\n // Without the sentence-initial \"A\": the paragraph embeds the clause\n // mid-sentence, and a pin is a verbatim substring of BOTH sides.\n { source: \"SPINE_PAGE\", phrase: \"MODIFIED requirement carries its FULL new text, not a diff\" },\n { source: \"SPINE_PAGE\", phrase: `**Restamping is not resolving.** A pin claims \"I read this version\".` },\n ],\n },\n];\n"]}
|
|
@@ -28,9 +28,8 @@
|
|
|
28
28
|
* the difference between a habit and a thing people skip.
|
|
29
29
|
*/
|
|
30
30
|
import { existsSync } from "node:fs";
|
|
31
|
-
import { relative } from "node:path";
|
|
32
31
|
import { FleetContext } from "../fleet-context.js";
|
|
33
|
-
import {} from "../c4/likec4.js";
|
|
32
|
+
import { brokenDocumentPaths } from "../c4/likec4.js";
|
|
34
33
|
import { serviceResolver } from "../c4/resolve/service.js";
|
|
35
34
|
import {} from "../vocabulary/maturity.js";
|
|
36
35
|
import { capabilityRollup, unresolvedCapabilities } from "../capabilities/rollup.js";
|
|
@@ -197,11 +196,7 @@ export async function explore(req) {
|
|
|
197
196
|
landscape: {
|
|
198
197
|
present,
|
|
199
198
|
parses,
|
|
200
|
-
broken: land === null
|
|
201
|
-
? []
|
|
202
|
-
: [...new Set(land.errors.map((e) => e.sourceFsPath).filter((p) => p !== undefined))]
|
|
203
|
-
.map((abs) => relative(docsDir, abs).split(/[\\/]/).join("/"))
|
|
204
|
-
.sort(),
|
|
199
|
+
broken: land === null ? [] : brokenDocumentPaths(docsDir, land.errors),
|
|
205
200
|
},
|
|
206
201
|
scaffold: newCommand(featureId, seeds, known),
|
|
207
202
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explore.js","sourceRoot":"","sources":["../../../src/core/explore/explore.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The blast radius of a change nobody has written down yet.\n *\n * Everything else in loam answers a question about documents that exist. This\n * module answers the one that comes BEFORE the first document: which services\n * does this feature actually touch? On a fleet of a hundred that call is the\n * hardest one in the cycle and the only one made with no tool in hand —\n * `loam new FEAT-101 --touches a --touches b` takes the answer as an argument\n * and scaffolds whatever it was told. A `--touches` list short by one service\n * is not caught by anything: the feature validates, archives, and ships with a\n * consumer nobody updated.\n *\n * So this states the work the same way `brief/brief.ts` does. It reads the fleet map\n * and the living contracts, reports the ring of services around the seeds, the\n * features already in flight over the same ground, and how far each service's\n * documentation has got — and stops. Which of those neighbours the feature\n * really touches is a judgement about intent, and loam does not make those.\n *\n * \"The fleet map\" here is the `architecture/` PROJECT — the landscape plus every\n * other `.likec4` under it, minus the generated views file — and not the\n * landscape FILE. See the read below for the disagreement that reading one file\n * caused.\n *\n * It is parsed ONCE for the whole exploration. Per-service reads of it exist\n * (`brief/landscape.ts`'s `landscapeContext`) and are correct for one service;\n * calling one of those per seed is how `validate --all` came to cost 13 seconds\n * on 120 services, and this command sits in front of authoring, where that is\n * the difference between a habit and a thing people skip.\n */\nimport { existsSync } from \"node:fs\";\nimport { relative } from \"node:path\";\nimport { FleetContext } from \"../fleet-context.js\";\nimport { type Rel } from \"../c4/likec4.js\";\nimport { serviceResolver } from \"../c4/resolve/service.js\";\nimport { type Maturity } from \"../vocabulary/maturity.js\";\nimport { capabilityRollup, unresolvedCapabilities } from \"../capabilities/rollup.js\";\nimport { compareIds, nearestIds, type ServiceEntry } from \"../repo/entries.js\";\nimport { landscapePath } from \"../repo/paths.js\";\nimport { readUseCases } from \"../usecases/fleet.js\";\nimport { servicesInFlowsClaiming } from \"../usecases/capability.js\";\nimport { describe, newCommand, operationOwner } from \"./describe.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\n\n/** One end of a call the fleet map already draws. */\nexport interface ExploreEdge {\n /** The service at the other end. */\n service: string;\n /** The operationId the call uses, or null for an edge nobody tied to one. */\n op: string | null;\n title: string | null;\n}\n\n/**\n * Why a service is in the answer. Seeds were asked for; the rest were derived.\n *\n * A neighbour on both sides of a seed reports `calls-seed` — see the overlap\n * rule in `explore`. The field is a hint about where to look, not a complete\n * description of the edges; `inbound`/`outbound` are that.\n */\nexport type ExploreReason = \"seed\" | \"calls-seed\" | \"called-by-seed\";\n\nexport interface ExploreService {\n id: string;\n reason: ExploreReason;\n /** Whether `services/<id>/` exists at all. */\n known: boolean;\n /**\n * How far this service's documentation has got, or null when it does not\n * exist yet. A `--touches` naming a service at `empty` or `partial` is a\n * different job from one naming a vouched service, and the difference decides\n * whether the feature starts with `loam adopt`.\n */\n maturity: Maturity | null;\n /** What stands between it and `vouched` — `maturityGaps`, so it matches `list --needs-work`. */\n missing: string[];\n /** Whether anything in the fleet map resolves to it. */\n modelled: boolean;\n /** operationIds its living contract exposes today, `x-loam-remove` markers excluded. */\n operations: string[];\n /**\n * Whether that contract could be read at all, beside the `error` the parser\n * gave when it could not.\n *\n * It rides next to `operations` rather than inside it for the reason `delta`\n * carries the same pair: an unreadable contract yields an EMPTY operation\n * list, indistinguishable from a service with no endpoints — and this is the\n * field the workflow tells an agent to read before deciding whether an\n * operation it is about to add already exists. Answering `[]` over a YAML\n * error is how a MODIFIED requirement gets authored as ADDED.\n */\n openapi: { unreadable: boolean; error?: string };\n inbound: ExploreEdge[];\n outbound: ExploreEdge[];\n}\n\n/** An active feature already working over ground the exploration covers. */\nexport interface ExploreOverlap {\n feature: string;\n /** The explored services it already carries a delta for. */\n services: string[];\n}\n\nexport interface Exploration {\n /** The seed ids, as asked for. */\n seeds: string[];\n /**\n * Seeds that name no `services/<id>/`, each with the closest real ids. A seed\n * may legitimately be a service the feature INTRODUCES, so this is reported\n * rather than refused — but a typo produces exactly the same shape, and the\n * near-miss list is what tells the two apart.\n */\n unknown: Array<{ id: string; nearest: string[] }>;\n /** Operation seeds that resolved to no service's living contract. */\n unresolvedOperations: string[];\n /**\n * Capability seeds that seeded nothing: not declared in\n * architecture/capabilities.yaml (the file may not exist at all — explore\n * refuses nothing, every miss is a field), or declared and realized by no\n * living requirement. One list on purpose; splitting the two miss kinds\n * waits for a consumer to ask.\n */\n unresolvedCapabilities: string[];\n /** Seeds first, then the ring, each in id order. */\n services: ExploreService[];\n /** Ids the ring added that were not asked for — the candidates to weigh. */\n neighbours: string[];\n overlaps: ExploreOverlap[];\n /**\n * `broken` is the `architecture/` documents that failed, docs-relative POSIX,\n * deduped and sorted — `[]` while `parses` is true. `parses` answers for the\n * PROJECT, so the broken document is very often a SIBLING beside a landscape\n * that reads perfectly, and naming the landscape file was a claim about bytes\n * loam read fine (verification 2026-09-04). Spelled as `landscape.invalid`\n * spells it, so the two surfaces name one file one way.\n */\n landscape: { present: boolean; parses: boolean; broken: string[] };\n /**\n * The literal `loam new` line the seeds imply — seeds only. The ring is\n * deliberately NOT folded in: this module's whole claim is that it does not\n * know which neighbours the feature touches, and a command line that quietly\n * included them would make the guess on the reader's behalf and look derived\n * while doing it.\n *\n * Named for what it does rather than `command`, which is the envelope's key\n * for the command that RAN. The rename is not cosmetic: `emitJson` spreads\n * the payload LAST, so a payload field called `command` would silently\n * OVERRIDE the envelope's — `command` would come back as\n * `\"loam new FEAT-000 …\"`, and every consumer branching on\n * `command === \"explore\"` (the same key `status`, `doctor`, `dependencies`,\n * `archive` and `unarchive` emit) would quietly stop matching, with tsc and\n * the linter green throughout.\n */\n scaffold: string;\n}\n\nexport interface ExploreRequest {\n docsDir: DocsDir;\n /** Service ids to explore around. Checked at the command boundary. */\n services: ServiceEntry[\"id\"][];\n /** operationIds to explore around; each resolves to the service that defines it. */\n operations: string[];\n /** Declared capability ids to explore around; each seeds its realizing services. */\n capabilities: string[];\n /** Placeholder feature id for the suggested command line. */\n featureId: string;\n context?: FleetContext;\n}\n\n/**\n * Read the fleet around a proposed change. Reads only; writes nothing, and\n * refuses nothing — every miss is reported as a field.\n */\nexport async function explore(req: ExploreRequest): Promise<Exploration> {\n const { docsDir, featureId } = req;\n const context = req.context ?? new FleetContext();\n const entries = await context.listServices(docsDir);\n const byId = new Map<string, ServiceEntry>(entries.map((e) => [e.id, e]));\n const known: ReadonlySet<string> = new Set(byId.keys());\n\n // The `architecture/` PROJECT, never `architecture/landscape.likec4` alone.\n // The map is a project — the landscape merged with every use case, palette and\n // second `model { }` block beside it — and reading one file of it made this\n // command answer differently from `loam adopt` and `loam context` about the\n // same tree (reproduced: with a broken `architecture/palette.likec4` beside a\n // landscape that parses, `context checkout-web --json` reported\n // `landscape.parses: false` while `explore checkout-web --json` reported\n // `parses: true` and went on to describe every edge). `core/pack/living.ts`\n // named this module as the last reader that disagreed. Whichever answer is\n // right, an agent handed both has no way to tell — and the renderer's answer\n // is the project's.\n //\n // `present` stays a fact about the FILE, because that file is the WRITE target:\n // `loam new`'s scaffold and every brief ask for edits to\n // `architecture/landscape.likec4` by name, and \"the project is empty\" is not\n // the same instruction as \"there is no map to edit\".\n const present = existsSync(landscapePath(docsDir));\n const land = present ? await context.architecture(docsDir) : null;\n const parses = land !== null && land.errors.length === 0;\n const elements = parses ? land.elements : [];\n const relationships: Rel[] = parses ? land.relationships : [];\n // One resolver for the whole scan, built with the real service ids so an edge\n // drawn into a modelled container (`paymentService.api`) counts for the\n // service that owns it — the same resolution `list`, `show` and `validate`\n // use, so no two commands can disagree about who calls whom.\n const svcOf = serviceResolver(elements, known);\n\n // Operation seeds resolve through the living contracts, not the map: the map\n // says who CALLS an operation, and the question here is who DEFINES it.\n const opSeeds: ServiceEntry[\"id\"][] = [];\n const unresolvedOperations: string[] = [];\n for (const op of req.operations) {\n const owner = await operationOwner(entries, op, context);\n if (owner === null) unresolvedOperations.push(op);\n else opSeeds.push(owner);\n }\n\n // Capability seeds resolve through the vocabulary and the fleet rollup —\n // one rollup pass for ALL requested ids, through this exploration's shared\n // context cache, never a fresh walk per capability. A realizing service is\n // by construction an enumerated one, so every seed it adds is `known`.\n //\n // And through the fleet's USE CASES, which answer the same question off a\n // different document. The rollup finds services whose living requirements\n // carry a `Capability:` line; a `dynamic view` tagged `#cap-<slug>` finds the\n // services the flow actually runs through — including ones whose spec.md has\n // never named the capability, which on a brownfield fleet is most of them.\n // The two are unioned rather than ranked because neither is a subset of the\n // other: a service can realize a capability without appearing in its drawn\n // flow, and a flow can pass through a service that has written nothing down.\n //\n // The scan gates its own load — a fleet whose documents mention no reserved\n // tag never starts LikeC4 for it — and this whole block is behind\n // `--capability` being passed at all. What it is no longer behind is the\n // project itself: the read above loads `architecture/` for every exploration,\n // so a `--capability` run pays for a SECOND parse of the same documents\n // (`readUseCases` takes a `DocsDir`, not this invocation's memo). Accepted\n // rather than unnoticed: the alternative is a seam that hands the scan a\n // pre-loaded project, which is a change to a module five callers share, and\n // the cost lands only on the flag that already opts into the fleet rollup.\n const capSeeds: ServiceEntry[\"id\"][] = [];\n let unresolvedCaps: string[] = [];\n if (req.capabilities.length > 0) {\n const vocab = await context.capabilities(docsDir);\n const rows = await capabilityRollup({ services: entries, vocab, read: (p) => context.readRequirements(p) });\n const wanted = new Set(req.capabilities);\n const realizing = new Set(rows.filter((r) => wanted.has(r.id)).flatMap((r) => r.services));\n const scan = await readUseCases({ docsDir, known });\n for (const id of servicesInFlowsClaiming(scan, req.capabilities)) realizing.add(id);\n capSeeds.push(...entries.filter((e) => realizing.has(e.id)).map((e) => e.id));\n // `unresolvedCapabilities` is unchanged on purpose: it grades the\n // VOCABULARY — declared or not, realized by a living requirement or not —\n // and a capability drawn in a flow but realized by nobody is still a\n // capability nothing implements. Letting a tag silence that would hide the\n // gap the field exists to name.\n unresolvedCaps = unresolvedCapabilities(rows, req.capabilities);\n }\n\n const seeds = [...new Set([...req.services, ...opSeeds, ...capSeeds])];\n const unknown = seeds\n .filter((id) => !known.has(id))\n .map((id) => ({ id, nearest: nearestIds(id, [...known]) }));\n\n // The ring: one hop, both directions. A seed that is not modelled contributes\n // nothing here and that is the honest answer — an invisible service has no\n // neighbours anyone can derive, which is what `landscape.service-unmodelled`\n // is about.\n //\n // The two directions are collected separately rather than written into one\n // map as the loop goes, because a neighbour can be BOTH — it calls a seed and\n // the seed calls it — and a single-map version answers whichever edge the\n // parser happened to yield last. That is a field whose value depends on the\n // order lines appear in a `.likec4` file, which is the kind of answer that\n // reads as derived and is not.\n const seedSet = new Set<string>(seeds);\n const callsSeed = new Set<string>();\n const calledBySeed = new Set<string>();\n for (const r of relationships) {\n const from = svcOf(r.source);\n const to = svcOf(r.target);\n if (seedSet.has(from) && !seedSet.has(to)) calledBySeed.add(to);\n if (seedSet.has(to) && !seedSet.has(from)) callsSeed.add(from);\n }\n\n // `calls-seed` wins the overlap, deterministically. Of the two directions it\n // is the one that more often has to be touched: a consumer depends on the\n // seed's contract, so a change to that contract is what breaks it, while a\n // provider the seed merely calls is usually unaffected by the seed changing.\n const ring = new Map<string, ExploreReason>([\n ...[...calledBySeed].map((id) => [id, \"called-by-seed\" as const] as const),\n ...[...callsSeed].map((id) => [id, \"calls-seed\" as const] as const),\n ]);\n\n const ordered: Array<{ id: string; reason: ExploreReason }> = [\n ...[...seeds].sort(compareIds).map((id) => ({ id, reason: \"seed\" as const })),\n ...[...ring]\n .sort(([a], [b]) => compareIds(a, b))\n .map(([id, reason]) => ({ id, reason })),\n ];\n\n const services: ExploreService[] = [];\n for (const { id, reason } of ordered) {\n services.push(\n await describe({\n id,\n reason,\n entry: byId.get(id),\n relationships,\n svcOf,\n elements,\n parses,\n context,\n }),\n );\n }\n\n const covered = new Set(services.map((s) => s.id));\n const features = await context.listFeatures(docsDir);\n const overlaps: ExploreOverlap[] = features\n .map((f) => ({ feature: f.id, services: f.services.filter((s) => covered.has(s)) }))\n .filter((o) => o.services.length > 0)\n .sort((a, b) => compareIds(a.feature, b.feature));\n\n return {\n seeds,\n unknown,\n unresolvedOperations,\n unresolvedCapabilities: unresolvedCaps,\n services,\n neighbours: [...ring.keys()].sort(compareIds),\n overlaps,\n landscape: {\n present,\n parses,\n broken:\n land === null\n ? []\n : [...new Set(land.errors.map((e) => e.sourceFsPath).filter((p): p is string => p !== undefined))]\n .map((abs) => relative(docsDir, abs).split(/[\\\\/]/).join(\"/\"))\n .sort(),\n },\n scaffold: newCommand(featureId, seeds, known),\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"explore.js","sourceRoot":"","sources":["../../../src/core/explore/explore.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The blast radius of a change nobody has written down yet.\n *\n * Everything else in loam answers a question about documents that exist. This\n * module answers the one that comes BEFORE the first document: which services\n * does this feature actually touch? On a fleet of a hundred that call is the\n * hardest one in the cycle and the only one made with no tool in hand —\n * `loam new FEAT-101 --touches a --touches b` takes the answer as an argument\n * and scaffolds whatever it was told. A `--touches` list short by one service\n * is not caught by anything: the feature validates, archives, and ships with a\n * consumer nobody updated.\n *\n * So this states the work the same way `brief/brief.ts` does. It reads the fleet map\n * and the living contracts, reports the ring of services around the seeds, the\n * features already in flight over the same ground, and how far each service's\n * documentation has got — and stops. Which of those neighbours the feature\n * really touches is a judgement about intent, and loam does not make those.\n *\n * \"The fleet map\" here is the `architecture/` PROJECT — the landscape plus every\n * other `.likec4` under it, minus the generated views file — and not the\n * landscape FILE. See the read below for the disagreement that reading one file\n * caused.\n *\n * It is parsed ONCE for the whole exploration. Per-service reads of it exist\n * (`brief/landscape.ts`'s `landscapeContext`) and are correct for one service;\n * calling one of those per seed is how `validate --all` came to cost 13 seconds\n * on 120 services, and this command sits in front of authoring, where that is\n * the difference between a habit and a thing people skip.\n */\nimport { existsSync } from \"node:fs\";\nimport { FleetContext } from \"../fleet-context.js\";\nimport { brokenDocumentPaths, type Rel } from \"../c4/likec4.js\";\nimport { serviceResolver } from \"../c4/resolve/service.js\";\nimport { type Maturity } from \"../vocabulary/maturity.js\";\nimport { capabilityRollup, unresolvedCapabilities } from \"../capabilities/rollup.js\";\nimport { compareIds, nearestIds, type ServiceEntry } from \"../repo/entries.js\";\nimport { landscapePath } from \"../repo/paths.js\";\nimport { readUseCases } from \"../usecases/fleet.js\";\nimport { servicesInFlowsClaiming } from \"../usecases/capability.js\";\nimport { describe, newCommand, operationOwner } from \"./describe.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\n\n/** One end of a call the fleet map already draws. */\nexport interface ExploreEdge {\n /** The service at the other end. */\n service: string;\n /** The operationId the call uses, or null for an edge nobody tied to one. */\n op: string | null;\n title: string | null;\n}\n\n/**\n * Why a service is in the answer. Seeds were asked for; the rest were derived.\n *\n * A neighbour on both sides of a seed reports `calls-seed` — see the overlap\n * rule in `explore`. The field is a hint about where to look, not a complete\n * description of the edges; `inbound`/`outbound` are that.\n */\nexport type ExploreReason = \"seed\" | \"calls-seed\" | \"called-by-seed\";\n\nexport interface ExploreService {\n id: string;\n reason: ExploreReason;\n /** Whether `services/<id>/` exists at all. */\n known: boolean;\n /**\n * How far this service's documentation has got, or null when it does not\n * exist yet. A `--touches` naming a service at `empty` or `partial` is a\n * different job from one naming a vouched service, and the difference decides\n * whether the feature starts with `loam adopt`.\n */\n maturity: Maturity | null;\n /** What stands between it and `vouched` — `maturityGaps`, so it matches `list --needs-work`. */\n missing: string[];\n /** Whether anything in the fleet map resolves to it. */\n modelled: boolean;\n /** operationIds its living contract exposes today, `x-loam-remove` markers excluded. */\n operations: string[];\n /**\n * Whether that contract could be read at all, beside the `error` the parser\n * gave when it could not.\n *\n * It rides next to `operations` rather than inside it for the reason `delta`\n * carries the same pair: an unreadable contract yields an EMPTY operation\n * list, indistinguishable from a service with no endpoints — and this is the\n * field the workflow tells an agent to read before deciding whether an\n * operation it is about to add already exists. Answering `[]` over a YAML\n * error is how a MODIFIED requirement gets authored as ADDED.\n */\n openapi: { unreadable: boolean; error?: string };\n inbound: ExploreEdge[];\n outbound: ExploreEdge[];\n}\n\n/** An active feature already working over ground the exploration covers. */\nexport interface ExploreOverlap {\n feature: string;\n /** The explored services it already carries a delta for. */\n services: string[];\n}\n\nexport interface Exploration {\n /** The seed ids, as asked for. */\n seeds: string[];\n /**\n * Seeds that name no `services/<id>/`, each with the closest real ids. A seed\n * may legitimately be a service the feature INTRODUCES, so this is reported\n * rather than refused — but a typo produces exactly the same shape, and the\n * near-miss list is what tells the two apart.\n */\n unknown: Array<{ id: string; nearest: string[] }>;\n /** Operation seeds that resolved to no service's living contract. */\n unresolvedOperations: string[];\n /**\n * Capability seeds that seeded nothing: not declared in\n * architecture/capabilities.yaml (the file may not exist at all — explore\n * refuses nothing, every miss is a field), or declared and realized by no\n * living requirement. One list on purpose; splitting the two miss kinds\n * waits for a consumer to ask.\n */\n unresolvedCapabilities: string[];\n /** Seeds first, then the ring, each in id order. */\n services: ExploreService[];\n /** Ids the ring added that were not asked for — the candidates to weigh. */\n neighbours: string[];\n overlaps: ExploreOverlap[];\n /**\n * `broken` is the `architecture/` documents that failed, docs-relative POSIX,\n * deduped and sorted — `[]` while `parses` is true. `parses` answers for the\n * PROJECT, so the broken document is very often a SIBLING beside a landscape\n * that reads perfectly, and naming the landscape file was a claim about bytes\n * loam read fine (verification 2026-09-04). Spelled as `landscape.invalid`\n * spells it (both through `c4/likec4.ts`'s `brokenDocumentPaths`), so the\n * two surfaces name one file one way.\n */\n landscape: { present: boolean; parses: boolean; broken: string[] };\n /**\n * The literal `loam new` line the seeds imply — seeds only. The ring is\n * deliberately NOT folded in: this module's whole claim is that it does not\n * know which neighbours the feature touches, and a command line that quietly\n * included them would make the guess on the reader's behalf and look derived\n * while doing it.\n *\n * Named for what it does rather than `command`, which is the envelope's key\n * for the command that RAN. The rename is not cosmetic: `emitJson` spreads\n * the payload LAST, so a payload field called `command` would silently\n * OVERRIDE the envelope's — `command` would come back as\n * `\"loam new FEAT-000 …\"`, and every consumer branching on\n * `command === \"explore\"` (the same key `status`, `doctor`, `dependencies`,\n * `archive` and `unarchive` emit) would quietly stop matching, with tsc and\n * the linter green throughout.\n */\n scaffold: string;\n}\n\nexport interface ExploreRequest {\n docsDir: DocsDir;\n /** Service ids to explore around. Checked at the command boundary. */\n services: ServiceEntry[\"id\"][];\n /** operationIds to explore around; each resolves to the service that defines it. */\n operations: string[];\n /** Declared capability ids to explore around; each seeds its realizing services. */\n capabilities: string[];\n /** Placeholder feature id for the suggested command line. */\n featureId: string;\n context?: FleetContext;\n}\n\n/**\n * Read the fleet around a proposed change. Reads only; writes nothing, and\n * refuses nothing — every miss is reported as a field.\n */\nexport async function explore(req: ExploreRequest): Promise<Exploration> {\n const { docsDir, featureId } = req;\n const context = req.context ?? new FleetContext();\n const entries = await context.listServices(docsDir);\n const byId = new Map<string, ServiceEntry>(entries.map((e) => [e.id, e]));\n const known: ReadonlySet<string> = new Set(byId.keys());\n\n // The `architecture/` PROJECT, never `architecture/landscape.likec4` alone.\n // The map is a project — the landscape merged with every use case, palette and\n // second `model { }` block beside it — and reading one file of it made this\n // command answer differently from `loam adopt` and `loam context` about the\n // same tree (reproduced: with a broken `architecture/palette.likec4` beside a\n // landscape that parses, `context checkout-web --json` reported\n // `landscape.parses: false` while `explore checkout-web --json` reported\n // `parses: true` and went on to describe every edge). `core/pack/living.ts`\n // named this module as the last reader that disagreed. Whichever answer is\n // right, an agent handed both has no way to tell — and the renderer's answer\n // is the project's.\n //\n // `present` stays a fact about the FILE, because that file is the WRITE target:\n // `loam new`'s scaffold and every brief ask for edits to\n // `architecture/landscape.likec4` by name, and \"the project is empty\" is not\n // the same instruction as \"there is no map to edit\".\n const present = existsSync(landscapePath(docsDir));\n const land = present ? await context.architecture(docsDir) : null;\n const parses = land !== null && land.errors.length === 0;\n const elements = parses ? land.elements : [];\n const relationships: Rel[] = parses ? land.relationships : [];\n // One resolver for the whole scan, built with the real service ids so an edge\n // drawn into a modelled container (`paymentService.api`) counts for the\n // service that owns it — the same resolution `list`, `show` and `validate`\n // use, so no two commands can disagree about who calls whom.\n const svcOf = serviceResolver(elements, known);\n\n // Operation seeds resolve through the living contracts, not the map: the map\n // says who CALLS an operation, and the question here is who DEFINES it.\n const opSeeds: ServiceEntry[\"id\"][] = [];\n const unresolvedOperations: string[] = [];\n for (const op of req.operations) {\n const owner = await operationOwner(entries, op, context);\n if (owner === null) unresolvedOperations.push(op);\n else opSeeds.push(owner);\n }\n\n // Capability seeds resolve through the vocabulary and the fleet rollup —\n // one rollup pass for ALL requested ids, through this exploration's shared\n // context cache, never a fresh walk per capability. A realizing service is\n // by construction an enumerated one, so every seed it adds is `known`.\n //\n // And through the fleet's USE CASES, which answer the same question off a\n // different document. The rollup finds services whose living requirements\n // carry a `Capability:` line; a `dynamic view` tagged `#cap-<slug>` finds the\n // services the flow actually runs through — including ones whose spec.md has\n // never named the capability, which on a brownfield fleet is most of them.\n // The two are unioned rather than ranked because neither is a subset of the\n // other: a service can realize a capability without appearing in its drawn\n // flow, and a flow can pass through a service that has written nothing down.\n //\n // The scan gates its own load — a fleet whose documents mention no reserved\n // tag never starts LikeC4 for it — and this whole block is behind\n // `--capability` being passed at all. What it is no longer behind is the\n // project itself: the read above loads `architecture/` for every exploration,\n // so a `--capability` run pays for a SECOND parse of the same documents\n // (`readUseCases` takes a `DocsDir`, not this invocation's memo). Accepted\n // rather than unnoticed: the alternative is a seam that hands the scan a\n // pre-loaded project, which is a change to a module five callers share, and\n // the cost lands only on the flag that already opts into the fleet rollup.\n const capSeeds: ServiceEntry[\"id\"][] = [];\n let unresolvedCaps: string[] = [];\n if (req.capabilities.length > 0) {\n const vocab = await context.capabilities(docsDir);\n const rows = await capabilityRollup({ services: entries, vocab, read: (p) => context.readRequirements(p) });\n const wanted = new Set(req.capabilities);\n const realizing = new Set(rows.filter((r) => wanted.has(r.id)).flatMap((r) => r.services));\n const scan = await readUseCases({ docsDir, known });\n for (const id of servicesInFlowsClaiming(scan, req.capabilities)) realizing.add(id);\n capSeeds.push(...entries.filter((e) => realizing.has(e.id)).map((e) => e.id));\n // `unresolvedCapabilities` is unchanged on purpose: it grades the\n // VOCABULARY — declared or not, realized by a living requirement or not —\n // and a capability drawn in a flow but realized by nobody is still a\n // capability nothing implements. Letting a tag silence that would hide the\n // gap the field exists to name.\n unresolvedCaps = unresolvedCapabilities(rows, req.capabilities);\n }\n\n const seeds = [...new Set([...req.services, ...opSeeds, ...capSeeds])];\n const unknown = seeds\n .filter((id) => !known.has(id))\n .map((id) => ({ id, nearest: nearestIds(id, [...known]) }));\n\n // The ring: one hop, both directions. A seed that is not modelled contributes\n // nothing here and that is the honest answer — an invisible service has no\n // neighbours anyone can derive, which is what `landscape.service-unmodelled`\n // is about.\n //\n // The two directions are collected separately rather than written into one\n // map as the loop goes, because a neighbour can be BOTH — it calls a seed and\n // the seed calls it — and a single-map version answers whichever edge the\n // parser happened to yield last. That is a field whose value depends on the\n // order lines appear in a `.likec4` file, which is the kind of answer that\n // reads as derived and is not.\n const seedSet = new Set<string>(seeds);\n const callsSeed = new Set<string>();\n const calledBySeed = new Set<string>();\n for (const r of relationships) {\n const from = svcOf(r.source);\n const to = svcOf(r.target);\n if (seedSet.has(from) && !seedSet.has(to)) calledBySeed.add(to);\n if (seedSet.has(to) && !seedSet.has(from)) callsSeed.add(from);\n }\n\n // `calls-seed` wins the overlap, deterministically. Of the two directions it\n // is the one that more often has to be touched: a consumer depends on the\n // seed's contract, so a change to that contract is what breaks it, while a\n // provider the seed merely calls is usually unaffected by the seed changing.\n const ring = new Map<string, ExploreReason>([\n ...[...calledBySeed].map((id) => [id, \"called-by-seed\" as const] as const),\n ...[...callsSeed].map((id) => [id, \"calls-seed\" as const] as const),\n ]);\n\n const ordered: Array<{ id: string; reason: ExploreReason }> = [\n ...[...seeds].sort(compareIds).map((id) => ({ id, reason: \"seed\" as const })),\n ...[...ring]\n .sort(([a], [b]) => compareIds(a, b))\n .map(([id, reason]) => ({ id, reason })),\n ];\n\n const services: ExploreService[] = [];\n for (const { id, reason } of ordered) {\n services.push(\n await describe({\n id,\n reason,\n entry: byId.get(id),\n relationships,\n svcOf,\n elements,\n parses,\n context,\n }),\n );\n }\n\n const covered = new Set(services.map((s) => s.id));\n const features = await context.listFeatures(docsDir);\n const overlaps: ExploreOverlap[] = features\n .map((f) => ({ feature: f.id, services: f.services.filter((s) => covered.has(s)) }))\n .filter((o) => o.services.length > 0)\n .sort((a, b) => compareIds(a.feature, b.feature));\n\n return {\n seeds,\n unknown,\n unresolvedOperations,\n unresolvedCapabilities: unresolvedCaps,\n services,\n neighbours: [...ring.keys()].sort(compareIds),\n overlaps,\n landscape: {\n present,\n parses,\n broken: land === null ? [] : brokenDocumentPaths(docsDir, land.errors),\n },\n scaffold: newCommand(featureId, seeds, known),\n };\n}\n"]}
|