@ybotok/loam 0.2.0-alpha.1 → 0.2.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3448 -0
- package/COMPARISON.md +91 -3
- package/CONTRIBUTING.md +37 -0
- package/MIGRATING-from-OpenSpec.md +47 -23
- package/QUICKSTART.md +189 -12
- package/README.md +274 -65
- package/ROADMAP.md +572 -31
- package/SCHEMA.md +1709 -155
- package/WORKFLOW.md +298 -72
- package/dist/cli.js +26 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +5 -10
- package/dist/commands/adopt/adopt.js.map +1 -1
- package/dist/commands/adopt/render.js +50 -9
- package/dist/commands/adopt/render.js.map +1 -1
- package/dist/commands/archive/archive.js +16 -19
- package/dist/commands/archive/archive.js.map +1 -1
- package/dist/commands/archive/closing.js +42 -0
- package/dist/commands/archive/closing.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +36 -42
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/consumers.js +56 -0
- package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +77 -43
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/document/head.js +151 -0
- package/dist/commands/archive/plan/document/head.js.map +1 -0
- package/dist/commands/archive/plan/document/links.js +284 -0
- package/dist/commands/archive/plan/document/links.js.map +1 -0
- package/dist/commands/archive/plan/document/run.js +136 -0
- package/dist/commands/archive/plan/document/run.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +21 -19
- package/dist/commands/archive/plan/gate.js.map +1 -1
- package/dist/commands/archive/plan/landscape.js +167 -30
- package/dist/commands/archive/plan/landscape.js.map +1 -1
- package/dist/commands/archive/plan/model/extending.js +85 -0
- package/dist/commands/archive/plan/model/extending.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +14 -19
- package/dist/commands/archive/plan/refusal.js.map +1 -1
- package/dist/commands/archive/plan/specs.js +137 -56
- package/dist/commands/archive/plan/specs.js.map +1 -1
- package/dist/commands/archive/plan/state.js +3 -0
- package/dist/commands/archive/plan/state.js.map +1 -1
- package/dist/commands/archive/run.js +134 -30
- package/dist/commands/archive/run.js.map +1 -1
- package/dist/commands/archive/shipped.js +49 -0
- package/dist/commands/archive/shipped.js.map +1 -0
- package/dist/commands/context/context.js +85 -18
- package/dist/commands/context/context.js.map +1 -1
- package/dist/commands/context/print.js +29 -7
- package/dist/commands/context/print.js.map +1 -1
- package/dist/commands/delta/delta.js +102 -14
- package/dist/commands/delta/delta.js.map +1 -1
- package/dist/commands/delta/print.js +17 -1
- package/dist/commands/delta/print.js.map +1 -1
- package/dist/commands/dependencies.js +3 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +20 -27
- package/dist/commands/diff/diff.js.map +1 -1
- package/dist/commands/doctor.js +60 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +89 -13
- package/dist/commands/explain/explain.js.map +1 -1
- package/dist/commands/explore.js +16 -10
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +45 -8
- package/dist/commands/gate/gate.js.map +1 -1
- package/dist/commands/gate/print.js +15 -3
- package/dist/commands/gate/print.js.map +1 -1
- package/dist/commands/gherkin/commit.js +13 -54
- package/dist/commands/gherkin/commit.js.map +1 -1
- package/dist/commands/gherkin/gherkin.js +36 -20
- package/dist/commands/gherkin/gherkin.js.map +1 -1
- package/dist/commands/gherkin/reconcile.js +10 -13
- package/dist/commands/gherkin/reconcile.js.map +1 -1
- package/dist/commands/init/first-hour.js +44 -0
- package/dist/commands/init/first-hour.js.map +1 -1
- package/dist/commands/init/init.js +18 -22
- package/dist/commands/init/init.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +4 -6
- package/dist/commands/list/campaign/campaign.js.map +1 -1
- package/dist/commands/list/json.js +5 -7
- package/dist/commands/list/json.js.map +1 -1
- package/dist/commands/list/list.js +44 -29
- package/dist/commands/list/list.js.map +1 -1
- package/dist/commands/list/print.js +52 -9
- package/dist/commands/list/print.js.map +1 -1
- package/dist/commands/list/suites/suites.js +140 -0
- package/dist/commands/list/suites/suites.js.map +1 -0
- package/dist/commands/list/views.js +37 -34
- package/dist/commands/list/views.js.map +1 -1
- package/dist/commands/mcp/dispatch.js +91 -36
- package/dist/commands/mcp/dispatch.js.map +1 -1
- package/dist/commands/mcp/mcp.js +56 -15
- package/dist/commands/mcp/mcp.js.map +1 -1
- package/dist/commands/mcp/serve.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/active.js +27 -22
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/target.js +2 -2
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/error.js +7 -8
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
- package/dist/commands/new/capability-template.js +118 -0
- package/dist/commands/new/capability-template.js.map +1 -0
- package/dist/commands/new/commit.js +8 -22
- package/dist/commands/new/commit.js.map +1 -1
- package/dist/commands/new/modifies.js +206 -0
- package/dist/commands/new/modifies.js.map +1 -0
- package/dist/commands/new/new.js +59 -14
- package/dist/commands/new/new.js.map +1 -1
- package/dist/commands/new/templates.js +48 -124
- package/dist/commands/new/templates.js.map +1 -1
- package/dist/commands/open.js +3 -7
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/policy/gate.js +27 -0
- package/dist/commands/policy/gate.js.map +1 -1
- package/dist/commands/rebase/plan.js +2 -2
- package/dist/commands/rebase/plan.js.map +1 -1
- package/dist/commands/rebase/rebase.js +60 -35
- package/dist/commands/rebase/rebase.js.map +1 -1
- package/dist/commands/seed/commit.js +55 -26
- package/dist/commands/seed/commit.js.map +1 -1
- package/dist/commands/seed/plan.js +158 -13
- package/dist/commands/seed/plan.js.map +1 -1
- package/dist/commands/seed/seed.js +13 -11
- package/dist/commands/seed/seed.js.map +1 -1
- package/dist/commands/show/feature.js +9 -5
- package/dist/commands/show/feature.js.map +1 -1
- package/dist/commands/show/introduced.js +157 -0
- package/dist/commands/show/introduced.js.map +1 -0
- package/dist/commands/show/marks.js +35 -6
- package/dist/commands/show/marks.js.map +1 -1
- package/dist/commands/show/service.js +41 -33
- package/dist/commands/show/service.js.map +1 -1
- package/dist/commands/show/show.js +17 -7
- package/dist/commands/show/show.js.map +1 -1
- package/dist/commands/status/fleet-next.js +90 -0
- package/dist/commands/status/fleet-next.js.map +1 -0
- package/dist/commands/status/json.js +2 -0
- package/dist/commands/status/json.js.map +1 -1
- package/dist/commands/status/print.js +89 -37
- package/dist/commands/status/print.js.map +1 -1
- package/dist/commands/status/status.js +3 -7
- package/dist/commands/status/status.js.map +1 -1
- package/dist/commands/steps/steps.js +103 -23
- package/dist/commands/steps/steps.js.map +1 -1
- package/dist/commands/subsystem/edit.js +7 -7
- package/dist/commands/subsystem/edit.js.map +1 -1
- package/dist/commands/subsystem/move.js +106 -46
- package/dist/commands/subsystem/move.js.map +1 -1
- package/dist/commands/subsystem/query.js +2 -4
- package/dist/commands/subsystem/query.js.map +1 -1
- package/dist/commands/subsystem/subsystem.js +4 -7
- package/dist/commands/subsystem/subsystem.js.map +1 -1
- package/dist/commands/subsystem/sync.js +289 -74
- package/dist/commands/subsystem/sync.js.map +1 -1
- package/dist/commands/subsystem/txn/exclude.js +132 -0
- package/dist/commands/subsystem/txn/exclude.js.map +1 -0
- package/dist/commands/subsystem/txn/links.js +128 -0
- package/dist/commands/subsystem/txn/links.js.map +1 -0
- package/dist/commands/subsystem/txn/report.js +174 -0
- package/dist/commands/subsystem/txn/report.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +147 -45
- package/dist/commands/subsystem/txn/txn.js.map +1 -1
- package/dist/commands/subsystem/txn/views.js +200 -21
- package/dist/commands/subsystem/txn/views.js.map +1 -1
- package/dist/commands/tasks/actions.js +107 -0
- package/dist/commands/tasks/actions.js.map +1 -0
- package/dist/commands/tasks/render.js +253 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +119 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +42 -26
- package/dist/commands/unarchive/manifest.js.map +1 -1
- package/dist/commands/unarchive/restore.js +83 -33
- package/dist/commands/unarchive/restore.js.map +1 -1
- package/dist/commands/unarchive/unarchive.js +22 -30
- package/dist/commands/unarchive/unarchive.js.map +1 -1
- package/dist/commands/validate/arch-coverage.js +78 -27
- package/dist/commands/validate/arch-coverage.js.map +1 -1
- package/dist/commands/validate/checks/fleet-shape.js +34 -126
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
- package/dist/commands/validate/checks/health-deps.js +9 -6
- package/dist/commands/validate/checks/health-deps.js.map +1 -1
- package/dist/commands/validate/checks/introduced.js +102 -0
- package/dist/commands/validate/checks/introduced.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +18 -8
- package/dist/commands/validate/checks/requirements.js.map +1 -1
- package/dist/commands/validate/checks/sources.js +11 -2
- package/dist/commands/validate/checks/sources.js.map +1 -1
- package/dist/commands/validate/coverage/covers-after.js +105 -0
- package/dist/commands/validate/coverage/covers-after.js.map +1 -0
- package/dist/commands/validate/feature.js +26 -20
- package/dist/commands/validate/feature.js.map +1 -1
- package/dist/commands/validate/fleet/census.js +37 -13
- package/dist/commands/validate/fleet/census.js.map +1 -1
- package/dist/commands/validate/fleet/landscape.js +144 -126
- package/dist/commands/validate/fleet/landscape.js.map +1 -1
- package/dist/commands/validate/fleet/load.js +66 -0
- package/dist/commands/validate/fleet/load.js.map +1 -1
- package/dist/commands/validate/fleet/map/attest.js +98 -0
- package/dist/commands/validate/fleet/map/attest.js.map +1 -0
- package/dist/commands/validate/fleet/map/bindings.js +107 -0
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
- package/dist/commands/validate/fleet/map/consumers.js +244 -0
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
- package/dist/commands/validate/fleet/map/isolation.js +116 -0
- package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
- package/dist/commands/validate/fleet/map/usecases.js +54 -0
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +44 -14
- package/dist/commands/validate/fleet/obligations.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/print.js +10 -2
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -1
- package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +50 -15
- package/dist/commands/validate/fleet/views/ids.js.map +1 -1
- package/dist/commands/validate/fleet/views/projects.js +278 -0
- package/dist/commands/validate/fleet/views/projects.js.map +1 -0
- package/dist/commands/validate/fleet/views/root-documents.js +83 -0
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +40 -47
- package/dist/commands/validate/fleet/views/stale.js.map +1 -1
- package/dist/commands/validate/links/corpus.js +1 -4
- package/dist/commands/validate/links/corpus.js.map +1 -1
- package/dist/commands/validate/links/glossary.js.map +1 -1
- package/dist/commands/validate/render/repeats.js +63 -0
- package/dist/commands/validate/render/repeats.js.map +1 -0
- package/dist/commands/validate/render/rollups.js +115 -0
- package/dist/commands/validate/render/rollups.js.map +1 -0
- package/dist/commands/validate/render/text.js +199 -0
- package/dist/commands/validate/render/text.js.map +1 -0
- package/dist/commands/validate/report.js +36 -160
- package/dist/commands/validate/report.js.map +1 -1
- package/dist/commands/validate/scope.js +113 -0
- package/dist/commands/validate/scope.js.map +1 -0
- package/dist/commands/validate/service/api.js +21 -107
- package/dist/commands/validate/service/api.js.map +1 -1
- package/dist/commands/validate/service/contracts/generated.js +134 -0
- package/dist/commands/validate/service/contracts/generated.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +36 -14
- package/dist/commands/validate/service/events/events.js.map +1 -1
- package/dist/commands/validate/service/events/message-producers.js +1 -1
- package/dist/commands/validate/service/events/message-producers.js.map +1 -1
- package/dist/commands/validate/service/evidence-pins.js +56 -10
- package/dist/commands/validate/service/evidence-pins.js.map +1 -1
- package/dist/commands/validate/service/model/diverged.js +226 -0
- package/dist/commands/validate/service/model/diverged.js.map +1 -0
- package/dist/commands/validate/service/model/grade.js +163 -0
- package/dist/commands/validate/service/model/grade.js.map +1 -0
- package/dist/commands/validate/service/service.js +121 -61
- package/dist/commands/validate/service/service.js.map +1 -1
- package/dist/commands/validate/service/specs.js +88 -28
- package/dist/commands/validate/service/specs.js.map +1 -1
- package/dist/commands/validate/service/spine.js +38 -3
- package/dist/commands/validate/service/spine.js.map +1 -1
- package/dist/commands/validate/service/usecases/tags.js +113 -0
- package/dist/commands/validate/service/usecases/tags.js.map +1 -0
- package/dist/commands/validate/service/usecases/usecases.js +209 -0
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/validate.js +85 -60
- package/dist/commands/validate/validate.js.map +1 -1
- package/dist/commands/verify/cross/diff.js +2 -6
- package/dist/commands/verify/cross/diff.js.map +1 -1
- package/dist/commands/verify/evidence/contract.js +1 -1
- package/dist/commands/verify/evidence/contract.js.map +1 -1
- package/dist/commands/verify/evidence/read.js +12 -3
- package/dist/commands/verify/evidence/read.js.map +1 -1
- package/dist/commands/verify/frozen.js +45 -23
- package/dist/commands/verify/frozen.js.map +1 -1
- package/dist/commands/verify/record.js +69 -17
- package/dist/commands/verify/record.js.map +1 -1
- package/dist/commands/verify/report.js +27 -44
- package/dist/commands/verify/report.js.map +1 -1
- package/dist/commands/verify/results.js +112 -30
- package/dist/commands/verify/results.js.map +1 -1
- package/dist/commands/verify/verify.js +55 -52
- package/dist/commands/verify/verify.js.map +1 -1
- package/dist/commands/vouch/pack/pack.js +2 -2
- package/dist/commands/vouch/pack/pack.js.map +1 -1
- package/dist/commands/vouch/pack/print.js +1 -6
- package/dist/commands/vouch/pack/print.js.map +1 -1
- package/dist/commands/vouch/pack/sections.js +1 -2
- package/dist/commands/vouch/pack/sections.js.map +1 -1
- package/dist/commands/vouch/run.js +26 -81
- package/dist/commands/vouch/run.js.map +1 -1
- package/dist/commands/vouch/sample/plan.js +20 -34
- package/dist/commands/vouch/sample/plan.js.map +1 -1
- package/dist/commands/vouch/vet/verify.js +39 -7
- package/dist/commands/vouch/vet/verify.js.map +1 -1
- package/dist/commands/vouch/vouch.js +10 -17
- package/dist/commands/vouch/vouch.js.map +1 -1
- package/dist/core/agent/agents-md/command-map.js +81 -106
- package/dist/core/agent/agents-md/command-map.js.map +1 -1
- package/dist/core/agent/agents-md/map/explain.js +21 -9
- package/dist/core/agent/agents-md/map/explain.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/context.js +17 -8
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
- package/dist/core/agent/agents-md/map/mcp.js +10 -7
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
- package/dist/core/agent/agents-md/map/status.js +24 -8
- package/dist/core/agent/agents-md/map/status.js.map +1 -1
- package/dist/core/agent/agents-md/map/subsystem.js +80 -8
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
- package/dist/core/agent/agents-md/map/usecases.js +88 -10
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
- package/dist/core/agent/agents-md/refusals.js +49 -22
- package/dist/core/agent/agents-md/refusals.js.map +1 -1
- package/dist/core/agent/agents-md.js +39 -6
- package/dist/core/agent/agents-md.js.map +1 -1
- package/dist/core/agent/agents-stamp.js +10 -0
- package/dist/core/agent/agents-stamp.js.map +1 -1
- package/dist/core/agent/protocol.js +1 -1
- package/dist/core/agent/protocol.js.map +1 -1
- package/dist/core/agent/scaffold.js +10 -15
- package/dist/core/agent/scaffold.js.map +1 -1
- package/dist/core/agent/support/report.js +46 -5
- package/dist/core/agent/support/report.js.map +1 -1
- package/dist/core/agent/tools/dialects.js +1 -0
- package/dist/core/agent/tools/dialects.js.map +1 -1
- package/dist/core/agent/tools/registry.js +41 -76
- package/dist/core/agent/tools/registry.js.map +1 -1
- package/dist/core/agent/workflows/adopt.js +158 -11
- package/dist/core/agent/workflows/adopt.js.map +1 -1
- package/dist/core/agent/workflows/check.js +78 -39
- package/dist/core/agent/workflows/check.js.map +1 -1
- package/dist/core/agent/workflows/closing.js +88 -27
- package/dist/core/agent/workflows/closing.js.map +1 -1
- package/dist/core/agent/workflows/feature.js +128 -13
- package/dist/core/agent/workflows/feature.js.map +1 -1
- package/dist/core/agent/workflows/implement.js +96 -13
- package/dist/core/agent/workflows/implement.js.map +1 -1
- package/dist/core/agent/workflows/reference/authoring.js +106 -4
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
- package/dist/core/agent/workflows/reference/codes.js +8 -6
- package/dist/core/agent/workflows/reference/codes.js.map +1 -1
- package/dist/core/agent/workflows/reference/done-check.js +37 -15
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
- package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +6 -3
- package/dist/core/agent/workflows/reference/reference.js.map +1 -1
- package/dist/core/agent/workflows/reference/spine.js +68 -27
- package/dist/core/agent/workflows/reference/spine.js.map +1 -1
- package/dist/core/asyncapi/baseline/plan.js +14 -81
- package/dist/core/asyncapi/baseline/plan.js.map +1 -1
- package/dist/core/asyncapi/digest.js +30 -25
- package/dist/core/asyncapi/digest.js.map +1 -1
- package/dist/core/asyncapi/merge/components.js +5 -4
- package/dist/core/asyncapi/merge/components.js.map +1 -1
- package/dist/core/asyncapi/merge/error.js +7 -2
- package/dist/core/asyncapi/merge/error.js.map +1 -1
- package/dist/core/asyncapi/merge/markers.js +32 -50
- package/dist/core/asyncapi/merge/markers.js.map +1 -1
- package/dist/core/asyncapi/merge/merge.js +33 -53
- package/dist/core/asyncapi/merge/merge.js.map +1 -1
- package/dist/core/asyncapi/merge/pin.js +12 -36
- package/dist/core/asyncapi/merge/pin.js.map +1 -1
- package/dist/core/asyncapi/model.js.map +1 -1
- package/dist/core/asyncapi/read.js +36 -12
- package/dist/core/asyncapi/read.js.map +1 -1
- package/dist/core/brief/brief.js +96 -36
- package/dist/core/brief/brief.js.map +1 -1
- package/dist/core/brief/checks.js +138 -3
- package/dist/core/brief/checks.js.map +1 -1
- package/dist/core/brief/landscape.js +209 -130
- package/dist/core/brief/landscape.js.map +1 -1
- package/dist/core/brief/map/extend.js +84 -0
- package/dist/core/brief/map/extend.js.map +1 -0
- package/dist/core/brief/map/owed.js +266 -0
- package/dist/core/brief/map/owed.js.map +1 -0
- package/dist/core/brief/targets.js +109 -31
- package/dist/core/brief/targets.js.map +1 -1
- package/dist/core/brief/unchecked.js +14 -3
- package/dist/core/brief/unchecked.js.map +1 -1
- package/dist/core/c4/arch.js +90 -182
- package/dist/core/c4/arch.js.map +1 -1
- package/dist/core/c4/direction/direction.js +114 -0
- package/dist/core/c4/direction/direction.js.map +1 -0
- package/dist/core/c4/likec4.js +169 -14
- package/dist/core/c4/likec4.js.map +1 -1
- package/dist/core/c4/locate/unlocated.js +150 -0
- package/dist/core/c4/locate/unlocated.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +160 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -1
- package/dist/core/c4/parsed/values.js +54 -1
- package/dist/core/c4/parsed/values.js.map +1 -1
- package/dist/core/c4/parsed/view-ids.js +39 -1
- package/dist/core/c4/parsed/view-ids.js.map +1 -1
- package/dist/core/c4/prefetch/fleet.js +134 -0
- package/dist/core/c4/prefetch/fleet.js.map +1 -0
- package/dist/core/c4/project/architecture.js +123 -7
- package/dist/core/c4/project/architecture.js.map +1 -1
- package/dist/core/c4/project/batch.js +140 -0
- package/dist/core/c4/project/batch.js.map +1 -0
- package/dist/core/c4/project/documents.js +43 -12
- package/dist/core/c4/project/documents.js.map +1 -1
- package/dist/core/c4/project/load.js +79 -43
- package/dist/core/c4/project/load.js.map +1 -1
- package/dist/core/c4/project/staged.js +277 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/attested.js +0 -0
- package/dist/core/c4/resolve/attested.js.map +1 -0
- package/dist/core/c4/resolve/external.js +51 -0
- package/dist/core/c4/resolve/external.js.map +1 -0
- package/dist/core/c4/resolve/service.js +78 -17
- package/dist/core/c4/resolve/service.js.map +1 -1
- package/dist/core/c4/resolve/steps.js +290 -0
- package/dist/core/c4/resolve/steps.js.map +1 -0
- package/dist/core/c4/resolve/systems.js +154 -0
- package/dist/core/c4/resolve/systems.js.map +1 -0
- package/dist/core/c4/root-project/exclude.js +352 -0
- package/dist/core/c4/root-project/exclude.js.map +1 -0
- package/dist/core/c4/seed/template.js +65 -1
- package/dist/core/c4/seed/template.js.map +1 -1
- package/dist/core/c4/service-model/created/models.js +96 -0
- package/dist/core/c4/service-model/created/models.js.map +1 -0
- package/dist/core/c4/service-model/documents.js +47 -0
- package/dist/core/c4/service-model/documents.js.map +1 -0
- package/dist/core/c4/service-model/fleet/extending.js +82 -0
- package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
- package/dist/core/c4/service-model/load.js +165 -0
- package/dist/core/c4/service-model/load.js.map +1 -0
- package/dist/core/c4/service-model/renderer.js +128 -0
- package/dist/core/c4/service-model/renderer.js.map +1 -0
- package/dist/core/c4/service-model/shape.js +106 -0
- package/dist/core/c4/service-model/shape.js.map +1 -0
- package/dist/core/c4/service-model/slice.js +188 -0
- package/dist/core/c4/service-model/slice.js.map +1 -0
- package/dist/core/c4/source-mask.js +297 -10
- package/dist/core/c4/source-mask.js.map +1 -1
- package/dist/core/c4/source-scan.js +222 -141
- package/dist/core/c4/source-scan.js.map +1 -1
- package/dist/core/c4/splice/authored-source.js +79 -13
- package/dist/core/c4/splice/authored-source.js.map +1 -1
- package/dist/core/c4/splice/contract.js +20 -0
- package/dist/core/c4/splice/contract.js.map +1 -1
- package/dist/core/c4/splice/delta-blocks.js +20 -20
- package/dist/core/c4/splice/delta-blocks.js.map +1 -1
- package/dist/core/c4/splice/identity/declared.js +87 -0
- package/dist/core/c4/splice/identity/declared.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +37 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -1
- package/dist/core/c4/splice/identity/existing.js +80 -0
- package/dist/core/c4/splice/identity/existing.js.map +1 -0
- package/dist/core/c4/splice/identity/interior.js +80 -0
- package/dist/core/c4/splice/identity/interior.js.map +1 -0
- package/dist/core/c4/splice/identity/owner.js +50 -0
- package/dist/core/c4/splice/identity/owner.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +182 -114
- package/dist/core/c4/splice/landscape-merge.js.map +1 -1
- package/dist/core/c4/splice/model/merge.js +151 -0
- package/dist/core/c4/splice/model/merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +160 -56
- package/dist/core/c4/splice/placement.js.map +1 -1
- package/dist/core/c4/splice/text/spot.js +131 -0
- package/dist/core/c4/splice/text/spot.js.map +1 -0
- package/dist/core/c4/workspace.js +13 -19
- package/dist/core/c4/workspace.js.map +1 -1
- package/dist/core/capabilities/capabilities.js +6 -6
- package/dist/core/capabilities/capabilities.js.map +1 -1
- package/dist/core/capabilities/delta/doc.js +7 -10
- package/dist/core/capabilities/delta/doc.js.map +1 -1
- package/dist/core/capabilities/delta/uncovered.js +2 -2
- package/dist/core/capabilities/delta/uncovered.js.map +1 -1
- package/dist/core/capabilities/findings.js +18 -22
- package/dist/core/capabilities/findings.js.map +1 -1
- package/dist/core/capabilities/realizes/findings.js +12 -19
- package/dist/core/capabilities/realizes/findings.js.map +1 -1
- package/dist/core/capabilities/realizes/join.js +0 -20
- package/dist/core/capabilities/realizes/join.js.map +1 -1
- package/dist/core/capabilities/rollup.js +6 -0
- package/dist/core/capabilities/rollup.js.map +1 -1
- package/dist/core/capabilities/tree.js +6 -28
- package/dist/core/capabilities/tree.js.map +1 -1
- package/dist/core/capabilities/usecase-join.js +3 -13
- package/dist/core/capabilities/usecase-join.js.map +1 -1
- package/dist/core/coherence/authoring/scaffold.js +11 -3
- package/dist/core/coherence/authoring/scaffold.js.map +1 -1
- package/dist/core/coherence/authoring/sentinels.js +2 -1
- package/dist/core/coherence/authoring/sentinels.js.map +1 -1
- package/dist/core/coherence/calls/called.js +52 -0
- package/dist/core/coherence/calls/called.js.map +1 -0
- package/dist/core/coherence/coherence.js +103 -22
- package/dist/core/coherence/coherence.js.map +1 -1
- package/dist/core/coherence/consumed/operations.js +70 -0
- package/dist/core/coherence/consumed/operations.js.map +1 -0
- package/dist/core/coherence/consumed/refusal.js +38 -0
- package/dist/core/coherence/consumed/refusal.js.map +1 -0
- package/dist/core/coherence/covers/health.js +85 -0
- package/dist/core/coherence/covers/health.js.map +1 -0
- package/dist/core/coherence/declared.js +60 -34
- package/dist/core/coherence/declared.js.map +1 -1
- package/dist/core/coherence/events/declared.js +44 -59
- package/dist/core/coherence/events/declared.js.map +1 -1
- package/dist/core/coherence/events/events.js +147 -16
- package/dist/core/coherence/events/events.js.map +1 -1
- package/dist/core/coherence/events/grades.js +31 -8
- package/dist/core/coherence/events/grades.js.map +1 -1
- package/dist/core/coherence/events/lookups.js +28 -87
- package/dist/core/coherence/events/lookups.js.map +1 -1
- package/dist/core/coherence/events/produced.js +100 -0
- package/dist/core/coherence/events/produced.js.map +1 -0
- package/dist/core/coherence/lookups.js +18 -78
- package/dist/core/coherence/lookups.js.map +1 -1
- package/dist/core/coherence/retired/archived.js +285 -0
- package/dist/core/coherence/retired/archived.js.map +1 -0
- package/dist/core/coherence/retired/event-pair.js +62 -0
- package/dist/core/coherence/retired/event-pair.js.map +1 -0
- package/dist/core/coherence/retired/merged.js +79 -0
- package/dist/core/coherence/retired/merged.js.map +1 -0
- package/dist/core/coherence/retired/retirement.js +49 -0
- package/dist/core/coherence/retired/retirement.js.map +1 -0
- package/dist/core/coherence/retired/revival/arrivals.js +131 -0
- package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
- package/dist/core/coherence/retired/revival/revived.js +297 -0
- package/dist/core/coherence/retired/revival/revived.js.map +1 -0
- package/dist/core/consumers/after.js +113 -0
- package/dist/core/consumers/after.js.map +1 -0
- package/dist/core/consumers/consumers.js +296 -0
- package/dist/core/consumers/consumers.js.map +1 -0
- package/dist/core/consumers/current.js +211 -0
- package/dist/core/consumers/current.js.map +1 -0
- package/dist/core/consumers/scan.js +46 -0
- package/dist/core/consumers/scan.js.map +1 -0
- package/dist/core/consumers/state.js +27 -0
- package/dist/core/consumers/state.js.map +1 -0
- package/dist/core/delta/delta.js +51 -6
- package/dist/core/delta/delta.js.map +1 -1
- package/dist/core/dependencies/fanin.js +2 -2
- package/dist/core/dependencies/fanin.js.map +1 -1
- package/dist/core/deployment/delta.js +191 -0
- package/dist/core/deployment/delta.js.map +1 -0
- package/dist/core/deployment/objects.js +145 -0
- package/dist/core/deployment/objects.js.map +1 -0
- package/dist/core/diff/base-git.js +94 -12
- package/dist/core/diff/base-git.js.map +1 -1
- package/dist/core/diff/base-state.js +49 -21
- package/dist/core/diff/base-state.js.map +1 -1
- package/dist/core/diff/joins.js +136 -0
- package/dist/core/diff/joins.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +22 -6
- package/dist/core/diff/scope/changed-paths.js.map +1 -1
- package/dist/core/diff/scope/edges.js +82 -0
- package/dist/core/diff/scope/edges.js.map +1 -0
- package/dist/core/diff/semantic.js +100 -31
- package/dist/core/diff/semantic.js.map +1 -1
- package/dist/core/docs.js +31 -22
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +34 -18
- package/dist/core/doctor/agents.js.map +1 -1
- package/dist/core/doctor/config.js +7 -3
- package/dist/core/doctor/config.js.map +1 -1
- package/dist/core/doctor/doctor.js +91 -11
- package/dist/core/doctor/doctor.js.map +1 -1
- package/dist/core/doctor/report.js.map +1 -1
- package/dist/core/doctor/reports/scan.js +242 -0
- package/dist/core/doctor/reports/scan.js.map +1 -0
- package/dist/core/document/apply.js +158 -11
- package/dist/core/document/apply.js.map +1 -1
- package/dist/core/document/frontmatter.js +55 -0
- package/dist/core/document/frontmatter.js.map +1 -1
- package/dist/core/document/parse.js +29 -6
- package/dist/core/document/parse.js.map +1 -1
- package/dist/core/document/scenarios.js +17 -0
- package/dist/core/document/scenarios.js.map +1 -1
- package/dist/core/document/spec.js +4 -11
- package/dist/core/document/spec.js.map +1 -1
- package/dist/core/envelope/config.js +10 -0
- package/dist/core/envelope/config.js.map +1 -1
- package/dist/core/envelope/json.js +34 -0
- package/dist/core/envelope/json.js.map +1 -1
- package/dist/core/explain/families.js +26 -21
- package/dist/core/explain/families.js.map +1 -1
- package/dist/core/explain/lookup.js +14 -1
- package/dist/core/explain/lookup.js.map +1 -1
- package/dist/core/explain/refusals.js +5 -5
- package/dist/core/explain/refusals.js.map +1 -1
- package/dist/core/explain/terms/documents.js +227 -0
- package/dist/core/explain/terms/documents.js.map +1 -0
- package/dist/core/explain/terms/done-check.js +144 -0
- package/dist/core/explain/terms/done-check.js.map +1 -0
- package/dist/core/explain/terms/entry.js +14 -0
- package/dist/core/explain/terms/entry.js.map +1 -0
- package/dist/core/explain/terms/stages.js +71 -0
- package/dist/core/explain/terms/stages.js.map +1 -0
- package/dist/core/explain/terms/tasks.js +97 -0
- package/dist/core/explain/terms/tasks.js.map +1 -0
- package/dist/core/explain/terms.js +68 -109
- package/dist/core/explain/terms.js.map +1 -1
- package/dist/core/explore/explore.js +40 -10
- package/dist/core/explore/explore.js.map +1 -1
- package/dist/core/fleet-context.js +81 -95
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +11 -4
- package/dist/core/gate/checks.js.map +1 -1
- package/dist/core/gate/partners.js +69 -28
- package/dist/core/gate/partners.js.map +1 -1
- package/dist/core/gate/report.js.map +1 -1
- package/dist/core/gate/verification.js +75 -12
- package/dist/core/gate/verification.js.map +1 -1
- package/dist/core/gherkin/stale.js +13 -37
- package/dist/core/gherkin/stale.js.map +1 -1
- package/dist/core/glossary/delta.js +10 -7
- package/dist/core/glossary/delta.js.map +1 -1
- package/dist/core/glossary/tree.js +6 -19
- package/dist/core/glossary/tree.js.map +1 -1
- package/dist/core/kernel/concurrency.js +19 -0
- package/dist/core/kernel/concurrency.js.map +1 -1
- package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
- package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
- package/dist/core/kernel/path-safety.js +38 -0
- package/dist/core/kernel/path-safety.js.map +1 -1
- package/dist/core/kernel/records.js +11 -0
- package/dist/core/kernel/records.js.map +1 -1
- package/dist/core/links/backlinks.js +1 -3
- package/dist/core/links/backlinks.js.map +1 -1
- package/dist/core/links/corpus.js +51 -37
- package/dist/core/links/corpus.js.map +1 -1
- package/dist/core/links/findings.js.map +1 -1
- package/dist/core/links/parse.js +38 -9
- package/dist/core/links/parse.js.map +1 -1
- package/dist/core/mcp/argv.js +101 -0
- package/dist/core/mcp/argv.js.map +1 -1
- package/dist/core/mcp/author-tools.js +2 -1
- package/dist/core/mcp/author-tools.js.map +1 -1
- package/dist/core/mcp/protocol.js +2 -2
- package/dist/core/mcp/protocol.js.map +1 -1
- package/dist/core/mcp/tools.js +43 -33
- package/dist/core/mcp/tools.js.map +1 -1
- package/dist/core/openapi/baseline/gate.js +53 -12
- package/dist/core/openapi/baseline/gate.js.map +1 -1
- package/dist/core/openapi/baseline/plan.js +40 -10
- package/dist/core/openapi/baseline/plan.js.map +1 -1
- package/dist/core/openapi/baseline/record.js +0 -1
- package/dist/core/openapi/baseline/record.js.map +1 -1
- package/dist/core/openapi/contract-text.js +33 -0
- package/dist/core/openapi/contract-text.js.map +1 -0
- package/dist/core/openapi/contract-tree.js +301 -0
- package/dist/core/openapi/contract-tree.js.map +1 -0
- package/dist/core/openapi/depth.js +38 -24
- package/dist/core/openapi/depth.js.map +1 -1
- package/dist/core/openapi/digest.js +52 -2
- package/dist/core/openapi/digest.js.map +1 -1
- package/dist/core/openapi/doc.js +12 -4
- package/dist/core/openapi/doc.js.map +1 -1
- package/dist/core/openapi/merge/components.js +25 -60
- package/dist/core/openapi/merge/components.js.map +1 -1
- package/dist/core/openapi/merge/error.js +3 -13
- package/dist/core/openapi/merge/error.js.map +1 -1
- package/dist/core/openapi/merge/markers.js +26 -30
- package/dist/core/openapi/merge/markers.js.map +1 -1
- package/dist/core/openapi/merge/merge.js +28 -52
- package/dist/core/openapi/merge/merge.js.map +1 -1
- package/dist/core/openapi/merge/pin.js +17 -35
- package/dist/core/openapi/merge/pin.js.map +1 -1
- package/dist/core/openspec/decide/verdict.js.map +1 -1
- package/dist/core/openspec/inventory.js +4 -5
- package/dist/core/openspec/inventory.js.map +1 -1
- package/dist/core/openspec/model/mapping.js +30 -28
- package/dist/core/openspec/model/mapping.js.map +1 -1
- package/dist/core/openspec/model/model.js +12 -7
- package/dist/core/openspec/model/model.js.map +1 -1
- package/dist/core/openspec/scan/changes.js +10 -4
- package/dist/core/openspec/scan/changes.js.map +1 -1
- package/dist/core/openspec/scan/config.js +7 -16
- package/dist/core/openspec/scan/config.js.map +1 -1
- package/dist/core/openspec/scan/shape.js +63 -19
- package/dist/core/openspec/scan/shape.js.map +1 -1
- package/dist/core/openspec/scan/walk.js +21 -38
- package/dist/core/openspec/scan/walk.js.map +1 -1
- package/dist/core/pack/living.js +43 -4
- package/dist/core/pack/living.js.map +1 -1
- package/dist/core/pack/pack.js +50 -6
- package/dist/core/pack/pack.js.map +1 -1
- package/dist/core/projection/arch-slice.js +2 -2
- package/dist/core/projection/arch-slice.js.map +1 -1
- package/dist/core/projection/introduced.js +14 -0
- package/dist/core/projection/introduced.js.map +1 -0
- package/dist/core/provenance/findings.js +48 -12
- package/dist/core/provenance/findings.js.map +1 -1
- package/dist/core/provenance/git.js +33 -57
- package/dist/core/provenance/git.js.map +1 -1
- package/dist/core/provenance/gitq/moves.js +71 -114
- package/dist/core/provenance/gitq/moves.js.map +1 -1
- package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
- package/dist/core/provenance/sources.js +23 -6
- package/dist/core/provenance/sources.js.map +1 -1
- package/dist/core/provenance/stamp.js +5 -17
- package/dist/core/provenance/stamp.js.map +1 -1
- package/dist/core/repo/authored/paths.js +18 -0
- package/dist/core/repo/authored/paths.js.map +1 -1
- package/dist/core/repo/entries.js.map +1 -1
- package/dist/core/repo/paths.js +92 -6
- package/dist/core/repo/paths.js.map +1 -1
- package/dist/core/repo/repo.js +74 -14
- package/dist/core/repo/repo.js.map +1 -1
- package/dist/core/repo/tree/find.js +12 -3
- package/dist/core/repo/tree/find.js.map +1 -1
- package/dist/core/repo/tree/fs.js +27 -1
- package/dist/core/repo/tree/fs.js.map +1 -1
- package/dist/core/repo/tree/render/body.js +258 -0
- package/dist/core/repo/tree/render/body.js.map +1 -0
- package/dist/core/repo/tree/render/projects.js +182 -0
- package/dist/core/repo/tree/render/projects.js.map +1 -0
- package/dist/core/repo/tree/render/service/header.js +125 -0
- package/dist/core/repo/tree/render/service/header.js.map +1 -0
- package/dist/core/repo/tree/render/service/peers.js +28 -0
- package/dist/core/repo/tree/render/service/peers.js.map +1 -0
- package/dist/core/repo/tree/render/service/view-id.js +67 -0
- package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
- package/dist/core/repo/tree/render/service/views.js +78 -0
- package/dist/core/repo/tree/render/service/views.js.map +1 -0
- package/dist/core/repo/tree/render/stale.js +42 -0
- package/dist/core/repo/tree/render/stale.js.map +1 -0
- package/dist/core/repo/tree/render/text.js +84 -0
- package/dist/core/repo/tree/render/text.js.map +1 -0
- package/dist/core/repo/tree/render/views.js +293 -0
- package/dist/core/repo/tree/render/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +53 -32
- package/dist/core/repo/tree/walk.js.map +1 -1
- package/dist/core/results.js +47 -12
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +121 -13
- package/dist/core/scaffold/landscape.js.map +1 -1
- package/dist/core/scaffold/legacy.js +271 -0
- package/dist/core/scaffold/legacy.js.map +1 -0
- package/dist/core/staging/commit.js +26 -15
- package/dist/core/staging/commit.js.map +1 -1
- package/dist/core/staging/lock.js +74 -12
- package/dist/core/staging/lock.js.map +1 -1
- package/dist/core/staging/recovery/intent.js +2 -5
- package/dist/core/staging/recovery/intent.js.map +1 -1
- package/dist/core/staging/recovery/recover.js +84 -6
- package/dist/core/staging/recovery/recover.js.map +1 -1
- package/dist/core/staging/snapshot/manifest.js +188 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +39 -45
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +24 -14
- package/dist/core/staging/txn/forward.js.map +1 -1
- package/dist/core/staging/writes.js.map +1 -1
- package/dist/core/status/actions/execution.js +11 -0
- package/dist/core/status/actions/execution.js.map +1 -1
- package/dist/core/status/contracts.js +39 -15
- package/dist/core/status/contracts.js.map +1 -1
- package/dist/core/status/feature/artifacts.js +33 -8
- package/dist/core/status/feature/artifacts.js.map +1 -1
- package/dist/core/status/feature/feature.js +24 -17
- package/dist/core/status/feature/feature.js.map +1 -1
- package/dist/core/status/feature/next.js +20 -7
- package/dist/core/status/feature/next.js.map +1 -1
- package/dist/core/status/feature/words.js +96 -0
- package/dist/core/status/feature/words.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +43 -14
- package/dist/core/status/fleet/fleet.js.map +1 -1
- package/dist/core/status/fleet/next.js +153 -58
- package/dist/core/status/fleet/next.js.map +1 -1
- package/dist/core/status/report.js.map +1 -1
- package/dist/core/status/scan.js.map +1 -1
- package/dist/core/status/verification.js +30 -15
- package/dist/core/status/verification.js.map +1 -1
- package/dist/core/tasks/packet.js +199 -0
- package/dist/core/tasks/packet.js.map +1 -0
- package/dist/core/tasks/record.js +43 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/sources.js +181 -0
- package/dist/core/tasks/sources.js.map +1 -0
- package/dist/core/tasks/stamps.js +76 -0
- package/dist/core/tasks/stamps.js.map +1 -0
- package/dist/core/tasks/unit.js +0 -0
- package/dist/core/tasks/unit.js.map +1 -0
- package/dist/core/usecases/capability.js +11 -14
- package/dist/core/usecases/capability.js.map +1 -1
- package/dist/core/usecases/delta/claims.js +31 -7
- package/dist/core/usecases/delta/claims.js.map +1 -1
- package/dist/core/usecases/delta/flows.js +5 -7
- package/dist/core/usecases/delta/flows.js.map +1 -1
- package/dist/core/usecases/delta/modified.js +315 -0
- package/dist/core/usecases/delta/modified.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +32 -191
- package/dist/core/usecases/delta/overlay.js.map +1 -1
- package/dist/core/usecases/fleet.js +195 -36
- package/dist/core/usecases/fleet.js.map +1 -1
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/capability-tag.js +8 -9
- package/dist/core/usecases/grade/capability-tag.js.map +1 -0
- package/dist/core/usecases/grade/feature.js +88 -0
- package/dist/core/usecases/grade/feature.js.map +1 -0
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/requirement-tag.js +3 -4
- package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/steps.js +102 -33
- package/dist/core/usecases/grade/steps.js.map +1 -0
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/usecases.js +23 -10
- package/dist/core/usecases/grade/usecases.js.map +1 -0
- package/dist/core/usecases/operations.js +26 -14
- package/dist/core/usecases/operations.js.map +1 -1
- package/dist/core/usecases/place.js.map +1 -1
- package/dist/core/usecases/service/exclude.js +119 -0
- package/dist/core/usecases/service/exclude.js.map +1 -0
- package/dist/core/usecases/service/flows.js +164 -0
- package/dist/core/usecases/service/flows.js.map +1 -0
- package/dist/core/usecases/suites/participants.js +83 -0
- package/dist/core/usecases/suites/participants.js.map +1 -0
- package/dist/core/usecases/suites/suites.js +45 -0
- package/dist/core/usecases/suites/suites.js.map +1 -0
- package/dist/core/verify/answers.js +12 -5
- package/dist/core/verify/answers.js.map +1 -1
- package/dist/core/verify/build.js +102 -82
- package/dist/core/verify/build.js.map +1 -1
- package/dist/core/verify/checklist.js +70 -12
- package/dist/core/verify/checklist.js.map +1 -1
- package/dist/core/verify/location.js +67 -0
- package/dist/core/verify/location.js.map +1 -0
- package/dist/core/verify/pins/lint.js +3 -2
- package/dist/core/verify/pins/lint.js.map +1 -1
- package/dist/core/verify/pins/pin.js +1 -1
- package/dist/core/verify/pins/pin.js.map +1 -1
- package/dist/core/verify/read/file.js +224 -0
- package/dist/core/verify/read/file.js.map +1 -0
- package/dist/core/verify/{file.js → read/shape.js} +16 -104
- package/dist/core/verify/read/shape.js.map +1 -0
- package/dist/core/verify/read/union.js +105 -0
- package/dist/core/verify/read/union.js.map +1 -0
- package/dist/core/verify/record.js +35 -12
- package/dist/core/verify/record.js.map +1 -1
- package/dist/core/verify/store/commit.js +40 -30
- package/dist/core/verify/store/commit.js.map +1 -1
- package/dist/core/verify/store/render.js +8 -4
- package/dist/core/verify/store/render.js.map +1 -1
- package/dist/core/vocabulary/issue.js +4 -0
- package/dist/core/vocabulary/issue.js.map +1 -1
- package/dist/core/vocabulary/maturity.js +75 -4
- package/dist/core/vocabulary/maturity.js.map +1 -1
- package/dist/core/vocabulary/report.js +16 -1
- package/dist/core/vocabulary/report.js.map +1 -1
- package/examples/README.md +54 -11
- package/examples/docs/architecture/landscape.likec4 +62 -6
- package/examples/docs/architecture/services.likec4 +70 -0
- package/examples/docs/architecture/subsystems.likec4 +7 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +16 -7
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +4 -1
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
- package/examples/docs/likec4.config.json +0 -1
- package/examples/docs/services/checkout-web/model.likec4 +39 -56
- package/examples/docs/services/order-service/arch.spec.md +13 -6
- package/examples/docs/services/order-service/asyncapi.yaml +3 -2
- package/examples/docs/services/order-service/model.likec4 +58 -70
- package/examples/docs/services/payment-service/arch.spec.md +7 -4
- package/examples/docs/services/payment-service/model.likec4 +38 -37
- package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
- package/examples/docs/services/platform/identity-service/model.likec4 +35 -37
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
- package/examples/docs/services/platform/notification-service/health.yaml +8 -3
- package/examples/docs/services/platform/notification-service/model.likec4 +43 -64
- package/package.json +1 -1
- package/dist/commands/validate/checks/vocabulary.js +0 -31
- package/dist/commands/validate/checks/vocabulary.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/capability-tag.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/steps.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/usecases.js.map +0 -1
- package/dist/core/agent/agents-md/artifacts.js +0 -220
- package/dist/core/agent/agents-md/artifacts.js.map +0 -1
- package/dist/core/agent/agents-md/cycle.js +0 -165
- package/dist/core/agent/agents-md/cycle.js.map +0 -1
- package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
- package/dist/core/agent/agents-md/spine.js +0 -40
- package/dist/core/agent/agents-md/spine.js.map +0 -1
- package/dist/core/coherence/events/merged.js +0 -40
- package/dist/core/coherence/events/merged.js.map +0 -1
- package/dist/core/diff/current-state.js +0 -96
- package/dist/core/diff/current-state.js.map +0 -1
- package/dist/core/diff/victims.js +0 -247
- package/dist/core/diff/victims.js.map +0 -1
- package/dist/core/repo/tree/views.js +0 -172
- package/dist/core/repo/tree/views.js.map +0 -1
- package/dist/core/staging/snapshot.js.map +0 -1
- package/dist/core/verify/file.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exclude.js","sourceRoot":"","sources":["../../../../src/commands/subsystem/txn/exclude.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The ROOT `likec4.config.json`'s `exclude` list, as `loam subsystem sync`\n * derives it from the shapes on disk.\n *\n * It sits beside `./views.ts` for that module's reason and by the same seam:\n * both answer \"what should this renderer-only file say, given the tree?\", both\n * are pure derivations one command writes, and keeping them together is what\n * stops the writer and the grader spelling one rule twice. The difference is\n * ownership, and it is stated in `core/c4/service-model/renderer.ts`: every byte\n * of the generated views file is loam's, while this file is the team's and loam\n * maintains exactly the `services/` entries in it. What an entry COVERS is\n * `core/c4/root-project/exclude.ts`'s question, asked of the directory the entry\n * names rather than of its spelling.\n *\n * It is a module rather than three functions in `../sync.ts` because that file\n * reached its line limit carrying them, and this is the phase boundary inside\n * it: `sync.ts` is the lock, the transaction and the report; this is one of the\n * three things it decides to write.\n */\nimport { readFile } from \"node:fs/promises\";\nimport { excludingEntry, parseRootProject, readRootExclude } from \"../../../core/c4/root-project/exclude.js\";\nimport { standaloneExclude } from \"../../../core/c4/service-model/renderer.js\";\nimport { serviceTreePath, type DocsDir } from \"../../../core/kernel/ids/dirs.js\";\nimport { rootProjectPath } from \"../../../core/repo/paths.js\";\nimport type { SurveyedModel } from \"../../../core/repo/tree/render/projects.js\";\nimport type { WalkedService } from \"../../../core/repo/tree/walk.js\";\nimport { planWrite, type PlannedWrite } from \"../../../core/staging/writes.js\";\n\n/** What one sync did to the ROOT project's `exclude` list. */\nexport interface ExcludePlan {\n /** Whether this run rewrites the list. */\n updated: boolean;\n /** The list as it stands after this run — the current one when nothing changed. */\n entries: string[];\n added: string[];\n removed: string[];\n /** The rewrite, staged with everything else. Null when nothing is owed. */\n write: PlannedWrite | null;\n /** The root file exists and loam could not read an `exclude` list out of it — reported, never rewritten. */\n unreadable: boolean;\n}\n\n/** The answer for a run that has no root file to read, and the shape every other arm fills. */\nexport const NO_EXCLUDE: ExcludePlan = {\n updated: false,\n entries: [],\n added: [],\n removed: [],\n write: null,\n unreadable: false,\n};\n\n/**\n * The root project's `exclude` list, recomputed from the shapes on disk.\n *\n * WHAT MAKES THIS SAFE TO RUN ON EVERY SYNC is the split `standaloneExclude`\n * enforces: the `services/` half of the list is loam's and every other entry is\n * the team's, kept in order. The scaffold's node_modules glob, `features/**`, a\n * team's own `drafts/**` all survive; only the entries that decide whether a\n * model is renderable are derived. A standalone model MUST be excluded (inside\n * the root project every kind it declares is a duplicate blamed on the map as\n * well) and an extending model must NOT be (the root project is the only place\n * it parses), so a service that migrates from one shape to the other has its\n * entry added or dropped on the next sync instead of quietly blanking a project.\n *\n * THE GATE keeps an old repository untouched. A fleet whose models all stand\n * alone and whose root already says `services/**` is already correct, and\n * rewriting it into one entry per service would be a diff with no fact behind\n * it — so the rewrite happens only when at least one model extends the map (the\n * blanket exclusion is then wrong) or some standalone model is not covered at\n * all (the renderer is merging it into the map right now). Comparing the parsed\n * ARRAYS rather than the bytes is the second half of the same rule: a file whose\n * `exclude` already says what this run would write is left exactly as the team\n * formatted it.\n *\n * A root config loam cannot read an `exclude` list out of is REPORTED and never\n * rewritten. Guessing at the JSON a team hand-wrote is how a writer destroys a\n * file it did not understand.\n */\nexport async function planExclude(\n docsDir: DocsDir,\n services: readonly WalkedService[],\n models: readonly SurveyedModel<WalkedService>[],\n): Promise<ExcludePlan> {\n const current = await readRootExclude(docsDir);\n if (current === null) return { ...NO_EXCLUDE, unreadable: true };\n const standalone = models.filter((m) => m.standalone).map((m) => serviceTreePath(m.service));\n // Both halves of the shape scan travel, not just the standalone one: an entry\n // is loam's to take back either because loam wrote it (a tree the enumeration\n // returns) or because it HIDES a model that only parses in the root project,\n // and only the extending list can answer the second question. Without it a\n // subsystem-wide `services/platform/**` survived every sync while\n // `service.model-excluded` named that same sync as the repair.\n const extending = models.filter((m) => !m.standalone).map((m) => serviceTreePath(m.service));\n const wanted = standaloneExclude(current, {\n standalone,\n extending,\n enumerated: services.map((svc) => serviceTreePath(svc)),\n });\n const uncovered = standalone.some((tree) => excludingEntry(current, tree) === null);\n if (extending.length === 0 && !uncovered) return { ...NO_EXCLUDE, entries: [...current] };\n if (current.length === wanted.length && current.every((entry, i) => entry === wanted[i])) {\n return { ...NO_EXCLUDE, entries: wanted };\n }\n const bytes = await rewrittenRootProject(docsDir, wanted);\n if (bytes === null) return { ...NO_EXCLUDE, entries: [...current], unreadable: true };\n return {\n updated: true,\n entries: wanted,\n added: wanted.filter((entry) => !current.includes(entry)),\n removed: current.filter((entry) => !wanted.includes(entry)),\n // `planWrite` decides create-vs-overwrite from the filesystem, so the root\n // file — which by definition already exists here — is staged as an\n // OVERWRITE, and `swapStaged` compares it against its pre-image immediately\n // before the rename: a team member editing the same file during the sync\n // stops the commit instead of having their bytes buried.\n write: planWrite(rootProjectPath(docsDir), bytes),\n unreadable: false,\n };\n}\n\n/**\n * The root project file with its `exclude` replaced and NOTHING else touched —\n * every other key kept, in the order the team wrote them, re-serialised as\n * 2-space JSON with a trailing newline (`core/docs.ts`'s own form, so a\n * scaffolded file round-trips byte for byte).\n *\n * Null when the file stopped being a JSON object between `readRootExclude` and\n * here, which is a concurrent edit rather than a state loam may write over.\n */\nasync function rewrittenRootProject(docsDir: DocsDir, exclude: readonly string[]): Promise<string | null> {\n let text: string;\n try {\n text = await readFile(rootProjectPath(docsDir), \"utf8\");\n } catch {\n // Unreadable is not \"excludes nothing\": the caller reports it and writes\n // nothing at all.\n return null;\n }\n // The SAME parse the grader read the list with — `parseRootProject`, which\n // tolerates the byte-order mark PowerShell's `Out-File` writes. Two parses\n // would mean a run that read an `exclude` here and then declared the file\n // unreadable at the write, which is exactly what a BOM produced before\n // (re-verification 2026-09-04, area C item 3). Re-read rather than carried:\n // the point of this read is that it happens immediately before the swap.\n const parsed = parseRootProject(text);\n if (parsed === null) return null;\n return `${JSON.stringify({ ...parsed, exclude: [...exclude] }, null, 2)}\\n`;\n}\n"]}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The link half of `subsystem move` and `rename`: every relative markdown link
|
|
3
|
+
* the renames would break, re-expressed so it reaches the same file.
|
|
4
|
+
*
|
|
5
|
+
* THE DEFECT THIS CLOSES. A move is a directory rename, and a relative link is
|
|
6
|
+
* a route from one directory to another. `services/orders/spec.md` citing
|
|
7
|
+
* `../../glossary/order.md` is two directories below the docs root; moved into
|
|
8
|
+
* `services/commerce/orders/` it is three, and the same text names
|
|
9
|
+
* `services/glossary/order.md`, which is nothing. The move reported success,
|
|
10
|
+
* staged the renames in git, and the next `validate --all` failed
|
|
11
|
+
* `link.unresolved` on every moved document that cited anything outside its
|
|
12
|
+
* own directory — the "failing between two commits" state the commit window
|
|
13
|
+
* exists to refuse. The same rename breaks the other direction too: a
|
|
14
|
+
* capability document or a glossary term citing `services/orders/spec.md`
|
|
15
|
+
* now points where nothing is.
|
|
16
|
+
*
|
|
17
|
+
* SO BOTH DIRECTIONS ARE REWRITTEN, with the one rule archive's merge uses
|
|
18
|
+
* (`core/links/parse.ts`'s `rebaseLinks`): the target is unchanged, only the
|
|
19
|
+
* route to it, and a link whose text still reaches its target from the new
|
|
20
|
+
* place keeps its exact spelling.
|
|
21
|
+
*
|
|
22
|
+
* - Every markdown file under a moved directory, whatever its name — a runbook,
|
|
23
|
+
* an ADR, a subsystem's own notes: the rename moves them all, so it owes them
|
|
24
|
+
* all the same correction. Written at the OLD path, because the transaction
|
|
25
|
+
* swaps files before it renames directories (`core/staging/txn/`), so the
|
|
26
|
+
* rewritten bytes travel with the rename.
|
|
27
|
+
* - Every other document in the link corpus (`core/links/corpus.ts`: the fleet's
|
|
28
|
+
* own documents, every service's, every in-flight feature's) whose links
|
|
29
|
+
* reach INTO a moved directory. Archived features are not in it, for the
|
|
30
|
+
* corpus's own reason: their links describe the tree as it was, and nothing
|
|
31
|
+
* grades them.
|
|
32
|
+
*
|
|
33
|
+
* A document that cannot be decoded is left as it is: rewriting means writing
|
|
34
|
+
* the whole file back, and `link.unreadable` already names it.
|
|
35
|
+
*/
|
|
36
|
+
import { dirname, resolve } from "node:path";
|
|
37
|
+
import { allAuthoredDocuments, movedMarkdown } from "../../../core/links/corpus.js";
|
|
38
|
+
import { rebaseLinks } from "../../../core/links/parse.js";
|
|
39
|
+
import { FleetContext } from "../../../core/fleet-context.js";
|
|
40
|
+
import { movedUnderVouch, parseFrontmatter } from "../../../core/document/frontmatter.js";
|
|
41
|
+
import { parseRequirements } from "../../../core/document/parse.js";
|
|
42
|
+
import { requirementDigest } from "../../../core/document/spec.js";
|
|
43
|
+
import { repoPath } from "../../../core/envelope/json.js";
|
|
44
|
+
import { featuresDir } from "../../../core/repo/paths.js";
|
|
45
|
+
import { inOrder } from "../../../core/kernel/concurrency.js";
|
|
46
|
+
import { acrossRename, isPathInside } from "../../../core/kernel/path-safety.js";
|
|
47
|
+
import { planWrite, readUtf8 } from "../../../core/staging/writes.js";
|
|
48
|
+
export async function movedLinks(docsDir, moves) {
|
|
49
|
+
const retarget = (target) => {
|
|
50
|
+
for (const move of moves) {
|
|
51
|
+
if (isPathInside(move.from, target))
|
|
52
|
+
return acrossRename(target, move.from, move.to);
|
|
53
|
+
}
|
|
54
|
+
return target;
|
|
55
|
+
};
|
|
56
|
+
const out = { writes: [], relinked: [], notices: [] };
|
|
57
|
+
// The moved documents first, then every other document the corpus names —
|
|
58
|
+
// one list, deduplicated in order, because the order is what `relinked`
|
|
59
|
+
// reports and a person reads it top to bottom.
|
|
60
|
+
const candidates = [];
|
|
61
|
+
for (const move of moves)
|
|
62
|
+
candidates.push(...(await movedMarkdown(move.from)));
|
|
63
|
+
try {
|
|
64
|
+
const corpus = await allAuthoredDocuments(docsDir, new FleetContext());
|
|
65
|
+
candidates.push(...corpus.filter((path) => !moves.some((move) => isPathInside(move.from, path))));
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
// The corpus walk enumerates every service and feature; a tree it cannot
|
|
69
|
+
// walk is one `validate` will diagnose, and the moved documents are still
|
|
70
|
+
// corrected. A move is not refused over a question it only asks to be
|
|
71
|
+
// helpful — but it does not pretend the question was answered either.
|
|
72
|
+
out.notices.push(`links INTO the moved directories were not checked — the fleet's documents could not be walked (${err instanceof Error ? err.message : String(err)}); ` +
|
|
73
|
+
"`loam validate --all` names any that broke.");
|
|
74
|
+
}
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
const unique = [];
|
|
77
|
+
for (const path of candidates) {
|
|
78
|
+
if (seen.has(resolve(path)))
|
|
79
|
+
continue;
|
|
80
|
+
seen.add(resolve(path));
|
|
81
|
+
unique.push(path);
|
|
82
|
+
}
|
|
83
|
+
// Read and rewrite with bounded concurrency — the whole corpus is read
|
|
84
|
+
// before the commit window can land — and apply in input order (`inOrder`).
|
|
85
|
+
const rewritten = await inOrder(unique, async (path) => {
|
|
86
|
+
let text;
|
|
87
|
+
try {
|
|
88
|
+
text = await readUtf8(path);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Absent (the corpus names every slot a service MAY fill — most have no
|
|
92
|
+
// runbook) or undecodable: either way there are no links to rewrite
|
|
93
|
+
// that loam could write back, and `link.unreadable` names the second.
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const after = retarget(path);
|
|
97
|
+
const next = rebaseLinks(text, { from: dirname(path), to: dirname(after), retarget });
|
|
98
|
+
return next === text ? null : { path, after, text, next };
|
|
99
|
+
});
|
|
100
|
+
for (const one of rewritten) {
|
|
101
|
+
if (one === null)
|
|
102
|
+
continue;
|
|
103
|
+
const { path, after, text, next } = one;
|
|
104
|
+
out.writes.push(planWrite(path, next));
|
|
105
|
+
out.relinked.push(after);
|
|
106
|
+
const where = repoPath(docsDir, after);
|
|
107
|
+
if (movedUnderVouch(parseFrontmatter(next), next) && !movedUnderVouch(parseFrontmatter(text), text)) {
|
|
108
|
+
out.notices.push(`${where} is vouched, and this move rewrote links in it — content.stale follows until its owner re-vouches.`);
|
|
109
|
+
}
|
|
110
|
+
// Living documents only: a `Based-On:` pin holds the digest of a LIVING
|
|
111
|
+
// requirement, so a feature's own delta text moving pins nothing.
|
|
112
|
+
const pinned = (md) => parseRequirements(md).map(requirementDigest).join(",");
|
|
113
|
+
if (!isPathInside(featuresDir(docsDir), path) && pinned(next) !== pinned(text)) {
|
|
114
|
+
out.notices.push(`${where}: links this move rewrote sit inside requirements, so a feature in flight that pins one with Based-On: ` +
|
|
115
|
+
"reports delta.baseline-stale until `loam rebase` re-pins it.");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The rewritten documents that do NOT ride a rename — the ones a move touches
|
|
122
|
+
* outside the directories it names, which its uncommitted-work refusal and its
|
|
123
|
+
* git staging have to be told about by path.
|
|
124
|
+
*/
|
|
125
|
+
export function outside(links, moves) {
|
|
126
|
+
return links.writes.map((w) => w.path).filter((path) => !moves.some((move) => isPathInside(move.from, path)));
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=links.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"links.js","sourceRoot":"","sources":["../../../../src/commands/subsystem/txn/links.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAC1F,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAqB,MAAM,iCAAiC,CAAC;AA2BzF,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAgB,EAAE,KAA+B;IAChF,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAU,EAAE;QAC1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;gBAAE,OAAO,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACvF,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IACF,MAAM,GAAG,GAAe,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAClE,0EAA0E;IAC1E,wEAAwE;IACxE,+CAA+C;IAC/C,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC/E,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,EAAE,IAAI,YAAY,EAAE,CAAC,CAAC;QACvE,UAAU,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACpG,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,yEAAyE;QACzE,0EAA0E;QAC1E,sEAAsE;QACtE,sEAAsE;QACtE,GAAG,CAAC,OAAO,CAAC,IAAI,CACd,kGAAkG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK;YACrJ,6CAA6C,CAChD,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAAE,SAAS;QACtC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IACD,uEAAuE;IACvE,4EAA4E;IAC5E,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACrD,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,wEAAwE;YACxE,oEAAoE;YACpE,sEAAsE;YACtE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QACtF,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC5D,CAAC,CAAC,CAAC;IACH,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,IAAI,GAAG,KAAK,IAAI;YAAE,SAAS;QAC3B,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC;QACxC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACvC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACvC,IAAI,eAAe,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC;YACpG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,oGAAoG,CAAC,CAAC;QACjI,CAAC;QACD,wEAAwE;QACxE,kEAAkE;QAClE,MAAM,MAAM,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9F,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/E,GAAG,CAAC,OAAO,CAAC,IAAI,CACd,GAAG,KAAK,yGAAyG;gBAC/G,8DAA8D,CACjE,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,KAAiB,EAAE,KAA+B;IACxE,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAChH,CAAC","sourcesContent":["/**\n * The link half of `subsystem move` and `rename`: every relative markdown link\n * the renames would break, re-expressed so it reaches the same file.\n *\n * THE DEFECT THIS CLOSES. A move is a directory rename, and a relative link is\n * a route from one directory to another. `services/orders/spec.md` citing\n * `../../glossary/order.md` is two directories below the docs root; moved into\n * `services/commerce/orders/` it is three, and the same text names\n * `services/glossary/order.md`, which is nothing. The move reported success,\n * staged the renames in git, and the next `validate --all` failed\n * `link.unresolved` on every moved document that cited anything outside its\n * own directory — the \"failing between two commits\" state the commit window\n * exists to refuse. The same rename breaks the other direction too: a\n * capability document or a glossary term citing `services/orders/spec.md`\n * now points where nothing is.\n *\n * SO BOTH DIRECTIONS ARE REWRITTEN, with the one rule archive's merge uses\n * (`core/links/parse.ts`'s `rebaseLinks`): the target is unchanged, only the\n * route to it, and a link whose text still reaches its target from the new\n * place keeps its exact spelling.\n *\n * - Every markdown file under a moved directory, whatever its name — a runbook,\n * an ADR, a subsystem's own notes: the rename moves them all, so it owes them\n * all the same correction. Written at the OLD path, because the transaction\n * swaps files before it renames directories (`core/staging/txn/`), so the\n * rewritten bytes travel with the rename.\n * - Every other document in the link corpus (`core/links/corpus.ts`: the fleet's\n * own documents, every service's, every in-flight feature's) whose links\n * reach INTO a moved directory. Archived features are not in it, for the\n * corpus's own reason: their links describe the tree as it was, and nothing\n * grades them.\n *\n * A document that cannot be decoded is left as it is: rewriting means writing\n * the whole file back, and `link.unreadable` already names it.\n */\nimport { dirname, resolve } from \"node:path\";\nimport { allAuthoredDocuments, movedMarkdown } from \"../../../core/links/corpus.js\";\nimport { rebaseLinks } from \"../../../core/links/parse.js\";\nimport { FleetContext } from \"../../../core/fleet-context.js\";\nimport { movedUnderVouch, parseFrontmatter } from \"../../../core/document/frontmatter.js\";\nimport { parseRequirements } from \"../../../core/document/parse.js\";\nimport { requirementDigest } from \"../../../core/document/spec.js\";\nimport { repoPath } from \"../../../core/envelope/json.js\";\nimport { featuresDir } from \"../../../core/repo/paths.js\";\nimport { inOrder } from \"../../../core/kernel/concurrency.js\";\nimport { acrossRename, isPathInside } from \"../../../core/kernel/path-safety.js\";\nimport { planWrite, readUtf8, type PlannedWrite } from \"../../../core/staging/writes.js\";\nimport type { DocsDir } from \"../../../core/kernel/ids/dirs.js\";\n\n/** One directory rename, absolute paths. */\nexport interface DirectoryMove {\n from: string;\n to: string;\n}\n\n/** The link rewrites a set of renames owes, and where each rewritten document will be read from. */\nexport interface MovedLinks {\n /** Planned at each document's CURRENT path — the swap lands before the rename carries it. */\n writes: PlannedWrite[];\n /** Each rewritten document's path once the move has landed, absolute, in the order written. */\n relinked: string[];\n /**\n * The notes a person owes a reading of. A rewritten route is still a\n * changed byte: under a `content_digest` it is `content.stale` until the\n * owner re-vouches, and inside a requirement it moves the digest a\n * `Based-On:` pin holds, so a feature in flight that pins it is\n * `delta.baseline-stale` until it is rebased. Neither is softened — the\n * archive merge reports the first the same way (`revouchOwed`) — but both\n * are said here, by path, rather than discovered by the next gate.\n */\n notices: string[];\n}\n\nexport async function movedLinks(docsDir: DocsDir, moves: readonly DirectoryMove[]): Promise<MovedLinks> {\n const retarget = (target: string): string => {\n for (const move of moves) {\n if (isPathInside(move.from, target)) return acrossRename(target, move.from, move.to);\n }\n return target;\n };\n const out: MovedLinks = { writes: [], relinked: [], notices: [] };\n // The moved documents first, then every other document the corpus names —\n // one list, deduplicated in order, because the order is what `relinked`\n // reports and a person reads it top to bottom.\n const candidates: string[] = [];\n for (const move of moves) candidates.push(...(await movedMarkdown(move.from)));\n try {\n const corpus = await allAuthoredDocuments(docsDir, new FleetContext());\n candidates.push(...corpus.filter((path) => !moves.some((move) => isPathInside(move.from, path))));\n } catch (err) {\n // The corpus walk enumerates every service and feature; a tree it cannot\n // walk is one `validate` will diagnose, and the moved documents are still\n // corrected. A move is not refused over a question it only asks to be\n // helpful — but it does not pretend the question was answered either.\n out.notices.push(\n `links INTO the moved directories were not checked — the fleet's documents could not be walked (${err instanceof Error ? err.message : String(err)}); ` +\n \"`loam validate --all` names any that broke.\",\n );\n }\n const seen = new Set<string>();\n const unique: string[] = [];\n for (const path of candidates) {\n if (seen.has(resolve(path))) continue;\n seen.add(resolve(path));\n unique.push(path);\n }\n // Read and rewrite with bounded concurrency — the whole corpus is read\n // before the commit window can land — and apply in input order (`inOrder`).\n const rewritten = await inOrder(unique, async (path) => {\n let text: string;\n try {\n text = await readUtf8(path);\n } catch {\n // Absent (the corpus names every slot a service MAY fill — most have no\n // runbook) or undecodable: either way there are no links to rewrite\n // that loam could write back, and `link.unreadable` names the second.\n return null;\n }\n const after = retarget(path);\n const next = rebaseLinks(text, { from: dirname(path), to: dirname(after), retarget });\n return next === text ? null : { path, after, text, next };\n });\n for (const one of rewritten) {\n if (one === null) continue;\n const { path, after, text, next } = one;\n out.writes.push(planWrite(path, next));\n out.relinked.push(after);\n const where = repoPath(docsDir, after);\n if (movedUnderVouch(parseFrontmatter(next), next) && !movedUnderVouch(parseFrontmatter(text), text)) {\n out.notices.push(`${where} is vouched, and this move rewrote links in it — content.stale follows until its owner re-vouches.`);\n }\n // Living documents only: a `Based-On:` pin holds the digest of a LIVING\n // requirement, so a feature's own delta text moving pins nothing.\n const pinned = (md: string): string => parseRequirements(md).map(requirementDigest).join(\",\");\n if (!isPathInside(featuresDir(docsDir), path) && pinned(next) !== pinned(text)) {\n out.notices.push(\n `${where}: links this move rewrote sit inside requirements, so a feature in flight that pins one with Based-On: ` +\n \"reports delta.baseline-stale until `loam rebase` re-pins it.\",\n );\n }\n }\n return out;\n}\n\n/**\n * The rewritten documents that do NOT ride a rename — the ones a move touches\n * outside the directories it names, which its uncommitted-work refusal and its\n * git staging have to be told about by path.\n */\nexport function outside(links: MovedLinks, moves: readonly DirectoryMove[]): string[] {\n return links.writes.map((w) => w.path).filter((path) => !moves.some((move) => isPathInside(move.from, path)));\n}\n"]}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What one `loam subsystem sync` SAYS it did — the `--json` envelope and the
|
|
3
|
+
* human lines, in one place.
|
|
4
|
+
*
|
|
5
|
+
* It sits beside `./views.ts` and `./exclude.ts` because it is the third answer
|
|
6
|
+
* about the same three files, and it moved out of `../sync.ts` for that file's
|
|
7
|
+
* standing reason: `sync.ts` is the lock, the transaction and the plan, and it
|
|
8
|
+
* reached the 400-line limit carrying the output too. Composing a report is not
|
|
9
|
+
* a phase of the commit, so nothing here reads the disk or decides anything — a
|
|
10
|
+
* caller hands over what happened and this spells it.
|
|
11
|
+
*/
|
|
12
|
+
import { emitJson } from "../../../core/envelope/json.js";
|
|
13
|
+
import { authoredRefusal } from "../../../core/repo/tree/render/service/header.js";
|
|
14
|
+
import { LANDSCAPE_UNREADABLE_NOTE } from "./views.js";
|
|
15
|
+
/** The second generated file's name, spelled once here so the key and the sentence cannot drift. */
|
|
16
|
+
const SERVICE_VIEWS = "architecture/services.likec4";
|
|
17
|
+
export function reportSync(json, out) {
|
|
18
|
+
// One reason today, and it is exactly the `action` it explains — spelled as a
|
|
19
|
+
// record so a second cause is an added value rather than a re-read of the
|
|
20
|
+
// sentence a person sees.
|
|
21
|
+
const blocked = out.action === "blocked" ? { reason: "landscape-invalid" } : null;
|
|
22
|
+
if (json) {
|
|
23
|
+
emitJson({
|
|
24
|
+
command: "subsystem",
|
|
25
|
+
path: "architecture/subsystems.likec4",
|
|
26
|
+
action: out.action,
|
|
27
|
+
subsystems: out.subsystems,
|
|
28
|
+
// ADDITIVE, and emitted on every run including the untouched one: a
|
|
29
|
+
// consumer must be able to read what happened to the second generated file
|
|
30
|
+
// without branching on whether this run happened to change it. `path` and
|
|
31
|
+
// `action` keep their frozen meaning — the subsystem file — so nothing
|
|
32
|
+
// reading them sees a new one.
|
|
33
|
+
serviceViews: { path: SERVICE_VIEWS, action: out.serviceViews },
|
|
34
|
+
...(blocked === null ? {} : { blocked }),
|
|
35
|
+
...(out.recovered === null ? {} : { recovered: out.recovered }),
|
|
36
|
+
projects: {
|
|
37
|
+
root: out.projects.root,
|
|
38
|
+
created: out.projects.created,
|
|
39
|
+
removed: out.projects.removed,
|
|
40
|
+
current: out.projects.current,
|
|
41
|
+
// Additive, and emitted in every mode including the untouched one: a
|
|
42
|
+
// consumer must be able to read what the root project now excludes
|
|
43
|
+
// without branching on whether this run happened to change it.
|
|
44
|
+
//
|
|
45
|
+
// `unreadable` travels with it because `entries: []` alone collapses the
|
|
46
|
+
// two answers `readRootExclude` insists must stay apart — "the file
|
|
47
|
+
// excludes nothing" and "loam could not read the file" are opposite
|
|
48
|
+
// facts about what the renderer will load, and the text view had the
|
|
49
|
+
// distinction while `--json` did not (verification 2026-09-04, review C).
|
|
50
|
+
exclude: {
|
|
51
|
+
updated: out.projects.exclude.updated,
|
|
52
|
+
entries: out.projects.exclude.entries,
|
|
53
|
+
added: out.projects.exclude.added,
|
|
54
|
+
removed: out.projects.exclude.removed,
|
|
55
|
+
unreadable: out.projects.exclude.unreadable,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (out.recovered !== null && out.recovered.outcome !== "consistent") {
|
|
62
|
+
console.log(`note: recovered an interrupted \`loam ${out.recovered.command}\` commit first (${out.recovered.outcome}).`);
|
|
63
|
+
}
|
|
64
|
+
console.log(views(out));
|
|
65
|
+
serviceViews(out.serviceViews);
|
|
66
|
+
// Owed on BOTH arms: the run that declined to rewrite an existing file, and
|
|
67
|
+
// the run that wrote the tolerant shape because there was none to protect.
|
|
68
|
+
if (out.mapUnreadable)
|
|
69
|
+
console.log(LANDSCAPE_UNREADABLE_NOTE);
|
|
70
|
+
projects(out.projects);
|
|
71
|
+
exclude(out.projects);
|
|
72
|
+
}
|
|
73
|
+
/** The one line about the generated views file. */
|
|
74
|
+
function views(out) {
|
|
75
|
+
// "nothing to write" is a claim about the WHOLE run, and it is false the moment
|
|
76
|
+
// any of this verb's FOUR writers landed something beside a current subsystem
|
|
77
|
+
// views file: the per-service views file, a project file created, one removed,
|
|
78
|
+
// or the root `exclude` rewritten. The exclude arm was missed when it was
|
|
79
|
+
// added, so the tail contradicted the very next line of output (verification
|
|
80
|
+
// 2026-09-04, review C) — and the per-service file is the same trap one file
|
|
81
|
+
// over, which is why it is in the same expression rather than a second one.
|
|
82
|
+
const quiet = out.serviceViews === "current" &&
|
|
83
|
+
out.projects.created.length === 0 &&
|
|
84
|
+
out.projects.removed.length === 0 &&
|
|
85
|
+
!out.projects.exclude.updated;
|
|
86
|
+
const sentence = {
|
|
87
|
+
current: `architecture/subsystems.likec4 is current (${out.subsystems} subsystem(s))${quiet ? " — nothing to write." : "."}`,
|
|
88
|
+
created: `wrote architecture/subsystems.likec4 — ${out.subsystems} subsystem view(s).`,
|
|
89
|
+
updated: `updated architecture/subsystems.likec4 — ${out.subsystems} subsystem view(s).`,
|
|
90
|
+
removed: `removed architecture/subsystems.likec4 — the tree has no subsystems, so the generated file must be absent.`,
|
|
91
|
+
blocked: "architecture/subsystems.likec4 left as it is — architecture/ does not parse as one project, so the " +
|
|
92
|
+
"render's element join is the landscape file's alone (a use-case document that binds an element of its " +
|
|
93
|
+
"own is not in it), and rewriting the file would take its `include` lines with it.",
|
|
94
|
+
refused: authoredRefusal("architecture/subsystems.likec4"),
|
|
95
|
+
};
|
|
96
|
+
return sentence[out.action];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The one line about `architecture/services.likec4`, printed on every answer but
|
|
100
|
+
* `current` — so on the two that left the file alone (`blocked`, `refused`) as
|
|
101
|
+
* well as the three that changed it. "Nothing happened to it, and here is why"
|
|
102
|
+
* is exactly the sentence a person needs; only "nothing happened to it because
|
|
103
|
+
* nothing needed to" is silence worth keeping.
|
|
104
|
+
*
|
|
105
|
+
* SILENT WHEN CURRENT, and that is the difference from the subsystem file's line
|
|
106
|
+
* above: that one is the sentence this command has always ended on and a person
|
|
107
|
+
* reads it as "the run happened", while a second unconditional line about a file
|
|
108
|
+
* nothing touched is noise on every run in a fleet that is already in order. The
|
|
109
|
+
* `--json` key is unconditional for the opposite reason — a consumer branches on
|
|
110
|
+
* a value, not on a line's presence.
|
|
111
|
+
*
|
|
112
|
+
* No view COUNT here, deliberately. The subsystem line counts subsystems because
|
|
113
|
+
* the tree answers that without reading anything; the per-service file draws
|
|
114
|
+
* only the services the MAP resolves, and the honest count is the render's, not
|
|
115
|
+
* the tree's. loam never reads a generated file's content (docs/DESIGN.md rule
|
|
116
|
+
* 26), so counting the views in it is the one place the count could come from
|
|
117
|
+
* and the one place it may not.
|
|
118
|
+
*/
|
|
119
|
+
function serviceViews(action) {
|
|
120
|
+
if (action === "current")
|
|
121
|
+
return;
|
|
122
|
+
const sentence = {
|
|
123
|
+
created: `wrote ${SERVICE_VIEWS} — one overview view per service the fleet map draws.`,
|
|
124
|
+
updated: `updated ${SERVICE_VIEWS} — one overview view per service the fleet map draws.`,
|
|
125
|
+
removed: `removed ${SERVICE_VIEWS} — the fleet map draws none of the services under services/, so the generated file must be absent.`,
|
|
126
|
+
blocked: `${SERVICE_VIEWS} left as it is — architecture/ does not parse as one project, so no service resolves to a ` +
|
|
127
|
+
"map element and the render would have emptied the file rather than improved it.",
|
|
128
|
+
refused: authoredRefusal(SERVICE_VIEWS),
|
|
129
|
+
};
|
|
130
|
+
console.log(sentence[action]);
|
|
131
|
+
}
|
|
132
|
+
/** The per-service project files this run created and removed. */
|
|
133
|
+
function projects(out) {
|
|
134
|
+
if (out.created.length > 0) {
|
|
135
|
+
console.log(`wrote ${out.created.length} services/<…>/likec4.config.json — one LikeC4 project per service model whose ` +
|
|
136
|
+
"model stands alone (an existing file is yours and is never rewritten; commit the new ones before a " +
|
|
137
|
+
"`loam subsystem move`, which refuses over untracked paths). With more than one project, " +
|
|
138
|
+
"likec4 validate at the docs root needs --project <name>; build and export take every project.");
|
|
139
|
+
}
|
|
140
|
+
// Named one per line: this is a DELETE of a file a team may have written, and
|
|
141
|
+
// a count would leave a reader nothing to check against their own diff.
|
|
142
|
+
for (const path of out.removed)
|
|
143
|
+
console.log(`removed ${path}`);
|
|
144
|
+
if (out.removed.length > 0) {
|
|
145
|
+
console.log("— that model extends the fleet map, and a project file beside it registers a second renderer project " +
|
|
146
|
+
"rooted at the service directory: `likec4 validate .` then refuses without `--project`, and wherever " +
|
|
147
|
+
"that project claims the model it loads it alone, where the map's kinds are not, and the fleet project " +
|
|
148
|
+
"loses the service's interior. This is what `service.likec4-config-stray` names.");
|
|
149
|
+
}
|
|
150
|
+
if (!out.root && out.modelled > 0) {
|
|
151
|
+
console.log("note: no likec4.config.json at the docs root, so no service project files were written — " +
|
|
152
|
+
"`loam doctor` prints the root file.");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/** The root project's `exclude`, and the one state loam refuses to touch. */
|
|
156
|
+
function exclude(out) {
|
|
157
|
+
const plan = out.exclude;
|
|
158
|
+
if (plan.updated) {
|
|
159
|
+
// Named entries rather than a count: this line is the whole record of a
|
|
160
|
+
// rewrite to a file the team owns, and "updated the exclude list" gives a
|
|
161
|
+
// reader nothing to check against their own diff.
|
|
162
|
+
const parts = [
|
|
163
|
+
...(plan.added.length > 0 ? [`+${plan.added.join(" +")}`] : []),
|
|
164
|
+
...(plan.removed.length > 0 ? [`-${plan.removed.join(" -")}`] : []),
|
|
165
|
+
];
|
|
166
|
+
console.log(`rewrote likec4.config.json's \`exclude\` (${parts.join(" ")}) — the root project excludes exactly the ` +
|
|
167
|
+
"models that stand alone; a model that extends the fleet map renders from the docs root and must not be excluded.");
|
|
168
|
+
}
|
|
169
|
+
if (plan.unreadable) {
|
|
170
|
+
console.log("note: likec4.config.json at the docs root is not a JSON object with a string `exclude` list, so it was " +
|
|
171
|
+
"left exactly as it is — loam does not rewrite a project file it cannot read.");
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../../../src/commands/subsystem/txn/report.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What one `loam subsystem sync` SAYS it did — the `--json` envelope and the\n * human lines, in one place.\n *\n * It sits beside `./views.ts` and `./exclude.ts` because it is the third answer\n * about the same three files, and it moved out of `../sync.ts` for that file's\n * standing reason: `sync.ts` is the lock, the transaction and the plan, and it\n * reached the 400-line limit carrying the output too. Composing a report is not\n * a phase of the commit, so nothing here reads the disk or decides anything — a\n * caller hands over what happened and this spells it.\n */\nimport { emitJson } from \"../../../core/envelope/json.js\";\nimport { authoredRefusal } from \"../../../core/repo/tree/render/service/header.js\";\nimport type { CommitRecovery } from \"../../../core/staging/interrupted.js\";\nimport type { ExcludePlan } from \"./exclude.js\";\nimport { LANDSCAPE_UNREADABLE_NOTE } from \"./views.js\";\n\n/**\n * What one sync did to the views file — and ONLY that file; the projects report\n * separately.\n *\n * `blocked` is the fifth answer: the map cannot be read, a generated file\n * already exists, and this run left it exactly as it is. The tolerant render\n * used to run anyway and rewrote a good file down to title and description\n * (verification 2026-09-04, W5). The project half is unaffected and still runs —\n * neither the per-service files nor the root `exclude` depend on the map.\n *\n * `refused` is the sixth, and it is about OWNERSHIP rather than about the map:\n * the file standing at a path loam generates does not open with loam's mark, so\n * it is somebody's authored document and this command will not take it. It is\n * the only action that also sets a non-zero exit code (`../sync.ts` says why),\n * because unlike `blocked` it is not a state any later run clears on its own.\n */\nexport type SyncAction = \"current\" | \"created\" | \"updated\" | \"removed\" | \"blocked\" | \"refused\";\n\n/** The second generated file's name, spelled once here so the key and the sentence cannot drift. */\nconst SERVICE_VIEWS = \"architecture/services.likec4\";\n\n/** Why a run answered `blocked`. One reason today; a key rather than a bare string so a second one is additive. */\ninterface SyncBlocked {\n reason: \"landscape-invalid\";\n}\n\n/** The additive `projects` payload key, and what the text lines are composed from. */\nexport interface ProjectsReport {\n root: boolean;\n /** POSIX paths relative to the DOCS ROOT, written this run, sorted by path. */\n created: string[];\n /**\n * POSIX paths relative to the DOCS ROOT, DELETED this run, sorted by path — a\n * `likec4.config.json` beside a model that extends the map. `[]` rather than\n * absent on a run that removed none, so a consumer reads the key.\n *\n * SORTED BY PATH rather than by service id, which is the order the survey\n * hands them over in: `../sync.ts` sorts both arrays where it spells them, so\n * the `--json` list and the `removed <path>` lines below can never disagree.\n */\n removed: string[];\n current: number;\n modelled: number;\n exclude: ExcludePlan;\n}\n\n/** Everything one run has to say, as the caller knows it. */\nexport interface SyncReport {\n /** `architecture/subsystems.likec4` — and nothing else; the `--json` `action` key is exactly this. */\n action: SyncAction;\n /**\n * `architecture/services.likec4` — the per-service overviews.\n *\n * A field of its own rather than a folded `action`, for the reason the shared\n * finding code carries the path: the two files drift for different reasons and\n * a reader told only that \"the generated views changed\" would have to diff the\n * repo to find out which one. `blocked` reaches it exactly as it reaches the\n * other, and for a sharper reason — with no readable map no service resolves,\n * so the tolerant render is the empty file rather than a poorer one.\n */\n serviceViews: SyncAction;\n subsystems: number;\n recovered: CommitRecovery | null;\n projects: ProjectsReport;\n /** The map could not be read at all — the note is owed whether or not a file was protected. */\n mapUnreadable: boolean;\n}\n\nexport function reportSync(json: boolean, out: SyncReport): void {\n // One reason today, and it is exactly the `action` it explains — spelled as a\n // record so a second cause is an added value rather than a re-read of the\n // sentence a person sees.\n const blocked: SyncBlocked | null = out.action === \"blocked\" ? { reason: \"landscape-invalid\" } : null;\n if (json) {\n emitJson({\n command: \"subsystem\",\n path: \"architecture/subsystems.likec4\",\n action: out.action,\n subsystems: out.subsystems,\n // ADDITIVE, and emitted on every run including the untouched one: a\n // consumer must be able to read what happened to the second generated file\n // without branching on whether this run happened to change it. `path` and\n // `action` keep their frozen meaning — the subsystem file — so nothing\n // reading them sees a new one.\n serviceViews: { path: SERVICE_VIEWS, action: out.serviceViews },\n ...(blocked === null ? {} : { blocked }),\n ...(out.recovered === null ? {} : { recovered: out.recovered }),\n projects: {\n root: out.projects.root,\n created: out.projects.created,\n removed: out.projects.removed,\n current: out.projects.current,\n // Additive, and emitted in every mode including the untouched one: a\n // consumer must be able to read what the root project now excludes\n // without branching on whether this run happened to change it.\n //\n // `unreadable` travels with it because `entries: []` alone collapses the\n // two answers `readRootExclude` insists must stay apart — \"the file\n // excludes nothing\" and \"loam could not read the file\" are opposite\n // facts about what the renderer will load, and the text view had the\n // distinction while `--json` did not (verification 2026-09-04, review C).\n exclude: {\n updated: out.projects.exclude.updated,\n entries: out.projects.exclude.entries,\n added: out.projects.exclude.added,\n removed: out.projects.exclude.removed,\n unreadable: out.projects.exclude.unreadable,\n },\n },\n });\n return;\n }\n if (out.recovered !== null && out.recovered.outcome !== \"consistent\") {\n console.log(\n `note: recovered an interrupted \\`loam ${out.recovered.command}\\` commit first (${out.recovered.outcome}).`,\n );\n }\n console.log(views(out));\n serviceViews(out.serviceViews);\n // Owed on BOTH arms: the run that declined to rewrite an existing file, and\n // the run that wrote the tolerant shape because there was none to protect.\n if (out.mapUnreadable) console.log(LANDSCAPE_UNREADABLE_NOTE);\n projects(out.projects);\n exclude(out.projects);\n}\n\n/** The one line about the generated views file. */\nfunction views(out: SyncReport): string {\n // \"nothing to write\" is a claim about the WHOLE run, and it is false the moment\n // any of this verb's FOUR writers landed something beside a current subsystem\n // views file: the per-service views file, a project file created, one removed,\n // or the root `exclude` rewritten. The exclude arm was missed when it was\n // added, so the tail contradicted the very next line of output (verification\n // 2026-09-04, review C) — and the per-service file is the same trap one file\n // over, which is why it is in the same expression rather than a second one.\n const quiet =\n out.serviceViews === \"current\" &&\n out.projects.created.length === 0 &&\n out.projects.removed.length === 0 &&\n !out.projects.exclude.updated;\n const sentence: Record<SyncAction, string> = {\n current: `architecture/subsystems.likec4 is current (${out.subsystems} subsystem(s))${quiet ? \" — nothing to write.\" : \".\"}`,\n created: `wrote architecture/subsystems.likec4 — ${out.subsystems} subsystem view(s).`,\n updated: `updated architecture/subsystems.likec4 — ${out.subsystems} subsystem view(s).`,\n removed: `removed architecture/subsystems.likec4 — the tree has no subsystems, so the generated file must be absent.`,\n blocked:\n \"architecture/subsystems.likec4 left as it is — architecture/ does not parse as one project, so the \" +\n \"render's element join is the landscape file's alone (a use-case document that binds an element of its \" +\n \"own is not in it), and rewriting the file would take its `include` lines with it.\",\n refused: authoredRefusal(\"architecture/subsystems.likec4\"),\n };\n return sentence[out.action];\n}\n\n/**\n * The one line about `architecture/services.likec4`, printed on every answer but\n * `current` — so on the two that left the file alone (`blocked`, `refused`) as\n * well as the three that changed it. \"Nothing happened to it, and here is why\"\n * is exactly the sentence a person needs; only \"nothing happened to it because\n * nothing needed to\" is silence worth keeping.\n *\n * SILENT WHEN CURRENT, and that is the difference from the subsystem file's line\n * above: that one is the sentence this command has always ended on and a person\n * reads it as \"the run happened\", while a second unconditional line about a file\n * nothing touched is noise on every run in a fleet that is already in order. The\n * `--json` key is unconditional for the opposite reason — a consumer branches on\n * a value, not on a line's presence.\n *\n * No view COUNT here, deliberately. The subsystem line counts subsystems because\n * the tree answers that without reading anything; the per-service file draws\n * only the services the MAP resolves, and the honest count is the render's, not\n * the tree's. loam never reads a generated file's content (docs/DESIGN.md rule\n * 26), so counting the views in it is the one place the count could come from\n * and the one place it may not.\n */\nfunction serviceViews(action: SyncAction): void {\n if (action === \"current\") return;\n const sentence: Record<Exclude<SyncAction, \"current\">, string> = {\n created: `wrote ${SERVICE_VIEWS} — one overview view per service the fleet map draws.`,\n updated: `updated ${SERVICE_VIEWS} — one overview view per service the fleet map draws.`,\n removed: `removed ${SERVICE_VIEWS} — the fleet map draws none of the services under services/, so the generated file must be absent.`,\n blocked:\n `${SERVICE_VIEWS} left as it is — architecture/ does not parse as one project, so no service resolves to a ` +\n \"map element and the render would have emptied the file rather than improved it.\",\n refused: authoredRefusal(SERVICE_VIEWS),\n };\n console.log(sentence[action]);\n}\n\n/** The per-service project files this run created and removed. */\nfunction projects(out: ProjectsReport): void {\n if (out.created.length > 0) {\n console.log(\n `wrote ${out.created.length} services/<…>/likec4.config.json — one LikeC4 project per service model whose ` +\n \"model stands alone (an existing file is yours and is never rewritten; commit the new ones before a \" +\n \"`loam subsystem move`, which refuses over untracked paths). With more than one project, \" +\n \"likec4 validate at the docs root needs --project <name>; build and export take every project.\",\n );\n }\n // Named one per line: this is a DELETE of a file a team may have written, and\n // a count would leave a reader nothing to check against their own diff.\n for (const path of out.removed) console.log(`removed ${path}`);\n if (out.removed.length > 0) {\n console.log(\n \"— that model extends the fleet map, and a project file beside it registers a second renderer project \" +\n \"rooted at the service directory: `likec4 validate .` then refuses without `--project`, and wherever \" +\n \"that project claims the model it loads it alone, where the map's kinds are not, and the fleet project \" +\n \"loses the service's interior. This is what `service.likec4-config-stray` names.\",\n );\n }\n if (!out.root && out.modelled > 0) {\n console.log(\n \"note: no likec4.config.json at the docs root, so no service project files were written — \" +\n \"`loam doctor` prints the root file.\",\n );\n }\n}\n\n/** The root project's `exclude`, and the one state loam refuses to touch. */\nfunction exclude(out: ProjectsReport): void {\n const plan = out.exclude;\n if (plan.updated) {\n // Named entries rather than a count: this line is the whole record of a\n // rewrite to a file the team owns, and \"updated the exclude list\" gives a\n // reader nothing to check against their own diff.\n const parts = [\n ...(plan.added.length > 0 ? [`+${plan.added.join(\" +\")}`] : []),\n ...(plan.removed.length > 0 ? [`-${plan.removed.join(\" -\")}`] : []),\n ];\n console.log(\n `rewrote likec4.config.json's \\`exclude\\` (${parts.join(\" \")}) — the root project excludes exactly the ` +\n \"models that stand alone; a model that extends the fleet map renders from the docs root and must not be excluded.\",\n );\n }\n if (plan.unreadable) {\n console.log(\n \"note: likec4.config.json at the docs root is not a JSON object with a string `exclude` list, so it was \" +\n \"left exactly as it is — loam does not rewrite a project file it cannot read.\",\n );\n }\n}\n"]}
|