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
|
@@ -20,8 +20,47 @@ var winAbsRE = regexp.MustCompile(`(?i)^[A-Za-z]:[/\\]`)
|
|
|
20
20
|
|
|
21
21
|
// SlicePaths is one path-disjoint eligibility unit.
|
|
22
22
|
type SlicePaths struct {
|
|
23
|
-
ID
|
|
24
|
-
|
|
23
|
+
ID string `json:"id"`
|
|
24
|
+
Workspace string `json:"workspace,omitempty"`
|
|
25
|
+
Paths []string `json:"paths"`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// SliceKey identifies a slice in its source workspace; empty means controller.
|
|
29
|
+
func SliceKey(workspace, id string) string {
|
|
30
|
+
if workspace == "" {
|
|
31
|
+
return id
|
|
32
|
+
}
|
|
33
|
+
return workspace + "/" + id
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
func normalizeSlices(controller string, slices []SlicePaths, root string) ([]SlicePaths, error) {
|
|
37
|
+
normalized := make([]SlicePaths, 0, len(slices))
|
|
38
|
+
seen := make(map[string]bool, len(slices))
|
|
39
|
+
for _, item := range slices {
|
|
40
|
+
if err := validateSliceID(item.ID); err != nil {
|
|
41
|
+
return nil, err
|
|
42
|
+
}
|
|
43
|
+
if item.Workspace != "" {
|
|
44
|
+
if err := validateSlug(item.Workspace); err != nil {
|
|
45
|
+
return nil, err
|
|
46
|
+
}
|
|
47
|
+
if item.Workspace == controller {
|
|
48
|
+
item.Workspace = ""
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
key := SliceKey(item.Workspace, item.ID)
|
|
52
|
+
if seen[key] {
|
|
53
|
+
return nil, fmt.Errorf("duplicate slice id %q", key)
|
|
54
|
+
}
|
|
55
|
+
seen[key] = true
|
|
56
|
+
paths, err := validateSlicePaths(item.Paths, fmt.Sprintf("slice %q", key), root)
|
|
57
|
+
if err != nil {
|
|
58
|
+
return nil, err
|
|
59
|
+
}
|
|
60
|
+
item.Paths = paths
|
|
61
|
+
normalized = append(normalized, item)
|
|
62
|
+
}
|
|
63
|
+
return normalized, nil
|
|
25
64
|
}
|
|
26
65
|
|
|
27
66
|
// NormalizePath mirrors scripts/check-path-disjoint.py: slash-normalize, reject
|
|
@@ -116,11 +155,16 @@ func CheckPathDisjoint(slices []SlicePaths, root string) ([]string, error) {
|
|
|
116
155
|
for index, item := range slices {
|
|
117
156
|
label := fmt.Sprintf("slice %d", index)
|
|
118
157
|
if item.ID != "" {
|
|
119
|
-
label = fmt.Sprintf("slice %q", item.ID)
|
|
120
|
-
ids = append(ids, item.ID)
|
|
158
|
+
label = fmt.Sprintf("slice %q", SliceKey(item.Workspace, item.ID))
|
|
159
|
+
ids = append(ids, SliceKey(item.Workspace, item.ID))
|
|
121
160
|
} else {
|
|
122
161
|
ids = append(ids, fmt.Sprintf("%d", index))
|
|
123
162
|
}
|
|
163
|
+
if item.Workspace != "" {
|
|
164
|
+
if err := validateSlug(item.Workspace); err != nil {
|
|
165
|
+
return nil, err
|
|
166
|
+
}
|
|
167
|
+
}
|
|
124
168
|
paths, err := validateSlicePaths(item.Paths, label, root)
|
|
125
169
|
if err != nil {
|
|
126
170
|
return nil, err
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
package parallel
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"errors"
|
|
5
|
+
"fmt"
|
|
6
|
+
"os"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
func fullyClean(worktree string) error {
|
|
10
|
+
out, err := git(worktree, "status", "--porcelain", "--untracked-files=all", "--ignored=matching")
|
|
11
|
+
if err != nil {
|
|
12
|
+
return err
|
|
13
|
+
}
|
|
14
|
+
if out != "" {
|
|
15
|
+
return fmt.Errorf("worktree has tracked, untracked, or ignored data: %s", worktree)
|
|
16
|
+
}
|
|
17
|
+
return nil
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// acceptedWorker checks the ref even when its checkout has already disappeared.
|
|
21
|
+
// Control rewrites WIP commits, so exact transfer identity replaces ancestry.
|
|
22
|
+
func acceptedWorker(root, slug string, lease *Lease, sl LeaseSlice, registered map[string]bool) error {
|
|
23
|
+
if sl.Branch != workerBranch(slug, lease.BatchID, sl.Workspace, sl.ID) || !ownedWorktreePath(root, lease.BatchID, sl) {
|
|
24
|
+
return fmt.Errorf("worker identity is not owned: %s (%s)", sl.WorktreePath, sl.Branch)
|
|
25
|
+
}
|
|
26
|
+
accepted, err := revParse(root, sl.TransferCommit)
|
|
27
|
+
if err != nil || sl.TransferCommit == "" {
|
|
28
|
+
return fmt.Errorf("worker has no usable accepted transfer: %s", sl.Branch)
|
|
29
|
+
}
|
|
30
|
+
tip, err := revParse(root, "refs/heads/"+sl.Branch)
|
|
31
|
+
if err != nil || tip != accepted {
|
|
32
|
+
return fmt.Errorf("worker branch differs from accepted transfer %s: %s", accepted, sl.Branch)
|
|
33
|
+
}
|
|
34
|
+
if _, err := os.Lstat(sl.WorktreePath); os.IsNotExist(err) {
|
|
35
|
+
if registered[resolvedPath(sl.WorktreePath)] {
|
|
36
|
+
return fmt.Errorf("missing worker checkout remains registered; preserve its index and recovery metadata: %s", sl.WorktreePath)
|
|
37
|
+
}
|
|
38
|
+
return nil
|
|
39
|
+
} else if err != nil {
|
|
40
|
+
return err
|
|
41
|
+
}
|
|
42
|
+
if !registered[resolvedPath(sl.WorktreePath)] {
|
|
43
|
+
return fmt.Errorf("worker path is not registered; leaving replacement untouched: %s", sl.WorktreePath)
|
|
44
|
+
}
|
|
45
|
+
ref, err := git(sl.WorktreePath, "symbolic-ref", "--quiet", "HEAD")
|
|
46
|
+
if err != nil || ref != "refs/heads/"+sl.Branch {
|
|
47
|
+
return fmt.Errorf("worker checkout switched branch: %s", sl.WorktreePath)
|
|
48
|
+
}
|
|
49
|
+
head, err := headSHA(sl.WorktreePath)
|
|
50
|
+
if err != nil || head != accepted {
|
|
51
|
+
return fmt.Errorf("worker checkout differs from accepted transfer: %s", sl.WorktreePath)
|
|
52
|
+
}
|
|
53
|
+
return fullyClean(sl.WorktreePath)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Prune removes only unchanged integrated checkouts, not refs or lease rows.
|
|
57
|
+
// Worker-bound review/proof and source bookkeeping must finish before callers prune.
|
|
58
|
+
func Prune(root, slug string) (removed []string, err error) {
|
|
59
|
+
err = withLeaseLock(root, slug, func() error {
|
|
60
|
+
path, err := LeasePath(root, slug)
|
|
61
|
+
if err != nil {
|
|
62
|
+
return err
|
|
63
|
+
}
|
|
64
|
+
lease, err := ReadLease(path)
|
|
65
|
+
if err != nil {
|
|
66
|
+
return err
|
|
67
|
+
}
|
|
68
|
+
if err := normalizeLease(lease, slug); err != nil {
|
|
69
|
+
return err
|
|
70
|
+
}
|
|
71
|
+
if _, err := controllerLease(root, slug); err != nil {
|
|
72
|
+
return err
|
|
73
|
+
}
|
|
74
|
+
if _, err := recoverLanding(root, slug, path, lease, false, false); err != nil {
|
|
75
|
+
return err
|
|
76
|
+
}
|
|
77
|
+
registered, err := registeredWorktrees(root)
|
|
78
|
+
if err != nil {
|
|
79
|
+
return err
|
|
80
|
+
}
|
|
81
|
+
var failures []error
|
|
82
|
+
for _, sl := range lease.Slices {
|
|
83
|
+
if sl.WrightStatus != WrightIntegrated {
|
|
84
|
+
continue
|
|
85
|
+
}
|
|
86
|
+
if err := acceptedWorker(root, slug, lease, sl, registered); err != nil {
|
|
87
|
+
failures = append(failures, fmt.Errorf("%s: %w", SliceKey(sl.Workspace, sl.ID), err))
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
90
|
+
if _, err := os.Lstat(sl.WorktreePath); os.IsNotExist(err) {
|
|
91
|
+
continue
|
|
92
|
+
}
|
|
93
|
+
if err := removeWorktree(root, sl.WorktreePath); err != nil {
|
|
94
|
+
failures = append(failures, fmt.Errorf("kept recovery path %s and ref %s: %w", sl.WorktreePath, sl.Branch, err))
|
|
95
|
+
continue
|
|
96
|
+
}
|
|
97
|
+
removed = append(removed, sl.WorktreePath)
|
|
98
|
+
}
|
|
99
|
+
return errors.Join(failures...)
|
|
100
|
+
})
|
|
101
|
+
return removed, err
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
func prepareStaging(root, slug string, lease *Lease, path, branch string) error {
|
|
105
|
+
claim := LeaseSlice{ID: "integrate", WorktreePath: path}
|
|
106
|
+
if !ownedWorktreePath(root, lease.BatchID, claim) {
|
|
107
|
+
return fmt.Errorf("staging path is not owned: %s", path)
|
|
108
|
+
}
|
|
109
|
+
registered, err := registeredWorktrees(root)
|
|
110
|
+
if err != nil {
|
|
111
|
+
return err
|
|
112
|
+
}
|
|
113
|
+
if _, err := os.Lstat(path); err == nil {
|
|
114
|
+
if !registered[resolvedPath(path)] {
|
|
115
|
+
return fmt.Errorf("staging path is not registered; leaving replacement untouched: %s", path)
|
|
116
|
+
}
|
|
117
|
+
ref, err := git(path, "symbolic-ref", "--quiet", "HEAD")
|
|
118
|
+
if err != nil || ref != "refs/heads/"+branch {
|
|
119
|
+
return fmt.Errorf("staging checkout changed branch: %s", path)
|
|
120
|
+
}
|
|
121
|
+
if err := fullyClean(path); err != nil {
|
|
122
|
+
return err
|
|
123
|
+
}
|
|
124
|
+
if err := removeWorktree(root, path); err != nil {
|
|
125
|
+
return fmt.Errorf("staging checkout kept at %s: %w", path, err)
|
|
126
|
+
}
|
|
127
|
+
} else if !os.IsNotExist(err) {
|
|
128
|
+
return err
|
|
129
|
+
} else if registered[resolvedPath(path)] {
|
|
130
|
+
return fmt.Errorf("missing staging checkout remains registered; preserve its metadata and recover explicitly: %s", path)
|
|
131
|
+
}
|
|
132
|
+
return deleteBranch(root, branch)
|
|
133
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
package parallel
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"os"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"sort"
|
|
8
|
+
|
|
9
|
+
"github.com/devrites/devrites/internal/state"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
// WithControlLock serializes controller admission and control-tip mutations.
|
|
13
|
+
// devritesRoot is explicit; callers take this lock before any feature lock.
|
|
14
|
+
func WithControlLock(devritesRoot string, fn func() error) error {
|
|
15
|
+
devritesRoot = filepath.Clean(devritesRoot)
|
|
16
|
+
if err := validateControlRoot(devritesRoot); err != nil {
|
|
17
|
+
return err
|
|
18
|
+
}
|
|
19
|
+
dir := devritesRoot
|
|
20
|
+
root := filepath.Dir(devritesRoot)
|
|
21
|
+
common, err := commonGitDir(root)
|
|
22
|
+
if err != nil {
|
|
23
|
+
return err
|
|
24
|
+
}
|
|
25
|
+
if common != "" {
|
|
26
|
+
dir = common
|
|
27
|
+
}
|
|
28
|
+
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
29
|
+
return err
|
|
30
|
+
}
|
|
31
|
+
return state.WithLock(filepath.Join(dir, "parallel.lock"), fn)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func commonGitDir(root string) (string, error) {
|
|
35
|
+
common, err := git(root, "rev-parse", "--git-common-dir")
|
|
36
|
+
if err == nil {
|
|
37
|
+
if !filepath.IsAbs(common) {
|
|
38
|
+
common = filepath.Join(root, common)
|
|
39
|
+
}
|
|
40
|
+
return resolvedPath(common), nil
|
|
41
|
+
}
|
|
42
|
+
dir, absErr := filepath.Abs(root)
|
|
43
|
+
if absErr != nil {
|
|
44
|
+
return "", absErr
|
|
45
|
+
}
|
|
46
|
+
for {
|
|
47
|
+
if _, statErr := os.Lstat(filepath.Join(dir, ".git")); !os.IsNotExist(statErr) {
|
|
48
|
+
return "", fmt.Errorf("parallel repository discovery: %w", err)
|
|
49
|
+
}
|
|
50
|
+
parent := filepath.Dir(dir)
|
|
51
|
+
if parent == dir {
|
|
52
|
+
return "", nil
|
|
53
|
+
}
|
|
54
|
+
dir = parent
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func validateControlRoot(root string) error {
|
|
59
|
+
info, err := os.Lstat(root)
|
|
60
|
+
if os.IsNotExist(err) {
|
|
61
|
+
return nil
|
|
62
|
+
}
|
|
63
|
+
if err != nil {
|
|
64
|
+
return err
|
|
65
|
+
}
|
|
66
|
+
if !info.IsDir() {
|
|
67
|
+
return fmt.Errorf("parallel control root is not a safe directory: %s", root)
|
|
68
|
+
}
|
|
69
|
+
return nil
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type repositoryLease struct {
|
|
73
|
+
root string
|
|
74
|
+
controller string
|
|
75
|
+
lease *Lease
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// controlLeases reads explicit paths, never the ambient workspace override.
|
|
79
|
+
func controlLeases(devritesRoot string) ([]repositoryLease, error) {
|
|
80
|
+
devritesRoot = filepath.Clean(devritesRoot)
|
|
81
|
+
if err := validateControlRoot(devritesRoot); err != nil {
|
|
82
|
+
return nil, err
|
|
83
|
+
}
|
|
84
|
+
root := filepath.Dir(devritesRoot)
|
|
85
|
+
roots := map[string]bool{resolvedPath(devritesRoot): true}
|
|
86
|
+
common, err := commonGitDir(root)
|
|
87
|
+
if err != nil {
|
|
88
|
+
return nil, err
|
|
89
|
+
}
|
|
90
|
+
if common != "" {
|
|
91
|
+
registered, err := registeredWorktrees(root)
|
|
92
|
+
if err != nil {
|
|
93
|
+
return nil, err
|
|
94
|
+
}
|
|
95
|
+
for path := range registered {
|
|
96
|
+
roots[filepath.Join(path, ".devrites")] = true
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
ordered := make([]string, 0, len(roots))
|
|
100
|
+
for path := range roots {
|
|
101
|
+
ordered = append(ordered, path)
|
|
102
|
+
}
|
|
103
|
+
sort.Strings(ordered)
|
|
104
|
+
var leases []repositoryLease
|
|
105
|
+
for _, control := range ordered {
|
|
106
|
+
work := filepath.Join(control, "work")
|
|
107
|
+
for _, path := range []string{control, work} {
|
|
108
|
+
if info, err := os.Lstat(path); err == nil && info.Mode()&os.ModeSymlink != 0 {
|
|
109
|
+
return nil, fmt.Errorf("parallel workspace path is a symlink: %s", path)
|
|
110
|
+
} else if err != nil && !os.IsNotExist(err) {
|
|
111
|
+
return nil, err
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
entries, err := os.ReadDir(work)
|
|
115
|
+
if os.IsNotExist(err) {
|
|
116
|
+
continue
|
|
117
|
+
}
|
|
118
|
+
if err != nil {
|
|
119
|
+
return nil, err
|
|
120
|
+
}
|
|
121
|
+
for _, entry := range entries {
|
|
122
|
+
if !entry.IsDir() && entry.Type()&os.ModeSymlink == 0 {
|
|
123
|
+
continue
|
|
124
|
+
}
|
|
125
|
+
path := filepath.Join(work, entry.Name(), "parallel-lease.md")
|
|
126
|
+
info, err := os.Lstat(path)
|
|
127
|
+
if os.IsNotExist(err) {
|
|
128
|
+
continue
|
|
129
|
+
}
|
|
130
|
+
if err != nil {
|
|
131
|
+
return nil, err
|
|
132
|
+
}
|
|
133
|
+
if err := validateSlug(entry.Name()); err != nil {
|
|
134
|
+
return nil, err
|
|
135
|
+
}
|
|
136
|
+
if entry.Type()&os.ModeSymlink != 0 || !info.Mode().IsRegular() {
|
|
137
|
+
return nil, fmt.Errorf("parallel lease path is not an owned regular file: %s", path)
|
|
138
|
+
}
|
|
139
|
+
lease, err := ReadLease(path)
|
|
140
|
+
if err != nil {
|
|
141
|
+
return nil, fmt.Errorf("controller %s: %w", entry.Name(), err)
|
|
142
|
+
}
|
|
143
|
+
if err := normalizeLease(lease, entry.Name()); err != nil {
|
|
144
|
+
return nil, err
|
|
145
|
+
}
|
|
146
|
+
leases = append(leases, repositoryLease{filepath.Dir(control), entry.Name(), lease})
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return leases, nil
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
func controllerLease(root, controller string) (*repositoryLease, error) {
|
|
153
|
+
leases, err := controlLeases(filepath.Join(root, ".devrites"))
|
|
154
|
+
if err != nil {
|
|
155
|
+
return nil, err
|
|
156
|
+
}
|
|
157
|
+
if len(leases) > 1 {
|
|
158
|
+
return nil, fmt.Errorf("multiple retained repository controller leases; cleanup explicitly before admission")
|
|
159
|
+
}
|
|
160
|
+
if len(leases) == 0 {
|
|
161
|
+
return nil, nil
|
|
162
|
+
}
|
|
163
|
+
found := &leases[0]
|
|
164
|
+
if controller != "" && (found.controller != controller || found.root != resolvedPath(root)) {
|
|
165
|
+
return nil, fmt.Errorf("repository controller lease retained by %s at %s; use its explicit root and --slug for mutations", found.controller, found.root)
|
|
166
|
+
}
|
|
167
|
+
return found, nil
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// WorkspaceLeased protects both controller and source workspaces until cleanup.
|
|
171
|
+
// devritesRoot is explicit; closeout holds WithControlLock through its rename.
|
|
172
|
+
func WorkspaceLeased(devritesRoot, workspace string) (bool, error) {
|
|
173
|
+
if err := validateSlug(workspace); err != nil {
|
|
174
|
+
return false, err
|
|
175
|
+
}
|
|
176
|
+
leases, err := controlLeases(devritesRoot)
|
|
177
|
+
if err != nil {
|
|
178
|
+
return false, err
|
|
179
|
+
}
|
|
180
|
+
for _, found := range leases {
|
|
181
|
+
if found.controller == workspace {
|
|
182
|
+
return true, nil
|
|
183
|
+
}
|
|
184
|
+
for _, sl := range found.lease.Slices {
|
|
185
|
+
if sl.Workspace == workspace {
|
|
186
|
+
return true, nil
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return false, nil
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
func validateSources(devritesRoot string, slices []SlicePaths) error {
|
|
194
|
+
seen := make(map[string]bool)
|
|
195
|
+
for _, sp := range slices {
|
|
196
|
+
if sp.Workspace == "" || seen[sp.Workspace] {
|
|
197
|
+
continue
|
|
198
|
+
}
|
|
199
|
+
seen[sp.Workspace] = true
|
|
200
|
+
if err := validateSource(devritesRoot, sp.Workspace); err != nil {
|
|
201
|
+
return err
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return nil
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
func validateSource(devritesRoot, workspace string) error {
|
|
208
|
+
if workspace == "" {
|
|
209
|
+
return nil
|
|
210
|
+
}
|
|
211
|
+
path := devritesRoot
|
|
212
|
+
for index, component := range []string{"", "work", workspace, state.LedgerFile} {
|
|
213
|
+
if component != "" {
|
|
214
|
+
path = filepath.Join(path, component)
|
|
215
|
+
}
|
|
216
|
+
info, err := os.Lstat(path)
|
|
217
|
+
if err != nil {
|
|
218
|
+
return fmt.Errorf("source workspace %s is not live: %w", workspace, err)
|
|
219
|
+
}
|
|
220
|
+
if (index == 3 && !info.Mode().IsRegular()) || (index != 3 && !info.IsDir()) {
|
|
221
|
+
return fmt.Errorf("source workspace %s has an unsafe live path: %s", workspace, path)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return nil
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
func validateLeaseSources(devritesRoot string, lease *Lease) error {
|
|
228
|
+
seen := make(map[string]bool)
|
|
229
|
+
for _, sl := range lease.Slices {
|
|
230
|
+
if seen[sl.Workspace] {
|
|
231
|
+
continue
|
|
232
|
+
}
|
|
233
|
+
if err := validateSource(devritesRoot, sl.Workspace); err != nil {
|
|
234
|
+
return err
|
|
235
|
+
}
|
|
236
|
+
seen[sl.Workspace] = true
|
|
237
|
+
}
|
|
238
|
+
return nil
|
|
239
|
+
}
|
|
@@ -23,39 +23,25 @@ func SelectGreedySeeded(cap int, seed, ready []SlicePaths, root string) ([]Slice
|
|
|
23
23
|
if cap < 1 || cap > MaxParallelSlices {
|
|
24
24
|
return nil, fmt.Errorf("cap must be 1-%d (got %d)", MaxParallelSlices, cap)
|
|
25
25
|
}
|
|
26
|
-
normalized :=
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
label = fmt.Sprintf("slice %q", item.ID)
|
|
35
|
-
} else {
|
|
36
|
-
return nil, fmt.Errorf("%s: missing id", label)
|
|
37
|
-
}
|
|
38
|
-
if _, ok := seen[item.ID]; ok {
|
|
39
|
-
return nil, fmt.Errorf("duplicate slice id %q", item.ID)
|
|
40
|
-
}
|
|
41
|
-
seen[item.ID] = struct{}{}
|
|
42
|
-
paths, err := validateSlicePaths(item.Paths, label, root)
|
|
43
|
-
if err != nil {
|
|
44
|
-
return nil, err
|
|
45
|
-
}
|
|
46
|
-
normalized = append(normalized, SlicePaths{ID: item.ID, Paths: paths})
|
|
26
|
+
normalized, err := normalizeSlices("", ready, root)
|
|
27
|
+
if err != nil {
|
|
28
|
+
return nil, err
|
|
29
|
+
}
|
|
30
|
+
seed, err = normalizeSlices("", seed, root)
|
|
31
|
+
if err != nil {
|
|
32
|
+
return nil, err
|
|
47
33
|
}
|
|
48
34
|
|
|
49
35
|
running := make(map[string]bool, len(seed))
|
|
50
36
|
for _, s := range seed {
|
|
51
|
-
running[s.ID] = true
|
|
37
|
+
running[SliceKey(s.Workspace, s.ID)] = true
|
|
52
38
|
}
|
|
53
39
|
selected := append([]SlicePaths{}, seed...)
|
|
54
40
|
for _, cand := range normalized {
|
|
55
41
|
if len(selected) >= cap {
|
|
56
42
|
break
|
|
57
43
|
}
|
|
58
|
-
if running[cand.ID] {
|
|
44
|
+
if running[SliceKey(cand.Workspace, cand.ID)] {
|
|
59
45
|
continue
|
|
60
46
|
}
|
|
61
47
|
if len(selected) == 0 {
|
|
@@ -79,32 +65,68 @@ func SelectGreedySeeded(cap int, seed, ready []SlicePaths, root string) ([]Slice
|
|
|
79
65
|
// imports this package.
|
|
80
66
|
var PlanReady func(root, slug string) ([]SlicePaths, error)
|
|
81
67
|
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
68
|
+
// WorkspaceReady supplies native-authorized candidates and per-workspace notices.
|
|
69
|
+
// main wires this hook from lib, which owns planning and dependency readiness.
|
|
70
|
+
var WorkspaceReady func(root, controller, target string) ([]SlicePaths, []string, error)
|
|
71
|
+
|
|
72
|
+
// SelectForSlug seeds every retained repository slot, regardless of source.
|
|
73
|
+
// Bare candidates belong to slug; returned foreign identities stay qualified
|
|
74
|
+
// relative to the retained controller. An omitted slug means controller-local.
|
|
86
75
|
func SelectForSlug(root, slug string, capN int, ready []SlicePaths) (eligible, picks []SlicePaths, running int, err error) {
|
|
87
|
-
|
|
88
|
-
|
|
76
|
+
if capN < 1 || capN > MaxParallelSlices {
|
|
77
|
+
return nil, nil, -1, fmt.Errorf("cap must be 1-%d (got %d)", MaxParallelSlices, capN)
|
|
78
|
+
}
|
|
89
79
|
if slug != "" {
|
|
90
|
-
|
|
80
|
+
if err := validateSlug(slug); err != nil {
|
|
81
|
+
return nil, nil, -1, err
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
running = -1
|
|
85
|
+
var seed []SlicePaths
|
|
86
|
+
controller := slug
|
|
87
|
+
var found *repositoryLease
|
|
88
|
+
if root != "" || slug != "" {
|
|
89
|
+
found, err = controllerLease(root, "")
|
|
91
90
|
if err != nil {
|
|
92
91
|
return nil, nil, -1, err
|
|
93
92
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
93
|
+
}
|
|
94
|
+
candidates := make([]SlicePaths, len(ready))
|
|
95
|
+
copy(candidates, ready)
|
|
96
|
+
if found != nil {
|
|
97
|
+
if found.lease.PendingLanding != nil {
|
|
98
|
+
return nil, nil, -1, fmt.Errorf("pending landing blocks admission; recover controller %s at %s with integrate --apply-to-control or abort", found.controller, found.root)
|
|
99
|
+
}
|
|
100
|
+
controller = found.controller
|
|
101
|
+
if slug != "" && slug != controller {
|
|
102
|
+
for i := range candidates {
|
|
103
|
+
if candidates[i].Workspace == "" {
|
|
104
|
+
candidates[i].Workspace = slug
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
+
seed = activeSlices(found.lease)
|
|
109
|
+
running = len(seed)
|
|
110
|
+
if capacity := leaseCapacity(found.lease); capN > capacity {
|
|
111
|
+
capN = capacity
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
eligible, err = normalizeSlices(controller, candidates, root)
|
|
115
|
+
if err != nil {
|
|
116
|
+
return nil, nil, -1, err
|
|
117
|
+
}
|
|
118
|
+
if found != nil {
|
|
119
|
+
named := make(map[string]bool, len(found.lease.Slices))
|
|
120
|
+
for _, sl := range found.lease.Slices {
|
|
121
|
+
named[SliceKey(sl.Workspace, sl.ID)] = true
|
|
122
|
+
}
|
|
123
|
+
filtered := eligible[:0]
|
|
124
|
+
for _, sp := range eligible {
|
|
125
|
+
if !named[SliceKey(sp.Workspace, sp.ID)] {
|
|
126
|
+
filtered = append(filtered, sp)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
eligible = filtered
|
|
108
130
|
}
|
|
109
131
|
picks, err = SelectGreedySeeded(capN, seed, eligible, root)
|
|
110
132
|
return eligible, picks, running, err
|
|
@@ -127,7 +149,7 @@ func selectMode(n int) string {
|
|
|
127
149
|
func formatSelect(picks []SlicePaths, running int) string {
|
|
128
150
|
ids := make([]string, len(picks))
|
|
129
151
|
for i, item := range picks {
|
|
130
|
-
ids[i] = item.ID
|
|
152
|
+
ids[i] = SliceKey(item.Workspace, item.ID)
|
|
131
153
|
}
|
|
132
154
|
mode := selectMode(len(picks))
|
|
133
155
|
if running > 0 && len(picks) > 0 {
|
|
@@ -265,7 +265,7 @@ func ConvertCursorToTable(lines []string) ([]string, bool) {
|
|
|
265
265
|
if strings.Contains(value, "|") {
|
|
266
266
|
continue
|
|
267
267
|
}
|
|
268
|
-
spelling, ok :=
|
|
268
|
+
spelling, ok := CanonicalCursorKey(key)
|
|
269
269
|
if !ok {
|
|
270
270
|
continue
|
|
271
271
|
}
|
|
@@ -278,14 +278,14 @@ func ConvertCursorToTable(lines []string) ([]string, bool) {
|
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
func isMigratableCursorKey(key string) bool {
|
|
281
|
-
_, ok :=
|
|
281
|
+
_, ok := CanonicalCursorKey(key)
|
|
282
282
|
return ok
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
//
|
|
285
|
+
// CanonicalCursorKey maps a cursor key (including aliases) to the
|
|
286
286
|
// canonical table-row spelling. Matching is normalization-based, so
|
|
287
|
-
// "Next step" resolves to the "next_action" spelling.
|
|
288
|
-
func
|
|
287
|
+
// "Next step" resolves to the "next_action" spelling. Unknown extensions return false.
|
|
288
|
+
func CanonicalCursorKey(key string) (string, bool) {
|
|
289
289
|
normalized := normalizeCursorKey(key)
|
|
290
290
|
canonicals := []string{CursorPhase, CursorStatus, CursorNextAction, CursorQuestionID,
|
|
291
291
|
CursorActiveSlice, CursorAFKSlicesRemaining, CursorSequenceParent,
|
package/engine/main.go
CHANGED
|
@@ -74,7 +74,7 @@ Usage:
|
|
|
74
74
|
devrites-engine check indexes [--root <dir>] Report manifest and code-index presence as JSON
|
|
75
75
|
devrites-engine detect commands [--root <dir>] [--json]
|
|
76
76
|
Resolve test/lint/vet/build commands from the repository's own wiring
|
|
77
|
-
devrites-engine parallel <subcommand> Deterministic parallel worktree lease/create/integrate/cleanup
|
|
77
|
+
devrites-engine parallel <subcommand> Deterministic parallel worktree lease/create/integrate/prune/cleanup
|
|
78
78
|
devrites-engine gates <subcommand> <slug> Machine-checked gates.md ledger: scaffold/status/run/reverify/lint/precheck/attest/abandon
|
|
79
79
|
devrites-engine state resolve <qid> "<ans>" Resolve an open question and update state atomically
|
|
80
80
|
devrites-engine state merge-manifest <slug> [pred...] Fold the recorded predecessor chain's manifests into the release candidate manifest
|
|
@@ -125,6 +125,7 @@ func init() {
|
|
|
125
125
|
}
|
|
126
126
|
// parallel cannot import lib (lib imports it), so `parallel select --from-plan` gets the plan-derived ready set through this hook.
|
|
127
127
|
parallel.PlanReady = lib.PlanReady
|
|
128
|
+
parallel.WorkspaceReady = lib.WorkspaceReady
|
|
128
129
|
// `gates precheck` runs `check windows` through this hook for the same reason.
|
|
129
130
|
acceptance.WindowsCheck = lib.RunCheckWindows
|
|
130
131
|
// ...and `gates precheck --slice` learns which writer gates to skip.
|
|
@@ -26,8 +26,8 @@ and only the orchestrator-supplied changed paths.
|
|
|
26
26
|
contradictory, whose output and exit come from different executions, whose
|
|
27
27
|
command masks status, or whose exit and output disagree. A pass after a failed
|
|
28
28
|
attempt on an unchanged digest is `flaky`: `fail` for its AC.
|
|
29
|
-
2. Confirm
|
|
30
|
-
|
|
29
|
+
2. Confirm proof belongs to the supplied candidate, except explicitly scoped
|
|
30
|
+
reuse backed by unchanged declared inputs and a valid executed origin.
|
|
31
31
|
3. Map real REQ/AC/scenario/link IDs **and meaning** to observed proof. Invented/
|
|
32
32
|
label-only maps or internal proof of an external outcome fail. Behavior MUST
|
|
33
33
|
be positive, discriminating; reject skipped/focused/filtered/pending, zero-test,
|
|
@@ -49,13 +49,20 @@ and only the orchestrator-supplied changed paths.
|
|
|
49
49
|
named blocker, never a pass. Otherwise use `cannot_verify`.
|
|
50
50
|
8. A manual gate whose `gates.md` note lacks the human's own words or source, is a
|
|
51
51
|
placeholder, or was runnable at Vet is `cannot_verify` ([`gates.md`](../skills/devrites-lib/reference/standards/gates.md)).
|
|
52
|
-
9. An engine transcript (`DEVRITES-GATE-TRANSCRIPT
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
9. An engine transcript (`DEVRITES-GATE-TRANSCRIPT v2` under `references/gates/`)
|
|
53
|
+
records one execution, not an assertion that proof is sufficient. Verify its
|
|
54
|
+
`TRANSCRIPT_SHA256` over all bytes before that footer; match the definition,
|
|
55
|
+
original output identity/byte count, declared inputs, EXIT and EXPECT verdict
|
|
56
|
+
against current ledger evidence and approved commands. Metadata and output may
|
|
57
|
+
be redacted; never hash the redacted body as the original output.
|
|
58
|
+
Reuse cites the unchanged executed origin path and its historical candidate
|
|
59
|
+
labels, with matching current `INPUTS_SHA256` and bounded dependency closure.
|
|
60
|
+
A legacy v1 or `-reused.log` alone cannot authorize reuse; request engine
|
|
61
|
+
`gates run`/`reverify --transcripts` to recover approved missing origins.
|
|
62
|
+
10. Before/after identities must match within the recorded execution.
|
|
63
|
+
Historical/current candidate differences need the scoped reuse justification
|
|
64
|
+
above; never relabel an old observation. Unexpected repository mutation fails
|
|
65
|
+
the side-effect boundary.
|
|
59
66
|
|
|
60
67
|
## Rules
|
|
61
68
|
|
|
@@ -37,6 +37,8 @@ lifecycle state from chat or optional `README.md`.
|
|
|
37
37
|
([`workspace-artifact-schema.md`](reference/workspace-artifact-schema.md)).
|
|
38
38
|
- [`reference/reply-contract.md`](reference/reply-contract.md): compact user-facing
|
|
39
39
|
completion states. The host renders the response normally.
|
|
40
|
+
- [`reference/parallel-workspaces.md`](reference/parallel-workspaces.md): explicit
|
|
41
|
+
phase targets, one isolated global controller, and source-owned proof.
|
|
40
42
|
- [`reference/visual-playbooks/index.md`](reference/visual-playbooks/index.md): progressive
|
|
41
43
|
visual HTML playbook router (load matching ids only; dual-read outline).
|
|
42
44
|
|