@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":"existing.js","sourceRoot":"","sources":["../../../../../src/core/c4/splice/identity/existing.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Which of a delta's tagged declarations the living fleet does NOT already have\n * — the third identity question of the archive's C4 merge, beside `./edges.ts`'s\n * \"which statement is this\" and `./owner.ts`'s \"which document owns it\".\n *\n * It moved out of `../landscape-merge.ts` when that file crossed the 400-line\n * limit, and this is the seam it wanted: everything here runs BEFORE a single\n * byte is placed, over parsed views and scans alone, and answers one question\n * that has nothing to do with where anything lands. What is left behind is the\n * splice itself.\n *\n * TWO JOINS, and the asymmetry between them is the whole subject. Ids are exact\n * and are checked against the map AND against every extending model, so\n * re-archiving is idempotent whichever document an addition landed in. Titles\n * are the id-less fallback every repository written before\n * `metadata { service }` relies on: global on the map (with the cross-service\n * collision refused rather than silently skipped) and scoped to one service in\n * the models, for the reason `./declared.ts` states.\n *\n * Relationships are matched by COUNT, not by membership: two edges the model\n * cannot tell apart are still two edges, and dropping the second one silently\n * loses a call the author drew.\n */\nimport type { Elem, Rel } from \"../../likec4.js\";\nimport { scanModel, type ScanKinds } from \"../../source-scan.js\";\nimport type { ExtendingModel } from \"../contract.js\";\nimport { modelDeclarations } from \"./declared.js\";\nimport { relKey } from \"./edges.js\";\n\nexport interface ExistingRequest {\n /** The living map's parsed elements. */\n livingEls: Elem[];\n /** The living map's parsed relationships. */\n livingRels: Rel[];\n /**\n * The corpus a service binding resolves against — the living map's elements\n * plus the delta's, so a declaration the delta introduces resolves the moment\n * its bytes would land.\n */\n bindEls: Elem[];\n /** EVERY element the delta declares — edge identity reads past the tagged ones. */\n deltaElements: Elem[];\n /** The delta's tagged elements and relationships: the candidate additions. */\n candidates: { els: Elem[]; rels: Rel[] };\n /** The fleet's extending models, whose declarations count as existence too. */\n models: readonly ExtendingModel[];\n /**\n * The kinds those models borrow from the map. A model's `kind name`\n * declaration or `a .kind b` edge the scan cannot see is one this join counts\n * as missing: the archive spliced a second copy of an edge the model already\n * drew in the dotted form (2026-10).\n */\n borrowed?: ScanKinds;\n}\n\nexport interface Additions {\n /** The tagged elements no living document already declares. */\n els: Elem[];\n /** The tagged relationships no living document already draws. */\n rels: Rel[];\n /**\n * Every id the extending models declare. Routing needs it as well: an\n * `extend` block's children are map fqns, so a container a model already draws\n * anchors an addition's id chain in the map's namespace exactly as a living\n * element does (`./owner.ts`).\n */\n declaredIds: Set<string>;\n /**\n * A title join the merge must refuse rather than take, present only when one\n * was found — the caller stops there and nothing is written.\n *\n * REPORTED, not thrown, and that is a package rule rather than a style\n * preference: `LandscapeSpliceError` lives in `../contract.ts`, and importing\n * it as a VALUE from here would make `splice/` and `splice/identity/` import\n * each other (`scripts/package-graph.mjs` refuses the cycle). The refusal text\n * belongs to the merge anyway — it is the one that decides to write.\n */\n collision?: { addition: Elem; living: Elem };\n}\n\n/**\n * Report (never guess) when a title join would cross two bound services: with\n * both sides carrying an explicit `metadata { service }` binding and every\n * binding disagreeing, they are provably DIFFERENT services' boxes sharing a\n * title ('API', 'Database'). Skipping would silently drop the addition, and any\n * delta edge into it would then refuse the whole archive at the merge's parse\n * net with a message about nothing.\n */\nexport function newAdditions(req: ExistingRequest): Additions {\n const { livingEls, livingRels, bindEls, deltaElements, candidates, models, borrowed } = req;\n const modelScans = models.map((model) => ({ scan: scanModel(model.text, borrowed) }));\n const declared = modelDeclarations(modelScans, bindEls);\n const haveIds = new Set([...livingEls.map((e) => e.id), ...declared.ids]);\n // The title join needs the matched element back, not just membership: the\n // cross-service guard below compares service BINDINGS across the join.\n const byTitle = new Map<string, Elem[]>();\n const seeTitle = (el: Elem): void => {\n byTitle.set(el.title, [...(byTitle.get(el.title) ?? []), el]);\n };\n for (const el of livingEls) seeTitle(el);\n const els: Elem[] = [];\n for (const e of candidates.els) {\n if (haveIds.has(e.id)) continue;\n // The addition's OWN service first, and before the map's global title\n // index: a box this service's model already draws is existence, whoever\n // else on the map happens to share the title.\n if (declared.declaresTitle(e.id, e.title)) continue;\n const sameTitle = byTitle.get(e.title);\n if (sameTitle !== undefined) {\n // A title match is the id-less fallback join, and skipping on it is only\n // safe when the two sides could be the same box.\n if (e.service !== undefined && sameTitle.every((m) => m.service !== undefined && m.service !== e.service)) {\n return { els, rels: [], declaredIds: new Set(declared.ids), collision: { addition: e, living: sameTitle[0]! } };\n }\n // KNOWN (narrowed by the guard above): with EITHER side unbound the title\n // join stays trusting — the unbound title-fallback is the legal legacy\n // pattern — so a cross-service collision hiding behind an unbound element\n // is still silently skipped here. Scoping titles per service is backlog.\n continue;\n }\n haveIds.add(e.id);\n seeTitle(e);\n els.push(e);\n }\n\n // An edge already in the landscape consumes one delta edge of the same\n // identity, which is what keeps re-archiving idempotent.\n const have = new Map<string, number>();\n for (const r of livingRels) {\n const k = relKey(livingEls, r);\n have.set(k, (have.get(k) ?? 0) + 1);\n }\n // An edge an extending model already draws consumes a delta edge exactly as a\n // living map edge does — keyed through the DELTA's elements, because the\n // model spells its endpoints in the map's fqn namespace and the delta must\n // too for the nesting to resolve at all.\n for (const { scan } of modelScans) {\n for (const r of scan?.rels ?? []) {\n const k = relKey(deltaElements, r);\n have.set(k, (have.get(k) ?? 0) + 1);\n }\n }\n const rels: Rel[] = [];\n for (const r of candidates.rels) {\n const k = relKey(deltaElements, r);\n const n = have.get(k) ?? 0;\n if (n > 0) {\n have.set(k, n - 1);\n continue;\n }\n rels.push(r);\n }\n return { els, rels, declaredIds: new Set(declared.ids) };\n}\n"]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `./owner.ts`'s question one construct up: not "whose interior is this id" but
|
|
3
|
+
* "does this whole NEW BLOCK hand its interior over" — decided ONCE per block,
|
|
4
|
+
* and read by BOTH halves of the archive's routing.
|
|
5
|
+
*
|
|
6
|
+
* A service the feature INTRODUCES arrives as one tagged element whose authored
|
|
7
|
+
* bytes already hold its containers. Those containers carry no feature tag of
|
|
8
|
+
* their own — LikeC4 does not inherit tags — so per-addition routing cannot see
|
|
9
|
+
* them: they rode onto the map inside their parent, and the service's extending
|
|
10
|
+
* model could then never declare them, because writing the container the adopt
|
|
11
|
+
* brief prescribes made the map's copy a duplicate and the service `c4.invalid`
|
|
12
|
+
* (verification 2026-09-04, refutation of E1). So the box lands on the map
|
|
13
|
+
* without its interior and the children go into the model's `extend <fqn> { }`
|
|
14
|
+
* block, which `../model/merge.ts` creates.
|
|
15
|
+
*
|
|
16
|
+
* ONE DECISION, NOT TWO, and that is the whole reason this is a module rather
|
|
17
|
+
* than a closure inside `../landscape-merge.ts`. A child of such a block CAN
|
|
18
|
+
* carry the feature tag, and then both halves see it: per-addition routing reads
|
|
19
|
+
* its tag and sends it to the model, while the block decision leaves the same
|
|
20
|
+
* child's bytes on the map. Each half was right on its own and the merge
|
|
21
|
+
* declared the child twice — `merge-failed`, exit 1, nothing written, on a delta
|
|
22
|
+
* neither half was wrong about (re-verification 2026-09-04). `covering` is what
|
|
23
|
+
* makes the routing defer: a declaration written inside a block is the BLOCK's
|
|
24
|
+
* to place, whether or not it is tagged.
|
|
25
|
+
*
|
|
26
|
+
* A block holding a RELATIONSHIP statement rides whole. Such an edge names its
|
|
27
|
+
* endpoints by their LOCAL names inside the block, and the model merge anchors a
|
|
28
|
+
* relationship at the model block's top level — splitting the two apart would
|
|
29
|
+
* leave the map naming children it no longer declares, and `api -> worker` at a
|
|
30
|
+
* model's top level resolves to nothing. The edge rides with its block, for the
|
|
31
|
+
* same reason its siblings do.
|
|
32
|
+
*/
|
|
33
|
+
import { parentIdOf } from "../../../kernel/ids/fqn/ancestors.js";
|
|
34
|
+
export function planInteriors(req) {
|
|
35
|
+
const { scan, deltaElements, owner, addedEls } = req;
|
|
36
|
+
const byId = new Map(scan.elements.map((e) => [e.id, e]));
|
|
37
|
+
const blocks = [];
|
|
38
|
+
const routed = [];
|
|
39
|
+
const omit = [];
|
|
40
|
+
for (const e of addedEls) {
|
|
41
|
+
// A block is an addition that lands on the MAP (nothing owns its parent)
|
|
42
|
+
// and whose own interior belongs to a model. An addition routed away is not
|
|
43
|
+
// a block: its children ride inside its bytes into the same model, which is
|
|
44
|
+
// `../model/merge.ts`'s own `rides` rule.
|
|
45
|
+
if (owner(parentIdOf(e.id)) !== undefined)
|
|
46
|
+
continue;
|
|
47
|
+
const model = owner(e.id);
|
|
48
|
+
if (model === undefined)
|
|
49
|
+
continue;
|
|
50
|
+
// Not in the scan: the splice loop refuses on its own, with the message that
|
|
51
|
+
// names the declaration it could not locate.
|
|
52
|
+
const src = byId.get(e.id);
|
|
53
|
+
if (src === undefined)
|
|
54
|
+
continue;
|
|
55
|
+
const kids = scan.elements.filter((c) => parentIdOf(c.id) === e.id);
|
|
56
|
+
if (kids.length === 0)
|
|
57
|
+
continue;
|
|
58
|
+
const els = kids
|
|
59
|
+
.map((c) => deltaElements.find((x) => x.id === c.id))
|
|
60
|
+
.filter((x) => x !== undefined);
|
|
61
|
+
// A child the parse does not carry is one the model merge could not splice
|
|
62
|
+
// either (it splices by id), so the whole block rides rather than losing it.
|
|
63
|
+
const splits = els.length === kids.length && !scan.rels.some((r) => r.start >= src.start && r.end <= src.end);
|
|
64
|
+
blocks.push({ range: { start: src.start, end: src.end }, fate: splits ? "split" : "whole" });
|
|
65
|
+
if (!splits)
|
|
66
|
+
continue;
|
|
67
|
+
routed.push({ model, els });
|
|
68
|
+
omit.push(...kids.map((c) => ({ start: c.start, end: c.end })));
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
omit,
|
|
72
|
+
routed,
|
|
73
|
+
covering: (at) => blocks.find((b) => inside(at, b.range))?.fate ?? null,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Strictly inside: the ranges of two declarations nest or are disjoint, never overlap. */
|
|
77
|
+
function inside(at, block) {
|
|
78
|
+
return at.start >= block.start && at.end <= block.end && (at.start !== block.start || at.end !== block.end);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=interior.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interior.js","sourceRoot":"","sources":["../../../../../src/core/c4/splice/identity/interior.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `./owner.ts`'s question one construct up: not \"whose interior is this id\" but\n * \"does this whole NEW BLOCK hand its interior over\" — decided ONCE per block,\n * and read by BOTH halves of the archive's routing.\n *\n * A service the feature INTRODUCES arrives as one tagged element whose authored\n * bytes already hold its containers. Those containers carry no feature tag of\n * their own — LikeC4 does not inherit tags — so per-addition routing cannot see\n * them: they rode onto the map inside their parent, and the service's extending\n * model could then never declare them, because writing the container the adopt\n * brief prescribes made the map's copy a duplicate and the service `c4.invalid`\n * (verification 2026-09-04, refutation of E1). So the box lands on the map\n * without its interior and the children go into the model's `extend <fqn> { }`\n * block, which `../model/merge.ts` creates.\n *\n * ONE DECISION, NOT TWO, and that is the whole reason this is a module rather\n * than a closure inside `../landscape-merge.ts`. A child of such a block CAN\n * carry the feature tag, and then both halves see it: per-addition routing reads\n * its tag and sends it to the model, while the block decision leaves the same\n * child's bytes on the map. Each half was right on its own and the merge\n * declared the child twice — `merge-failed`, exit 1, nothing written, on a delta\n * neither half was wrong about (re-verification 2026-09-04). `covering` is what\n * makes the routing defer: a declaration written inside a block is the BLOCK's\n * to place, whether or not it is tagged.\n *\n * A block holding a RELATIONSHIP statement rides whole. Such an edge names its\n * endpoints by their LOCAL names inside the block, and the model merge anchors a\n * relationship at the model block's top level — splitting the two apart would\n * leave the map naming children it no longer declares, and `api -> worker` at a\n * model's top level resolves to nothing. The edge rides with its block, for the\n * same reason its siblings do.\n */\nimport { parentIdOf } from \"../../../kernel/ids/fqn/ancestors.js\";\nimport type { Elem } from \"../../likec4.js\";\nimport type { ScannedModel } from \"../../source-scan.js\";\nimport type { SourceRange } from \"../authored-source.js\";\nimport type { ExtendingModel } from \"../contract.js\";\n\n/** What one block decided about everything written inside it. */\nexport type BlockFate = \"whole\" | \"split\";\n\nexport interface InteriorRequest {\n /** The delta's declarations located in source — the bytes every decision is about. */\n scan: ScannedModel;\n /** EVERY element the delta declares: a child the parse does not carry cannot be routed. */\n deltaElements: readonly Elem[];\n /** Which document owns a given parent id's interior (`./owner.ts`). */\n owner: (parentId: string) => ExtendingModel | undefined;\n /** The delta's declarations this merge is adding — where the blocks are found. */\n addedEls: readonly Elem[];\n}\n\n/** One split block's share: what its service's model takes, and what the map must drop. */\nexport interface RoutedInterior {\n model: ExtendingModel;\n els: Elem[];\n}\n\nexport interface Interiors {\n /** Delta ranges the map's spliced bytes must leave behind — the split blocks' children. */\n readonly omit: readonly SourceRange[];\n /** What each split block hands the model that owns it. */\n readonly routed: readonly RoutedInterior[];\n /**\n * The decision of the block a statement is written INSIDE, or null when no\n * block holds it and ordinary routing applies. A block's own declaration is\n * not inside itself and answers null.\n */\n covering: (at: SourceRange) => BlockFate | null;\n}\n\nexport function planInteriors(req: InteriorRequest): Interiors {\n const { scan, deltaElements, owner, addedEls } = req;\n const byId = new Map(scan.elements.map((e) => [e.id, e]));\n const blocks: Array<{ range: SourceRange; fate: BlockFate }> = [];\n const routed: RoutedInterior[] = [];\n const omit: SourceRange[] = [];\n\n for (const e of addedEls) {\n // A block is an addition that lands on the MAP (nothing owns its parent)\n // and whose own interior belongs to a model. An addition routed away is not\n // a block: its children ride inside its bytes into the same model, which is\n // `../model/merge.ts`'s own `rides` rule.\n if (owner(parentIdOf(e.id)) !== undefined) continue;\n const model = owner(e.id);\n if (model === undefined) continue;\n // Not in the scan: the splice loop refuses on its own, with the message that\n // names the declaration it could not locate.\n const src = byId.get(e.id);\n if (src === undefined) continue;\n const kids = scan.elements.filter((c) => parentIdOf(c.id) === e.id);\n if (kids.length === 0) continue;\n const els = kids\n .map((c) => deltaElements.find((x) => x.id === c.id))\n .filter((x): x is Elem => x !== undefined);\n // A child the parse does not carry is one the model merge could not splice\n // either (it splices by id), so the whole block rides rather than losing it.\n const splits = els.length === kids.length && !scan.rels.some((r) => r.start >= src.start && r.end <= src.end);\n blocks.push({ range: { start: src.start, end: src.end }, fate: splits ? \"split\" : \"whole\" });\n if (!splits) continue;\n routed.push({ model, els });\n omit.push(...kids.map((c) => ({ start: c.start, end: c.end })));\n }\n\n return {\n omit,\n routed,\n covering: (at) => blocks.find((b) => inside(at, b.range))?.fate ?? null,\n };\n}\n\n/** Strictly inside: the ranges of two declarations nest or are disjoint, never overlap. */\nfunction inside(at: SourceRange, block: SourceRange): boolean {\n return at.start >= block.start && at.end <= block.end && (at.start !== block.start || at.end !== block.end);\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which DOCUMENT owns the home of a new declaration — the other identity
|
|
3
|
+
* question the archive's C4 merge asks, beside `./edges.ts`'s "which statement
|
|
4
|
+
* is this".
|
|
5
|
+
*
|
|
6
|
+
* A declaration nested under a service's element belongs to that service's
|
|
7
|
+
* `model.likec4` when the model EXTENDS the fleet map: that is the only
|
|
8
|
+
* document allowed to declare the service's interior (SCHEMA.md, "the map holds
|
|
9
|
+
* no service's interior"), and the map's copy becomes a duplicate the moment
|
|
10
|
+
* the model writes its own — which is exactly what the adopt brief tells a
|
|
11
|
+
* service to do, and exactly the failure this closes (verification 2026-09-04,
|
|
12
|
+
* E1).
|
|
13
|
+
*
|
|
14
|
+
* The PARENT is what resolves, never the element itself, so the caller hands in
|
|
15
|
+
* the parent id and this answers "whose interior is that". A service's own
|
|
16
|
+
* element on the map has a parent that stands for nothing — a grouping box, or
|
|
17
|
+
* the model root — so it resolves to no service with a model, stays on the map,
|
|
18
|
+
* and every service-level edge between two of them stays with it. Asking about a
|
|
19
|
+
* service element's OWN id is the same question one level down, and that is how
|
|
20
|
+
* the landscape merge learns where a NEW service's interior belongs.
|
|
21
|
+
*
|
|
22
|
+
* A service with a STANDALONE model, or none at all, is simply absent from the
|
|
23
|
+
* list and therefore owns nothing here: the map draws its containers, which is
|
|
24
|
+
* legal and is what every repository did before the extending shape existed.
|
|
25
|
+
*/
|
|
26
|
+
import { ancestorIds } from "../../../kernel/ids/fqn/ancestors.js";
|
|
27
|
+
import { serviceResolver } from "../../resolve/service.js";
|
|
28
|
+
export function ownerOf(req) {
|
|
29
|
+
const { bindEls, living, declared, added, models } = req;
|
|
30
|
+
if (models.length === 0)
|
|
31
|
+
return () => undefined;
|
|
32
|
+
const byService = new Map(models.map((m) => [m.service, m]));
|
|
33
|
+
const resolve = serviceResolver(bindEls);
|
|
34
|
+
return (parentId) => {
|
|
35
|
+
if (parentId === "")
|
|
36
|
+
return undefined;
|
|
37
|
+
// Walk up until the chain reaches an id the map's namespace already holds.
|
|
38
|
+
// Everything below that point has to be a declaration this delta ADDS —
|
|
39
|
+
// a child of a container the same delta introduces, or the new service
|
|
40
|
+
// element itself — because those ids will exist once the merge lands.
|
|
41
|
+
for (const a of ancestorIds(parentId)) {
|
|
42
|
+
if (living.has(a) || declared.has(a))
|
|
43
|
+
break;
|
|
44
|
+
if (!added.has(a))
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
return byService.get(resolve(parentId));
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=owner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"owner.js","sourceRoot":"","sources":["../../../../../src/core/c4/splice/identity/owner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAsC3D,MAAM,UAAU,OAAO,CAAC,GAAiB;IACvC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IACzD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC;IAChD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACzC,OAAO,CAAC,QAAgB,EAA8B,EAAE;QACtD,IAAI,QAAQ,KAAK,EAAE;YAAE,OAAO,SAAS,CAAC;QACtC,2EAA2E;QAC3E,wEAAwE;QACxE,uEAAuE;QACvE,sEAAsE;QACtE,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,MAAM;YAC5C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,OAAO,SAAS,CAAC;QACtC,CAAC;QACD,OAAO,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1C,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Which DOCUMENT owns the home of a new declaration — the other identity\n * question the archive's C4 merge asks, beside `./edges.ts`'s \"which statement\n * is this\".\n *\n * A declaration nested under a service's element belongs to that service's\n * `model.likec4` when the model EXTENDS the fleet map: that is the only\n * document allowed to declare the service's interior (SCHEMA.md, \"the map holds\n * no service's interior\"), and the map's copy becomes a duplicate the moment\n * the model writes its own — which is exactly what the adopt brief tells a\n * service to do, and exactly the failure this closes (verification 2026-09-04,\n * E1).\n *\n * The PARENT is what resolves, never the element itself, so the caller hands in\n * the parent id and this answers \"whose interior is that\". A service's own\n * element on the map has a parent that stands for nothing — a grouping box, or\n * the model root — so it resolves to no service with a model, stays on the map,\n * and every service-level edge between two of them stays with it. Asking about a\n * service element's OWN id is the same question one level down, and that is how\n * the landscape merge learns where a NEW service's interior belongs.\n *\n * A service with a STANDALONE model, or none at all, is simply absent from the\n * list and therefore owns nothing here: the map draws its containers, which is\n * legal and is what every repository did before the extending shape existed.\n */\nimport { ancestorIds } from \"../../../kernel/ids/fqn/ancestors.js\";\nimport type { Elem } from \"../../likec4.js\";\nimport { serviceResolver } from \"../../resolve/service.js\";\nimport type { ExtendingModel } from \"../contract.js\";\n\nexport interface OwnerRequest {\n /**\n * The corpus the parent id resolves against — the LIVING map's elements plus\n * the delta's own, so an element the delta introduces resolves the moment its\n * bytes would land.\n */\n bindEls: Elem[];\n /**\n * The ids the LIVING map declares. Reaching one is what proves the id chain is\n * spelled in the map's own namespace.\n */\n living: ReadonlySet<string>;\n /**\n * The ids the fleet's extending models declare inside their `extend` blocks.\n * Those are map fqns too — an `extend` frame reopens an element the map owns —\n * so a container already drawn in a model anchors the chain exactly as a living\n * one does, and an edge into a child of it still routes.\n */\n declared: ReadonlySet<string>;\n /**\n * The ids this merge is ADDING: the delta's declarations that survived the\n * existence joins. An id that is neither living, declared, nor added is one the\n * delta spells under its OWN name for an element the map already holds under\n * another — the legacy title join, which the landscape merge still merges for.\n * Routing it would open an `extend` block on an fqn the map has never heard of,\n * and the model's parse net would refuse an archive that used to merge\n * (verification 2026-09-04, refutation of E1: the guard used to accept any\n * chain whose ANCESTOR was living, so a title-joined name inside a group the\n * map declares — `marketplace.orderSvc` under the living `marketplace` — passed\n * it and every grouped fleet's legacy delta became `merge-failed`).\n */\n added: ReadonlySet<string>;\n models: readonly ExtendingModel[];\n}\n\nexport function ownerOf(req: OwnerRequest): (parentId: string) => ExtendingModel | undefined {\n const { bindEls, living, declared, added, models } = req;\n if (models.length === 0) return () => undefined;\n const byService = new Map(models.map((m) => [m.service, m]));\n const resolve = serviceResolver(bindEls);\n return (parentId: string): ExtendingModel | undefined => {\n if (parentId === \"\") return undefined;\n // Walk up until the chain reaches an id the map's namespace already holds.\n // Everything below that point has to be a declaration this delta ADDS —\n // a child of a container the same delta introduces, or the new service\n // element itself — because those ids will exist once the merge lands.\n for (const a of ancestorIds(parentId)) {\n if (living.has(a) || declared.has(a)) break;\n if (!added.has(a)) return undefined;\n }\n return byService.get(resolve(parentId));\n };\n}\n"]}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parentIdOf } from "../../kernel/ids/fqn/ancestors.js";
|
|
2
|
+
import { errorText, loadSource } from "../likec4.js";
|
|
3
|
+
import { firstUnlocated, unlocatedReason } from "../locate/unlocated.js";
|
|
2
4
|
import { elementService, serviceOf } from "../resolve/service.js";
|
|
3
|
-
import { scanModel } from "../source-scan.js";
|
|
4
|
-
import { spliceSource } from "./authored-source.js";
|
|
5
|
-
import { LandscapeSpliceError } from "./contract.js";
|
|
5
|
+
import { kindsDeclared, scanModel } from "../source-scan.js";
|
|
6
|
+
import { matchLineEndings, spliceSource } from "./authored-source.js";
|
|
7
|
+
import { assertSpliceVisible, LandscapeSpliceError, } from "./contract.js";
|
|
6
8
|
import { assertMergeableDelta } from "./delta-blocks.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
+
import { relSortKey, relStatementKey, scannedStatementKey } from "./identity/edges.js";
|
|
10
|
+
import { newAdditions } from "./identity/existing.js";
|
|
11
|
+
import { planInteriors } from "./identity/interior.js";
|
|
12
|
+
import { ownerOf } from "./identity/owner.js";
|
|
13
|
+
import { elementSpot, relSpot, topStatements } from "./placement.js";
|
|
14
|
+
import { nestedInsert } from "./text/spot.js";
|
|
9
15
|
/* ------------------------------------------------------------------ */
|
|
10
16
|
/* Merging */
|
|
11
17
|
/* ------------------------------------------------------------------ */
|
|
@@ -33,20 +39,40 @@ import { elementSpot, nestedInsert, relSpot, topStatements, } from "./placement.
|
|
|
33
39
|
* dotted id at top level, which LikeC4 rejects. The additions carry no marker
|
|
34
40
|
* comment: which archive added what is the git history's to say.
|
|
35
41
|
*
|
|
36
|
-
* Existence is checked semantically against the parsed landscape
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* existence hit but a collision, and refuses the archive (see the guard).
|
|
42
|
+
* Existence is checked semantically against the parsed landscape AND against
|
|
43
|
+
* every extending model the request carries (by element id/title and by edge
|
|
44
|
+
* identity), so re-archiving is idempotent whichever document the additions
|
|
45
|
+
* landed in — `./identity/existing.ts` holds that phase and its two joins, and
|
|
46
|
+
* this function only turns the collision it reports into the refusal.
|
|
42
47
|
*
|
|
43
48
|
* Splicing is text surgery, so the computed result is PARSED before it is
|
|
44
49
|
* returned: a merged landscape LikeC4 rejects refuses the archive at plan time
|
|
45
50
|
* (merge-failed, nothing written — the unparseable-delta discipline) instead
|
|
46
51
|
* of landing in the living docs.
|
|
52
|
+
*
|
|
53
|
+
* NOT EVERYTHING LANDS HERE. A service whose model EXTENDS this map owns its
|
|
54
|
+
* own interior, and an addition nested under such a service is ROUTED to that
|
|
55
|
+
* model instead (`./identity/owner.ts` decides, `./model/merge.ts` splices).
|
|
56
|
+
* Until it was, a delta's container landed in the map and the service was
|
|
57
|
+
* `c4.invalid` — a duplicate declaration — the moment its model wrote the same
|
|
58
|
+
* container, which is exactly what the adopt brief tells it to do
|
|
59
|
+
* (verification 2026-09-04, E1). With no extending models in the request this
|
|
60
|
+
* function behaves as it always did.
|
|
61
|
+
*
|
|
62
|
+
* Routing per ADDITION is not the whole of it, because a service the feature
|
|
63
|
+
* INTRODUCES carries its interior in one element's authored bytes and those
|
|
64
|
+
* children carry no feature tag of their own. `./identity/interior.ts` decides, once
|
|
65
|
+
* per such block, whether it hands that interior to the model — cut out of what
|
|
66
|
+
* lands on the map — or rides whole; the routing below DEFERS to that decision
|
|
67
|
+
* for everything written inside the block, which is what keeps the two from
|
|
68
|
+
* placing the same child twice.
|
|
47
69
|
*/
|
|
48
70
|
export async function planLandscapeMerge(merge) {
|
|
49
71
|
const { landscapeText: text, deltaText, deltaElements, newEls, newRels, featureId } = merge;
|
|
72
|
+
const models = merge.models ?? [];
|
|
73
|
+
// What every extending model borrows from this map: its kinds, without which
|
|
74
|
+
// a model's scan reads `container outbox` and `a .delivers b` as property lines.
|
|
75
|
+
const borrowed = kindsDeclared(text);
|
|
50
76
|
// First, and before the early return for "nothing to add": a block this merge
|
|
51
77
|
// cannot carry is lost whether or not the delta also has tagged elements to
|
|
52
78
|
// splice. See delta-blocks.ts.
|
|
@@ -55,65 +81,44 @@ export async function planLandscapeMerge(merge) {
|
|
|
55
81
|
if (land.errors.length > 0) {
|
|
56
82
|
throw new LandscapeSpliceError(`landscape.likec4 has ${land.errors.length} error(s) — fix it before archiving`);
|
|
57
83
|
}
|
|
58
|
-
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// 'Database') — the skip would silently drop the addition, and any delta
|
|
78
|
-
// edge into it would then refuse the whole archive at the parse net
|
|
79
|
-
// below with a message about nothing. Refuse here instead, at plan time,
|
|
80
|
-
// naming both sides.
|
|
81
|
-
if (e.service !== undefined && sameTitle.every((m) => m.service !== undefined && m.service !== e.service)) {
|
|
82
|
-
const m = sameTitle[0];
|
|
83
|
-
throw new LandscapeSpliceError(`the delta's '${e.id}' (bound to service '${e.service}') shares the title '${e.title}' with '${m.id}' (bound to service '${m.service}') — a title join across services would silently drop the addition; ` +
|
|
84
|
-
`retitle one of them, or reuse the id '${m.id}' if they really are the same element`);
|
|
85
|
-
}
|
|
86
|
-
// KNOWN (narrowed by the guard above): with EITHER side unbound the title
|
|
87
|
-
// join stays trusting — the unbound title-fallback is the legal legacy
|
|
88
|
-
// pattern — so a cross-service collision hiding behind an unbound element
|
|
89
|
-
// is still silently skipped here. Scoping titles per service is backlog.
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
haveIds.add(e.id);
|
|
93
|
-
seeTitle(e);
|
|
94
|
-
addedEls.push(e);
|
|
95
|
-
}
|
|
96
|
-
// Edges are matched by COUNT, not by membership: two edges the model cannot tell
|
|
97
|
-
// apart are still two edges, and dropping the second one silently loses a call
|
|
98
|
-
// the author drew. An edge already in the landscape consumes one delta edge of
|
|
99
|
-
// the same identity, which is what keeps re-archiving idempotent.
|
|
100
|
-
const have = new Map();
|
|
101
|
-
for (const r of land.relationships) {
|
|
102
|
-
const k = relKey(land.elements, r);
|
|
103
|
-
have.set(k, (have.get(k) ?? 0) + 1);
|
|
84
|
+
// Service binding for the existence joins AND for routing and placement:
|
|
85
|
+
// living elements first (they win a shared id), the delta's after — a spliced
|
|
86
|
+
// statement's id resolves to its service the moment its bytes land in the scan.
|
|
87
|
+
const bindEls = [...land.elements, ...deltaElements.filter((d) => !land.elements.some((l) => l.id === d.id))];
|
|
88
|
+
// What the living fleet already has — the map AND every extending model, by id
|
|
89
|
+
// and by title. `./identity/existing.ts` holds both joins and their asymmetry.
|
|
90
|
+
const added = newAdditions({
|
|
91
|
+
livingEls: land.elements,
|
|
92
|
+
livingRels: land.relationships,
|
|
93
|
+
bindEls,
|
|
94
|
+
deltaElements,
|
|
95
|
+
candidates: { els: newEls, rels: newRels },
|
|
96
|
+
models,
|
|
97
|
+
borrowed,
|
|
98
|
+
});
|
|
99
|
+
if (added.collision !== undefined) {
|
|
100
|
+
const { addition: e, living: m } = added.collision;
|
|
101
|
+
throw new LandscapeSpliceError(`the delta's '${e.id}' (bound to service '${e.service}') shares the title '${e.title}' with '${m.id}' (bound to service '${m.service}') — a title join across services would silently drop the addition; ` +
|
|
102
|
+
`retitle one of them, or reuse the id '${m.id}' if they really are the same element`);
|
|
104
103
|
}
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
104
|
+
const addedEls = added.els;
|
|
105
|
+
const addedRels = added.rels;
|
|
106
|
+
const owner = ownerOf({
|
|
107
|
+
bindEls,
|
|
108
|
+
living: new Set(land.elements.map((e) => e.id)),
|
|
109
|
+
declared: added.declaredIds,
|
|
110
|
+
added: new Set(addedEls.map((e) => e.id)),
|
|
111
|
+
models,
|
|
112
|
+
});
|
|
113
|
+
// Nothing to add: the same shape the merge returned before routing existed,
|
|
114
|
+
// and the reason it is decided HERE rather than after the loops below — a
|
|
115
|
+
// no-op archive must not have to scan the delta, nor answer the landscape
|
|
116
|
+
// guards further down, which refuse documents this merge is not touching.
|
|
117
|
+
// Equivalent to the old "nothing reached the map and nothing was routed":
|
|
118
|
+
// every addition ends up in one of those two, so an empty pair means both.
|
|
119
|
+
if (addedEls.length === 0 && addedRels.length === 0) {
|
|
120
|
+
return { content: null, addedEls: [], addedRels: [], models: [] };
|
|
114
121
|
}
|
|
115
|
-
if (addedEls.length === 0 && addedRels.length === 0)
|
|
116
|
-
return { content: null, addedEls, addedRels };
|
|
117
122
|
const scan = scanModel(deltaText);
|
|
118
123
|
if (scan === null) {
|
|
119
124
|
throw new LandscapeSpliceError("delta.likec4 has no model block — nothing to splice the additions from");
|
|
@@ -123,6 +128,62 @@ export async function planLandscapeMerge(merge) {
|
|
|
123
128
|
// parent is itself new is recognised as riding inside the parent's text and
|
|
124
129
|
// is never inserted twice.
|
|
125
130
|
const byId = new Map(scan.elements.map((e) => [e.id, e]));
|
|
131
|
+
// Relationships: match each parsed addition back to its statement in the
|
|
132
|
+
// delta source — full identity (`relStatementKey`), consumed one statement
|
|
133
|
+
// per addition so duplicates stay duplicates. Built before the routing
|
|
134
|
+
// because routing has to know WHERE an edge was written: one drawn inside a
|
|
135
|
+
// block that rides whole is already on the map. A statement is keyed with the
|
|
136
|
+
// tags its kind gives it, which the parsed addition carries and its text does not.
|
|
137
|
+
const pool = new Map();
|
|
138
|
+
for (const s of scan.rels) {
|
|
139
|
+
const k = scannedStatementKey(s, merge.deltaKindTags ?? {});
|
|
140
|
+
pool.set(k, [...(pool.get(k) ?? []), s]);
|
|
141
|
+
}
|
|
142
|
+
const interiors = planInteriors({ scan, deltaElements, owner, addedEls });
|
|
143
|
+
const routed = new Map();
|
|
144
|
+
const into = (model) => {
|
|
145
|
+
const existing = routed.get(model.path);
|
|
146
|
+
if (existing !== undefined)
|
|
147
|
+
return existing;
|
|
148
|
+
const fresh = { model, els: [], rels: [], borrowed };
|
|
149
|
+
routed.set(model.path, fresh);
|
|
150
|
+
return fresh;
|
|
151
|
+
};
|
|
152
|
+
for (const share of interiors.routed)
|
|
153
|
+
into(share.model).els.push(...share.els);
|
|
154
|
+
const mapEls = [];
|
|
155
|
+
for (const e of addedEls) {
|
|
156
|
+
const src = byId.get(e.id);
|
|
157
|
+
// Written inside a block that has already decided: a split block handed it
|
|
158
|
+
// to the model with its siblings, and a whole one carries it onto the map
|
|
159
|
+
// in the parent's own bytes, where the splice loop's `rides` finds it. Both
|
|
160
|
+
// are placed exactly once, which is the point of asking the block first.
|
|
161
|
+
const fate = src === undefined ? null : interiors.covering(src);
|
|
162
|
+
if (fate === "split")
|
|
163
|
+
continue;
|
|
164
|
+
const model = fate === "whole" ? undefined : owner(parentIdOf(e.id));
|
|
165
|
+
if (model === undefined)
|
|
166
|
+
mapEls.push(e);
|
|
167
|
+
else
|
|
168
|
+
into(model).els.push(e);
|
|
169
|
+
}
|
|
170
|
+
const mapRels = [];
|
|
171
|
+
for (const r of addedRels) {
|
|
172
|
+
// An edge written inside a block that rides whole names its endpoints by
|
|
173
|
+
// their LOCAL names and reads only there; it stays with its block.
|
|
174
|
+
const stmts = pool.get(relStatementKey(r)) ?? [];
|
|
175
|
+
const inBlock = stmts.length > 0 && stmts.every((s) => interiors.covering(s) !== null);
|
|
176
|
+
// Otherwise the SOURCE decides: a call is drawn where the caller draws its
|
|
177
|
+
// calls, and only when the source is not itself interior does the target's
|
|
178
|
+
// owner get the edge. A service-level edge belongs to neither and stays on
|
|
179
|
+
// the map.
|
|
180
|
+
const model = inBlock ? undefined : owner(parentIdOf(r.source)) ?? owner(parentIdOf(r.target));
|
|
181
|
+
if (model === undefined)
|
|
182
|
+
mapRels.push(r);
|
|
183
|
+
else
|
|
184
|
+
into(model).rels.push(r);
|
|
185
|
+
}
|
|
186
|
+
const touchesMap = mapEls.length > 0 || mapRels.length > 0;
|
|
126
187
|
const spliced = [];
|
|
127
188
|
const rides = (start, end) => spliced.some((r) => start >= r.start && end <= r.end);
|
|
128
189
|
// The living model, scanned on MASKED source (scanModel) and RE-SCANNED
|
|
@@ -137,10 +198,6 @@ export async function planLandscapeMerge(merge) {
|
|
|
137
198
|
// LikeC4, so the parse net below would pass a landscape containing none of
|
|
138
199
|
// the architecture).
|
|
139
200
|
let content = text;
|
|
140
|
-
// Service binding for placement: living elements first (they win a shared
|
|
141
|
-
// id), the delta's after — a spliced statement's id resolves to its service
|
|
142
|
-
// the moment its bytes land in the scan.
|
|
143
|
-
const bindEls = [...land.elements, ...deltaElements.filter((d) => !land.elements.some((l) => l.id === d.id))];
|
|
144
201
|
let livingScan = scanModel(content);
|
|
145
202
|
let stmts = livingScan === null ? [] : topStatements(livingScan, bindEls);
|
|
146
203
|
const rescan = () => {
|
|
@@ -155,16 +212,19 @@ export async function planLandscapeMerge(merge) {
|
|
|
155
212
|
// Built fresh at every use, never captured: `content` and `stmts` are rebound
|
|
156
213
|
// by each rescan, and a region assembled before a splice describes a document
|
|
157
214
|
// that no longer exists.
|
|
158
|
-
const modelRegion = () => ({ text: content, stmts,
|
|
159
|
-
|
|
215
|
+
const modelRegion = () => ({ text: content, stmts, blocks: requireModel().blocks });
|
|
216
|
+
// Every insert must be one the next scan sees (`assertSpliceVisible`).
|
|
217
|
+
const applyAt = (at, insert, what) => {
|
|
218
|
+
const before = livingScan;
|
|
160
219
|
content = content.slice(0, at) + insert + content.slice(at);
|
|
161
220
|
rescan();
|
|
221
|
+
assertSpliceVisible(before, livingScan, what);
|
|
162
222
|
};
|
|
163
|
-
const applyTop = (spot, block) => {
|
|
223
|
+
const applyTop = (spot, block, what) => {
|
|
164
224
|
// A bare spot shares its line with other text (the closing brace, or a
|
|
165
225
|
// statement the block displaces) — it brings its own newlines; a
|
|
166
226
|
// line-start spot slots between lines.
|
|
167
|
-
applyAt(spot.at, spot.bare ? `\n${block}\n` : `${block}\n
|
|
227
|
+
applyAt(spot.at, spot.bare ? `\n${block}\n` : `${block}\n`, what);
|
|
168
228
|
};
|
|
169
229
|
// Placement walks the scanned statement layout, so a declaration the scan
|
|
170
230
|
// cannot see is one placement would blindly splice around — LikeC4 accepts
|
|
@@ -173,15 +233,19 @@ export async function planLandscapeMerge(merge) {
|
|
|
173
233
|
// element bound to its service would miss its neighborhood, and a bodyless
|
|
174
234
|
// parent gaining a body could wrap the wrong declaration. Refuse
|
|
175
235
|
// mechanically (the parse-net discipline) instead of splicing blind.
|
|
236
|
+
//
|
|
237
|
+
// THAT something is unlocated is decided here, from the parse already in
|
|
238
|
+
// hand; WHAT and why is `firstUnlocated`'s, at the price of a second parse on
|
|
239
|
+
// this path alone. The message used to guess "most often two declarations
|
|
240
|
+
// sharing one line" whatever the map held, and a fleet read it over a
|
|
241
|
+
// declaration on a line of its own in a second `model { }` block the scan
|
|
242
|
+
// did not read then (2026-10): it names LikeC4's line now, and a shared line
|
|
243
|
+
// only when that line shows one.
|
|
176
244
|
if (livingScan !== null) {
|
|
177
245
|
const seen = new Set(livingScan.elements.map((e) => e.id));
|
|
178
|
-
const
|
|
179
|
-
if (
|
|
180
|
-
throw new LandscapeSpliceError(
|
|
181
|
-
}
|
|
182
|
-
if (livingScan.rels.length < land.relationships.length) {
|
|
183
|
-
throw new LandscapeSpliceError(`landscape.likec4 declares ${land.relationships.length} relationship(s) but placement can locate only ${livingScan.rels.length} — most often two statements sharing one line; give each its own line, then re-run`);
|
|
184
|
-
}
|
|
246
|
+
const blind = land.elements.some((e) => !seen.has(e.id)) || livingScan.rels.length < land.relationships.length;
|
|
247
|
+
if (blind)
|
|
248
|
+
throw new LandscapeSpliceError(unlocatedReason("landscape.likec4", await firstUnlocated(text, livingScan)));
|
|
185
249
|
}
|
|
186
250
|
const livingParentOf = (parentId) => {
|
|
187
251
|
if (livingScan === null)
|
|
@@ -199,7 +263,7 @@ export async function planLandscapeMerge(merge) {
|
|
|
199
263
|
};
|
|
200
264
|
// Ancestors first: a spliced parent covers its children before they are seen.
|
|
201
265
|
const depth = (id) => id.split(".").length;
|
|
202
|
-
const sortedEls = [...
|
|
266
|
+
const sortedEls = [...mapEls].sort((a, b) => depth(a.id) - depth(b.id) || (byId.get(a.id)?.start ?? 0) - (byId.get(b.id)?.start ?? 0));
|
|
203
267
|
for (const e of sortedEls) {
|
|
204
268
|
const src = byId.get(e.id);
|
|
205
269
|
if (src === undefined) {
|
|
@@ -207,10 +271,15 @@ export async function planLandscapeMerge(merge) {
|
|
|
207
271
|
}
|
|
208
272
|
if (rides(src.start, src.end))
|
|
209
273
|
continue;
|
|
274
|
+
// Every split block's children, whichever block they belong to:
|
|
275
|
+
// `spliceSource` keeps only the ranges that fall inside the bytes it is
|
|
276
|
+
// carrying, so a block riding inside ANOTHER new block still loses its own
|
|
277
|
+
// interior on the way to the map.
|
|
278
|
+
const omit = interiors.omit;
|
|
210
279
|
const dot = e.id.lastIndexOf(".");
|
|
211
280
|
if (dot === -1) {
|
|
212
281
|
const spot = elementSpot(modelRegion(), e.id, elementService(e));
|
|
213
|
-
applyTop(spot, spliceSource(deltaText, src, featureId, " "));
|
|
282
|
+
applyTop(spot, spliceSource(deltaText, src, { featureId, indent: " ", omit }), e.id);
|
|
214
283
|
spliced.push({ start: src.start, end: src.end });
|
|
215
284
|
continue;
|
|
216
285
|
}
|
|
@@ -219,24 +288,14 @@ export async function planLandscapeMerge(merge) {
|
|
|
219
288
|
if (parent === null) {
|
|
220
289
|
throw new LandscapeSpliceError(`'${e.id}' nests under '${parentId}', which is neither in the living landscape nor added by this delta — there is nowhere to insert it`);
|
|
221
290
|
}
|
|
222
|
-
const nested = nestedInsert(content, parent, spliceSource(deltaText, src, featureId, parent.indent + " "));
|
|
223
|
-
applyAt(nested.at, nested.insert);
|
|
291
|
+
const nested = nestedInsert(content, parent, spliceSource(deltaText, src, { featureId, indent: parent.indent + " ", omit }));
|
|
292
|
+
applyAt(nested.at, nested.insert, e.id);
|
|
224
293
|
spliced.push({ start: src.start, end: src.end });
|
|
225
294
|
}
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// without them two additions differing only by `publishes` share one pool
|
|
231
|
-
// entry, and `shift()` hands the second one the first one's authored bytes.
|
|
232
|
-
const relKeyOf = (r) => JSON.stringify([r.source, r.target, r.title ?? "", r.op ?? "", r.publishes ?? "", r.consumes ?? "", [...r.tags].sort()]);
|
|
233
|
-
const pool = new Map();
|
|
234
|
-
for (const s of scan.rels) {
|
|
235
|
-
const k = relKeyOf(s);
|
|
236
|
-
pool.set(k, [...(pool.get(k) ?? []), s]);
|
|
237
|
-
}
|
|
238
|
-
for (const r of addedRels) {
|
|
239
|
-
const s = pool.get(relKeyOf(r))?.shift();
|
|
295
|
+
// Each map-bound addition takes its statement out of the pool built above:
|
|
296
|
+
// one statement per addition, so duplicates stay duplicates.
|
|
297
|
+
for (const r of mapRels) {
|
|
298
|
+
const s = pool.get(relStatementKey(r))?.shift();
|
|
240
299
|
if (s === undefined) {
|
|
241
300
|
throw new LandscapeSpliceError(`cannot locate the '${r.source} -> ${r.target}' relationship in delta.likec4 — the landscape merge splices authored source, and no matching declaration was found`);
|
|
242
301
|
}
|
|
@@ -248,22 +307,31 @@ export async function planLandscapeMerge(merge) {
|
|
|
248
307
|
// safety-netted by the re-parse below), never which service a check
|
|
249
308
|
// grades.
|
|
250
309
|
const spot = relSpot(modelRegion(), serviceOf(deltaElements, r.source), key);
|
|
251
|
-
applyTop(spot, spliceSource(deltaText, s, featureId, " "));
|
|
310
|
+
applyTop(spot, spliceSource(deltaText, s, { featureId, indent: " " }), `${r.source} -> ${r.target}`);
|
|
252
311
|
}
|
|
253
312
|
// The safety net: prove the computed landscape parses before anything is
|
|
254
313
|
// written. Splice bugs — and legal inputs the living document cannot absorb,
|
|
255
314
|
// like a kind its specification never declares — refuse here, at plan time,
|
|
256
|
-
// instead of corrupting the one file the whole fleet reads.
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
315
|
+
// instead of corrupting the one file the whole fleet reads. Skipped when
|
|
316
|
+
// every addition was routed away: the text is the one already parsed above,
|
|
317
|
+
// and the models get their own net from the caller, which is the only side
|
|
318
|
+
// that can stage a model beside the map it extends.
|
|
319
|
+
// The splice composed bytes from two documents, and the delta's newlines are
|
|
320
|
+
// not necessarily the map's. Corrected before the net, so what is proven is
|
|
321
|
+
// what would be written.
|
|
322
|
+
content = matchLineEndings(text, content);
|
|
323
|
+
if (touchesMap) {
|
|
324
|
+
const check = await loadSource(content);
|
|
325
|
+
if (check.errors.length > 0) {
|
|
326
|
+
const detail = check.errors
|
|
327
|
+
.slice(0, 3)
|
|
328
|
+
.map(errorText)
|
|
329
|
+
.join("; ");
|
|
330
|
+
throw new LandscapeSpliceError(`the merged landscape would not parse (${check.errors.length} error(s): ${detail}) — nothing was written. ` +
|
|
331
|
+
`The delta's additions do not fit the living landscape as authored — most often an element kind or tag ` +
|
|
332
|
+
`its specification block does not declare; fix the landscape's specification or the delta, then re-run`);
|
|
333
|
+
}
|
|
266
334
|
}
|
|
267
|
-
return { content, addedEls, addedRels };
|
|
335
|
+
return { content: touchesMap ? content : null, addedEls: mapEls, addedRels: mapRels, models: [...routed.values()] };
|
|
268
336
|
}
|
|
269
337
|
//# sourceMappingURL=landscape-merge.js.map
|