@ybotok/loam 0.1.0-beta.2 → 0.2.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2570 -61
- package/COMPARISON.md +80 -63
- package/CONTRIBUTING.md +84 -0
- package/MIGRATING-from-OpenSpec.md +213 -54
- package/QUICKSTART.md +125 -0
- package/README.md +450 -150
- package/ROADMAP.md +494 -0
- package/SCHEMA.md +2362 -245
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +701 -0
- package/dist/cli.js +113 -19
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +209 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +268 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +77 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +159 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +317 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +161 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +111 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +237 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +27 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +251 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/context/context.js +99 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +283 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +279 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +205 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +9 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +93 -0
- package/dist/commands/diff/diff.js.map +1 -0
- package/dist/commands/diff/print.js +38 -0
- package/dist/commands/diff/print.js.map +1 -0
- package/dist/commands/doctor.js +5 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +151 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +29 -24
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +115 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +54 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +146 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +246 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +149 -0
- package/dist/commands/gherkin/reconcile.js.map +1 -0
- package/dist/commands/gherkin/render.js +77 -0
- package/dist/commands/gherkin/render.js.map +1 -0
- package/dist/commands/init/example.js +204 -0
- package/dist/commands/init/example.js.map +1 -0
- package/dist/commands/init/first-hour.js +28 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +146 -71
- package/dist/commands/init/init.js.map +1 -0
- package/dist/commands/init/mcp.js +131 -0
- package/dist/commands/init/mcp.js.map +1 -0
- package/dist/commands/init/options.js +78 -0
- package/dist/commands/init/options.js.map +1 -0
- package/dist/commands/instructions.js +82 -14
- package/dist/commands/instructions.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +65 -0
- package/dist/commands/list/campaign/campaign.js.map +1 -0
- package/dist/commands/list/campaign/owners.js +65 -0
- package/dist/commands/list/campaign/owners.js.map +1 -0
- package/dist/commands/list/json.js +157 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +343 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +301 -0
- package/dist/commands/list/print.js.map +1 -0
- package/dist/commands/list/review.js +120 -0
- package/dist/commands/list/review.js.map +1 -0
- package/dist/commands/list/views.js +105 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +183 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +34 -0
- package/dist/commands/mcp/mcp.js.map +1 -0
- package/dist/commands/mcp/serve.js +55 -0
- package/dist/commands/mcp/serve.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/active.js +170 -0
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
- package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/living.js +62 -0
- package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/target.js +219 -0
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +19 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/read.js +49 -0
- package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
- package/dist/commands/migrate-openspec/print.js +89 -0
- package/dist/commands/migrate-openspec/print.js.map +1 -0
- package/dist/commands/new/commit.js +76 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/new.js +283 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +355 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +203 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/policy/format.js +152 -0
- package/dist/commands/policy/format.js.map +1 -0
- package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
- package/dist/commands/policy/gate.js.map +1 -0
- package/dist/commands/rebase/edit.js +106 -0
- package/dist/commands/rebase/edit.js.map +1 -0
- package/dist/commands/rebase/living.js +185 -0
- package/dist/commands/rebase/living.js.map +1 -0
- package/dist/commands/rebase/plan.js +245 -0
- package/dist/commands/rebase/plan.js.map +1 -0
- package/dist/commands/rebase/rebase.js +275 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +192 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +133 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +172 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +178 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/marks.js +24 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/{show.js → show/service.js} +63 -152
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +77 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/json.js +45 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +157 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +119 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +189 -0
- package/dist/commands/steps/steps.js.map +1 -0
- package/dist/commands/subsystem/edit.js +192 -0
- package/dist/commands/subsystem/edit.js.map +1 -0
- package/dist/commands/subsystem/move.js +265 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +115 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +101 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +103 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +94 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +70 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +160 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +67 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +194 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +296 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +55 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +254 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +76 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/checks/vocabulary.js +31 -0
- package/dist/commands/validate/checks/vocabulary.js.map +1 -0
- package/dist/commands/validate/feature.js +216 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +69 -0
- package/dist/commands/validate/fleet/census.js.map +1 -0
- package/dist/commands/validate/fleet/kind-tags.js +39 -0
- package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
- package/dist/commands/validate/fleet/landscape.js +353 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +52 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +236 -0
- package/dist/commands/validate/fleet/obligations.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/print.js +63 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/place.js +13 -0
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/steps.js +197 -0
- package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
- package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +40 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +59 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +92 -0
- package/dist/commands/validate/links/corpus.js.map +1 -0
- package/dist/commands/validate/links/glossary.js +75 -0
- package/dist/commands/validate/links/glossary.js.map +1 -0
- package/dist/commands/validate/report.js +269 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/service/api.js +338 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +219 -0
- package/dist/commands/validate/service/events/events.js.map +1 -0
- package/dist/commands/validate/service/events/message-producers.js +77 -0
- package/dist/commands/validate/service/events/message-producers.js.map +1 -0
- package/dist/commands/validate/service/evidence-pins.js +131 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/service.js +250 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +219 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +113 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/validate.js +338 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +182 -0
- package/dist/commands/verify/cross/diff.js.map +1 -0
- package/dist/commands/verify/evidence/contract.js +32 -0
- package/dist/commands/verify/evidence/contract.js.map +1 -0
- package/dist/commands/verify/evidence/pins.js +52 -0
- package/dist/commands/verify/evidence/pins.js.map +1 -0
- package/dist/commands/verify/evidence/read.js +72 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +241 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +226 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +223 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +246 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +217 -0
- package/dist/commands/verify/verify.js.map +1 -0
- package/dist/commands/vouch/contract.js +11 -0
- package/dist/commands/vouch/contract.js.map +1 -0
- package/dist/commands/vouch/pack/contract.js +2 -0
- package/dist/commands/vouch/pack/contract.js.map +1 -0
- package/dist/commands/vouch/pack/pack.js +266 -0
- package/dist/commands/vouch/pack/pack.js.map +1 -0
- package/dist/commands/vouch/pack/print.js +271 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +142 -0
- package/dist/commands/vouch/pack/sections.js.map +1 -0
- package/dist/commands/vouch/prompt/confirm.js +46 -0
- package/dist/commands/vouch/prompt/confirm.js.map +1 -0
- package/dist/commands/vouch/report.js +101 -0
- package/dist/commands/vouch/report.js.map +1 -0
- package/dist/commands/vouch/run.js +285 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +125 -0
- package/dist/commands/vouch/sample/plan.js.map +1 -0
- package/dist/commands/vouch/sample/print.js +109 -0
- package/dist/commands/vouch/sample/print.js.map +1 -0
- package/dist/commands/vouch/vet/verify.js +123 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +176 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/artifacts.js +220 -0
- package/dist/core/agent/agents-md/artifacts.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +324 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/cycle.js +165 -0
- package/dist/core/agent/agents-md/cycle.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +34 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +41 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +62 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +32 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +60 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +246 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
- package/dist/core/agent/agents-md/spine.js +40 -0
- package/dist/core/agent/agents-md/spine.js.map +1 -0
- package/dist/core/agent/agents-md.js +170 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/agent/agents-stamp.js +155 -0
- package/dist/core/agent/agents-stamp.js.map +1 -0
- package/dist/core/agent/contract.js +2 -0
- package/dist/core/agent/contract.js.map +1 -0
- package/dist/core/agent/protocol.js +193 -0
- package/dist/core/agent/protocol.js.map +1 -0
- package/dist/core/agent/scaffold.js +259 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +103 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +150 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +228 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +133 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +334 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +262 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +105 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +105 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +209 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +65 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +188 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +16 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +297 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +110 -0
- package/dist/core/asyncapi/baseline/plan.js.map +1 -0
- package/dist/core/asyncapi/baseline/surfaces.js +54 -0
- package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
- package/dist/core/asyncapi/depth.js +164 -0
- package/dist/core/asyncapi/depth.js.map +1 -0
- package/dist/core/asyncapi/digest.js +141 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +91 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +33 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +308 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +215 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +107 -0
- package/dist/core/asyncapi/merge/pin.js.map +1 -0
- package/dist/core/asyncapi/model.js +11 -0
- package/dist/core/asyncapi/model.js.map +1 -0
- package/dist/core/asyncapi/producers.js +50 -0
- package/dist/core/asyncapi/producers.js.map +1 -0
- package/dist/core/asyncapi/read.js +239 -0
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +225 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +250 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +194 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/targets.js +226 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +47 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +282 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/likec4.js +88 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +57 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +75 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/project/architecture.js +45 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/documents.js +58 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +183 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/resolve/service.js +113 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/seed/fleet-file.js +201 -0
- package/dist/core/c4/seed/fleet-file.js.map +1 -0
- package/dist/core/c4/seed/items.js +91 -0
- package/dist/core/c4/seed/items.js.map +1 -0
- package/dist/core/c4/seed/stamp.js +48 -0
- package/dist/core/c4/seed/stamp.js.map +1 -0
- package/dist/core/c4/seed/template.js +109 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/source-mask.js +82 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +227 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +101 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +10 -0
- package/dist/core/c4/splice/contract.js.map +1 -0
- package/dist/core/c4/splice/delta-blocks.js +126 -0
- package/dist/core/c4/splice/delta-blocks.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +36 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +269 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +194 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/workspace.js +172 -0
- package/dist/core/c4/workspace.js.map +1 -0
- package/dist/core/capabilities/authoring/notes.js +141 -0
- package/dist/core/capabilities/authoring/notes.js.map +1 -0
- package/dist/core/capabilities/capabilities.js +124 -0
- package/dist/core/capabilities/capabilities.js.map +1 -0
- package/dist/core/capabilities/delta/doc.js +50 -0
- package/dist/core/capabilities/delta/doc.js.map +1 -0
- package/dist/core/capabilities/delta/overlay.js +129 -0
- package/dist/core/capabilities/delta/overlay.js.map +1 -0
- package/dist/core/capabilities/delta/summary.js +57 -0
- package/dist/core/capabilities/delta/summary.js.map +1 -0
- package/dist/core/capabilities/delta/tree.js +43 -0
- package/dist/core/capabilities/delta/tree.js.map +1 -0
- package/dist/core/capabilities/delta/uncovered.js +222 -0
- package/dist/core/capabilities/delta/uncovered.js.map +1 -0
- package/dist/core/capabilities/findings.js +342 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +181 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +143 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +199 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +126 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +277 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +177 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +74 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/coherence.js +251 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/declared.js +269 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +206 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +204 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +166 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +122 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/merged.js +40 -0
- package/dist/core/coherence/events/merged.js.map +1 -0
- package/dist/core/coherence/living.js +198 -0
- package/dist/core/coherence/living.js.map +1 -0
- package/dist/core/coherence/lookups.js +155 -0
- package/dist/core/coherence/lookups.js.map +1 -0
- package/dist/core/coherence/pending.js +39 -0
- package/dist/core/coherence/pending.js.map +1 -0
- package/dist/core/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.js.map +1 -0
- package/dist/core/delta/claims.js +73 -0
- package/dist/core/delta/claims.js.map +1 -0
- package/dist/core/delta/delta.js +296 -0
- package/dist/core/delta/delta.js.map +1 -0
- package/dist/core/delta/document.js +177 -0
- package/dist/core/delta/document.js.map +1 -0
- package/dist/core/delta/scope.js +48 -0
- package/dist/core/delta/scope.js.map +1 -0
- package/dist/core/delta/select.js +237 -0
- package/dist/core/delta/select.js.map +1 -0
- package/dist/core/dependencies/dependencies.js +141 -0
- package/dist/core/dependencies/dependencies.js.map +1 -0
- package/dist/core/dependencies/facts.js +165 -0
- package/dist/core/dependencies/facts.js.map +1 -0
- package/dist/core/dependencies/fanin.js +88 -0
- package/dist/core/dependencies/fanin.js.map +1 -0
- package/dist/core/dependencies/graph.js +106 -0
- package/dist/core/dependencies/graph.js.map +1 -0
- package/dist/core/diff/base-git.js +148 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +209 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/current-state.js +96 -0
- package/dist/core/diff/current-state.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +188 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/semantic.js +243 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/diff/victims.js +247 -0
- package/dist/core/diff/victims.js.map +1 -0
- package/dist/core/docs.js +59 -55
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +222 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +135 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +275 -0
- package/dist/core/doctor/doctor.js.map +1 -0
- package/dist/core/doctor/report.js +13 -0
- package/dist/core/doctor/report.js.map +1 -0
- package/dist/core/doctor/residue.js +110 -0
- package/dist/core/doctor/residue.js.map +1 -0
- package/dist/core/document/apply.js +77 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
- package/dist/core/document/frontmatter.js.map +1 -0
- package/dist/core/document/grammar/directives.js +143 -0
- package/dist/core/document/grammar/directives.js.map +1 -0
- package/dist/core/document/parse.js +263 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +221 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +241 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +79 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +175 -0
- package/dist/core/envelope/json.js.map +1 -0
- package/dist/core/{version.js → envelope/version.js} +3 -3
- package/dist/core/envelope/version.js.map +1 -0
- package/dist/core/explain/families.js +175 -0
- package/dist/core/explain/families.js.map +1 -0
- package/dist/core/explain/fix-tables.js +178 -0
- package/dist/core/explain/fix-tables.js.map +1 -0
- package/dist/core/explain/lookup.js +181 -0
- package/dist/core/explain/lookup.js.map +1 -0
- package/dist/core/explain/refusals.js +49 -0
- package/dist/core/explain/refusals.js.map +1 -0
- package/dist/core/explain/terms.js +144 -0
- package/dist/core/explain/terms.js.map +1 -0
- package/dist/core/explore/describe.js +105 -0
- package/dist/core/explore/describe.js.map +1 -0
- package/dist/core/{explore.js → explore/explore.js} +50 -101
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +132 -77
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +201 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +205 -0
- package/dist/core/gate/partners.js.map +1 -0
- package/dist/core/gate/report.js +47 -0
- package/dist/core/gate/report.js.map +1 -0
- package/dist/core/gate/verification.js +113 -0
- package/dist/core/gate/verification.js.map +1 -0
- package/dist/core/gherkin/digest.js +60 -0
- package/dist/core/gherkin/digest.js.map +1 -0
- package/dist/core/gherkin/emit.js +177 -0
- package/dist/core/gherkin/emit.js.map +1 -0
- package/dist/core/gherkin/read.js +76 -0
- package/dist/core/gherkin/read.js.map +1 -0
- package/dist/core/gherkin/stale.js +234 -0
- package/dist/core/gherkin/stale.js.map +1 -0
- package/dist/core/gherkin/stamp.js +77 -0
- package/dist/core/gherkin/stamp.js.map +1 -0
- package/dist/core/gherkin/steps/catalogue.js +154 -0
- package/dist/core/gherkin/steps/catalogue.js.map +1 -0
- package/dist/core/gherkin/steps/inventory.js +98 -0
- package/dist/core/gherkin/steps/inventory.js.map +1 -0
- package/dist/core/gherkin/steps/phrase.js +72 -0
- package/dist/core/gherkin/steps/phrase.js.map +1 -0
- package/dist/core/glossary/delta.js +106 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +86 -0
- package/dist/core/glossary/tree.js.map +1 -0
- package/dist/core/kernel/concurrency.js.map +1 -0
- package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
- package/dist/core/kernel/document-bytes.js.map +1 -0
- package/dist/core/kernel/fences.js +42 -0
- package/dist/core/kernel/fences.js.map +1 -0
- package/dist/core/kernel/ids/capability.js +72 -0
- package/dist/core/kernel/ids/capability.js.map +1 -0
- package/dist/core/kernel/ids/dirs.js +33 -0
- package/dist/core/kernel/ids/dirs.js.map +1 -0
- package/dist/core/kernel/ids/feature.js +75 -0
- package/dist/core/kernel/ids/feature.js.map +1 -0
- package/dist/core/kernel/ids/service.js +156 -0
- package/dist/core/kernel/ids/service.js.map +1 -0
- package/dist/core/kernel/ids/subsystem.js +63 -0
- package/dist/core/kernel/ids/subsystem.js.map +1 -0
- package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +68 -0
- package/dist/core/links/backlinks.js.map +1 -0
- package/dist/core/links/case.js +74 -0
- package/dist/core/links/case.js.map +1 -0
- package/dist/core/links/corpus.js +104 -0
- package/dist/core/links/corpus.js.map +1 -0
- package/dist/core/links/findings.js +110 -0
- package/dist/core/links/findings.js.map +1 -0
- package/dist/core/links/parse.js +236 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +111 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +72 -0
- package/dist/core/mcp/author-tools.js.map +1 -0
- package/dist/core/mcp/framing.js +46 -0
- package/dist/core/mcp/framing.js.map +1 -0
- package/dist/core/mcp/protocol.js +280 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/tools.js +314 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/obligations/obligations.js +106 -0
- package/dist/core/obligations/obligations.js.map +1 -0
- package/dist/core/openapi/baseline/gate.js +166 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +112 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +175 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/depth.js +122 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +189 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +44 -106
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +234 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +26 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +208 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +256 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +128 -0
- package/dist/core/openapi/merge/pin.js.map +1 -0
- package/dist/core/openspec/decide/capabilities.js +244 -0
- package/dist/core/openspec/decide/capabilities.js.map +1 -0
- package/dist/core/openspec/decide/dispositions.js +63 -0
- package/dist/core/openspec/decide/dispositions.js.map +1 -0
- package/dist/core/openspec/decide/renames.js +179 -0
- package/dist/core/openspec/decide/renames.js.map +1 -0
- package/dist/core/openspec/decide/verdict.js +84 -0
- package/dist/core/openspec/decide/verdict.js.map +1 -0
- package/dist/core/openspec/inventory.js +221 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +76 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +65 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +235 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +200 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +260 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +133 -0
- package/dist/core/openspec/scan/walk.js.map +1 -0
- package/dist/core/openspec/scan/workspace.js +71 -0
- package/dist/core/openspec/scan/workspace.js.map +1 -0
- package/dist/core/owners/codeowners.js +141 -0
- package/dist/core/owners/codeowners.js.map +1 -0
- package/dist/core/pack/features.js +120 -0
- package/dist/core/pack/features.js.map +1 -0
- package/dist/core/pack/joins.js +112 -0
- package/dist/core/pack/joins.js.map +1 -0
- package/dist/core/pack/living.js +118 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +76 -0
- package/dist/core/pack/pack.js.map +1 -0
- package/dist/core/permissions/permissions.js +87 -0
- package/dist/core/permissions/permissions.js.map +1 -0
- package/dist/core/projection/api.js +84 -0
- package/dist/core/projection/api.js.map +1 -0
- package/dist/core/projection/arch-slice.js +63 -0
- package/dist/core/projection/arch-slice.js.map +1 -0
- package/dist/core/projection/events.js +34 -0
- package/dist/core/projection/events.js.map +1 -0
- package/dist/core/provenance/findings.js +208 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +225 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +182 -0
- package/dist/core/provenance/gitq/moves.js.map +1 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
- package/dist/core/provenance/sample/scope.js +238 -0
- package/dist/core/provenance/sample/scope.js.map +1 -0
- package/dist/core/provenance/sample/sections.js +61 -0
- package/dist/core/provenance/sample/sections.js.map +1 -0
- package/dist/core/provenance/sources.js +263 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +232 -0
- package/dist/core/provenance/stamp.js.map +1 -0
- package/dist/core/provenance/walk.js +157 -0
- package/dist/core/provenance/walk.js.map +1 -0
- package/dist/core/repo/authored/paths.js +192 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +236 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +248 -0
- package/dist/core/repo/repo.js.map +1 -0
- package/dist/core/repo/service-target.js +153 -0
- package/dist/core/repo/service-target.js.map +1 -0
- package/dist/core/repo/state.js +58 -0
- package/dist/core/repo/state.js.map +1 -0
- package/dist/core/repo/tree/find.js +52 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +64 -0
- package/dist/core/repo/tree/fs.js.map +1 -0
- package/dist/core/repo/tree/marker.js +61 -0
- package/dist/core/repo/tree/marker.js.map +1 -0
- package/dist/core/repo/tree/views.js +172 -0
- package/dist/core/repo/tree/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +234 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +99 -2
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +131 -0
- package/dist/core/scaffold/landscape.js.map +1 -0
- package/dist/core/scaffold/readme.js +84 -0
- package/dist/core/scaffold/readme.js.map +1 -0
- package/dist/core/staging/commit.js +241 -0
- package/dist/core/staging/commit.js.map +1 -0
- package/dist/core/staging/interrupted.js +96 -0
- package/dist/core/staging/interrupted.js.map +1 -0
- package/dist/core/staging/lock.js +206 -0
- package/dist/core/staging/lock.js.map +1 -0
- package/dist/core/staging/recovery/finding.js +35 -0
- package/dist/core/staging/recovery/finding.js.map +1 -0
- package/dist/core/staging/recovery/intent.js +98 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +126 -0
- package/dist/core/staging/recovery/recover.js.map +1 -0
- package/dist/core/staging/recovery/residue.js +62 -0
- package/dist/core/staging/recovery/residue.js.map +1 -0
- package/dist/core/staging/snapshot.js +202 -0
- package/dist/core/staging/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +171 -0
- package/dist/core/staging/txn/forward.js.map +1 -0
- package/dist/core/staging/txn/journal.js +139 -0
- package/dist/core/staging/txn/journal.js.map +1 -0
- package/dist/core/staging/txn/transaction.js +75 -0
- package/dist/core/staging/txn/transaction.js.map +1 -0
- package/dist/core/staging/writes.js +113 -0
- package/dist/core/staging/writes.js.map +1 -0
- package/dist/core/status/actions/execution.js +49 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +102 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +171 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +207 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +150 -0
- package/dist/core/status/feature/next.js.map +1 -0
- package/dist/core/status/feature/state.js +21 -0
- package/dist/core/status/feature/state.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +187 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +207 -0
- package/dist/core/status/fleet/next.js.map +1 -0
- package/dist/core/status/interrupted.js +97 -0
- package/dist/core/status/interrupted.js.map +1 -0
- package/dist/core/status/report.js +31 -0
- package/dist/core/status/report.js.map +1 -0
- package/dist/core/status/scan.js +41 -0
- package/dist/core/status/scan.js.map +1 -0
- package/dist/core/status/verification.js +201 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/usecases/capability.js +169 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +116 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +103 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +235 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +137 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/operations.js +111 -0
- package/dist/core/usecases/operations.js.map +1 -0
- package/dist/core/usecases/place.js +44 -0
- package/dist/core/usecases/place.js.map +1 -0
- package/dist/core/usecases/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +173 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +150 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +201 -0
- package/dist/core/verify/checklist.js.map +1 -0
- package/dist/core/verify/claims/identity.js +61 -0
- package/dist/core/verify/claims/identity.js.map +1 -0
- package/dist/core/verify/cross/diff.js +97 -0
- package/dist/core/verify/cross/diff.js.map +1 -0
- package/dist/core/verify/evidence/contract.js +169 -0
- package/dist/core/verify/evidence/contract.js.map +1 -0
- package/dist/core/verify/file.js +257 -0
- package/dist/core/verify/file.js.map +1 -0
- package/dist/core/verify/pins/lint.js +157 -0
- package/dist/core/verify/pins/lint.js.map +1 -0
- package/dist/core/verify/pins/pin.js +95 -0
- package/dist/core/verify/pins/pin.js.map +1 -0
- package/dist/core/verify/record.js +142 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +89 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +57 -0
- package/dist/core/verify/store/render.js.map +1 -0
- package/dist/core/vocabulary/health.js +91 -0
- package/dist/core/vocabulary/health.js.map +1 -0
- package/dist/core/vocabulary/issue.js +55 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +145 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/{report.js → vocabulary/report.js} +30 -2
- package/dist/core/vocabulary/report.js.map +1 -0
- package/dist/core/vocabulary/steps.js +266 -0
- package/dist/core/vocabulary/steps.js.map +1 -0
- package/dist/core/workspace/discover.js +239 -0
- package/dist/core/workspace/discover.js.map +1 -0
- package/dist/core/workspace/render.js +52 -0
- package/dist/core/workspace/render.js.map +1 -0
- package/examples/README.md +189 -0
- package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
- package/examples/docs/architecture/capabilities.yaml +31 -0
- package/examples/docs/architecture/landscape.likec4 +280 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/subsystems.likec4 +11 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
- package/examples/docs/capabilities/checkout/spec.md +55 -0
- package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
- package/examples/docs/capabilities/order-notifications/spec.md +43 -0
- package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
- package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
- package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
- package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
- package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
- package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
- package/examples/docs/glossary/order.md +15 -0
- package/examples/docs/glossary/payments/authorization.md +14 -0
- package/examples/docs/likec4.config.json +9 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +109 -0
- package/examples/docs/services/checkout-web/spec.md +91 -0
- package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
- package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
- package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
- package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
- package/examples/docs/services/order-service/arch.spec.md +127 -0
- package/examples/docs/services/order-service/asyncapi.yaml +108 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +138 -0
- package/examples/docs/services/order-service/openapi.yaml +257 -0
- package/examples/docs/services/order-service/runbook.md +62 -0
- package/examples/docs/services/order-service/spec.md +134 -0
- package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
- package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
- package/examples/docs/services/payment-service/arch.spec.md +73 -0
- package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
- package/examples/docs/services/payment-service/health.yaml +39 -0
- package/examples/docs/services/payment-service/model.likec4 +67 -0
- package/examples/docs/services/payment-service/openapi.yaml +151 -0
- package/examples/docs/services/payment-service/runbook.md +37 -0
- package/examples/docs/services/payment-service/spec.md +88 -0
- package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
- package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
- package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
- package/examples/docs/services/platform/identity-service/runbook.md +95 -0
- package/examples/docs/services/platform/identity-service/spec.md +119 -0
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
- package/examples/docs/services/platform/notification-service/health.yaml +35 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
- package/examples/docs/services/platform/notification-service/runbook.md +48 -0
- package/examples/docs/services/platform/notification-service/spec.md +112 -0
- package/examples/docs/services/platform/subsystem.yaml +2 -0
- package/examples/fleet.yaml +57 -0
- package/package.json +19 -6
- package/dist/commands/adopt.js +0 -240
- package/dist/commands/adopt.js.map +0 -1
- package/dist/commands/archive.js +0 -1313
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/delta.js +0 -388
- package/dist/commands/delta.js.map +0 -1
- package/dist/commands/docs-repo-gate.js.map +0 -1
- package/dist/commands/format.js +0 -17
- package/dist/commands/format.js.map +0 -1
- package/dist/commands/gherkin.js +0 -309
- package/dist/commands/gherkin.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/list.js +0 -291
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/migrate-openspec.js +0 -950
- package/dist/commands/migrate-openspec.js.map +0 -1
- package/dist/commands/new.js +0 -413
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/rebase.js +0 -356
- package/dist/commands/rebase.js.map +0 -1
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/status.js +0 -254
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unarchive.js.map +0 -1
- package/dist/commands/validate.js +0 -1591
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/verify.js +0 -775
- package/dist/commands/verify.js.map +0 -1
- package/dist/commands/vouch.js +0 -343
- package/dist/commands/vouch.js.map +0 -1
- package/dist/core/agent.js +0 -2065
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agents-stamp.js +0 -68
- package/dist/core/agents-stamp.js.map +0 -1
- package/dist/core/arch.js +0 -130
- package/dist/core/arch.js.map +0 -1
- package/dist/core/brief.js +0 -733
- package/dist/core/brief.js.map +0 -1
- package/dist/core/coherence.js +0 -577
- package/dist/core/coherence.js.map +0 -1
- package/dist/core/concurrency.js.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/delta.js +0 -476
- package/dist/core/delta.js.map +0 -1
- package/dist/core/dependencies.js +0 -356
- package/dist/core/dependencies.js.map +0 -1
- package/dist/core/doctor.js +0 -559
- package/dist/core/doctor.js.map +0 -1
- package/dist/core/document-bytes.js.map +0 -1
- package/dist/core/explore.js.map +0 -1
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/gherkin.js +0 -463
- package/dist/core/gherkin.js.map +0 -1
- package/dist/core/health.js +0 -67
- package/dist/core/health.js.map +0 -1
- package/dist/core/ids.js +0 -122
- package/dist/core/ids.js.map +0 -1
- package/dist/core/issue.js +0 -9
- package/dist/core/issue.js.map +0 -1
- package/dist/core/json.js +0 -74
- package/dist/core/json.js.map +0 -1
- package/dist/core/likec4.js +0 -479
- package/dist/core/likec4.js.map +0 -1
- package/dist/core/maturity.js +0 -66
- package/dist/core/maturity.js.map +0 -1
- package/dist/core/openapi-merge.js +0 -552
- package/dist/core/openapi-merge.js.map +0 -1
- package/dist/core/openapi.js.map +0 -1
- package/dist/core/openspec-inventory.js +0 -1440
- package/dist/core/openspec-inventory.js.map +0 -1
- package/dist/core/path-safety.js.map +0 -1
- package/dist/core/provenance.js +0 -720
- package/dist/core/provenance.js.map +0 -1
- package/dist/core/records.js.map +0 -1
- package/dist/core/repo.js +0 -436
- package/dist/core/repo.js.map +0 -1
- package/dist/core/report.js.map +0 -1
- package/dist/core/spec.js +0 -481
- package/dist/core/spec.js.map +0 -1
- package/dist/core/staging.js +0 -890
- package/dist/core/staging.js.map +0 -1
- package/dist/core/status.js +0 -1104
- package/dist/core/status.js.map +0 -1
- package/dist/core/steps.js +0 -72
- package/dist/core/steps.js.map +0 -1
- package/dist/core/verify.js +0 -807
- package/dist/core/verify.js.map +0 -1
- package/dist/core/version.js.map +0 -1
- /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
- /package/dist/core/{records.js → kernel/records.js} +0 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The whole repository — why the fleet form is cheaper than the feature form.
|
|
3
|
+
*
|
|
4
|
+
* `loam status` with no feature runs over every active feature, and deriving a
|
|
5
|
+
* coherence report or a verification checklist per feature means spinning a
|
|
6
|
+
* fresh LikeC4 workspace per feature. On a fleet-sized repository that is the
|
|
7
|
+
* cost that gets a command switched off — `list` made the same call about its
|
|
8
|
+
* verification column. So the fleet form grades nothing: it reports artifact
|
|
9
|
+
* PRESENCE, the dependency order, and a verification record only where one
|
|
10
|
+
* already exists, and its `next[]` hands off to `loam status <FEAT>`, which is
|
|
11
|
+
* where the checks actually run.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { readFile } from "node:fs/promises";
|
|
15
|
+
import { analyzeDependencies } from "../../dependencies/dependencies.js";
|
|
16
|
+
import {} from "../../dependencies/facts.js";
|
|
17
|
+
import { isLandscapeStub } from "../../scaffold/landscape.js";
|
|
18
|
+
import { repoPath } from "../../envelope/json.js";
|
|
19
|
+
import { FleetContext } from "../../fleet-context.js";
|
|
20
|
+
import { compareIds } from "../../repo/entries.js";
|
|
21
|
+
import { featurePaths, featureSpecPaths, landscapePath } from "../../repo/paths.js";
|
|
22
|
+
import { listFeatures, listServices } from "../../repo/repo.js";
|
|
23
|
+
import { contractOwners, contractsHeldElsewhere, owesContract } from "../contracts.js";
|
|
24
|
+
import { readInterruptedCommit } from "../interrupted.js";
|
|
25
|
+
import { undocumented, vouched, } from "../report.js";
|
|
26
|
+
import { governedServices, scanDeltas } from "../scan.js";
|
|
27
|
+
import { fullyVerified, verificationState } from "../verification.js";
|
|
28
|
+
import { fleetNext } from "./next.js";
|
|
29
|
+
/**
|
|
30
|
+
* The fleet view: how much of `services/` anyone has written down, every
|
|
31
|
+
* feature in flight with the stage it has reached, and the order they have to
|
|
32
|
+
* land in. Nothing here is graded — the module header says why — so the stages
|
|
33
|
+
* are drawn from artifact presence and from a record that already exists, and
|
|
34
|
+
* `next[]` hands off to `loam status <FEAT>` for everything else.
|
|
35
|
+
*/
|
|
36
|
+
export async function fleetStatus(docsDir, opts = {}) {
|
|
37
|
+
const context = opts.context ?? new FleetContext();
|
|
38
|
+
const interrupted = await readInterruptedCommit(docsDir);
|
|
39
|
+
const narrowed = opts.service;
|
|
40
|
+
const all = await listServices(docsDir, context);
|
|
41
|
+
const services = narrowed === undefined ? all : all.filter((s) => s.id === narrowed);
|
|
42
|
+
// The service this repository says it IS, and whether the fleet has heard of
|
|
43
|
+
// it. Asked against the UNNARROWED list, because "is it adopted" is a question
|
|
44
|
+
// about the fleet and not about the view.
|
|
45
|
+
//
|
|
46
|
+
// Both facts travel, where only the unadopted case used to. This value was a
|
|
47
|
+
// `string | null` that went null exactly when the service directory EXISTED,
|
|
48
|
+
// so the walk could see the repository it stands in only while that
|
|
49
|
+
// repository was undocumented — and a developer in an adopted service repo
|
|
50
|
+
// got the whole fleet's worklist with their own boundary buried in it.
|
|
51
|
+
const binding = opts.bound === undefined ? null : { id: opts.bound, adopted: all.some((s) => s.id === opts.bound) };
|
|
52
|
+
const graph = await analyzeDependencies(docsDir, undefined, context);
|
|
53
|
+
const entries = await listFeatures(docsDir, {}, context);
|
|
54
|
+
const inScope = narrowed === undefined ? entries : entries.filter((f) => f.services.some((s) => s === narrowed));
|
|
55
|
+
// Once for the fleet, not once per feature: which features hold a contract
|
|
56
|
+
// for which service is one fact about the repository, and every feature below
|
|
57
|
+
// reads its own row out of it. Built over the UNNARROWED list on purpose — a
|
|
58
|
+
// `--service` view still has to know that a feature outside it discharges the
|
|
59
|
+
// contract, or the narrowing would invent an obligation.
|
|
60
|
+
const owners = await contractOwners(docsDir, context);
|
|
61
|
+
const features = await Promise.all(inScope.map((f) => fleetFeature(docsDir, f, {
|
|
62
|
+
graph,
|
|
63
|
+
contracted: contractsHeldElsewhere(owners, f.id),
|
|
64
|
+
living: new Map(all.map((s) => [s.id, s])),
|
|
65
|
+
context,
|
|
66
|
+
interrupted,
|
|
67
|
+
})));
|
|
68
|
+
features.sort((a, b) => compareIds(a.id, b.id));
|
|
69
|
+
// The first-hour ladder's fact, computed exactly when the ladder can apply
|
|
70
|
+
// — an unnarrowed run over a fleet with zero services and zero features —
|
|
71
|
+
// so the read disappears from every repository that has anything in it.
|
|
72
|
+
// Withheld on narrowed runs for the same reason the binding is withheld
|
|
73
|
+
// below: `--service X` is an explicit question about X, and the
|
|
74
|
+
// repository's onboarding ladder would be a different question's answer.
|
|
75
|
+
const teaching = narrowed === undefined && services.length === 0 && features.length === 0
|
|
76
|
+
? { landscape: await landscapeTeaching(docsDir) }
|
|
77
|
+
: null;
|
|
78
|
+
return {
|
|
79
|
+
interrupted,
|
|
80
|
+
services: {
|
|
81
|
+
total: services.length,
|
|
82
|
+
undocumented: services.filter(undocumented).length,
|
|
83
|
+
draft: services.filter((s) => !undocumented(s) && !vouched(s)).length,
|
|
84
|
+
vouched: services.filter(vouched).length,
|
|
85
|
+
// A subset of `vouched`, never a fourth bucket: those services ARE
|
|
86
|
+
// vouched, and the three counts still sum to `total`. It rides beside
|
|
87
|
+
// the count it qualifies because this line is the fleet's trust
|
|
88
|
+
// headline, and "118 vouched" over a fleet where 90 of them were read
|
|
89
|
+
// from a sample is the misreading the scope exists to prevent.
|
|
90
|
+
sampledVouched: services.filter((s) => vouched(s) && s.vouchScope === "sampled").length,
|
|
91
|
+
},
|
|
92
|
+
features,
|
|
93
|
+
order: graph.order.filter((id) => features.some((f) => f.id === id)),
|
|
94
|
+
service: narrowed ?? null,
|
|
95
|
+
// The binding is passed only when this run was NOT narrowed, and that guard
|
|
96
|
+
// is unchanged now that the binding also decides ORDER. `--service X` is an
|
|
97
|
+
// explicit question about X, and answering it with a step about whichever
|
|
98
|
+
// service loam.json happens to name would be a different question's answer
|
|
99
|
+
// at the top of the list — which is as true of a rung promoted to the front
|
|
100
|
+
// as it was of `next.adopt-bound` emitted out of nowhere. A narrowed run
|
|
101
|
+
// sees at most the one service it asked about anyway, so withholding the
|
|
102
|
+
// binding here costs the reader nothing and keeps `--service X` answering
|
|
103
|
+
// only about X.
|
|
104
|
+
next: fleetNext({ services, features, graph, interrupted, teaching }, narrowed === undefined ? binding : null),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Which first-hour state the fleet map is in: absent, still the scaffold's own
|
|
109
|
+
* untouched bytes, or authored. One file read and a byte comparison — the
|
|
110
|
+
* module header's cost rule stands, no LikeC4 workspace is spun here.
|
|
111
|
+
*/
|
|
112
|
+
async function landscapeTeaching(docsDir) {
|
|
113
|
+
const lp = landscapePath(docsDir);
|
|
114
|
+
if (!existsSync(lp))
|
|
115
|
+
return "missing";
|
|
116
|
+
try {
|
|
117
|
+
return isLandscapeStub(await readFile(lp, "utf8")) ? "stub" : "authored";
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// Unreadable is not untouched. A map that cannot be read — a directory in
|
|
121
|
+
// the file's place, a permission — must not be called the scaffold's stub
|
|
122
|
+
// ("missing" and "stub" would each put a false statement in next[]), so it
|
|
123
|
+
// reads as "authored", which only drops the one teaching step: the gate
|
|
124
|
+
// entry still names `loam validate --all`, where an unreadable landscape
|
|
125
|
+
// is actually graded, and letting this read throw would hand the whole
|
|
126
|
+
// orientation surface — a command that reports and never gates — to the
|
|
127
|
+
// repository-unavailable refusal over a file status does not even parse.
|
|
128
|
+
return "authored";
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function fleetFeature(docsDir, feature, view) {
|
|
132
|
+
const { graph, contracted, living, context, interrupted } = view;
|
|
133
|
+
const paths = featurePaths(feature.dir);
|
|
134
|
+
const missing = [];
|
|
135
|
+
if (!existsSync(paths.intent))
|
|
136
|
+
missing.push("intent");
|
|
137
|
+
if (feature.services.length === 0)
|
|
138
|
+
missing.push("spec");
|
|
139
|
+
// Requirement text, not a coherence run: `Operations:` lines are read off the
|
|
140
|
+
// same cached parse `list` already pays for, and the contract question needs
|
|
141
|
+
// them (owesContract). No LikeC4 workspace is spun here, which is the cost
|
|
142
|
+
// this form actually refuses.
|
|
143
|
+
const governs = governedServices(await scanDeltas(docsDir, feature, feature.services, context));
|
|
144
|
+
for (const svc of feature.services) {
|
|
145
|
+
const p = featureSpecPaths(feature.dir, svc);
|
|
146
|
+
if (!existsSync(p.spec))
|
|
147
|
+
missing.push(`${svc}/spec`);
|
|
148
|
+
// The same question featureArtifacts asks, through the same function: the
|
|
149
|
+
// two forms must never disagree about whether a feature owes a contract.
|
|
150
|
+
if (owesContract(living.get(svc), contracted.has(svc), governs.has(svc)) && !existsSync(p.openapi)) {
|
|
151
|
+
missing.push(`${svc}/openapi`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const verification = (await verificationState(docsDir, feature)).state;
|
|
155
|
+
const blockedBy = graph.nodes.find((n) => n.id === feature.id)?.dependsOn ?? [];
|
|
156
|
+
// No `draft` here, ever: that verdict needs the coherence run this form
|
|
157
|
+
// refuses to pay for, and inferring it from presence alone would be a second
|
|
158
|
+
// opinion about validity — the one thing status must never invent.
|
|
159
|
+
//
|
|
160
|
+
// The interrupted commit leads, exactly as it does in the feature form: every
|
|
161
|
+
// presence test below is a question about files a killed `archive` may have
|
|
162
|
+
// half-written, so answering `done` from them is a claim about bytes nobody
|
|
163
|
+
// has established. Without this the two forms contradicted each other over
|
|
164
|
+
// one repository — `loam status --json` said `done` and offered "ship it"
|
|
165
|
+
// while `loam status <FEAT>` said `blocked` — and the rule in report.ts's
|
|
166
|
+
// header is that this projection is never greener than the gates.
|
|
167
|
+
const stage = interrupted !== null
|
|
168
|
+
? "blocked"
|
|
169
|
+
: missing.length > 0
|
|
170
|
+
? "missing"
|
|
171
|
+
: blockedBy.length > 0
|
|
172
|
+
? "blocked"
|
|
173
|
+
: fullyVerified(verification)
|
|
174
|
+
? "done"
|
|
175
|
+
: "ready";
|
|
176
|
+
return {
|
|
177
|
+
id: feature.id,
|
|
178
|
+
dirName: feature.dirName,
|
|
179
|
+
path: repoPath(docsDir, feature.dir),
|
|
180
|
+
stage,
|
|
181
|
+
services: feature.services,
|
|
182
|
+
blockedBy,
|
|
183
|
+
missing,
|
|
184
|
+
verification,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=fleet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fleet.js","sourceRoot":"","sources":["../../../../src/core/status/fleet/fleet.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The whole repository — why the fleet form is cheaper than the feature form.\n *\n * `loam status` with no feature runs over every active feature, and deriving a\n * coherence report or a verification checklist per feature means spinning a\n * fresh LikeC4 workspace per feature. On a fleet-sized repository that is the\n * cost that gets a command switched off — `list` made the same call about its\n * verification column. So the fleet form grades nothing: it reports artifact\n * PRESENCE, the dependency order, and a verification record only where one\n * already exists, and its `next[]` hands off to `loam status <FEAT>`, which is\n * where the checks actually run.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { analyzeDependencies } from \"../../dependencies/dependencies.js\";\nimport { type DependencyGraph } from \"../../dependencies/facts.js\";\nimport { isLandscapeStub } from \"../../scaffold/landscape.js\";\nimport { repoPath } from \"../../envelope/json.js\";\nimport { FleetContext } from \"../../fleet-context.js\";\nimport { compareIds, type FeatureEntry, type ServiceEntry } from \"../../repo/entries.js\";\nimport { featurePaths, featureSpecPaths, landscapePath } from \"../../repo/paths.js\";\nimport { listFeatures, listServices } from \"../../repo/repo.js\";\nimport { contractOwners, contractsHeldElsewhere, owesContract } from \"../contracts.js\";\nimport { readInterruptedCommit } from \"../interrupted.js\";\nimport {\n undocumented,\n vouched,\n type ArtifactStatus,\n type FleetFeatureState,\n type FleetStatusReport,\n type InterruptedCommit,\n} from \"../report.js\";\nimport { governedServices, scanDeltas } from \"../scan.js\";\nimport { fullyVerified, verificationState } from \"../verification.js\";\nimport { fleetNext, type Binding } from \"./next.js\";\nimport type { DocsDir } from \"../../kernel/ids/dirs.js\";\n\n/**\n * The fleet view: how much of `services/` anyone has written down, every\n * feature in flight with the stage it has reached, and the order they have to\n * land in. Nothing here is graded — the module header says why — so the stages\n * are drawn from artifact presence and from a record that already exists, and\n * `next[]` hands off to `loam status <FEAT>` for everything else.\n */\nexport async function fleetStatus(\n docsDir: DocsDir,\n opts: { service?: string; bound?: string; context?: FleetContext } = {},\n): Promise<FleetStatusReport> {\n const context = opts.context ?? new FleetContext();\n const interrupted = await readInterruptedCommit(docsDir);\n const narrowed = opts.service;\n const all = await listServices(docsDir, context);\n const services = narrowed === undefined ? all : all.filter((s) => s.id === narrowed);\n // The service this repository says it IS, and whether the fleet has heard of\n // it. Asked against the UNNARROWED list, because \"is it adopted\" is a question\n // about the fleet and not about the view.\n //\n // Both facts travel, where only the unadopted case used to. This value was a\n // `string | null` that went null exactly when the service directory EXISTED,\n // so the walk could see the repository it stands in only while that\n // repository was undocumented — and a developer in an adopted service repo\n // got the whole fleet's worklist with their own boundary buried in it.\n const binding: Binding | null =\n opts.bound === undefined ? null : { id: opts.bound, adopted: all.some((s) => s.id === opts.bound) };\n const graph = await analyzeDependencies(docsDir, undefined, context);\n const entries = await listFeatures(docsDir, {}, context);\n const inScope = narrowed === undefined ? entries : entries.filter((f) => f.services.some((s) => s === narrowed));\n // Once for the fleet, not once per feature: which features hold a contract\n // for which service is one fact about the repository, and every feature below\n // reads its own row out of it. Built over the UNNARROWED list on purpose — a\n // `--service` view still has to know that a feature outside it discharges the\n // contract, or the narrowing would invent an obligation.\n const owners = await contractOwners(docsDir, context);\n\n const features = await Promise.all(\n inScope.map((f) =>\n fleetFeature(docsDir, f, {\n graph,\n contracted: contractsHeldElsewhere(owners, f.id),\n living: new Map(all.map((s) => [s.id, s])),\n context,\n interrupted,\n }),\n ),\n );\n features.sort((a, b) => compareIds(a.id, b.id));\n\n // The first-hour ladder's fact, computed exactly when the ladder can apply\n // — an unnarrowed run over a fleet with zero services and zero features —\n // so the read disappears from every repository that has anything in it.\n // Withheld on narrowed runs for the same reason the binding is withheld\n // below: `--service X` is an explicit question about X, and the\n // repository's onboarding ladder would be a different question's answer.\n const teaching =\n narrowed === undefined && services.length === 0 && features.length === 0\n ? { landscape: await landscapeTeaching(docsDir) }\n : null;\n\n return {\n interrupted,\n services: {\n total: services.length,\n undocumented: services.filter(undocumented).length,\n draft: services.filter((s) => !undocumented(s) && !vouched(s)).length,\n vouched: services.filter(vouched).length,\n // A subset of `vouched`, never a fourth bucket: those services ARE\n // vouched, and the three counts still sum to `total`. It rides beside\n // the count it qualifies because this line is the fleet's trust\n // headline, and \"118 vouched\" over a fleet where 90 of them were read\n // from a sample is the misreading the scope exists to prevent.\n sampledVouched: services.filter((s) => vouched(s) && s.vouchScope === \"sampled\").length,\n },\n features,\n order: graph.order.filter((id) => features.some((f) => f.id === id)),\n service: narrowed ?? null,\n // The binding is passed only when this run was NOT narrowed, and that guard\n // is unchanged now that the binding also decides ORDER. `--service X` is an\n // explicit question about X, and answering it with a step about whichever\n // service loam.json happens to name would be a different question's answer\n // at the top of the list — which is as true of a rung promoted to the front\n // as it was of `next.adopt-bound` emitted out of nowhere. A narrowed run\n // sees at most the one service it asked about anyway, so withholding the\n // binding here costs the reader nothing and keeps `--service X` answering\n // only about X.\n next: fleetNext(\n { services, features, graph, interrupted, teaching },\n narrowed === undefined ? binding : null,\n ),\n };\n}\n\n/**\n * Which first-hour state the fleet map is in: absent, still the scaffold's own\n * untouched bytes, or authored. One file read and a byte comparison — the\n * module header's cost rule stands, no LikeC4 workspace is spun here.\n */\nasync function landscapeTeaching(docsDir: DocsDir): Promise<\"missing\" | \"stub\" | \"authored\"> {\n const lp = landscapePath(docsDir);\n if (!existsSync(lp)) return \"missing\";\n try {\n return isLandscapeStub(await readFile(lp, \"utf8\")) ? \"stub\" : \"authored\";\n } catch {\n // Unreadable is not untouched. A map that cannot be read — a directory in\n // the file's place, a permission — must not be called the scaffold's stub\n // (\"missing\" and \"stub\" would each put a false statement in next[]), so it\n // reads as \"authored\", which only drops the one teaching step: the gate\n // entry still names `loam validate --all`, where an unreadable landscape\n // is actually graded, and letting this read throw would hand the whole\n // orientation surface — a command that reports and never gates — to the\n // repository-unavailable refusal over a file status does not even parse.\n return \"authored\";\n }\n}\n\n/** What a feature's fleet row needs about the fleet AROUND it. */\ninterface FleetView {\n graph: DependencyGraph;\n /** Operations some other feature's contract already holds. */\n contracted: ReadonlySet<string>;\n /** The enumeration's entries by id — where each living service is and what it has (owesContract reads both). */\n living: ReadonlyMap<string, ServiceEntry>;\n context: FleetContext;\n interrupted: InterruptedCommit | null;\n}\n\nasync function fleetFeature(\n docsDir: DocsDir,\n feature: FeatureEntry,\n view: FleetView,\n): Promise<FleetFeatureState> {\n const { graph, contracted, living, context, interrupted } = view;\n const paths = featurePaths(feature.dir);\n const missing: string[] = [];\n if (!existsSync(paths.intent)) missing.push(\"intent\");\n if (feature.services.length === 0) missing.push(\"spec\");\n // Requirement text, not a coherence run: `Operations:` lines are read off the\n // same cached parse `list` already pays for, and the contract question needs\n // them (owesContract). No LikeC4 workspace is spun here, which is the cost\n // this form actually refuses.\n const governs = governedServices(await scanDeltas(docsDir, feature, feature.services, context));\n for (const svc of feature.services) {\n const p = featureSpecPaths(feature.dir, svc);\n if (!existsSync(p.spec)) missing.push(`${svc}/spec`);\n // The same question featureArtifacts asks, through the same function: the\n // two forms must never disagree about whether a feature owes a contract.\n if (owesContract(living.get(svc), contracted.has(svc), governs.has(svc)) && !existsSync(p.openapi)) {\n missing.push(`${svc}/openapi`);\n }\n }\n const verification = (await verificationState(docsDir, feature)).state;\n const blockedBy = graph.nodes.find((n) => n.id === feature.id)?.dependsOn ?? [];\n\n // No `draft` here, ever: that verdict needs the coherence run this form\n // refuses to pay for, and inferring it from presence alone would be a second\n // opinion about validity — the one thing status must never invent.\n //\n // The interrupted commit leads, exactly as it does in the feature form: every\n // presence test below is a question about files a killed `archive` may have\n // half-written, so answering `done` from them is a claim about bytes nobody\n // has established. Without this the two forms contradicted each other over\n // one repository — `loam status --json` said `done` and offered \"ship it\"\n // while `loam status <FEAT>` said `blocked` — and the rule in report.ts's\n // header is that this projection is never greener than the gates.\n const stage: ArtifactStatus =\n interrupted !== null\n ? \"blocked\"\n : missing.length > 0\n ? \"missing\"\n : blockedBy.length > 0\n ? \"blocked\"\n : fullyVerified(verification)\n ? \"done\"\n : \"ready\";\n\n return {\n id: feature.id,\n dirName: feature.dirName,\n path: repoPath(docsDir, feature.dir),\n stage,\n services: feature.services,\n blockedBy,\n missing,\n verification,\n };\n}\n"]}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { serviceTreePath } from "../../kernel/ids/dirs.js";
|
|
2
|
+
import { compareIds } from "../../repo/entries.js";
|
|
3
|
+
import { recoverStep } from "../interrupted.js";
|
|
4
|
+
import { undocumented, } from "../report.js";
|
|
5
|
+
/** How urgent a stage is at fleet level. See {@link fleetNext}. */
|
|
6
|
+
const STAGE_RANK = {
|
|
7
|
+
done: 0,
|
|
8
|
+
ready: 1,
|
|
9
|
+
draft: 2,
|
|
10
|
+
missing: 3,
|
|
11
|
+
blocked: 4,
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* How many per-service and per-feature steps the fleet form will print before
|
|
15
|
+
* it stops and says how many it left out. A fleet mid-adoption produced 135
|
|
16
|
+
* entries under the heading "the next thing to do" — a list nobody reads is a
|
|
17
|
+
* list that is not navigation, and the first ten are the ten that matter
|
|
18
|
+
* because the ordering below is already most-unblocking-first.
|
|
19
|
+
*
|
|
20
|
+
* Exported so the test asserts the cap through the constant: a literal 10 in a
|
|
21
|
+
* fixture is a second declaration of the limit, free to disagree the day this
|
|
22
|
+
* one moves.
|
|
23
|
+
*/
|
|
24
|
+
export const FLEET_NEXT_LIMIT = 10;
|
|
25
|
+
export function fleetNext(fleet, binding) {
|
|
26
|
+
const { services, features, graph, interrupted, teaching } = fleet;
|
|
27
|
+
const steps = [];
|
|
28
|
+
// The two arms of the binding, each named for the question it answers. The
|
|
29
|
+
// first reproduces the old parameter exactly, so everything reading it below
|
|
30
|
+
// is unchanged; the second is the fact that used to be thrown away.
|
|
31
|
+
const unadoptedBinding = binding !== null && !binding.adopted ? binding.id : null;
|
|
32
|
+
const adoptedBinding = binding !== null && binding.adopted ? binding.id : null;
|
|
33
|
+
// The repository this command is standing in names a service the fleet has no
|
|
34
|
+
// directory for. First, ahead of every other service's partial adoption,
|
|
35
|
+
// because it is the only step that is about HERE.
|
|
36
|
+
//
|
|
37
|
+
// This form used to count the fleet and ignore the binding entirely, so in a
|
|
38
|
+
// service repo bound to an unadopted service — a freshly wired one, the most
|
|
39
|
+
// common repo there is — an empty fleet made "every service is written down"
|
|
40
|
+
// vacuously true and `next.fleet-clean` came out top. `loam doctor` had the
|
|
41
|
+
// right answer (`doctor.service-unknown`) at the same moment, and the
|
|
42
|
+
// documented agent loop reads `status`: an agent following it was sent to
|
|
43
|
+
// start a feature instead of adopting the service under its feet.
|
|
44
|
+
if (unadoptedBinding !== null) {
|
|
45
|
+
steps.push({
|
|
46
|
+
code: "next.adopt-bound",
|
|
47
|
+
statement: `This repository's loam.json says it is '${unadoptedBinding}', and the fleet has no ` +
|
|
48
|
+
`services/${unadoptedBinding}/ — nothing about the service you are standing in is written down yet.`,
|
|
49
|
+
command: `loam adopt --service ${unadoptedBinding} --json`,
|
|
50
|
+
service: unadoptedBinding,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
// The first hour of a docs repo, in order. Zero services and zero features
|
|
54
|
+
// used to fall through every loop below into `next.fleet-clean` — the header
|
|
55
|
+
// says why that answer was vacuous — so the emptiest repository loam serves
|
|
56
|
+
// got the least from the command whose whole purpose is "what do I do next".
|
|
57
|
+
// These are ordinary steps on purpose: the gate entry still closes the list,
|
|
58
|
+
// and the tail ternary is untouched. The bind/adopt rungs are suppressed when
|
|
59
|
+
// `next.adopt-bound` above already names the exact adopt to run, and the
|
|
60
|
+
// whole ladder is withheld on narrowed runs (`teaching === null`).
|
|
61
|
+
if (teaching !== null && services.length === 0 && features.length === 0) {
|
|
62
|
+
if (teaching.landscape !== "authored") {
|
|
63
|
+
steps.push({
|
|
64
|
+
code: "next.author-landscape",
|
|
65
|
+
statement: teaching.landscape === "missing"
|
|
66
|
+
? "architecture/landscape.likec4 does not exist — the fleet map is the one artifact every " +
|
|
67
|
+
"cross-service check reads. Run `loam init --create` to scaffold it, then draw the first service."
|
|
68
|
+
: "architecture/landscape.likec4 is still the scaffold's untouched map — no service is drawn. " +
|
|
69
|
+
"State the facts in a fleet.yaml (service ids, `a -> b` calls) and run " +
|
|
70
|
+
"`loam seed --from fleet.yaml` to template the map mechanically — or open the file " +
|
|
71
|
+
"and follow its own comments. Either way loam never guesses who calls whom.",
|
|
72
|
+
// The command each arm's own prose already names, and for a while it
|
|
73
|
+
// was neither: both arms carried the gate. WORKFLOW.md documents the
|
|
74
|
+
// agent loop as "read next[0], run the command it names, repeat" and
|
|
75
|
+
// every generated skill says to branch on the code rather than the
|
|
76
|
+
// prose — so an agent on the first rung of the first hour ran
|
|
77
|
+
// `validate --all` against a repository with no services in it, which
|
|
78
|
+
// answers ok:true with `landscape.matched` and changes nothing, and
|
|
79
|
+
// came back to the identical next[0] forever. A livelock on day zero,
|
|
80
|
+
// on the one command built to answer "what now". The gate is still
|
|
81
|
+
// named: `next.fleet-gate` closes this same list.
|
|
82
|
+
command: teaching.landscape === "missing" ? "loam init --create" : "loam seed --from fleet.yaml",
|
|
83
|
+
path: "architecture/landscape.likec4",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
if (unadoptedBinding === null) {
|
|
87
|
+
steps.push({
|
|
88
|
+
code: "next.bind-service",
|
|
89
|
+
statement: "No service repository is bound to this fleet yet. From a service's own repo, point --docs " +
|
|
90
|
+
"here and --service at its canonical id, then commit the loam.json it writes.",
|
|
91
|
+
command: "loam init --docs <path-to-this-docs-repo> --service <service-id>",
|
|
92
|
+
});
|
|
93
|
+
steps.push({
|
|
94
|
+
code: "next.adopt-first",
|
|
95
|
+
statement: "services/ is empty — nothing about any service is written down yet. Adopt the first one: " +
|
|
96
|
+
"the brief walks an agent through writing its baseline docs as draft.",
|
|
97
|
+
command: "loam adopt --service <service-id> --json",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// The per-service rungs are collected into their own list rather than pushed
|
|
102
|
+
// straight onto `steps`, because the partition below acts on them as a group
|
|
103
|
+
// — and only on them. Nothing here may float above `next.adopt-bound` or the
|
|
104
|
+
// first-hour ladder, both of which are about the repository rather than about
|
|
105
|
+
// any one service in the fleet.
|
|
106
|
+
const perService = [];
|
|
107
|
+
for (const s of services.filter(undocumented)) {
|
|
108
|
+
perService.push({
|
|
109
|
+
code: "next.adopt",
|
|
110
|
+
statement: `${serviceTreePath(s)}/ has no spec.md — nothing about ${s.id} is written down, so no feature can be graded against it.`,
|
|
111
|
+
command: `loam adopt --service ${s.id} --json`,
|
|
112
|
+
service: s.id,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
// Adoption does not end at spec.md. A service with a living spec and no
|
|
116
|
+
// model.likec4 is the state archive itself warns about (`service.no-model`)
|
|
117
|
+
// and the fleet gate reports — invisible here until now, because this form
|
|
118
|
+
// looked at exactly one bit of each service's artifact set.
|
|
119
|
+
for (const s of services.filter((x) => !undocumented(x) && !x.has.model)) {
|
|
120
|
+
perService.push({
|
|
121
|
+
code: "next.complete-service",
|
|
122
|
+
statement: `${serviceTreePath(s)}/ has a spec.md but no model.likec4 — the fleet gate reports the service incomplete until something models it.`,
|
|
123
|
+
command: `loam validate --service ${s.id} --json`,
|
|
124
|
+
service: s.id,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
// The boundary this repository IS comes first among the boundaries it merely
|
|
128
|
+
// shares a fleet with. A stable PARTITION and deliberately not a sort: the
|
|
129
|
+
// bound service's rungs move to the front and every other service keeps the
|
|
130
|
+
// alphabetical order it already had, so the list an unbound reader sees — a
|
|
131
|
+
// docs repo, CI, `loam validate --all`'s scorecard — is byte-for-byte the one
|
|
132
|
+
// it saw before.
|
|
133
|
+
//
|
|
134
|
+
// The cap is why this is ordering and not cosmetics. Ten rungs print, and in
|
|
135
|
+
// the ten-repo case WORKFLOW.md describes every developer's `loam status`
|
|
136
|
+
// opened with nine other services' adoption work; past ten services the one
|
|
137
|
+
// rung this developer can actually act on was elided entirely, leaving a list
|
|
138
|
+
// of nothing but other people's boundaries under the heading "next". No new
|
|
139
|
+
// code is emitted for any of this — `next[]` has always been documented as
|
|
140
|
+
// most-unblocking first, and this is the line that makes the claim true from
|
|
141
|
+
// where the reader is standing.
|
|
142
|
+
steps.push(...(adoptedBinding === null
|
|
143
|
+
? perService
|
|
144
|
+
: [
|
|
145
|
+
...perService.filter((s) => s.service === adoptedBinding),
|
|
146
|
+
...perService.filter((s) => s.service !== adoptedBinding),
|
|
147
|
+
]));
|
|
148
|
+
const ordered = [...features].sort((a, b) => STAGE_RANK[a.stage] - STAGE_RANK[b.stage] ||
|
|
149
|
+
graph.order.indexOf(a.id) - graph.order.indexOf(b.id) ||
|
|
150
|
+
compareIds(a.id, b.id));
|
|
151
|
+
for (const f of ordered) {
|
|
152
|
+
if (f.stage === "done") {
|
|
153
|
+
steps.push({
|
|
154
|
+
code: "next.archive",
|
|
155
|
+
statement: `${f.id} is authored and verified — ship it, and everything waiting on it is released.`,
|
|
156
|
+
command: `loam archive ${f.id} --dry-run --json`,
|
|
157
|
+
});
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
steps.push({
|
|
161
|
+
code: "next.feature",
|
|
162
|
+
statement:
|
|
163
|
+
// The list, not the stage, is what this sentence names. `blocked` has
|
|
164
|
+
// two causes now — another feature in flight, and an interrupted commit
|
|
165
|
+
// that stalls the whole repository — and the second one names no
|
|
166
|
+
// feature, so keying off the stage alone printed "FEAT-1 is waiting
|
|
167
|
+
// on ." The recover step above already says what the repository is
|
|
168
|
+
// waiting on.
|
|
169
|
+
f.stage === "blocked" && f.blockedBy.length > 0
|
|
170
|
+
? `${f.id} is waiting on ${f.blockedBy.join(", ")}.`
|
|
171
|
+
: `${f.id} is at '${f.stage}'${f.missing.length > 0 ? ` — missing ${f.missing.join(", ")}` : ""}.`,
|
|
172
|
+
command: `loam status ${f.id} --json`,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
const elided = Math.max(0, steps.length - FLEET_NEXT_LIMIT);
|
|
176
|
+
// Outside the cap, not merely first inside it: the one step that must never
|
|
177
|
+
// be the one this list left out.
|
|
178
|
+
const out = [...(interrupted === null ? [] : [recoverStep(interrupted)]), ...steps.slice(0, FLEET_NEXT_LIMIT)];
|
|
179
|
+
if (elided > 0) {
|
|
180
|
+
out.push({
|
|
181
|
+
code: "next.elided",
|
|
182
|
+
statement: `${elided} more step(s) of the same kinds were left out — this list is ordered most-unblocking first, so work down it and run status again.`,
|
|
183
|
+
command: "loam list --json",
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
out.push(steps.length === 0
|
|
187
|
+
? {
|
|
188
|
+
code: "next.fleet-clean",
|
|
189
|
+
statement: "Nothing is in flight and every service is written down — keep the fleet green, then start the next feature.",
|
|
190
|
+
command: "loam validate --all --json",
|
|
191
|
+
}
|
|
192
|
+
: {
|
|
193
|
+
code: "next.fleet-gate",
|
|
194
|
+
// `loam validate --all` inside the backticks, not the bare
|
|
195
|
+
// `validate --all` this sentence carried for a year: a span without
|
|
196
|
+
// the binary name is invisible to every check that reads a
|
|
197
|
+
// backticked `loam <verb>` as an instruction — the parse check in
|
|
198
|
+
// test/agent-commands-runnable.test.ts, and the statement/command
|
|
199
|
+
// invariant in test/status.test.ts. A prefix is cheaper than an
|
|
200
|
+
// exemption, and the exemption is what lets a wrong command through.
|
|
201
|
+
statement: `${features.length} feature(s) in flight over ${services.length} service(s) — ` +
|
|
202
|
+
"status grades none of them; `loam validate --all` is the gate this repository has to pass, and it is what CI runs.",
|
|
203
|
+
command: "loam validate --all --json",
|
|
204
|
+
});
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=next.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"next.js","sourceRoot":"","sources":["../../../../src/core/status/fleet/next.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAqB,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,YAAY,GAKb,MAAM,cAAc,CAAC;AAEtB,mEAAmE;AACnE,MAAM,UAAU,GAAmC;IACjD,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,KAAK,EAAE,CAAC;IACR,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;CACX,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAqDnC,MAAM,UAAU,SAAS,CAAC,KAAY,EAAE,OAAuB;IAC7D,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACnE,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,2EAA2E;IAC3E,6EAA6E;IAC7E,oEAAoE;IACpE,MAAM,gBAAgB,GAAG,OAAO,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAClF,MAAM,cAAc,GAAG,OAAO,KAAK,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAE/E,8EAA8E;IAC9E,yEAAyE;IACzE,kDAAkD;IAClD,EAAE;IACF,6EAA6E;IAC7E,6EAA6E;IAC7E,6EAA6E;IAC7E,4EAA4E;IAC5E,sEAAsE;IACtE,0EAA0E;IAC1E,kEAAkE;IAClE,IAAI,gBAAgB,KAAK,IAAI,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,kBAAkB;YACxB,SAAS,EACP,2CAA2C,gBAAgB,0BAA0B;gBACrF,YAAY,gBAAgB,wEAAwE;YACtG,OAAO,EAAE,wBAAwB,gBAAgB,SAAS;YAC1D,OAAO,EAAE,gBAAgB;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,2EAA2E;IAC3E,6EAA6E;IAC7E,4EAA4E;IAC5E,6EAA6E;IAC7E,6EAA6E;IAC7E,8EAA8E;IAC9E,yEAAyE;IACzE,mEAAmE;IACnE,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxE,IAAI,QAAQ,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,uBAAuB;gBAC7B,SAAS,EACP,QAAQ,CAAC,SAAS,KAAK,SAAS;oBAC9B,CAAC,CAAC,yFAAyF;wBACzF,kGAAkG;oBACpG,CAAC,CAAC,6FAA6F;wBAC7F,wEAAwE;wBACxE,oFAAoF;wBACpF,4EAA4E;gBAClF,qEAAqE;gBACrE,qEAAqE;gBACrE,qEAAqE;gBACrE,mEAAmE;gBACnE,8DAA8D;gBAC9D,sEAAsE;gBACtE,oEAAoE;gBACpE,sEAAsE;gBACtE,mEAAmE;gBACnE,kDAAkD;gBAClD,OAAO,EAAE,QAAQ,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,6BAA6B;gBAChG,IAAI,EAAE,+BAA+B;aACtC,CAAC,CAAC;QACL,CAAC;QACD,IAAI,gBAAgB,KAAK,IAAI,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,mBAAmB;gBACzB,SAAS,EACP,4FAA4F;oBAC5F,8EAA8E;gBAChF,OAAO,EAAE,kEAAkE;aAC5E,CAAC,CAAC;YACH,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,kBAAkB;gBACxB,SAAS,EACP,2FAA2F;oBAC3F,sEAAsE;gBACxE,OAAO,EAAE,0CAA0C;aACpD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,6EAA6E;IAC7E,6EAA6E;IAC7E,8EAA8E;IAC9E,gCAAgC;IAChC,MAAM,UAAU,GAAe,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9C,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,YAAY;YAClB,SAAS,EAAE,GAAG,eAAe,CAAC,CAAC,CAAC,oCAAoC,CAAC,CAAC,EAAE,2DAA2D;YACnI,OAAO,EAAE,wBAAwB,CAAC,CAAC,EAAE,SAAS;YAC9C,OAAO,EAAE,CAAC,CAAC,EAAE;SACd,CAAC,CAAC;IACL,CAAC;IAED,wEAAwE;IACxE,4EAA4E;IAC5E,2EAA2E;IAC3E,4DAA4D;IAC5D,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACzE,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,uBAAuB;YAC7B,SAAS,EAAE,GAAG,eAAe,CAAC,CAAC,CAAC,gHAAgH;YAChJ,OAAO,EAAE,2BAA2B,CAAC,CAAC,EAAE,SAAS;YACjD,OAAO,EAAE,CAAC,CAAC,EAAE;SACd,CAAC,CAAC;IACL,CAAC;IAED,6EAA6E;IAC7E,2EAA2E;IAC3E,4EAA4E;IAC5E,4EAA4E;IAC5E,8EAA8E;IAC9E,iBAAiB;IACjB,EAAE;IACF,6EAA6E;IAC7E,0EAA0E;IAC1E,4EAA4E;IAC5E,8EAA8E;IAC9E,4EAA4E;IAC5E,2EAA2E;IAC3E,6EAA6E;IAC7E,gCAAgC;IAChC,KAAK,CAAC,IAAI,CACR,GAAG,CAAC,cAAc,KAAK,IAAI;QACzB,CAAC,CAAC,UAAU;QACZ,CAAC,CAAC;YACE,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,cAAc,CAAC;YACzD,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,cAAc,CAAC;SAC1D,CAAC,CACP,CAAC;IAEF,MAAM,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC;QACzC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CACzB,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,cAAc;gBACpB,SAAS,EAAE,GAAG,CAAC,CAAC,EAAE,gFAAgF;gBAClG,OAAO,EAAE,gBAAgB,CAAC,CAAC,EAAE,mBAAmB;aACjD,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,cAAc;YACpB,SAAS;YACP,sEAAsE;YACtE,wEAAwE;YACxE,iEAAiE;YACjE,oEAAoE;YACpE,mEAAmE;YACnE,cAAc;YACd,CAAC,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC;gBAC7C,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBACpD,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG;YACtG,OAAO,EAAE,eAAe,CAAC,CAAC,EAAE,SAAS;SACtC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,gBAAgB,CAAC,CAAC;IAC5D,4EAA4E;IAC5E,iCAAiC;IACjC,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAC/G,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACf,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,aAAa;YACnB,SAAS,EAAE,GAAG,MAAM,mIAAmI;YACvJ,OAAO,EAAE,kBAAkB;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,IAAI,CACN,KAAK,CAAC,MAAM,KAAK,CAAC;QAChB,CAAC,CAAC;YACE,IAAI,EAAE,kBAAkB;YACxB,SAAS,EACP,6GAA6G;YAC/G,OAAO,EAAE,4BAA4B;SACtC;QACH,CAAC,CAAC;YACE,IAAI,EAAE,iBAAiB;YACvB,2DAA2D;YAC3D,oEAAoE;YACpE,2DAA2D;YAC3D,kEAAkE;YAClE,kEAAkE;YAClE,gEAAgE;YAChE,qEAAqE;YACrE,SAAS,EACP,GAAG,QAAQ,CAAC,MAAM,8BAA8B,QAAQ,CAAC,MAAM,gBAAgB;gBAC/E,oHAAoH;YACtH,OAAO,EAAE,4BAA4B;SACtC,CACN,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/**\n * `next[]` — the whole repository: adoption gaps first, then every feature in\n * flight, most-unblocking first, capped so the list stays navigation rather\n * than inventory.\n */\nimport type { DependencyGraph } from \"../../dependencies/facts.js\";\nimport { serviceTreePath } from \"../../kernel/ids/dirs.js\";\nimport { compareIds, type ServiceEntry } from \"../../repo/entries.js\";\nimport { recoverStep } from \"../interrupted.js\";\nimport {\n undocumented,\n type ArtifactStatus,\n type FleetFeatureState,\n type InterruptedCommit,\n type NextStep,\n} from \"../report.js\";\n\n/** How urgent a stage is at fleet level. See {@link fleetNext}. */\nconst STAGE_RANK: Record<ArtifactStatus, number> = {\n done: 0,\n ready: 1,\n draft: 2,\n missing: 3,\n blocked: 4,\n};\n\n/**\n * How many per-service and per-feature steps the fleet form will print before\n * it stops and says how many it left out. A fleet mid-adoption produced 135\n * entries under the heading \"the next thing to do\" — a list nobody reads is a\n * list that is not navigation, and the first ten are the ten that matter\n * because the ordering below is already most-unblocking-first.\n *\n * Exported so the test asserts the cap through the constant: a literal 10 in a\n * fixture is a second declaration of the limit, free to disagree the day this\n * one moves.\n */\nexport const FLEET_NEXT_LIMIT = 10;\n\n/**\n * Fleet-level steps, most-unblocking first. A feature ready to ship comes\n * before one that still needs authoring, because archiving it is what releases\n * everything queued behind it; a blocked feature comes last, because there is\n * nothing to do about it from here — its prerequisite is already higher up the\n * list under its own entry.\n *\n * The gate is the LAST entry and it is always there. `next.fleet-clean` used to\n * be the only route to `loam validate --all`, and it was emitted only when\n * nothing was in flight — so a repository that FAILS the fleet gate, which is\n * every repository with work in it, was handed a green-looking list that never\n * once named the command CI runs. This form grades nothing; the least it can do\n * is say where grading happens. `next.fleet-clean` is also no longer the\n * empty-repo answer: over zero services, \"every service is written down\" is\n * vacuously true, and the first hour of a docs repo used to get that green\n * sentence instead of its first three steps. The teaching ladder below owns\n * that case now, and the clean entry survives only for its truthful one —\n * services exist, and nothing is owed.\n */\n/** The whole fleet as the next-step walk reads it. */\nexport interface Fleet {\n services: ServiceEntry[];\n features: FleetFeatureState[];\n graph: DependencyGraph;\n interrupted: InterruptedCommit | null;\n /**\n * The ladder's fact, present exactly when the ladder can apply — an\n * unnarrowed run over an empty fleet. `null` otherwise: on a narrowed run\n * (withheld for the reason fleet.ts records beside the binding) and on any\n * fleet with services or features, where fleet.ts skips the read entirely.\n */\n teaching: { landscape: \"missing\" | \"stub\" | \"authored\" } | null;\n}\n\n/**\n * What this repository says it IS, as the walk needs it — and it needs BOTH\n * facts, which is why this is a record and not the bare id it used to be.\n *\n * `adopted: false` is the case the walk always handled: the fleet has no\n * `services/<id>/`, and `next.adopt-bound` leads. `adopted: true` was invisible\n * — the parameter was `string | null` and went null exactly when the directory\n * existed — so a repository bound to a service the fleet DOES know got the\n * whole system's worklist in alphabetical order, with its own boundary\n * somewhere in the middle of it or, past ten services, not on the list at all.\n */\nexport interface Binding {\n id: string;\n /** Whether the fleet has a `services/<id>/` for it. */\n adopted: boolean;\n}\n\nexport function fleetNext(fleet: Fleet, binding: Binding | null): NextStep[] {\n const { services, features, graph, interrupted, teaching } = fleet;\n const steps: NextStep[] = [];\n // The two arms of the binding, each named for the question it answers. The\n // first reproduces the old parameter exactly, so everything reading it below\n // is unchanged; the second is the fact that used to be thrown away.\n const unadoptedBinding = binding !== null && !binding.adopted ? binding.id : null;\n const adoptedBinding = binding !== null && binding.adopted ? binding.id : null;\n\n // The repository this command is standing in names a service the fleet has no\n // directory for. First, ahead of every other service's partial adoption,\n // because it is the only step that is about HERE.\n //\n // This form used to count the fleet and ignore the binding entirely, so in a\n // service repo bound to an unadopted service — a freshly wired one, the most\n // common repo there is — an empty fleet made \"every service is written down\"\n // vacuously true and `next.fleet-clean` came out top. `loam doctor` had the\n // right answer (`doctor.service-unknown`) at the same moment, and the\n // documented agent loop reads `status`: an agent following it was sent to\n // start a feature instead of adopting the service under its feet.\n if (unadoptedBinding !== null) {\n steps.push({\n code: \"next.adopt-bound\",\n statement:\n `This repository's loam.json says it is '${unadoptedBinding}', and the fleet has no ` +\n `services/${unadoptedBinding}/ — nothing about the service you are standing in is written down yet.`,\n command: `loam adopt --service ${unadoptedBinding} --json`,\n service: unadoptedBinding,\n });\n }\n\n // The first hour of a docs repo, in order. Zero services and zero features\n // used to fall through every loop below into `next.fleet-clean` — the header\n // says why that answer was vacuous — so the emptiest repository loam serves\n // got the least from the command whose whole purpose is \"what do I do next\".\n // These are ordinary steps on purpose: the gate entry still closes the list,\n // and the tail ternary is untouched. The bind/adopt rungs are suppressed when\n // `next.adopt-bound` above already names the exact adopt to run, and the\n // whole ladder is withheld on narrowed runs (`teaching === null`).\n if (teaching !== null && services.length === 0 && features.length === 0) {\n if (teaching.landscape !== \"authored\") {\n steps.push({\n code: \"next.author-landscape\",\n statement:\n teaching.landscape === \"missing\"\n ? \"architecture/landscape.likec4 does not exist — the fleet map is the one artifact every \" +\n \"cross-service check reads. Run `loam init --create` to scaffold it, then draw the first service.\"\n : \"architecture/landscape.likec4 is still the scaffold's untouched map — no service is drawn. \" +\n \"State the facts in a fleet.yaml (service ids, `a -> b` calls) and run \" +\n \"`loam seed --from fleet.yaml` to template the map mechanically — or open the file \" +\n \"and follow its own comments. Either way loam never guesses who calls whom.\",\n // The command each arm's own prose already names, and for a while it\n // was neither: both arms carried the gate. WORKFLOW.md documents the\n // agent loop as \"read next[0], run the command it names, repeat\" and\n // every generated skill says to branch on the code rather than the\n // prose — so an agent on the first rung of the first hour ran\n // `validate --all` against a repository with no services in it, which\n // answers ok:true with `landscape.matched` and changes nothing, and\n // came back to the identical next[0] forever. A livelock on day zero,\n // on the one command built to answer \"what now\". The gate is still\n // named: `next.fleet-gate` closes this same list.\n command: teaching.landscape === \"missing\" ? \"loam init --create\" : \"loam seed --from fleet.yaml\",\n path: \"architecture/landscape.likec4\",\n });\n }\n if (unadoptedBinding === null) {\n steps.push({\n code: \"next.bind-service\",\n statement:\n \"No service repository is bound to this fleet yet. From a service's own repo, point --docs \" +\n \"here and --service at its canonical id, then commit the loam.json it writes.\",\n command: \"loam init --docs <path-to-this-docs-repo> --service <service-id>\",\n });\n steps.push({\n code: \"next.adopt-first\",\n statement:\n \"services/ is empty — nothing about any service is written down yet. Adopt the first one: \" +\n \"the brief walks an agent through writing its baseline docs as draft.\",\n command: \"loam adopt --service <service-id> --json\",\n });\n }\n }\n\n // The per-service rungs are collected into their own list rather than pushed\n // straight onto `steps`, because the partition below acts on them as a group\n // — and only on them. Nothing here may float above `next.adopt-bound` or the\n // first-hour ladder, both of which are about the repository rather than about\n // any one service in the fleet.\n const perService: NextStep[] = [];\n for (const s of services.filter(undocumented)) {\n perService.push({\n code: \"next.adopt\",\n statement: `${serviceTreePath(s)}/ has no spec.md — nothing about ${s.id} is written down, so no feature can be graded against it.`,\n command: `loam adopt --service ${s.id} --json`,\n service: s.id,\n });\n }\n\n // Adoption does not end at spec.md. A service with a living spec and no\n // model.likec4 is the state archive itself warns about (`service.no-model`)\n // and the fleet gate reports — invisible here until now, because this form\n // looked at exactly one bit of each service's artifact set.\n for (const s of services.filter((x) => !undocumented(x) && !x.has.model)) {\n perService.push({\n code: \"next.complete-service\",\n statement: `${serviceTreePath(s)}/ has a spec.md but no model.likec4 — the fleet gate reports the service incomplete until something models it.`,\n command: `loam validate --service ${s.id} --json`,\n service: s.id,\n });\n }\n\n // The boundary this repository IS comes first among the boundaries it merely\n // shares a fleet with. A stable PARTITION and deliberately not a sort: the\n // bound service's rungs move to the front and every other service keeps the\n // alphabetical order it already had, so the list an unbound reader sees — a\n // docs repo, CI, `loam validate --all`'s scorecard — is byte-for-byte the one\n // it saw before.\n //\n // The cap is why this is ordering and not cosmetics. Ten rungs print, and in\n // the ten-repo case WORKFLOW.md describes every developer's `loam status`\n // opened with nine other services' adoption work; past ten services the one\n // rung this developer can actually act on was elided entirely, leaving a list\n // of nothing but other people's boundaries under the heading \"next\". No new\n // code is emitted for any of this — `next[]` has always been documented as\n // most-unblocking first, and this is the line that makes the claim true from\n // where the reader is standing.\n steps.push(\n ...(adoptedBinding === null\n ? perService\n : [\n ...perService.filter((s) => s.service === adoptedBinding),\n ...perService.filter((s) => s.service !== adoptedBinding),\n ]),\n );\n\n const ordered = [...features].sort(\n (a, b) =>\n STAGE_RANK[a.stage] - STAGE_RANK[b.stage] ||\n graph.order.indexOf(a.id) - graph.order.indexOf(b.id) ||\n compareIds(a.id, b.id),\n );\n for (const f of ordered) {\n if (f.stage === \"done\") {\n steps.push({\n code: \"next.archive\",\n statement: `${f.id} is authored and verified — ship it, and everything waiting on it is released.`,\n command: `loam archive ${f.id} --dry-run --json`,\n });\n continue;\n }\n steps.push({\n code: \"next.feature\",\n statement:\n // The list, not the stage, is what this sentence names. `blocked` has\n // two causes now — another feature in flight, and an interrupted commit\n // that stalls the whole repository — and the second one names no\n // feature, so keying off the stage alone printed \"FEAT-1 is waiting\n // on .\" The recover step above already says what the repository is\n // waiting on.\n f.stage === \"blocked\" && f.blockedBy.length > 0\n ? `${f.id} is waiting on ${f.blockedBy.join(\", \")}.`\n : `${f.id} is at '${f.stage}'${f.missing.length > 0 ? ` — missing ${f.missing.join(\", \")}` : \"\"}.`,\n command: `loam status ${f.id} --json`,\n });\n }\n\n const elided = Math.max(0, steps.length - FLEET_NEXT_LIMIT);\n // Outside the cap, not merely first inside it: the one step that must never\n // be the one this list left out.\n const out = [...(interrupted === null ? [] : [recoverStep(interrupted)]), ...steps.slice(0, FLEET_NEXT_LIMIT)];\n if (elided > 0) {\n out.push({\n code: \"next.elided\",\n statement: `${elided} more step(s) of the same kinds were left out — this list is ordered most-unblocking first, so work down it and run status again.`,\n command: \"loam list --json\",\n });\n }\n\n out.push(\n steps.length === 0\n ? {\n code: \"next.fleet-clean\",\n statement:\n \"Nothing is in flight and every service is written down — keep the fleet green, then start the next feature.\",\n command: \"loam validate --all --json\",\n }\n : {\n code: \"next.fleet-gate\",\n // `loam validate --all` inside the backticks, not the bare\n // `validate --all` this sentence carried for a year: a span without\n // the binary name is invisible to every check that reads a\n // backticked `loam <verb>` as an instruction — the parse check in\n // test/agent-commands-runnable.test.ts, and the statement/command\n // invariant in test/status.test.ts. A prefix is cheaper than an\n // exemption, and the exemption is what lets a wrong command through.\n statement:\n `${features.length} feature(s) in flight over ${services.length} service(s) — ` +\n \"status grades none of them; `loam validate --all` is the gate this repository has to pass, and it is what CI runs.\",\n command: \"loam validate --all --json\",\n },\n );\n return out;\n}\n"]}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one state that outranks everything else: a journaled writer — archive,
|
|
3
|
+
* unarchive, rebase, vouch, new, or a record — killed mid-commit, read off
|
|
4
|
+
* the intent journal `.loam-commit` leaves in the docs repo. The shape both report forms carry it in is `InterruptedCommit`
|
|
5
|
+
* (report.ts); this module is the cheap read behind it, and the recovery step
|
|
6
|
+
* that leads every `next[]` while the journal exists.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { COMMIT_INTENT } from "../staging/interrupted.js";
|
|
11
|
+
import { readCommitIntent } from "../staging/recovery/intent.js";
|
|
12
|
+
import { readTxnIntent } from "../staging/txn/journal.js";
|
|
13
|
+
/**
|
|
14
|
+
* The intent journal, if a commit left one behind. Null on every healthy repo,
|
|
15
|
+
* which is every repo except one whose last write was killed.
|
|
16
|
+
*
|
|
17
|
+
* Cheap on purpose: an `existsSync` and, at most, one small JSON read. `doctor`
|
|
18
|
+
* pays for the whole `scanWritePathResidue` walk because it is a diagnosis;
|
|
19
|
+
* `status` is run before every step of the loop and asks the one question whose
|
|
20
|
+
* answer invalidates all its others.
|
|
21
|
+
*/
|
|
22
|
+
export async function readInterruptedCommit(docsDir) {
|
|
23
|
+
const intent = await readCommitIntent(docsDir);
|
|
24
|
+
if (intent === null) {
|
|
25
|
+
if (!existsSync(join(docsDir, COMMIT_INTENT)))
|
|
26
|
+
return null;
|
|
27
|
+
// Version 2 — the smaller journaled transaction. Its `rerun` field IS the
|
|
28
|
+
// recovering command: recovery runs at the start of that command's next
|
|
29
|
+
// invocation, exactly as archive's does under its own lock.
|
|
30
|
+
const txn = await readTxnIntent(docsDir);
|
|
31
|
+
if (txn !== null) {
|
|
32
|
+
return {
|
|
33
|
+
command: txn.command,
|
|
34
|
+
feature: txn.target,
|
|
35
|
+
host: txn.host,
|
|
36
|
+
pid: txn.pid,
|
|
37
|
+
at: txn.at,
|
|
38
|
+
files: txn.files.map((f) => f.path),
|
|
39
|
+
unreadable: false,
|
|
40
|
+
recover: txn.rerun,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
command: null,
|
|
45
|
+
feature: null,
|
|
46
|
+
host: null,
|
|
47
|
+
pid: null,
|
|
48
|
+
at: null,
|
|
49
|
+
files: [],
|
|
50
|
+
unreadable: true,
|
|
51
|
+
recover: null,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
command: intent.command,
|
|
56
|
+
feature: intent.feature,
|
|
57
|
+
// Coerced here rather than trusted. `readCommitIntent` validates exactly the
|
|
58
|
+
// fields a REPAIR needs — the version, the command, the restore direction,
|
|
59
|
+
// the feature, the two move paths and the file digests — so `host`, `pid`
|
|
60
|
+
// and `at` arrive as whatever the journal happened to hold, `undefined`
|
|
61
|
+
// included. That is worse than null in both renderings: `JSON.stringify`
|
|
62
|
+
// drops an undefined value's key entirely, so `--json` loses the field
|
|
63
|
+
// instead of reporting it empty, and the two human lines print
|
|
64
|
+
// "(undefined, pid undefined, undefined)". These three are the label a
|
|
65
|
+
// person places the crash against and nothing branches on them, so the
|
|
66
|
+
// coercion belongs at this boundary — widening the validator would change
|
|
67
|
+
// which journals `archive` and `unarchive` agree to repair, which is a
|
|
68
|
+
// decision about somebody's half-written docs, not about a label.
|
|
69
|
+
host: typeof intent.host === "string" ? intent.host : null,
|
|
70
|
+
pid: typeof intent.pid === "number" ? intent.pid : null,
|
|
71
|
+
at: typeof intent.at === "string" ? intent.at : null,
|
|
72
|
+
files: intent.files.map((f) => f.path),
|
|
73
|
+
unreadable: false,
|
|
74
|
+
// The recovering command is the interrupted one re-run: it repairs first,
|
|
75
|
+
// under the lock, from the snapshot it took before the commit. Spelled per
|
|
76
|
+
// branch rather than interpolated, like doctor's own repair line, so
|
|
77
|
+
// test/agent-commands-runnable.test.ts can parse it against the real program.
|
|
78
|
+
recover: intent.command === "archive" ? `loam archive ${intent.feature}` : `loam unarchive ${intent.feature}`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The step that has to come before every other one. Always first, and never
|
|
83
|
+
* elided by the fleet form's cap: nothing else in the list can be done until
|
|
84
|
+
* somebody knows whether the living docs are the docs.
|
|
85
|
+
*/
|
|
86
|
+
export function recoverStep(i) {
|
|
87
|
+
return {
|
|
88
|
+
code: "next.recover-commit",
|
|
89
|
+
statement: i.unreadable
|
|
90
|
+
? `${COMMIT_INTENT} in this docs repo cannot be read — a commit was interrupted and the one record of which files it had already written is unreadable. Nothing below can be trusted until a human compares the living docs against version control.`
|
|
91
|
+
: `A \`${i.recover}\` was killed mid-commit (${i.host}, pid ${i.pid}, ${i.at}) — ${i.files.length} file(s) may be half-written: ${i.files.join(", ")}. Everything below is derived from those files.`,
|
|
92
|
+
// No command loam offers repairs an unreadable journal — saying otherwise
|
|
93
|
+
// would send an agent to run something that refuses.
|
|
94
|
+
command: i.recover ?? "loam doctor --json",
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=interrupted.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interrupted.js","sourceRoot":"","sources":["../../../src/core/status/interrupted.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The one state that outranks everything else: a journaled writer — archive,\n * unarchive, rebase, vouch, new, or a record — killed mid-commit, read off\n * the intent journal `.loam-commit` leaves in the docs repo. The shape both report forms carry it in is `InterruptedCommit`\n * (report.ts); this module is the cheap read behind it, and the recovery step\n * that leads every `next[]` while the journal exists.\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { COMMIT_INTENT } from \"../staging/interrupted.js\";\nimport { readCommitIntent } from \"../staging/recovery/intent.js\";\nimport { readTxnIntent } from \"../staging/txn/journal.js\";\nimport type { InterruptedCommit, NextStep } from \"./report.js\";\n\n/**\n * The intent journal, if a commit left one behind. Null on every healthy repo,\n * which is every repo except one whose last write was killed.\n *\n * Cheap on purpose: an `existsSync` and, at most, one small JSON read. `doctor`\n * pays for the whole `scanWritePathResidue` walk because it is a diagnosis;\n * `status` is run before every step of the loop and asks the one question whose\n * answer invalidates all its others.\n */\nexport async function readInterruptedCommit(docsDir: string): Promise<InterruptedCommit | null> {\n const intent = await readCommitIntent(docsDir);\n if (intent === null) {\n if (!existsSync(join(docsDir, COMMIT_INTENT))) return null;\n // Version 2 — the smaller journaled transaction. Its `rerun` field IS the\n // recovering command: recovery runs at the start of that command's next\n // invocation, exactly as archive's does under its own lock.\n const txn = await readTxnIntent(docsDir);\n if (txn !== null) {\n return {\n command: txn.command,\n feature: txn.target,\n host: txn.host,\n pid: txn.pid,\n at: txn.at,\n files: txn.files.map((f) => f.path),\n unreadable: false,\n recover: txn.rerun,\n };\n }\n return {\n command: null,\n feature: null,\n host: null,\n pid: null,\n at: null,\n files: [],\n unreadable: true,\n recover: null,\n };\n }\n return {\n command: intent.command,\n feature: intent.feature,\n // Coerced here rather than trusted. `readCommitIntent` validates exactly the\n // fields a REPAIR needs — the version, the command, the restore direction,\n // the feature, the two move paths and the file digests — so `host`, `pid`\n // and `at` arrive as whatever the journal happened to hold, `undefined`\n // included. That is worse than null in both renderings: `JSON.stringify`\n // drops an undefined value's key entirely, so `--json` loses the field\n // instead of reporting it empty, and the two human lines print\n // \"(undefined, pid undefined, undefined)\". These three are the label a\n // person places the crash against and nothing branches on them, so the\n // coercion belongs at this boundary — widening the validator would change\n // which journals `archive` and `unarchive` agree to repair, which is a\n // decision about somebody's half-written docs, not about a label.\n host: typeof intent.host === \"string\" ? intent.host : null,\n pid: typeof intent.pid === \"number\" ? intent.pid : null,\n at: typeof intent.at === \"string\" ? intent.at : null,\n files: intent.files.map((f) => f.path),\n unreadable: false,\n // The recovering command is the interrupted one re-run: it repairs first,\n // under the lock, from the snapshot it took before the commit. Spelled per\n // branch rather than interpolated, like doctor's own repair line, so\n // test/agent-commands-runnable.test.ts can parse it against the real program.\n recover: intent.command === \"archive\" ? `loam archive ${intent.feature}` : `loam unarchive ${intent.feature}`,\n };\n}\n\n/**\n * The step that has to come before every other one. Always first, and never\n * elided by the fleet form's cap: nothing else in the list can be done until\n * somebody knows whether the living docs are the docs.\n */\nexport function recoverStep(i: InterruptedCommit): NextStep {\n return {\n code: \"next.recover-commit\",\n statement: i.unreadable\n ? `${COMMIT_INTENT} in this docs repo cannot be read — a commit was interrupted and the one record of which files it had already written is unreadable. Nothing below can be trusted until a human compares the living docs against version control.`\n : `A \\`${i.recover}\\` was killed mid-commit (${i.host}, pid ${i.pid}, ${i.at}) — ${i.files.length} file(s) may be half-written: ${i.files.join(\", \")}. Everything below is derived from those files.`,\n // No command loam offers repairs an unreadable journal — saying otherwise\n // would send an agent to run something that refuses.\n command: i.recover ?? \"loam doctor --json\",\n };\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** The closed set. The module header says what each value instructs. */
|
|
2
|
+
export const ARTIFACT_STATUSES = ["missing", "blocked", "draft", "ready", "done"];
|
|
3
|
+
/**
|
|
4
|
+
* The artifact kinds a feature can owe, in the order the cycle authors them.
|
|
5
|
+
* `spec`, `arch-spec`, `openapi` and `asyncapi` are per-service and repeat
|
|
6
|
+
* once per service the feature touches; `capabilities` repeats once per
|
|
7
|
+
* capability document the feature's delta carries; the rest are feature-wide.
|
|
8
|
+
*
|
|
9
|
+
* `capabilities` sits where an analyst writes it — the business promise comes
|
|
10
|
+
* before the services that keep it, and a capability-only feature is a real and
|
|
11
|
+
* ordinary first commit.
|
|
12
|
+
*/
|
|
13
|
+
export const ARTIFACT_IDS = [
|
|
14
|
+
"intent",
|
|
15
|
+
"delta",
|
|
16
|
+
"capabilities",
|
|
17
|
+
"spec",
|
|
18
|
+
"arch-spec",
|
|
19
|
+
"openapi",
|
|
20
|
+
"asyncapi",
|
|
21
|
+
"verification",
|
|
22
|
+
];
|
|
23
|
+
/** Nothing is written down: no living spec at all. Every other absence is partial adoption. */
|
|
24
|
+
export function undocumented(s) {
|
|
25
|
+
return !s.has.spec;
|
|
26
|
+
}
|
|
27
|
+
/** A person stamped it — `loam vouch`'s exact postcondition, read back off the frontmatter. */
|
|
28
|
+
export function vouched(s) {
|
|
29
|
+
return s.status === "verified" && s.sources.stamped;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=report.js.map
|