devrites 7.2.7 → 7.3.0
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 +40 -0
- package/README.md +6 -1
- package/docs/candidate-integrity.md +10 -0
- package/docs/cli.md +7 -1
- package/docs/command-map.md +9 -2
- package/docs/engine/commands.md +50 -4
- package/docs/orchestration.md +35 -13
- package/docs/skills.md +5 -0
- package/engine/internal/acceptance/cli.go +35 -30
- package/engine/internal/acceptance/preconditions.go +1 -1
- package/engine/internal/acceptance/run.go +138 -53
- package/engine/internal/acceptance/transcript.go +236 -45
- package/engine/internal/devritespaths/paths.go +23 -5
- package/engine/internal/gate/gate.go +6 -0
- package/engine/internal/install/apply.go +5 -0
- package/engine/internal/install/merge.go +48 -6
- package/engine/internal/install/preflight.go +21 -3
- package/engine/internal/install/uninstall.go +9 -10
- package/engine/internal/lib/apply_bundle.go +7 -1
- package/engine/internal/lib/candidate.go +20 -7
- package/engine/internal/lib/candidate_coverage.go +2 -19
- package/engine/internal/lib/closeout.go +22 -10
- package/engine/internal/lib/context.go +67 -47
- package/engine/internal/lib/context_io.go +171 -0
- package/engine/internal/lib/detect.go +8 -8
- package/engine/internal/lib/dispatch.go +6 -0
- package/engine/internal/lib/packet.go +37 -7
- package/engine/internal/lib/packet_freeze.go +60 -12
- package/engine/internal/lib/packet_integrity.go +179 -0
- package/engine/internal/lib/perturb.go +3 -3
- package/engine/internal/lib/resolve.go +10 -5
- package/engine/internal/lib/slicecheck.go +7 -1
- package/engine/internal/lib/state_edit.go +9 -2
- package/engine/internal/lib/taskgraph.go +20 -36
- package/engine/internal/lib/triggers.go +30 -31
- package/engine/internal/lib/workspace_pool.go +330 -0
- package/engine/internal/parallel/cli.go +190 -49
- package/engine/internal/parallel/git.go +47 -14
- package/engine/internal/parallel/landing.go +232 -0
- package/engine/internal/parallel/lease.go +97 -18
- package/engine/internal/parallel/ops.go +312 -155
- package/engine/internal/parallel/pathdisjoint.go +48 -4
- package/engine/internal/parallel/prune.go +133 -0
- package/engine/internal/parallel/repository.go +239 -0
- package/engine/internal/parallel/select.go +64 -42
- package/engine/internal/state/cursor.go +5 -5
- package/engine/main.go +2 -1
- package/pack/.claude/agents/devrites-proof-runner.md +16 -9
- package/pack/.claude/skills/devrites-lib/SKILL.md +2 -0
- package/pack/.claude/skills/devrites-lib/reference/candidate-integrity.md +7 -3
- package/pack/.claude/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
- package/pack/.claude/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
- package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
- package/pack/.claude/skills/devrites-lib/reference/standards/agents.md +7 -3
- package/pack/.claude/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
- package/pack/.claude/skills/devrites-lib/reference/standards/gates.md +18 -9
- package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
- package/pack/.claude/skills/rite-autocomplete/SKILL.md +13 -10
- package/pack/.claude/skills/rite-autocomplete/reference/lookahead.md +4 -4
- package/pack/.claude/skills/rite-autocomplete/reference/loop.md +13 -9
- package/pack/.claude/skills/rite-build/SKILL.md +13 -10
- package/pack/.claude/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/.claude/skills/rite-build/reference/checkpoint.md +1 -1
- package/pack/.claude/skills/rite-build/reference/parallel-batch.md +60 -39
- package/pack/.claude/skills/rite-build/reference/phase-contract.md +8 -5
- package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +7 -7
- package/pack/.claude/skills/rite-clarify/SKILL.md +2 -2
- package/pack/.claude/skills/rite-converge/SKILL.md +4 -4
- package/pack/.claude/skills/rite-define/SKILL.md +7 -3
- package/pack/.claude/skills/rite-define/reference/plan-template.md +4 -2
- package/pack/.claude/skills/rite-plan/SKILL.md +11 -8
- package/pack/.claude/skills/rite-plan/reference/dependency-graph.md +9 -2
- package/pack/.claude/skills/rite-plan/reference/slicing.md +2 -0
- package/pack/.claude/skills/rite-polish/SKILL.md +3 -3
- package/pack/.claude/skills/rite-prove/SKILL.md +9 -5
- package/pack/.claude/skills/rite-resolve/SKILL.md +3 -3
- package/pack/.claude/skills/rite-resolve/reference/answer-protocol.md +2 -0
- package/pack/.claude/skills/rite-review/SKILL.md +4 -3
- package/pack/.claude/skills/rite-review/reference/feature-scoped-review.md +2 -2
- package/pack/.claude/skills/rite-seal/SKILL.md +1 -1
- package/pack/.claude/skills/rite-seal/reference/phase-contract.md +1 -1
- package/pack/.claude/skills/rite-ship/SKILL.md +2 -2
- package/pack/.claude/skills/rite-ship/reference/git-ship.md +2 -2
- package/pack/.claude/skills/rite-spec/SKILL.md +8 -5
- package/pack/.claude/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/.claude/skills/rite-temper/SKILL.md +3 -3
- package/pack/.claude/skills/rite-vet/SKILL.md +9 -5
- package/pack/.claude/skills/rite-vet/reference/review-axes.md +12 -5
- package/pack/generated/claude/agents/devrites-proof-runner.md +16 -9
- package/pack/generated/claude/skills/devrites-lib/SKILL.md +2 -0
- package/pack/generated/claude/skills/devrites-lib/reference/candidate-integrity.md +7 -3
- package/pack/generated/claude/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
- package/pack/generated/claude/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
- package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
- package/pack/generated/claude/skills/devrites-lib/reference/standards/agents.md +7 -3
- package/pack/generated/claude/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
- package/pack/generated/claude/skills/devrites-lib/reference/standards/gates.md +18 -9
- package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
- package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +13 -10
- package/pack/generated/claude/skills/rite-autocomplete/reference/lookahead.md +4 -4
- package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +13 -9
- package/pack/generated/claude/skills/rite-build/SKILL.md +13 -10
- package/pack/generated/claude/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/claude/skills/rite-build/reference/checkpoint.md +1 -1
- package/pack/generated/claude/skills/rite-build/reference/parallel-batch.md +60 -39
- package/pack/generated/claude/skills/rite-build/reference/phase-contract.md +8 -5
- package/pack/generated/claude/skills/rite-build/reference/wright-dispatch.md +7 -7
- package/pack/generated/claude/skills/rite-clarify/SKILL.md +2 -2
- package/pack/generated/claude/skills/rite-converge/SKILL.md +4 -4
- package/pack/generated/claude/skills/rite-define/SKILL.md +7 -3
- package/pack/generated/claude/skills/rite-define/reference/plan-template.md +4 -2
- package/pack/generated/claude/skills/rite-plan/SKILL.md +11 -8
- package/pack/generated/claude/skills/rite-plan/reference/dependency-graph.md +9 -2
- package/pack/generated/claude/skills/rite-plan/reference/slicing.md +2 -0
- package/pack/generated/claude/skills/rite-polish/SKILL.md +3 -3
- package/pack/generated/claude/skills/rite-prove/SKILL.md +9 -5
- package/pack/generated/claude/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/claude/skills/rite-resolve/reference/answer-protocol.md +2 -0
- package/pack/generated/claude/skills/rite-review/SKILL.md +4 -3
- package/pack/generated/claude/skills/rite-review/reference/feature-scoped-review.md +2 -2
- package/pack/generated/claude/skills/rite-seal/SKILL.md +1 -1
- package/pack/generated/claude/skills/rite-seal/reference/phase-contract.md +1 -1
- package/pack/generated/claude/skills/rite-ship/SKILL.md +2 -2
- package/pack/generated/claude/skills/rite-ship/reference/git-ship.md +2 -2
- package/pack/generated/claude/skills/rite-spec/SKILL.md +8 -5
- package/pack/generated/claude/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/generated/claude/skills/rite-temper/SKILL.md +3 -3
- package/pack/generated/claude/skills/rite-vet/SKILL.md +9 -5
- package/pack/generated/claude/skills/rite-vet/reference/review-axes.md +12 -5
- package/pack/generated/codex/agents/devrites-proof-runner.toml +16 -9
- package/pack/generated/codex/skills/devrites-lib/SKILL.md +2 -0
- package/pack/generated/codex/skills/devrites-lib/reference/candidate-integrity.md +7 -3
- package/pack/generated/codex/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
- package/pack/generated/codex/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
- package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
- package/pack/generated/codex/skills/devrites-lib/reference/standards/agents.md +7 -3
- package/pack/generated/codex/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
- package/pack/generated/codex/skills/devrites-lib/reference/standards/gates.md +18 -9
- package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
- package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +13 -10
- package/pack/generated/codex/skills/rite-autocomplete/reference/lookahead.md +4 -4
- package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +13 -9
- package/pack/generated/codex/skills/rite-build/SKILL.md +13 -10
- package/pack/generated/codex/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/codex/skills/rite-build/reference/checkpoint.md +1 -1
- package/pack/generated/codex/skills/rite-build/reference/parallel-batch.md +60 -39
- package/pack/generated/codex/skills/rite-build/reference/phase-contract.md +8 -5
- package/pack/generated/codex/skills/rite-build/reference/wright-dispatch.md +7 -7
- package/pack/generated/codex/skills/rite-clarify/SKILL.md +2 -2
- package/pack/generated/codex/skills/rite-converge/SKILL.md +4 -4
- package/pack/generated/codex/skills/rite-define/SKILL.md +7 -3
- package/pack/generated/codex/skills/rite-define/reference/plan-template.md +4 -2
- package/pack/generated/codex/skills/rite-plan/SKILL.md +11 -8
- package/pack/generated/codex/skills/rite-plan/reference/dependency-graph.md +9 -2
- package/pack/generated/codex/skills/rite-plan/reference/slicing.md +2 -0
- package/pack/generated/codex/skills/rite-polish/SKILL.md +3 -3
- package/pack/generated/codex/skills/rite-prove/SKILL.md +9 -5
- package/pack/generated/codex/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/codex/skills/rite-resolve/reference/answer-protocol.md +2 -0
- package/pack/generated/codex/skills/rite-review/SKILL.md +4 -3
- package/pack/generated/codex/skills/rite-review/reference/feature-scoped-review.md +2 -2
- package/pack/generated/codex/skills/rite-seal/SKILL.md +1 -1
- package/pack/generated/codex/skills/rite-seal/reference/phase-contract.md +1 -1
- package/pack/generated/codex/skills/rite-ship/SKILL.md +2 -2
- package/pack/generated/codex/skills/rite-ship/reference/git-ship.md +2 -2
- package/pack/generated/codex/skills/rite-spec/SKILL.md +8 -5
- package/pack/generated/codex/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/generated/codex/skills/rite-temper/SKILL.md +3 -3
- package/pack/generated/codex/skills/rite-vet/SKILL.md +9 -5
- package/pack/generated/codex/skills/rite-vet/reference/review-axes.md +12 -5
- package/pack/generated/devin/agents/devrites-proof-runner.md +16 -9
- package/pack/generated/devin/skills/devrites-lib/SKILL.md +2 -0
- package/pack/generated/devin/skills/devrites-lib/reference/candidate-integrity.md +7 -3
- package/pack/generated/devin/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
- package/pack/generated/devin/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
- package/pack/generated/devin/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
- package/pack/generated/devin/skills/devrites-lib/reference/standards/agents.md +7 -3
- package/pack/generated/devin/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
- package/pack/generated/devin/skills/devrites-lib/reference/standards/gates.md +18 -9
- package/pack/generated/devin/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
- package/pack/generated/devin/skills/rite-autocomplete/SKILL.md +13 -10
- package/pack/generated/devin/skills/rite-autocomplete/reference/lookahead.md +4 -4
- package/pack/generated/devin/skills/rite-autocomplete/reference/loop.md +13 -9
- package/pack/generated/devin/skills/rite-build/SKILL.md +13 -10
- package/pack/generated/devin/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/devin/skills/rite-build/reference/checkpoint.md +1 -1
- package/pack/generated/devin/skills/rite-build/reference/parallel-batch.md +60 -39
- package/pack/generated/devin/skills/rite-build/reference/phase-contract.md +8 -5
- package/pack/generated/devin/skills/rite-build/reference/wright-dispatch.md +7 -7
- package/pack/generated/devin/skills/rite-clarify/SKILL.md +2 -2
- package/pack/generated/devin/skills/rite-converge/SKILL.md +4 -4
- package/pack/generated/devin/skills/rite-define/SKILL.md +7 -3
- package/pack/generated/devin/skills/rite-define/reference/plan-template.md +4 -2
- package/pack/generated/devin/skills/rite-plan/SKILL.md +11 -8
- package/pack/generated/devin/skills/rite-plan/reference/dependency-graph.md +9 -2
- package/pack/generated/devin/skills/rite-plan/reference/slicing.md +2 -0
- package/pack/generated/devin/skills/rite-polish/SKILL.md +3 -3
- package/pack/generated/devin/skills/rite-prove/SKILL.md +9 -5
- package/pack/generated/devin/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/devin/skills/rite-resolve/reference/answer-protocol.md +2 -0
- package/pack/generated/devin/skills/rite-review/SKILL.md +4 -3
- package/pack/generated/devin/skills/rite-review/reference/feature-scoped-review.md +2 -2
- package/pack/generated/devin/skills/rite-seal/SKILL.md +1 -1
- package/pack/generated/devin/skills/rite-seal/reference/phase-contract.md +1 -1
- package/pack/generated/devin/skills/rite-ship/SKILL.md +2 -2
- package/pack/generated/devin/skills/rite-ship/reference/git-ship.md +2 -2
- package/pack/generated/devin/skills/rite-spec/SKILL.md +8 -5
- package/pack/generated/devin/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/generated/devin/skills/rite-temper/SKILL.md +3 -3
- package/pack/generated/devin/skills/rite-vet/SKILL.md +9 -5
- package/pack/generated/devin/skills/rite-vet/reference/review-axes.md +12 -5
- package/pack/generated/dsh/agents/devrites-proof-runner.md +16 -9
- package/pack/generated/dsh/runtime/cordis.patch.yml +1 -1
- package/pack/generated/dsh/skills/devrites-lib/SKILL.md +2 -0
- package/pack/generated/dsh/skills/devrites-lib/reference/candidate-integrity.md +7 -3
- package/pack/generated/dsh/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
- package/pack/generated/dsh/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
- package/pack/generated/dsh/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
- package/pack/generated/dsh/skills/devrites-lib/reference/standards/agents.md +7 -3
- package/pack/generated/dsh/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
- package/pack/generated/dsh/skills/devrites-lib/reference/standards/gates.md +18 -9
- package/pack/generated/dsh/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
- package/pack/generated/dsh/skills/rite-autocomplete/SKILL.md +13 -10
- package/pack/generated/dsh/skills/rite-autocomplete/reference/lookahead.md +4 -4
- package/pack/generated/dsh/skills/rite-autocomplete/reference/loop.md +13 -9
- package/pack/generated/dsh/skills/rite-build/SKILL.md +13 -10
- package/pack/generated/dsh/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/dsh/skills/rite-build/reference/checkpoint.md +1 -1
- package/pack/generated/dsh/skills/rite-build/reference/parallel-batch.md +60 -39
- package/pack/generated/dsh/skills/rite-build/reference/phase-contract.md +8 -5
- package/pack/generated/dsh/skills/rite-build/reference/wright-dispatch.md +7 -7
- package/pack/generated/dsh/skills/rite-clarify/SKILL.md +2 -2
- package/pack/generated/dsh/skills/rite-converge/SKILL.md +4 -4
- package/pack/generated/dsh/skills/rite-define/SKILL.md +7 -3
- package/pack/generated/dsh/skills/rite-define/reference/plan-template.md +4 -2
- package/pack/generated/dsh/skills/rite-plan/SKILL.md +11 -8
- package/pack/generated/dsh/skills/rite-plan/reference/dependency-graph.md +9 -2
- package/pack/generated/dsh/skills/rite-plan/reference/slicing.md +2 -0
- package/pack/generated/dsh/skills/rite-polish/SKILL.md +3 -3
- package/pack/generated/dsh/skills/rite-prove/SKILL.md +9 -5
- package/pack/generated/dsh/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/dsh/skills/rite-resolve/reference/answer-protocol.md +2 -0
- package/pack/generated/dsh/skills/rite-review/SKILL.md +4 -3
- package/pack/generated/dsh/skills/rite-review/reference/feature-scoped-review.md +2 -2
- package/pack/generated/dsh/skills/rite-seal/SKILL.md +1 -1
- package/pack/generated/dsh/skills/rite-seal/reference/phase-contract.md +1 -1
- package/pack/generated/dsh/skills/rite-ship/SKILL.md +2 -2
- package/pack/generated/dsh/skills/rite-ship/reference/git-ship.md +2 -2
- package/pack/generated/dsh/skills/rite-spec/SKILL.md +8 -5
- package/pack/generated/dsh/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/generated/dsh/skills/rite-temper/SKILL.md +3 -3
- package/pack/generated/dsh/skills/rite-vet/SKILL.md +9 -5
- package/pack/generated/dsh/skills/rite-vet/reference/review-axes.md +12 -5
- package/pack/generated/omp/agents/devrites-proof-runner.md +16 -9
- package/pack/generated/omp/commands/rite-build.md +1 -1
- package/pack/generated/omp/skills/devrites-lib/SKILL.md +2 -0
- package/pack/generated/omp/skills/devrites-lib/reference/candidate-integrity.md +7 -3
- package/pack/generated/omp/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
- package/pack/generated/omp/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
- package/pack/generated/omp/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
- package/pack/generated/omp/skills/devrites-lib/reference/standards/agents.md +11 -3
- package/pack/generated/omp/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
- package/pack/generated/omp/skills/devrites-lib/reference/standards/gates.md +18 -9
- package/pack/generated/omp/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
- package/pack/generated/omp/skills/rite-autocomplete/SKILL.md +13 -10
- package/pack/generated/omp/skills/rite-autocomplete/reference/lookahead.md +4 -4
- package/pack/generated/omp/skills/rite-autocomplete/reference/loop.md +13 -9
- package/pack/generated/omp/skills/rite-build/SKILL.md +13 -10
- package/pack/generated/omp/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/omp/skills/rite-build/reference/checkpoint.md +1 -1
- package/pack/generated/omp/skills/rite-build/reference/parallel-batch.md +60 -39
- package/pack/generated/omp/skills/rite-build/reference/phase-contract.md +8 -5
- package/pack/generated/omp/skills/rite-build/reference/wright-dispatch.md +7 -7
- package/pack/generated/omp/skills/rite-clarify/SKILL.md +2 -2
- package/pack/generated/omp/skills/rite-converge/SKILL.md +4 -4
- package/pack/generated/omp/skills/rite-define/SKILL.md +7 -3
- package/pack/generated/omp/skills/rite-define/reference/plan-template.md +4 -2
- package/pack/generated/omp/skills/rite-plan/SKILL.md +11 -8
- package/pack/generated/omp/skills/rite-plan/reference/dependency-graph.md +9 -2
- package/pack/generated/omp/skills/rite-plan/reference/slicing.md +2 -0
- package/pack/generated/omp/skills/rite-polish/SKILL.md +3 -3
- package/pack/generated/omp/skills/rite-prove/SKILL.md +9 -5
- package/pack/generated/omp/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/omp/skills/rite-resolve/reference/answer-protocol.md +2 -0
- package/pack/generated/omp/skills/rite-review/SKILL.md +4 -3
- package/pack/generated/omp/skills/rite-review/reference/feature-scoped-review.md +2 -2
- package/pack/generated/omp/skills/rite-seal/SKILL.md +1 -1
- package/pack/generated/omp/skills/rite-seal/reference/phase-contract.md +1 -1
- package/pack/generated/omp/skills/rite-ship/SKILL.md +2 -2
- package/pack/generated/omp/skills/rite-ship/reference/git-ship.md +2 -2
- package/pack/generated/omp/skills/rite-spec/SKILL.md +8 -5
- package/pack/generated/omp/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/generated/omp/skills/rite-temper/SKILL.md +3 -3
- package/pack/generated/omp/skills/rite-vet/SKILL.md +9 -5
- package/pack/generated/omp/skills/rite-vet/reference/review-axes.md +12 -5
- package/pack/generated/pi/agents/devrites-proof-runner.md +16 -9
- package/pack/generated/pi/prompts/rite-build.md +1 -1
- package/pack/generated/pi/skills/devrites-lib/SKILL.md +2 -0
- package/pack/generated/pi/skills/devrites-lib/reference/candidate-integrity.md +7 -3
- package/pack/generated/pi/skills/devrites-lib/reference/parallel-dispatch.md +3 -0
- package/pack/generated/pi/skills/devrites-lib/reference/parallel-workspaces.md +202 -0
- package/pack/generated/pi/skills/devrites-lib/reference/standards/afk-hitl.md +9 -12
- package/pack/generated/pi/skills/devrites-lib/reference/standards/agents.md +7 -3
- package/pack/generated/pi/skills/devrites-lib/reference/standards/context-hygiene.md +1 -1
- package/pack/generated/pi/skills/devrites-lib/reference/standards/gates.md +18 -9
- package/pack/generated/pi/skills/devrites-lib/reference/workspace-artifact-schema.md +10 -0
- package/pack/generated/pi/skills/rite-autocomplete/SKILL.md +13 -10
- package/pack/generated/pi/skills/rite-autocomplete/reference/lookahead.md +4 -4
- package/pack/generated/pi/skills/rite-autocomplete/reference/loop.md +13 -9
- package/pack/generated/pi/skills/rite-build/SKILL.md +13 -10
- package/pack/generated/pi/skills/rite-build/reference/afk-discipline.md +1 -1
- package/pack/generated/pi/skills/rite-build/reference/checkpoint.md +1 -1
- package/pack/generated/pi/skills/rite-build/reference/parallel-batch.md +60 -39
- package/pack/generated/pi/skills/rite-build/reference/phase-contract.md +8 -5
- package/pack/generated/pi/skills/rite-build/reference/wright-dispatch.md +7 -7
- package/pack/generated/pi/skills/rite-clarify/SKILL.md +2 -2
- package/pack/generated/pi/skills/rite-converge/SKILL.md +4 -4
- package/pack/generated/pi/skills/rite-define/SKILL.md +7 -3
- package/pack/generated/pi/skills/rite-define/reference/plan-template.md +4 -2
- package/pack/generated/pi/skills/rite-plan/SKILL.md +11 -8
- package/pack/generated/pi/skills/rite-plan/reference/dependency-graph.md +9 -2
- package/pack/generated/pi/skills/rite-plan/reference/slicing.md +2 -0
- package/pack/generated/pi/skills/rite-polish/SKILL.md +3 -3
- package/pack/generated/pi/skills/rite-prove/SKILL.md +9 -5
- package/pack/generated/pi/skills/rite-resolve/SKILL.md +3 -3
- package/pack/generated/pi/skills/rite-resolve/reference/answer-protocol.md +2 -0
- package/pack/generated/pi/skills/rite-review/SKILL.md +4 -3
- package/pack/generated/pi/skills/rite-review/reference/feature-scoped-review.md +2 -2
- package/pack/generated/pi/skills/rite-seal/SKILL.md +1 -1
- package/pack/generated/pi/skills/rite-seal/reference/phase-contract.md +1 -1
- package/pack/generated/pi/skills/rite-ship/SKILL.md +2 -2
- package/pack/generated/pi/skills/rite-ship/reference/git-ship.md +2 -2
- package/pack/generated/pi/skills/rite-spec/SKILL.md +8 -5
- package/pack/generated/pi/skills/rite-spec/reference/state-workspace.md +5 -0
- package/pack/generated/pi/skills/rite-temper/SKILL.md +3 -3
- package/pack/generated/pi/skills/rite-vet/SKILL.md +9 -5
- package/pack/generated/pi/skills/rite-vet/reference/review-axes.md +12 -5
- package/package.json +1 -1
- package/scripts/build-host-artifacts.sh +5 -6
- package/scripts/omp-generate.sh +24 -14
|
@@ -27,12 +27,13 @@ var (
|
|
|
27
27
|
|
|
28
28
|
// CreateOpts configures parallel worktree creation.
|
|
29
29
|
type CreateOpts struct {
|
|
30
|
-
Root
|
|
31
|
-
Slug
|
|
32
|
-
BatchID
|
|
33
|
-
BaseSHA
|
|
34
|
-
Session
|
|
35
|
-
Slices
|
|
30
|
+
Root string
|
|
31
|
+
Slug string
|
|
32
|
+
BatchID string
|
|
33
|
+
BaseSHA string
|
|
34
|
+
Session string
|
|
35
|
+
Slices []SlicePaths
|
|
36
|
+
Capacity int
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
// withLeaseLock serializes lease read-modify-write across engine processes:
|
|
@@ -42,11 +43,13 @@ func withLeaseLock(repoRoot, slug string, fn func() error) error {
|
|
|
42
43
|
if err := validateSlug(slug); err != nil {
|
|
43
44
|
return err
|
|
44
45
|
}
|
|
45
|
-
return
|
|
46
|
-
|
|
46
|
+
return WithControlLock(filepath.Join(repoRoot, devritespaths.DevritesRootName), func() error {
|
|
47
|
+
return state.WithFeatureLock(
|
|
48
|
+
filepath.Join(repoRoot, devritespaths.DevritesRootName), slug, fn)
|
|
49
|
+
})
|
|
47
50
|
}
|
|
48
51
|
|
|
49
|
-
// Create
|
|
52
|
+
// Create validates and creates 1-10 isolated worktrees with a durable writer cap.
|
|
50
53
|
func Create(opts CreateOpts) (lease *Lease, err error) {
|
|
51
54
|
err = withLeaseLock(opts.Root, opts.Slug, func() error {
|
|
52
55
|
lease, err = createLocked(opts)
|
|
@@ -70,7 +73,29 @@ func createLocked(opts CreateOpts) (*Lease, error) {
|
|
|
70
73
|
if err := checkParallelSliceCount(len(opts.Slices)); err != nil {
|
|
71
74
|
return nil, err
|
|
72
75
|
}
|
|
73
|
-
if
|
|
76
|
+
if err := validateCapacity(opts.Capacity); err != nil {
|
|
77
|
+
return nil, err
|
|
78
|
+
}
|
|
79
|
+
if opts.Capacity == 0 {
|
|
80
|
+
opts.Capacity = MaxParallelSlices
|
|
81
|
+
}
|
|
82
|
+
if len(opts.Slices) > opts.Capacity {
|
|
83
|
+
return nil, fmt.Errorf("create would make %d slices active; parallel allows at most %d", len(opts.Slices), opts.Capacity)
|
|
84
|
+
}
|
|
85
|
+
normalized, err := normalizeSlices(opts.Slug, opts.Slices, opts.Root)
|
|
86
|
+
if err != nil {
|
|
87
|
+
return nil, err
|
|
88
|
+
}
|
|
89
|
+
opts.Slices = normalized
|
|
90
|
+
if err := validateSources(filepath.Join(opts.Root, devritespaths.DevritesRootName), opts.Slices); err != nil {
|
|
91
|
+
return nil, err
|
|
92
|
+
}
|
|
93
|
+
if len(opts.Slices) >= 2 {
|
|
94
|
+
if _, err := CheckPathDisjoint(opts.Slices, opts.Root); err != nil {
|
|
95
|
+
return nil, err
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if _, err := controllerLease(opts.Root, opts.Slug); err != nil {
|
|
74
99
|
return nil, err
|
|
75
100
|
}
|
|
76
101
|
base, err := revParse(opts.Root, opts.BaseSHA)
|
|
@@ -84,6 +109,10 @@ func createLocked(opts CreateOpts) (*Lease, error) {
|
|
|
84
109
|
if _, err := os.Stat(leasePath); err == nil {
|
|
85
110
|
return nil, fmt.Errorf("lease already exists: %s", leasePath)
|
|
86
111
|
}
|
|
112
|
+
checkout, controlRef, err := controlIdentity(opts.Root)
|
|
113
|
+
if err != nil {
|
|
114
|
+
return nil, err
|
|
115
|
+
}
|
|
87
116
|
|
|
88
117
|
session := opts.Session
|
|
89
118
|
if session == "" {
|
|
@@ -99,7 +128,10 @@ func createLocked(opts CreateOpts) (*Lease, error) {
|
|
|
99
128
|
BatchID: opts.BatchID,
|
|
100
129
|
CreatedAt: NowUTC(),
|
|
101
130
|
BaseSHA: base,
|
|
131
|
+
ControlCheckout: checkout,
|
|
132
|
+
ControlRef: controlRef,
|
|
102
133
|
N: len(slices),
|
|
134
|
+
Capacity: opts.Capacity,
|
|
103
135
|
Status: StatusRunning,
|
|
104
136
|
ControlPIDOrSession: session,
|
|
105
137
|
Slices: slices,
|
|
@@ -128,6 +160,13 @@ func createWorktrees(root, slug, batchID, base string, specs []SlicePaths) ([]Le
|
|
|
128
160
|
if err := deleteBranch(root, sl.Branch); err != nil {
|
|
129
161
|
warnf("branch cleanup %s: %v", sl.Branch, err)
|
|
130
162
|
}
|
|
163
|
+
if ownedWorktreePath(root, batchID, sl) {
|
|
164
|
+
if sl.Workspace != "" {
|
|
165
|
+
_ = os.Remove(filepath.Dir(sl.WorktreePath))
|
|
166
|
+
_ = os.Remove(filepath.Join(ScratchRoot(root), batchID, "_workspaces"))
|
|
167
|
+
}
|
|
168
|
+
_ = os.Remove(filepath.Join(ScratchRoot(root), batchID))
|
|
169
|
+
}
|
|
131
170
|
}
|
|
132
171
|
}
|
|
133
172
|
for _, sp := range specs {
|
|
@@ -142,43 +181,46 @@ func createWorktrees(root, slug, batchID, base string, specs []SlicePaths) ([]Le
|
|
|
142
181
|
}
|
|
143
182
|
|
|
144
183
|
func createWorktree(root, slug, batchID, base string, sp SlicePaths) (LeaseSlice, error) {
|
|
145
|
-
if
|
|
146
|
-
return LeaseSlice{},
|
|
147
|
-
}
|
|
148
|
-
paths, err := validateSlicePaths(sp.Paths, fmt.Sprintf("slice %q", sp.ID), root)
|
|
149
|
-
if err != nil {
|
|
150
|
-
return LeaseSlice{}, err
|
|
184
|
+
if sp.Workspace == "" && sp.ID == "integrate" {
|
|
185
|
+
return LeaseSlice{}, fmt.Errorf("slice id %q is reserved for staging integration", sp.ID)
|
|
151
186
|
}
|
|
152
|
-
branch :=
|
|
153
|
-
wt :=
|
|
187
|
+
branch := workerBranch(slug, batchID, sp.Workspace, sp.ID)
|
|
188
|
+
wt := workerWorktreePath(root, batchID, sp.Workspace, sp.ID)
|
|
154
189
|
if _, err := os.Stat(wt); err == nil {
|
|
155
190
|
return LeaseSlice{}, fmt.Errorf("worktree path already exists: %s", wt)
|
|
156
191
|
}
|
|
192
|
+
claim := LeaseSlice{ID: sp.ID, Workspace: sp.Workspace, WorktreePath: wt}
|
|
193
|
+
if !ownedWorktreePath(root, batchID, claim) {
|
|
194
|
+
return LeaseSlice{}, fmt.Errorf("worktree path is not owned: %s", wt)
|
|
195
|
+
}
|
|
157
196
|
if err := os.MkdirAll(filepath.Dir(wt), 0o755); err != nil {
|
|
158
197
|
return LeaseSlice{}, err
|
|
159
198
|
}
|
|
160
199
|
if err := worktreeAdd(root, wt, branch, base); err != nil {
|
|
161
|
-
return LeaseSlice{}, fmt.Errorf("worktree add %s: %w", sp.ID, err)
|
|
200
|
+
return LeaseSlice{}, fmt.Errorf("worktree add %s: %w", SliceKey(sp.Workspace, sp.ID), err)
|
|
162
201
|
}
|
|
163
202
|
return LeaseSlice{
|
|
164
203
|
ID: sp.ID,
|
|
165
|
-
|
|
204
|
+
Workspace: sp.Workspace,
|
|
205
|
+
Paths: sp.Paths,
|
|
166
206
|
WorktreePath: wt,
|
|
167
207
|
Branch: branch,
|
|
168
208
|
WrightStatus: WrightPending,
|
|
169
209
|
}, nil
|
|
170
210
|
}
|
|
171
211
|
|
|
172
|
-
// AddOpts configures
|
|
212
|
+
// AddOpts configures worker refill or an explicit metadata-only capacity update.
|
|
173
213
|
type AddOpts struct {
|
|
174
|
-
Root
|
|
175
|
-
Slug
|
|
176
|
-
Slices
|
|
214
|
+
Root string
|
|
215
|
+
Slug string
|
|
216
|
+
Slices []SlicePaths
|
|
217
|
+
Capacity int
|
|
177
218
|
}
|
|
178
219
|
|
|
179
220
|
// Add refills freed slots of a running lease: each new slice gets a worktree
|
|
180
221
|
// from the current control tip, under the same path-disjoint and cap rules as
|
|
181
222
|
// the slices still active. Landed (integrated) slices no longer claim paths.
|
|
223
|
+
// An explicit Capacity with no Slices changes only the bound, not lease status.
|
|
182
224
|
func Add(opts AddOpts) (lease *Lease, err error) {
|
|
183
225
|
err = withLeaseLock(opts.Root, opts.Slug, func() error {
|
|
184
226
|
lease, err = addLocked(opts)
|
|
@@ -191,8 +233,8 @@ func addLocked(opts AddOpts) (*Lease, error) {
|
|
|
191
233
|
if abs, err := filepath.Abs(opts.Root); err == nil {
|
|
192
234
|
opts.Root = abs
|
|
193
235
|
}
|
|
194
|
-
if len(opts.Slices) == 0 {
|
|
195
|
-
return nil, fmt.Errorf("add requires at least one slice")
|
|
236
|
+
if len(opts.Slices) == 0 && opts.Capacity == 0 {
|
|
237
|
+
return nil, fmt.Errorf("add requires at least one slice or an explicit cap")
|
|
196
238
|
}
|
|
197
239
|
leasePath, err := LeasePath(opts.Root, opts.Slug)
|
|
198
240
|
if err != nil {
|
|
@@ -202,8 +244,26 @@ func addLocked(opts AddOpts) (*Lease, error) {
|
|
|
202
244
|
if err != nil {
|
|
203
245
|
return nil, err
|
|
204
246
|
}
|
|
205
|
-
if lease.
|
|
206
|
-
return nil,
|
|
247
|
+
if err := normalizeLease(lease, opts.Slug); err != nil {
|
|
248
|
+
return nil, err
|
|
249
|
+
}
|
|
250
|
+
if _, err := recoverLanding(opts.Root, opts.Slug, leasePath, lease, false, false); err != nil {
|
|
251
|
+
return nil, err
|
|
252
|
+
}
|
|
253
|
+
if _, err := controllerLease(opts.Root, opts.Slug); err != nil {
|
|
254
|
+
return nil, err
|
|
255
|
+
}
|
|
256
|
+
if err := validateLeaseSources(filepath.Join(opts.Root, devritespaths.DevritesRootName), lease); err != nil {
|
|
257
|
+
return nil, err
|
|
258
|
+
}
|
|
259
|
+
if err := validateCapacity(opts.Capacity); err != nil {
|
|
260
|
+
return nil, err
|
|
261
|
+
}
|
|
262
|
+
if opts.Capacity == 0 {
|
|
263
|
+
opts.Capacity = leaseCapacity(lease)
|
|
264
|
+
}
|
|
265
|
+
if lease.Status != StatusRunning && lease.Status != StatusComplete {
|
|
266
|
+
return nil, fmt.Errorf("add requires status=running|complete (have %s)", lease.Status)
|
|
207
267
|
}
|
|
208
268
|
head, err := revParse(opts.Root, expectedControl(lease))
|
|
209
269
|
if err != nil {
|
|
@@ -215,34 +275,40 @@ func addLocked(opts AddOpts) (*Lease, error) {
|
|
|
215
275
|
|
|
216
276
|
seen := make(map[string]bool, len(lease.Slices)+len(opts.Slices))
|
|
217
277
|
for _, sl := range lease.Slices {
|
|
218
|
-
seen[sl.ID] = true
|
|
278
|
+
seen[SliceKey(sl.Workspace, sl.ID)] = true
|
|
279
|
+
}
|
|
280
|
+
added, err := normalizeSlices(opts.Slug, opts.Slices, opts.Root)
|
|
281
|
+
if err != nil {
|
|
282
|
+
return nil, err
|
|
283
|
+
}
|
|
284
|
+
if err := validateSources(filepath.Join(opts.Root, devritespaths.DevritesRootName), added); err != nil {
|
|
285
|
+
return nil, err
|
|
219
286
|
}
|
|
220
|
-
added := make([]SlicePaths, 0, len(opts.Slices))
|
|
221
287
|
var addedPaths []string
|
|
222
|
-
for _, sp := range
|
|
223
|
-
|
|
224
|
-
|
|
288
|
+
for _, sp := range added {
|
|
289
|
+
key := SliceKey(sp.Workspace, sp.ID)
|
|
290
|
+
if seen[key] {
|
|
291
|
+
return nil, fmt.Errorf("slice id %q already in lease", key)
|
|
225
292
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
}
|
|
229
|
-
seen[sp.ID] = true
|
|
230
|
-
paths, err := validateSlicePaths(sp.Paths, fmt.Sprintf("slice %q", sp.ID), opts.Root)
|
|
231
|
-
if err != nil {
|
|
232
|
-
return nil, err
|
|
233
|
-
}
|
|
234
|
-
added = append(added, SlicePaths{ID: sp.ID, Paths: paths})
|
|
235
|
-
addedPaths = append(addedPaths, paths...)
|
|
293
|
+
seen[key] = true
|
|
294
|
+
addedPaths = append(addedPaths, sp.Paths...)
|
|
236
295
|
}
|
|
237
296
|
all := append(activeSlices(lease), added...)
|
|
238
|
-
if len(all) >
|
|
239
|
-
return nil, fmt.Errorf("add would make %d slices active; parallel allows at most %d", len(all),
|
|
297
|
+
if len(all) > opts.Capacity {
|
|
298
|
+
return nil, fmt.Errorf("add would make %d slices active; parallel allows at most %d", len(all), opts.Capacity)
|
|
240
299
|
}
|
|
241
300
|
if len(all) >= 2 {
|
|
242
301
|
if _, err := CheckPathDisjoint(all, opts.Root); err != nil {
|
|
243
302
|
return nil, err
|
|
244
303
|
}
|
|
245
304
|
}
|
|
305
|
+
if len(added) == 0 {
|
|
306
|
+
lease.Capacity = opts.Capacity
|
|
307
|
+
if err := WriteLease(leasePath, lease); err != nil {
|
|
308
|
+
return nil, err
|
|
309
|
+
}
|
|
310
|
+
return lease, nil
|
|
311
|
+
}
|
|
246
312
|
// The new worktree starts from control HEAD, so uncommitted user work on
|
|
247
313
|
// its paths would be neither in the slice nor safe from its landing.
|
|
248
314
|
dirty, err := porcelainDirtyPaths(opts.Root, addedPaths)
|
|
@@ -262,6 +328,8 @@ func addLocked(opts AddOpts) (*Lease, error) {
|
|
|
262
328
|
}
|
|
263
329
|
lease.Slices = append(lease.Slices, made...)
|
|
264
330
|
lease.N = len(lease.Slices)
|
|
331
|
+
lease.Capacity = opts.Capacity
|
|
332
|
+
lease.Status = StatusRunning
|
|
265
333
|
if err := WriteLease(leasePath, lease); err != nil {
|
|
266
334
|
rollback()
|
|
267
335
|
return nil, err
|
|
@@ -287,6 +355,19 @@ func recordGreenLocked(repoRoot, slug, sliceID, commit string) (*Lease, error) {
|
|
|
287
355
|
if err != nil {
|
|
288
356
|
return nil, err
|
|
289
357
|
}
|
|
358
|
+
if err := normalizeLease(lease, slug); err != nil {
|
|
359
|
+
return nil, err
|
|
360
|
+
}
|
|
361
|
+
if _, err := controllerLease(repoRoot, slug); err != nil {
|
|
362
|
+
return nil, err
|
|
363
|
+
}
|
|
364
|
+
if _, err := recoverLanding(repoRoot, slug, leasePath, lease, false, false); err != nil {
|
|
365
|
+
return nil, err
|
|
366
|
+
}
|
|
367
|
+
sliceID, err = normalizeSliceRef(slug, sliceID)
|
|
368
|
+
if err != nil {
|
|
369
|
+
return nil, err
|
|
370
|
+
}
|
|
290
371
|
if lease.Status != StatusRunning && lease.Status != StatusIntegrateFailed {
|
|
291
372
|
return nil, fmt.Errorf("record-green requires status=running|integrate-failed (have %s)", lease.Status)
|
|
292
373
|
}
|
|
@@ -296,7 +377,7 @@ func recordGreenLocked(repoRoot, slug, sliceID, commit string) (*Lease, error) {
|
|
|
296
377
|
}
|
|
297
378
|
found := false
|
|
298
379
|
for i := range lease.Slices {
|
|
299
|
-
if lease.Slices[i].ID == sliceID {
|
|
380
|
+
if SliceKey(lease.Slices[i].Workspace, lease.Slices[i].ID) == sliceID {
|
|
300
381
|
if lease.Slices[i].WrightStatus == WrightIntegrated {
|
|
301
382
|
// Re-greening a landed slice would land its work a second time.
|
|
302
383
|
return nil, fmt.Errorf("slice %s already integrated", sliceID)
|
|
@@ -335,6 +416,15 @@ func abortLocked(repoRoot, slug string) (*Lease, error) {
|
|
|
335
416
|
if err != nil {
|
|
336
417
|
return nil, err
|
|
337
418
|
}
|
|
419
|
+
if err := normalizeLease(lease, slug); err != nil {
|
|
420
|
+
return nil, err
|
|
421
|
+
}
|
|
422
|
+
if _, err := controllerLease(repoRoot, slug); err != nil {
|
|
423
|
+
return nil, err
|
|
424
|
+
}
|
|
425
|
+
if _, err := recoverLanding(repoRoot, slug, leasePath, lease, false, true); err != nil {
|
|
426
|
+
return nil, err
|
|
427
|
+
}
|
|
338
428
|
if lease.Status == StatusComplete {
|
|
339
429
|
return nil, fmt.Errorf("abort refused: lease already complete — the batch landed in control; nothing to discard")
|
|
340
430
|
}
|
|
@@ -399,6 +489,36 @@ func integrateLocked(opts IntegrateOpts) (tip string, lease *Lease, err error) {
|
|
|
399
489
|
if err != nil {
|
|
400
490
|
return "", nil, err
|
|
401
491
|
}
|
|
492
|
+
if err := normalizeLease(lease, opts.Slug); err != nil {
|
|
493
|
+
return "", nil, err
|
|
494
|
+
}
|
|
495
|
+
if _, err := controllerLease(opts.Root, opts.Slug); err != nil {
|
|
496
|
+
return "", nil, err
|
|
497
|
+
}
|
|
498
|
+
if opts.Slice != "" {
|
|
499
|
+
opts.Slice, err = normalizeSliceRef(opts.Slug, opts.Slice)
|
|
500
|
+
if err != nil {
|
|
501
|
+
return "", nil, err
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
resume := opts.ApplyToControl && lease.PendingLanding != nil && lease.PendingLanding.Slice == opts.Slice
|
|
505
|
+
if _, err := recoverLanding(opts.Root, opts.Slug, leasePath, lease, resume, false); err != nil {
|
|
506
|
+
return "", nil, err
|
|
507
|
+
}
|
|
508
|
+
if opts.ApplyToControl {
|
|
509
|
+
if accepted, err := acceptedRetry(opts.Root, lease, opts.Slice); err != nil {
|
|
510
|
+
return "", nil, err
|
|
511
|
+
} else if accepted != "" {
|
|
512
|
+
return accepted, lease, nil
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
if lease.ControlCheckout == "" && lease.ControlRef == "" {
|
|
516
|
+
checkout, ref, err := controlIdentity(opts.Root)
|
|
517
|
+
if err != nil {
|
|
518
|
+
return "", nil, err
|
|
519
|
+
}
|
|
520
|
+
lease.ControlCheckout, lease.ControlRef = checkout, ref
|
|
521
|
+
}
|
|
402
522
|
if lease.Status != StatusRunning && lease.Status != StatusIntegrateFailed {
|
|
403
523
|
return "", nil, fmt.Errorf("integrate requires status=running|integrate-failed (have %s)", lease.Status)
|
|
404
524
|
}
|
|
@@ -416,7 +536,7 @@ func integrateLocked(opts IntegrateOpts) (tip string, lease *Lease, err error) {
|
|
|
416
536
|
for i, sl := range lease.Slices {
|
|
417
537
|
switch {
|
|
418
538
|
case opts.Slice == "" && sl.WrightStatus != WrightIntegrated,
|
|
419
|
-
opts.Slice != "" && sl.ID == opts.Slice:
|
|
539
|
+
opts.Slice != "" && SliceKey(sl.Workspace, sl.ID) == opts.Slice:
|
|
420
540
|
targets = append(targets, i)
|
|
421
541
|
}
|
|
422
542
|
}
|
|
@@ -449,23 +569,17 @@ func integrateLocked(opts IntegrateOpts) (tip string, lease *Lease, err error) {
|
|
|
449
569
|
for _, i := range targets {
|
|
450
570
|
sl := lease.Slices[i]
|
|
451
571
|
if sl.WrightStatus != WrightGreen {
|
|
452
|
-
return "", nil, fmt.Errorf("slice %s is not green", sl.ID)
|
|
572
|
+
return "", nil, fmt.Errorf("slice %s is not green", SliceKey(sl.Workspace, sl.ID))
|
|
453
573
|
}
|
|
454
574
|
if sl.TransferCommit == "" {
|
|
455
|
-
return "", nil, fmt.Errorf("slice %s missing transfer_commit", sl.ID)
|
|
575
|
+
return "", nil, fmt.Errorf("slice %s missing transfer_commit", SliceKey(sl.Workspace, sl.ID))
|
|
456
576
|
}
|
|
457
577
|
}
|
|
458
578
|
|
|
459
579
|
ibranch := IntegrateBranchName(opts.Slug, lease.BatchID)
|
|
460
580
|
stageWT := filepath.Join(ScratchRoot(opts.Root), lease.BatchID, "integrate")
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
// branch delete and worktree add below can succeed on retry.
|
|
464
|
-
if _, err := git(opts.Root, "worktree", "prune"); err != nil {
|
|
465
|
-
warnf("worktree prune: %v", err)
|
|
466
|
-
}
|
|
467
|
-
if exists, _ := branchExists(opts.Root, ibranch); exists {
|
|
468
|
-
_ = deleteBranch(opts.Root, ibranch)
|
|
581
|
+
if err := prepareStaging(opts.Root, opts.Slug, lease, stageWT, ibranch); err != nil {
|
|
582
|
+
return "", nil, err
|
|
469
583
|
}
|
|
470
584
|
if err := os.MkdirAll(filepath.Dir(stageWT), 0o755); err != nil {
|
|
471
585
|
return "", nil, err
|
|
@@ -481,9 +595,6 @@ func integrateLocked(opts IntegrateOpts) (tip string, lease *Lease, err error) {
|
|
|
481
595
|
if err := deleteBranch(opts.Root, ibranch); err != nil {
|
|
482
596
|
warnf("integrate branch cleanup: %v", err)
|
|
483
597
|
}
|
|
484
|
-
if _, err := git(opts.Root, "worktree", "prune"); err != nil {
|
|
485
|
-
warnf("worktree prune: %v", err)
|
|
486
|
-
}
|
|
487
598
|
lease.Status = StatusIntegrateFailed
|
|
488
599
|
if err := writeLease(leasePath, lease); err != nil {
|
|
489
600
|
// The integrate-failed transition must survive a transient write
|
|
@@ -502,22 +613,24 @@ func integrateLocked(opts IntegrateOpts) (tip string, lease *Lease, err error) {
|
|
|
502
613
|
|
|
503
614
|
for _, i := range targets {
|
|
504
615
|
sl := lease.Slices[i]
|
|
616
|
+
key := SliceKey(sl.Workspace, sl.ID)
|
|
505
617
|
// Each slice is proven against the commit its worktree was cut from,
|
|
506
618
|
// which for a refill is a later control tip than the batch base.
|
|
507
619
|
base, err := revParse(opts.Root, sliceBase(lease, sl))
|
|
508
620
|
if err != nil {
|
|
509
|
-
return fail(fmt.Errorf("slice %s base: %w",
|
|
621
|
+
return fail(fmt.Errorf("slice %s base: %w", key, err))
|
|
510
622
|
}
|
|
511
623
|
tc, err := revParse(opts.Root, sl.TransferCommit)
|
|
512
624
|
if err != nil {
|
|
513
|
-
return fail(fmt.Errorf("slice %s transfer: %w",
|
|
625
|
+
return fail(fmt.Errorf("slice %s transfer: %w", key, err))
|
|
514
626
|
}
|
|
515
627
|
ok, err := isAncestor(opts.Root, base, tc)
|
|
628
|
+
lease.Slices[i].TransferCommit = tc
|
|
516
629
|
if err != nil {
|
|
517
630
|
return fail(err)
|
|
518
631
|
}
|
|
519
632
|
if !ok {
|
|
520
|
-
return fail(fmt.Errorf("transfer_commit for %s is not a descendant of base",
|
|
633
|
+
return fail(fmt.Errorf("transfer_commit for %s is not a descendant of base", key))
|
|
521
634
|
}
|
|
522
635
|
got, err := diffNames(opts.Root, base, tc)
|
|
523
636
|
if err != nil {
|
|
@@ -527,7 +640,7 @@ func integrateLocked(opts IntegrateOpts) (tip string, lease *Lease, err error) {
|
|
|
527
640
|
sort.Strings(want)
|
|
528
641
|
sort.Strings(got)
|
|
529
642
|
if !pathListsEqual(want, got) {
|
|
530
|
-
return fail(fmt.Errorf("exact-path proof failed for slice %s: want=%v got=%v",
|
|
643
|
+
return fail(fmt.Errorf("exact-path proof failed for slice %s: want=%v got=%v", key, want, got))
|
|
531
644
|
}
|
|
532
645
|
for _, p := range got {
|
|
533
646
|
if p == ".devrites" || strings.HasPrefix(p, ".devrites/") {
|
|
@@ -537,14 +650,18 @@ func integrateLocked(opts IntegrateOpts) (tip string, lease *Lease, err error) {
|
|
|
537
650
|
|
|
538
651
|
if err := cherryPickNoCommit(stageWT, base, tc); err != nil {
|
|
539
652
|
cherryPickAbort(stageWT)
|
|
540
|
-
return fail(fmt.Errorf("apply failed for slice %s: %w",
|
|
653
|
+
return fail(fmt.Errorf("apply failed for slice %s: %w", key, err))
|
|
541
654
|
}
|
|
542
655
|
subj, err := commitSubject(opts.Root, tc)
|
|
543
656
|
if err != nil {
|
|
544
|
-
return fail(fmt.Errorf("transfer subject for %s: %w",
|
|
657
|
+
return fail(fmt.Errorf("transfer subject for %s: %w", key, err))
|
|
658
|
+
}
|
|
659
|
+
source := sl.Workspace
|
|
660
|
+
if source == "" {
|
|
661
|
+
source = opts.Slug
|
|
545
662
|
}
|
|
546
|
-
if _, err = stagePathsAndCommit(stageWT, controlCommitMessage(
|
|
547
|
-
return fail(fmt.Errorf("control commit for %s: %w",
|
|
663
|
+
if _, err = stagePathsAndCommit(stageWT, controlCommitMessage(source, subj), sl.Paths); err != nil {
|
|
664
|
+
return fail(fmt.Errorf("control commit for %s: %w", key, err))
|
|
548
665
|
}
|
|
549
666
|
cherryPickQuit(stageWT)
|
|
550
667
|
}
|
|
@@ -560,25 +677,28 @@ func integrateLocked(opts IntegrateOpts) (tip string, lease *Lease, err error) {
|
|
|
560
677
|
}
|
|
561
678
|
warnf("staging worktree cleanup: %v", err)
|
|
562
679
|
}
|
|
563
|
-
if _, err := git(opts.Root, "worktree", "prune"); err != nil {
|
|
564
|
-
warnf("worktree prune: %v", err)
|
|
565
|
-
}
|
|
566
680
|
|
|
567
681
|
if opts.ApplyToControl {
|
|
568
|
-
if err :=
|
|
569
|
-
return
|
|
682
|
+
if err := ensureControllerIdentity(opts.Root, lease); err != nil {
|
|
683
|
+
return "", nil, err
|
|
684
|
+
}
|
|
685
|
+
checkout, ref, err := controlIdentity(opts.Root)
|
|
686
|
+
if err != nil {
|
|
687
|
+
return "", nil, err
|
|
688
|
+
}
|
|
689
|
+
lease.ControlCheckout, lease.ControlRef = checkout, ref
|
|
690
|
+
record := &landing{
|
|
691
|
+
BatchID: lease.BatchID, Controller: opts.Slug, Checkout: checkout,
|
|
692
|
+
Ref: ref, PriorTip: expected, NewTip: tip, Slice: opts.Slice,
|
|
570
693
|
}
|
|
571
694
|
for _, i := range targets {
|
|
572
|
-
lease.Slices[i]
|
|
695
|
+
record.Targets = append(record.Targets, lease.Slices[i])
|
|
573
696
|
}
|
|
574
|
-
lease.
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
lease.Status = StatusRunning
|
|
578
|
-
if len(activeSlices(lease)) == 0 {
|
|
579
|
-
lease.Status = StatusComplete
|
|
697
|
+
lease.PendingLanding = record
|
|
698
|
+
if err := writeLease(leasePath, lease); err != nil {
|
|
699
|
+
return "", nil, fmt.Errorf("prepare landing before control fast-forward: %w", err)
|
|
580
700
|
}
|
|
581
|
-
if err :=
|
|
701
|
+
if _, err := recoverLanding(opts.Root, opts.Slug, leasePath, lease, true, false); err != nil {
|
|
582
702
|
return "", nil, err
|
|
583
703
|
}
|
|
584
704
|
} else if err := ensureControlAtBase(opts.Root, expected); err != nil {
|
|
@@ -648,7 +768,7 @@ type Salvage struct {
|
|
|
648
768
|
// root down to the worktree directory may be a symlink.
|
|
649
769
|
func ownedWorktreePath(repoRoot, batchID string, sl LeaseSlice) bool {
|
|
650
770
|
got, err1 := filepath.Abs(sl.WorktreePath)
|
|
651
|
-
want, err2 := filepath.Abs(
|
|
771
|
+
want, err2 := filepath.Abs(workerWorktreePath(repoRoot, batchID, sl.Workspace, sl.ID))
|
|
652
772
|
root, err3 := filepath.Abs(repoRoot)
|
|
653
773
|
if err1 != nil || err2 != nil || err3 != nil || got != want {
|
|
654
774
|
return false
|
|
@@ -689,12 +809,9 @@ func salvageSlice(sl LeaseSlice, batchID string) (string, error) {
|
|
|
689
809
|
fmt.Sprintf("devrites: salvage WIP (%s)", batchID), sl.Paths)
|
|
690
810
|
}
|
|
691
811
|
|
|
692
|
-
// Cleanup removes
|
|
693
|
-
//
|
|
694
|
-
//
|
|
695
|
-
// allowlisted changes become a commit on the slice branch — and keeps every
|
|
696
|
-
// branch whose tip moved past that slice's base as the durable rejected-work
|
|
697
|
-
// ref.
|
|
812
|
+
// Cleanup removes unchanged integrated checkouts and refs, salvages allowlisted
|
|
813
|
+
// nonintegrated work when forced, then clears the lease. Late data or changed
|
|
814
|
+
// refs remain available through the returned recovery paths and branches.
|
|
698
815
|
func Cleanup(repoRoot, slug string, force bool) (salvaged []Salvage, err error) {
|
|
699
816
|
err = withLeaseLock(repoRoot, slug, func() error {
|
|
700
817
|
salvaged, err = cleanupLocked(repoRoot, slug, force)
|
|
@@ -715,10 +832,18 @@ func cleanupLocked(repoRoot, slug string, force bool) ([]Salvage, error) {
|
|
|
715
832
|
if err != nil {
|
|
716
833
|
return nil, err
|
|
717
834
|
}
|
|
835
|
+
if err := normalizeLease(lease, slug); err != nil {
|
|
836
|
+
return nil, err
|
|
837
|
+
}
|
|
838
|
+
if _, err := controllerLease(repoRoot, slug); err != nil {
|
|
839
|
+
return nil, err
|
|
840
|
+
}
|
|
841
|
+
if _, err := recoverLanding(repoRoot, slug, leasePath, lease, false, false); err != nil {
|
|
842
|
+
return nil, err
|
|
843
|
+
}
|
|
718
844
|
if lease.Status != StatusComplete && !force {
|
|
719
845
|
return nil, fmt.Errorf("cleanup refuses status=%s without --force (non-complete cleanup salvages work onto slice branches)", lease.Status)
|
|
720
846
|
}
|
|
721
|
-
complete := lease.Status == StatusComplete
|
|
722
847
|
// Ownership comes from what git registered, read before anything is
|
|
723
848
|
// removed, never from the lease's own claim.
|
|
724
849
|
registered, err := registeredWorktrees(repoRoot)
|
|
@@ -727,66 +852,101 @@ func cleanupLocked(repoRoot, slug string, force bool) ([]Salvage, error) {
|
|
|
727
852
|
}
|
|
728
853
|
var salvaged []Salvage
|
|
729
854
|
var failed, stranded, unconfirmed []string
|
|
730
|
-
keptWorktrees := map[string]bool{}
|
|
731
855
|
for _, sl := range lease.Slices {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
landed := complete || sl.WrightStatus == WrightIntegrated
|
|
856
|
+
key := SliceKey(sl.Workspace, sl.ID)
|
|
857
|
+
landed := sl.WrightStatus == WrightIntegrated
|
|
735
858
|
salvageFailed := false
|
|
736
859
|
// Only the deterministic scratch layout is ours to touch. A forged or
|
|
737
860
|
// stale lease worktree_path is never salvaged into (git ops would run
|
|
738
861
|
// in an arbitrary repo) and never removed (RemoveAll would delete an
|
|
739
862
|
// arbitrary directory).
|
|
740
863
|
inScratch := sl.WorktreePath != "" && ownedWorktreePath(repoRoot, lease.BatchID, sl)
|
|
741
|
-
owned := inScratch && createdWorktree(registered, sl.WorktreePath)
|
|
864
|
+
owned := inScratch && sl.Branch == workerBranch(slug, lease.BatchID, sl.Workspace, sl.ID) && createdWorktree(registered, sl.WorktreePath)
|
|
865
|
+
if owned {
|
|
866
|
+
if _, err := os.Stat(sl.WorktreePath); err == nil {
|
|
867
|
+
branch, err := git(sl.WorktreePath, "symbolic-ref", "--quiet", "--short", "HEAD")
|
|
868
|
+
if err != nil || branch != sl.Branch {
|
|
869
|
+
owned = false
|
|
870
|
+
warnf("slice %s no longer has its registered worker branch; leaving %s untouched", key, sl.WorktreePath)
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
742
874
|
if sl.WorktreePath != "" && !owned {
|
|
743
|
-
// Never salvaged, so the batch sweep must not delete this slice's
|
|
744
|
-
// scratch entry either (e.g. a --root spelled through a symlink).
|
|
745
|
-
keptWorktrees[sl.ID] = true
|
|
746
875
|
if inScratch {
|
|
747
|
-
warnf("slice %s worktree_path %q is not a worktree git registered; leaving it untouched",
|
|
748
|
-
|
|
876
|
+
warnf("slice %s worktree_path %q is not a worktree this lease owns and git registered; leaving it untouched",
|
|
877
|
+
key, sl.WorktreePath)
|
|
749
878
|
} else {
|
|
750
879
|
warnf("slice %s worktree_path %q is outside %s; leaving it untouched",
|
|
751
|
-
|
|
880
|
+
key, sl.WorktreePath, ScratchRoot(repoRoot))
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
present := false
|
|
884
|
+
if _, err := os.Lstat(sl.WorktreePath); err == nil || !os.IsNotExist(err) {
|
|
885
|
+
present = true
|
|
886
|
+
}
|
|
887
|
+
missingRegistered := !present && registered[resolvedPath(sl.WorktreePath)]
|
|
888
|
+
if missingRegistered {
|
|
889
|
+
warnf("preserving missing slice %s registration, index and recovery metadata; recovery path=%s ref=%s", key, sl.WorktreePath, sl.Branch)
|
|
890
|
+
salvageFailed = true
|
|
891
|
+
}
|
|
892
|
+
if !owned && present {
|
|
893
|
+
salvageFailed = true
|
|
894
|
+
}
|
|
895
|
+
if landed && !missingRegistered {
|
|
896
|
+
exists, branchErr := branchExists(repoRoot, sl.Branch)
|
|
897
|
+
if branchErr == nil && !exists && !present {
|
|
898
|
+
continue
|
|
899
|
+
}
|
|
900
|
+
if err := acceptedWorker(repoRoot, slug, lease, sl, registered); err != nil {
|
|
901
|
+
warnf("preserving integrated slice %s: %v; recovery path=%s ref=%s", key, err, sl.WorktreePath, sl.Branch)
|
|
902
|
+
salvageFailed = true
|
|
752
903
|
}
|
|
753
904
|
}
|
|
754
905
|
if !landed && owned {
|
|
755
906
|
if _, err := salvage(sl, lease.BatchID); err != nil {
|
|
756
|
-
warnf("salvage %s: %v",
|
|
907
|
+
warnf("salvage %s: %v", key, err)
|
|
757
908
|
salvageFailed = true
|
|
758
|
-
keptWorktrees[sl.ID] = true
|
|
759
909
|
}
|
|
760
910
|
}
|
|
761
|
-
if owned && !salvageFailed {
|
|
762
|
-
if err :=
|
|
763
|
-
warnf("
|
|
911
|
+
if owned && present && !salvageFailed {
|
|
912
|
+
if err := fullyClean(sl.WorktreePath); err != nil {
|
|
913
|
+
warnf("preserving residual data for %s: %v; recovery ref=%s", key, err, sl.Branch)
|
|
914
|
+
salvageFailed = true
|
|
764
915
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
916
|
+
}
|
|
917
|
+
if owned && present && !salvageFailed {
|
|
918
|
+
if err := removeWorktree(repoRoot, sl.WorktreePath); err != nil {
|
|
919
|
+
warnf("worktree cleanup %s (recovery ref=%s): %v", sl.WorktreePath, sl.Branch, err)
|
|
920
|
+
salvageFailed = true
|
|
921
|
+
failed = append(failed, key)
|
|
768
922
|
// git can unregister a worktree and still exit non-zero, so the
|
|
769
923
|
// exit code says nothing about registration; ask git again.
|
|
770
924
|
if reg, rerr := registeredWorktrees(repoRoot); rerr != nil {
|
|
771
925
|
unconfirmed = append(unconfirmed, sl.WorktreePath)
|
|
772
|
-
} else if !
|
|
926
|
+
} else if !reg[resolvedPath(sl.WorktreePath)] {
|
|
773
927
|
// A rerun refuses an unregistered directory as not
|
|
774
928
|
// created by us, so it will not delete it.
|
|
775
929
|
stranded = append(stranded, sl.WorktreePath)
|
|
776
930
|
}
|
|
777
931
|
}
|
|
778
932
|
}
|
|
779
|
-
if sl.Branch != "" &&
|
|
780
|
-
warnf("slice %s branch %q
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
933
|
+
if sl.Branch != "" && sl.Branch != workerBranch(slug, lease.BatchID, sl.Workspace, sl.ID) {
|
|
934
|
+
warnf("slice %s branch %q does not match its worker namespace; leaving it untouched",
|
|
935
|
+
key, sl.Branch)
|
|
936
|
+
tip, _ := revParse(repoRoot, "refs/heads/"+sl.Branch)
|
|
937
|
+
result := Salvage{SliceID: key, Branch: sl.Branch, Commit: tip}
|
|
938
|
+
if present || missingRegistered {
|
|
939
|
+
result.Worktree = sl.WorktreePath
|
|
784
940
|
}
|
|
941
|
+
salvaged = append(salvaged, result)
|
|
785
942
|
continue
|
|
786
943
|
}
|
|
787
944
|
if sl.Branch != "" {
|
|
788
945
|
keep := salvageFailed
|
|
789
946
|
tip := ""
|
|
947
|
+
if t, err := revParse(repoRoot, "refs/heads/"+sl.Branch); err == nil {
|
|
948
|
+
tip = t
|
|
949
|
+
}
|
|
790
950
|
if !landed {
|
|
791
951
|
base := ""
|
|
792
952
|
if b, err := revParse(repoRoot, sliceBase(lease, sl)); err != nil {
|
|
@@ -803,22 +963,25 @@ func cleanupLocked(repoRoot, slug string, force bool) ([]Salvage, error) {
|
|
|
803
963
|
}
|
|
804
964
|
}
|
|
805
965
|
if keep {
|
|
806
|
-
s := Salvage{SliceID:
|
|
807
|
-
if salvageFailed {
|
|
966
|
+
s := Salvage{SliceID: key, Branch: sl.Branch, Commit: tip}
|
|
967
|
+
if salvageFailed && (present || missingRegistered) {
|
|
808
968
|
s.Worktree = sl.WorktreePath
|
|
809
969
|
}
|
|
810
970
|
salvaged = append(salvaged, s)
|
|
811
|
-
} else
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
if
|
|
817
|
-
|
|
971
|
+
} else {
|
|
972
|
+
deleteTip := tip
|
|
973
|
+
if landed {
|
|
974
|
+
deleteTip = sl.TransferCommit
|
|
975
|
+
}
|
|
976
|
+
if err := deleteBranchAt(repoRoot, sl.Branch, deleteTip); err != nil {
|
|
977
|
+
warnf("branch cleanup %s: %v", sl.Branch, err)
|
|
978
|
+
if owned || sl.WorktreePath == "" {
|
|
979
|
+
failed = append(failed, key)
|
|
980
|
+
}
|
|
818
981
|
}
|
|
819
982
|
}
|
|
820
983
|
} else if salvageFailed {
|
|
821
|
-
salvaged = append(salvaged, Salvage{SliceID:
|
|
984
|
+
salvaged = append(salvaged, Salvage{SliceID: key, Worktree: sl.WorktreePath})
|
|
822
985
|
}
|
|
823
986
|
}
|
|
824
987
|
ibranch := IntegrateBranchName(slug, lease.BatchID)
|
|
@@ -831,43 +994,26 @@ func cleanupLocked(repoRoot, slug string, force bool) ([]Salvage, error) {
|
|
|
831
994
|
}
|
|
832
995
|
if keep {
|
|
833
996
|
salvaged = append(salvaged, Salvage{SliceID: "integrate", Branch: ibranch, Commit: itip})
|
|
834
|
-
} else if err :=
|
|
997
|
+
} else if err := deleteBranchAt(repoRoot, ibranch, itip); err != nil {
|
|
835
998
|
warnf("integrate branch cleanup %s: %v", ibranch, err)
|
|
836
999
|
failed = append(failed, "integrate")
|
|
837
1000
|
}
|
|
838
1001
|
}
|
|
839
1002
|
batchDir := filepath.Join(ScratchRoot(repoRoot), lease.BatchID)
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
} else if entries, err := os.ReadDir(batchDir); err == nil {
|
|
847
|
-
// A failed salvage keeps its worktree as the only copy, and an entry git
|
|
848
|
-
// never registered is not something Create made.
|
|
849
|
-
for _, e := range entries {
|
|
850
|
-
p := filepath.Join(batchDir, e.Name())
|
|
851
|
-
if keptWorktrees[e.Name()] {
|
|
852
|
-
continue
|
|
853
|
-
}
|
|
854
|
-
if !createdWorktree(registered, p) {
|
|
855
|
-
warnf("scratch entry %q is not a worktree git registered; leaving it untouched", p)
|
|
856
|
-
continue
|
|
857
|
-
}
|
|
858
|
-
if err := os.RemoveAll(p); err != nil {
|
|
859
|
-
warnf("scratch entry cleanup %s: %v", e.Name(), err)
|
|
860
|
-
failed = append(failed, e.Name())
|
|
1003
|
+
claim := LeaseSlice{ID: "integrate", WorktreePath: WorkerWorktreePath(repoRoot, lease.BatchID, "integrate")}
|
|
1004
|
+
if ownedWorktreePath(repoRoot, lease.BatchID, claim) {
|
|
1005
|
+
// Remove only empty source namespaces; unknown or unsalvaged files stay.
|
|
1006
|
+
for _, sl := range lease.Slices {
|
|
1007
|
+
if sl.Workspace != "" && ownedWorktreePath(repoRoot, lease.BatchID, sl) {
|
|
1008
|
+
_ = os.Remove(filepath.Join(batchDir, "_workspaces", sl.Workspace))
|
|
861
1009
|
}
|
|
862
1010
|
}
|
|
1011
|
+
namespace := filepath.Join(batchDir, "_workspaces")
|
|
1012
|
+
if info, err := os.Lstat(namespace); err == nil && info.IsDir() {
|
|
1013
|
+
_ = os.Remove(namespace)
|
|
1014
|
+
}
|
|
863
1015
|
// Fails harmlessly while anything was left behind.
|
|
864
1016
|
_ = os.Remove(batchDir)
|
|
865
|
-
} else if !os.IsNotExist(err) {
|
|
866
|
-
warnf("scratch cleanup %s: %v", batchDir, err)
|
|
867
|
-
failed = append(failed, "scratch")
|
|
868
|
-
}
|
|
869
|
-
if _, err := git(repoRoot, "worktree", "prune"); err != nil {
|
|
870
|
-
warnf("worktree prune: %v", err)
|
|
871
1017
|
}
|
|
872
1018
|
if len(failed) > 0 {
|
|
873
1019
|
// The lease is the only index of what is left on disk; keep it so a
|
|
@@ -891,27 +1037,38 @@ func StatusReport(repoRoot, slug string) (string, error) {
|
|
|
891
1037
|
if err != nil {
|
|
892
1038
|
return "", err
|
|
893
1039
|
}
|
|
894
|
-
|
|
1040
|
+
found, err := controllerLease(repoRoot, "")
|
|
1041
|
+
if err != nil {
|
|
1042
|
+
return "", err
|
|
1043
|
+
}
|
|
1044
|
+
if found == nil {
|
|
895
1045
|
return fmt.Sprintf("status: no lease at %s\n", leasePath), nil
|
|
896
1046
|
}
|
|
897
|
-
lease
|
|
1047
|
+
lease := found.lease
|
|
1048
|
+
leasePath, err = LeasePath(found.root, found.controller)
|
|
898
1049
|
if err != nil {
|
|
899
1050
|
return "", err
|
|
900
1051
|
}
|
|
901
1052
|
var b strings.Builder
|
|
902
1053
|
fmt.Fprintf(&b, "lease: %s\n", leasePath)
|
|
1054
|
+
fmt.Fprintf(&b, "controller: %s\n", found.controller)
|
|
1055
|
+
fmt.Fprintf(&b, "capacity: %d\n", leaseCapacity(lease))
|
|
903
1056
|
fmt.Fprintf(&b, "status: %s\n", lease.Status)
|
|
904
1057
|
fmt.Fprintf(&b, "base_sha: %s\n", lease.BaseSHA)
|
|
905
1058
|
if lease.ControlTip != "" {
|
|
906
1059
|
fmt.Fprintf(&b, "control_tip: %s\n", lease.ControlTip)
|
|
907
1060
|
}
|
|
1061
|
+
if lease.PendingLanding != nil {
|
|
1062
|
+
fmt.Fprintf(&b, "pending_landing: %s -> %s; recover with integrate --apply-to-control or abort\n",
|
|
1063
|
+
lease.PendingLanding.PriorTip, lease.PendingLanding.NewTip)
|
|
1064
|
+
}
|
|
908
1065
|
for _, sl := range lease.Slices {
|
|
909
1066
|
tc := sl.TransferCommit
|
|
910
1067
|
if tc == "" {
|
|
911
1068
|
tc = "-"
|
|
912
1069
|
}
|
|
913
1070
|
fmt.Fprintf(&b, "slice %s: wright=%s wt=%s branch=%s transfer=%s",
|
|
914
|
-
sl.ID, sl.WrightStatus, sl.WorktreePath, sl.Branch, tc)
|
|
1071
|
+
SliceKey(sl.Workspace, sl.ID), sl.WrightStatus, sl.WorktreePath, sl.Branch, tc)
|
|
915
1072
|
if sl.BaseSHA != "" {
|
|
916
1073
|
fmt.Fprintf(&b, " base=%s", sl.BaseSHA)
|
|
917
1074
|
}
|