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
|
@@ -361,6 +361,10 @@ func clearAwaiting(sfile, qid string) error {
|
|
|
361
361
|
return fmt.Errorf("read state %s: %w", sfile, err)
|
|
362
362
|
}
|
|
363
363
|
lines := splitLinesNoTrailing(data)
|
|
364
|
+
visible, err := structuralLines(data)
|
|
365
|
+
if err != nil {
|
|
366
|
+
return fmt.Errorf("read state %s: %w", sfile, err)
|
|
367
|
+
}
|
|
364
368
|
resumePolicy, _ := state.PolicyFor(state.PhaseBuild)
|
|
365
369
|
if rawPhase, ok := state.CursorField(lines, state.CursorPhase); ok {
|
|
366
370
|
if fields := strings.Fields(strings.ToLower(rawPhase)); len(fields) > 0 {
|
|
@@ -373,7 +377,7 @@ func clearAwaiting(sfile, qid string) error {
|
|
|
373
377
|
// First check whether the awaiting block references this question at all.
|
|
374
378
|
inAw := false
|
|
375
379
|
var awaitingLines []string
|
|
376
|
-
for _, line := range
|
|
380
|
+
for _, line := range visible {
|
|
377
381
|
switch {
|
|
378
382
|
case awaitingRe.MatchString(line):
|
|
379
383
|
inAw = true
|
|
@@ -400,7 +404,8 @@ func clearAwaiting(sfile, qid string) error {
|
|
|
400
404
|
ts := nowUTC()
|
|
401
405
|
var out []string
|
|
402
406
|
inAw, inLog, logAppended := false, false, false
|
|
403
|
-
for
|
|
407
|
+
for i, original := range lines {
|
|
408
|
+
line := visible[i]
|
|
404
409
|
if awaitingRe.MatchString(line) {
|
|
405
410
|
inAw = true
|
|
406
411
|
continue
|
|
@@ -413,7 +418,7 @@ func clearAwaiting(sfile, qid string) error {
|
|
|
413
418
|
}
|
|
414
419
|
switch {
|
|
415
420
|
case logHdrRe.MatchString(line):
|
|
416
|
-
out = append(out,
|
|
421
|
+
out = append(out, original)
|
|
417
422
|
inLog = true
|
|
418
423
|
continue
|
|
419
424
|
case inLog && hdrSpaceRe.MatchString(line):
|
|
@@ -422,10 +427,10 @@ func clearAwaiting(sfile, qid string) error {
|
|
|
422
427
|
logAppended = true
|
|
423
428
|
}
|
|
424
429
|
inLog = false
|
|
425
|
-
out = append(out,
|
|
430
|
+
out = append(out, original)
|
|
426
431
|
continue
|
|
427
432
|
}
|
|
428
|
-
out = append(out,
|
|
433
|
+
out = append(out, original)
|
|
429
434
|
}
|
|
430
435
|
if inLog && !logAppended {
|
|
431
436
|
out = append(out, fmt.Sprintf("- %s %s: resolved %s", ts, resumePolicy.Target, qid))
|
|
@@ -7,6 +7,7 @@ import (
|
|
|
7
7
|
"regexp"
|
|
8
8
|
"strings"
|
|
9
9
|
|
|
10
|
+
"github.com/devrites/devrites/internal/markdowntext"
|
|
10
11
|
"github.com/devrites/devrites/internal/state"
|
|
11
12
|
)
|
|
12
13
|
|
|
@@ -21,7 +22,7 @@ import (
|
|
|
21
22
|
// 0 contract holds 2 usage error 3 blocked: problems listed
|
|
22
23
|
|
|
23
24
|
var (
|
|
24
|
-
sliceFieldRe = regexp.MustCompile(`(?m)^([A-Za-z][A-Za-z /_-]*)
|
|
25
|
+
sliceFieldRe = regexp.MustCompile(`(?m)^([A-Za-z][A-Za-z /_-]*):[ \t]*(.*)$`)
|
|
25
26
|
sliceACRe = regexp.MustCompile(`\bAC-\d+\b`)
|
|
26
27
|
pathGlobCharRe = regexp.MustCompile(`[*?\[\]{}]`)
|
|
27
28
|
pathTraversalRe = regexp.MustCompile(`(^|/)\.\.(/|$)`)
|
|
@@ -48,6 +49,11 @@ func sliceSizeAdvisory(block string) (int, bool) {
|
|
|
48
49
|
// sliceFields extracts the single-line `Field: value` pairs of a slice block.
|
|
49
50
|
func sliceFields(block string) map[string]string {
|
|
50
51
|
fields := map[string]string{}
|
|
52
|
+
structural, err := markdowntext.Structural([]byte(block))
|
|
53
|
+
if err != nil {
|
|
54
|
+
return fields
|
|
55
|
+
}
|
|
56
|
+
block = string(structural)
|
|
51
57
|
for _, m := range sliceFieldRe.FindAllStringSubmatch(block, -1) {
|
|
52
58
|
key := strings.ToLower(strings.TrimSpace(m[1]))
|
|
53
59
|
if _, seen := fields[key]; !seen {
|
|
@@ -58,10 +58,17 @@ func RunStateSet(root string, args []string, stdout, stderr io.Writer) int {
|
|
|
58
58
|
return fail(stderr, stateSetUsage, 2)
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
if !cursorKeyPattern.MatchString(key)
|
|
61
|
+
if !cursorKeyPattern.MatchString(key) {
|
|
62
62
|
return fail(stderr, fmt.Sprintf("state set: key %q is not a snake_case cursor key or repeats", key), 2)
|
|
63
63
|
}
|
|
64
|
-
|
|
64
|
+
if canonical, ok := state.CanonicalCursorKey(key); ok {
|
|
65
|
+
key = canonical
|
|
66
|
+
}
|
|
67
|
+
identity := strings.ReplaceAll(key, "_", "")
|
|
68
|
+
if seen[identity] {
|
|
69
|
+
return fail(stderr, fmt.Sprintf("state set: key %q is not a snake_case cursor key or repeats", key), 2)
|
|
70
|
+
}
|
|
71
|
+
seen[identity] = true
|
|
65
72
|
changes = append(changes, change{key, value})
|
|
66
73
|
}
|
|
67
74
|
sfile, code := stateEditWorkspace(root, slug, "state.md", stderr)
|
|
@@ -201,34 +201,10 @@ func PrecheckSkips(root, slug, slice string, gateIDs []string) (map[string]strin
|
|
|
201
201
|
// manifest and lockfile when it declares external dependencies. root is the
|
|
202
202
|
// .devrites directory.
|
|
203
203
|
func planReady(root, slug string) ([]parallel.SlicePaths, error) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
graph := ParseTaskGraph(raw)
|
|
209
|
-
if len(graph.Problems) > 0 {
|
|
210
|
-
return nil, fmt.Errorf("tasks.md: %s", strings.Join(graph.Problems, "; "))
|
|
211
|
-
}
|
|
212
|
-
built, err := builtSlices(root, slug)
|
|
213
|
-
if err != nil {
|
|
214
|
-
return nil, err
|
|
215
|
-
}
|
|
216
|
-
isBuilt := func(id string) bool { return built[sliceNumber(id)] }
|
|
217
|
-
paths, _ := sliceWritePaths(raw, graph)
|
|
218
|
-
project := filepath.Dir(root)
|
|
219
|
-
var ready []parallel.SlicePaths
|
|
220
|
-
for _, s := range graph.Slices {
|
|
221
|
-
if isBuilt(s.ID) || slices.ContainsFunc(s.Dependencies, func(dep string) bool { return !isBuilt(dep) }) {
|
|
222
|
-
continue
|
|
223
|
-
}
|
|
224
|
-
if len(paths[s.ID]) == 0 {
|
|
225
|
-
return nil, fmt.Errorf("%s has no Writer allowlist or Files likely touched", s.ID)
|
|
226
|
-
}
|
|
227
|
-
block, _ := state.ExtractTaskSlice(raw, s.ID)
|
|
228
|
-
external, _ := fieldValue(sliceFields(block), "external dependencies")
|
|
229
|
-
ready = append(ready, parallel.SlicePaths{ID: s.ID, Paths: withManifests(project, paths[s.ID], external)})
|
|
230
|
-
}
|
|
231
|
-
return ready, nil
|
|
204
|
+
ready, _, err := workspacePlanReady(root, slug, false, func(name string) ([]byte, error) {
|
|
205
|
+
return readWorkspaceArtifact(root, slug, name)
|
|
206
|
+
})
|
|
207
|
+
return ready, err
|
|
232
208
|
}
|
|
233
209
|
|
|
234
210
|
// builtWordRe marks a checked state.md item as a built checkpoint.
|
|
@@ -240,7 +216,13 @@ var builtWordRe = regexp.MustCompile(`(?i)\bbuilt\b`)
|
|
|
240
216
|
// was checkpointed and whose section has a `Checkpoint: <sha>` line — a missed
|
|
241
217
|
// checkbox must not keep dependents out of the ready set.
|
|
242
218
|
func builtSlices(root, slug string) (map[string]bool, error) {
|
|
243
|
-
|
|
219
|
+
return builtSlicesFrom(func(name string) ([]byte, error) {
|
|
220
|
+
return readWorkspaceArtifact(root, slug, name)
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
func builtSlicesFrom(read func(string) ([]byte, error)) (map[string]bool, error) {
|
|
225
|
+
raw, err := read("state.md")
|
|
244
226
|
if err != nil {
|
|
245
227
|
return nil, err
|
|
246
228
|
}
|
|
@@ -257,7 +239,7 @@ func builtSlices(root, slug string) (map[string]bool, error) {
|
|
|
257
239
|
built[strings.TrimLeft(m[1], "0")] = true
|
|
258
240
|
}
|
|
259
241
|
}
|
|
260
|
-
extra, err :=
|
|
242
|
+
extra, err := evidenceBuiltFrom(read)
|
|
261
243
|
if err != nil {
|
|
262
244
|
return nil, err
|
|
263
245
|
}
|
|
@@ -273,9 +255,9 @@ var (
|
|
|
273
255
|
checkpointSHARe = regexp.MustCompile(`(?m)^[ \t]*Checkpoint: [0-9a-fA-F]{7,40}\b`)
|
|
274
256
|
)
|
|
275
257
|
|
|
276
|
-
//
|
|
277
|
-
func
|
|
278
|
-
raw, err :=
|
|
258
|
+
// evidenceBuiltFrom reads evidence.md checkpoint sections. A missing file is none.
|
|
259
|
+
func evidenceBuiltFrom(read func(string) ([]byte, error)) (map[string]bool, error) {
|
|
260
|
+
raw, err := read("evidence.md")
|
|
279
261
|
if err != nil {
|
|
280
262
|
if errors.Is(err, os.ErrNotExist) {
|
|
281
263
|
return map[string]bool{}, nil
|
|
@@ -421,9 +403,11 @@ func planBatch(root, slug string, capN int) (eligible, batch []string, err error
|
|
|
421
403
|
return nil, nil, err
|
|
422
404
|
}
|
|
423
405
|
ids := func(in []parallel.SlicePaths) []string {
|
|
424
|
-
out
|
|
425
|
-
for
|
|
426
|
-
|
|
406
|
+
var out []string
|
|
407
|
+
for _, s := range in {
|
|
408
|
+
if s.Workspace == "" || s.Workspace == slug {
|
|
409
|
+
out = append(out, s.ID)
|
|
410
|
+
}
|
|
427
411
|
}
|
|
428
412
|
return out
|
|
429
413
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
package lib
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
-
"
|
|
4
|
+
"errors"
|
|
5
5
|
"os"
|
|
6
|
-
"path/filepath"
|
|
7
6
|
"regexp"
|
|
8
7
|
"slices"
|
|
9
8
|
"sort"
|
|
@@ -52,7 +51,7 @@ var (
|
|
|
52
51
|
// corpus (minus the template's AI-SPEC annex) names a model, agent, RAG, or
|
|
53
52
|
// tool surface.
|
|
54
53
|
func keepModelSurface(role string, facts triggerFacts) bool {
|
|
55
|
-
return role == "security-auditor" || facts.aiSpec || strings.TrimSpace(facts.corpus) == "" ||
|
|
54
|
+
return roleBase(role) == "security-auditor" || facts.aiSpec || strings.TrimSpace(facts.corpus) == "" ||
|
|
56
55
|
aiSignalRe.MatchString(aiAnnexRe.ReplaceAllString(facts.corpus, "$1"))
|
|
57
56
|
}
|
|
58
57
|
|
|
@@ -82,8 +81,7 @@ var triggerSignals = []struct {
|
|
|
82
81
|
|
|
83
82
|
// suggestTriggers returns declared, unselected trigger names whose firing facts
|
|
84
83
|
// hold in this workspace. Sorted for stable output.
|
|
85
|
-
func suggestTriggers(manifest loadsManifest,
|
|
86
|
-
facts := gatherTriggerFacts(root, featureDir, opts.role)
|
|
84
|
+
func suggestTriggers(manifest loadsManifest, opts contextOpts, facts triggerFacts) []string {
|
|
87
85
|
var suggested []string
|
|
88
86
|
for name := range manifest.Triggers {
|
|
89
87
|
if slices.Contains(opts.triggers, name) {
|
|
@@ -101,45 +99,46 @@ func suggestTriggers(manifest loadsManifest, root, featureDir string, opts conte
|
|
|
101
99
|
return suggested
|
|
102
100
|
}
|
|
103
101
|
|
|
104
|
-
func gatherTriggerFacts(root,
|
|
105
|
-
facts := triggerFacts{role: role}
|
|
102
|
+
func gatherTriggerFacts(root, role string, sources *contextSources) (triggerFacts, error) {
|
|
103
|
+
facts := triggerFacts{role: roleBase(role)}
|
|
106
104
|
if root != "" {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
facts.afkParallel = afkAllowsParallel(string(data))
|
|
112
|
-
}
|
|
105
|
+
sentinels := contextSources{dir: root}
|
|
106
|
+
data, err := sentinels.read("AFK")
|
|
107
|
+
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
|
108
|
+
return facts, err
|
|
113
109
|
}
|
|
114
|
-
|
|
115
|
-
|
|
110
|
+
facts.afk = err == nil
|
|
111
|
+
facts.afkParallel = afkAllowsParallel(string(data))
|
|
112
|
+
_, err = sentinels.read("principles.md")
|
|
113
|
+
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
|
114
|
+
return facts, err
|
|
116
115
|
}
|
|
116
|
+
facts.principles = err == nil
|
|
117
117
|
}
|
|
118
|
-
if
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
if sources.dir != "" {
|
|
119
|
+
_, err := sources.read("ai-spec.md")
|
|
120
|
+
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
|
121
|
+
return facts, err
|
|
121
122
|
}
|
|
123
|
+
facts.aiSpec = err == nil
|
|
122
124
|
var corpus strings.Builder
|
|
123
125
|
for _, name := range triggerEvidenceFiles {
|
|
124
|
-
|
|
125
|
-
info, err := os.Stat(path)
|
|
126
|
-
if err != nil || !info.Mode().IsRegular() {
|
|
127
|
-
continue
|
|
128
|
-
}
|
|
129
|
-
f, err := os.Open(path) // #nosec G304 -- workspace artifact; read is capped below
|
|
126
|
+
data, err := sources.read(name)
|
|
130
127
|
if err != nil {
|
|
131
|
-
|
|
128
|
+
if errors.Is(err, os.ErrNotExist) {
|
|
129
|
+
continue
|
|
130
|
+
}
|
|
131
|
+
return facts, err
|
|
132
132
|
}
|
|
133
|
-
data
|
|
134
|
-
|
|
135
|
-
if err == nil {
|
|
136
|
-
corpus.Write(data)
|
|
137
|
-
corpus.WriteByte('\n')
|
|
133
|
+
if len(data) > triggerEvidenceFileCap {
|
|
134
|
+
data = data[:triggerEvidenceFileCap]
|
|
138
135
|
}
|
|
136
|
+
corpus.Write(data)
|
|
137
|
+
corpus.WriteByte('\n')
|
|
139
138
|
}
|
|
140
139
|
facts.corpus = strings.ToLower(corpus.String())
|
|
141
140
|
}
|
|
142
|
-
return facts
|
|
141
|
+
return facts, nil
|
|
143
142
|
}
|
|
144
143
|
|
|
145
144
|
var afkParallelRe = regexp.MustCompile(`(?m)^\s*max_parallel\s*:\s*([0-9]+)\s*$`)
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
package lib
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"errors"
|
|
5
|
+
"fmt"
|
|
6
|
+
"os"
|
|
7
|
+
"path/filepath"
|
|
8
|
+
"strings"
|
|
9
|
+
|
|
10
|
+
"github.com/devrites/devrites/internal/devritespaths"
|
|
11
|
+
"github.com/devrites/devrites/internal/gate"
|
|
12
|
+
"github.com/devrites/devrites/internal/markdowntext"
|
|
13
|
+
"github.com/devrites/devrites/internal/parallel"
|
|
14
|
+
"github.com/devrites/devrites/internal/state"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
// WorkspaceReady admits only the controller or its recorded forward continuation.
|
|
18
|
+
// Notices describe withheld work without removing other workspaces from the pool.
|
|
19
|
+
func WorkspaceReady(repoRoot, controller, target string) ([]parallel.SlicePaths, []string, error) {
|
|
20
|
+
root := filepath.Join(repoRoot, devritespaths.DevritesRootName)
|
|
21
|
+
if !devritespaths.ValidSlug(controller) || !devritespaths.ValidSlug(target) {
|
|
22
|
+
return nil, nil, fmt.Errorf("invalid controller or target workspace slug")
|
|
23
|
+
}
|
|
24
|
+
if _, err := devritespaths.WorkspaceOverrideChecked(root, target); err != nil {
|
|
25
|
+
return nil, []string{fmt.Sprintf("%s: global workspace admission preserves DEVRITES_WORKSPACE scope: %v; unset DEVRITES_WORKSPACE to query the global pool", target, err)}, nil
|
|
26
|
+
}
|
|
27
|
+
if _, err := devritespaths.ExistingFeatureDirChecked(root, controller); err != nil {
|
|
28
|
+
return nil, nil, fmt.Errorf("controller %s: %w", controller, err)
|
|
29
|
+
}
|
|
30
|
+
observation, err := state.ObserveWorkspace(root, target)
|
|
31
|
+
if err != nil {
|
|
32
|
+
return nil, []string{fmt.Sprintf("%s: state unavailable: %v; repair workspace and rerun /rite-vet", target, err)}, nil
|
|
33
|
+
}
|
|
34
|
+
cursor, _ := observation.Fact(state.LedgerFile)
|
|
35
|
+
cursorBytes := cursor.Bytes()
|
|
36
|
+
if target != controller {
|
|
37
|
+
if err := forwardWorkspace(root, controller, target, cursorBytes); err != nil {
|
|
38
|
+
return nil, []string{fmt.Sprintf("%s: %v", target, err)}, nil
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
result, err := gate.CheckObserved(gate.Readiness, root, observation)
|
|
42
|
+
if err != nil {
|
|
43
|
+
return nil, []string{fmt.Sprintf("%s: readiness unavailable: %v; repair workspace and rerun /rite-vet", target, err)}, nil
|
|
44
|
+
}
|
|
45
|
+
structuralCursor, _ := markdowntext.Structural(cursorBytes)
|
|
46
|
+
status, _ := state.CursorField(strings.Split(string(structuralCursor), "\n"), state.CursorStatus)
|
|
47
|
+
var notices []string
|
|
48
|
+
if result.Phase != state.PhaseVet && result.Phase != state.PhaseBuild {
|
|
49
|
+
notices = append(notices, fmt.Sprintf("%s: phase %s is not Build entry; native Plan/Vet must prepare this workspace before admission", target, result.Phase))
|
|
50
|
+
}
|
|
51
|
+
if result.Phase == state.PhaseVet && status != "ready" {
|
|
52
|
+
notices = append(notices, fmt.Sprintf("%s: Vet is not ready; native Plan/Vet must complete before admission", target))
|
|
53
|
+
}
|
|
54
|
+
switch status {
|
|
55
|
+
case "awaiting_human", "blocked", "shipped", "done", "archived":
|
|
56
|
+
notices = append(notices, fmt.Sprintf("%s: status %s withholds writer admission; native controller must resolve this state", target, status))
|
|
57
|
+
}
|
|
58
|
+
if result.Blocked {
|
|
59
|
+
for _, line := range strings.Split(strings.TrimSpace(result.Render()), "\n") {
|
|
60
|
+
notices = append(notices, target+": "+line)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if len(notices) > 0 {
|
|
64
|
+
return nil, notices, nil
|
|
65
|
+
}
|
|
66
|
+
ready, notices, err := workspacePlanReady(root, target, target != controller, func(name string) ([]byte, error) {
|
|
67
|
+
fact, ok := observation.Fact(state.ArtifactPath(name))
|
|
68
|
+
if !ok || fact.State() == state.ArtifactAbsent {
|
|
69
|
+
return nil, os.ErrNotExist
|
|
70
|
+
}
|
|
71
|
+
if fact.State() != state.ArtifactPresent && fact.State() != state.ArtifactEmpty {
|
|
72
|
+
return nil, fmt.Errorf("%s: retained artifact is %s", name, fact.State())
|
|
73
|
+
}
|
|
74
|
+
return fact.Bytes(), nil
|
|
75
|
+
})
|
|
76
|
+
if err != nil {
|
|
77
|
+
return nil, notices, err
|
|
78
|
+
}
|
|
79
|
+
if target != controller {
|
|
80
|
+
for i := range ready {
|
|
81
|
+
ready[i].Workspace = target
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return ready, notices, nil
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// readSequenceArtifact permits archived predecessors, never an archived writer.
|
|
88
|
+
func readSequenceArtifact(root, slug, name string) ([]byte, error) {
|
|
89
|
+
dir, err := devritespaths.ExistingCanonicalFeatureDirChecked(root, slug)
|
|
90
|
+
if errors.Is(err, os.ErrNotExist) {
|
|
91
|
+
dir, err = devritespaths.ExistingArchivedFeatureDirChecked(root, slug)
|
|
92
|
+
}
|
|
93
|
+
if err != nil {
|
|
94
|
+
return nil, err
|
|
95
|
+
}
|
|
96
|
+
return readBoundedRegularFile(filepath.Join(dir, name), workspaceArtifactLimit)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
func forwardWorkspace(root, controller, target string, targetState []byte) error {
|
|
100
|
+
seen := map[string]bool{}
|
|
101
|
+
current := target
|
|
102
|
+
found := false
|
|
103
|
+
for range maxSequenceChain {
|
|
104
|
+
if seen[current] {
|
|
105
|
+
return fmt.Errorf("sequence_parent cycle at %s; repair native sequence cursor", current)
|
|
106
|
+
}
|
|
107
|
+
seen[current] = true
|
|
108
|
+
found = found || current == controller
|
|
109
|
+
// Target is already retained from its live workspace observation.
|
|
110
|
+
raw := targetState
|
|
111
|
+
if current != target {
|
|
112
|
+
var err error
|
|
113
|
+
raw, err = readSequenceArtifact(root, current, "state.md")
|
|
114
|
+
if err != nil {
|
|
115
|
+
return fmt.Errorf("sequence_parent %s unavailable: %w", current, err)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
structural, err := markdowntext.Structural(raw)
|
|
119
|
+
if err != nil {
|
|
120
|
+
return fmt.Errorf("sequence_parent %s state.md is invalid Markdown", current)
|
|
121
|
+
}
|
|
122
|
+
parent, _ := state.CursorField(strings.Split(string(structural), "\n"), state.CursorSequenceParent)
|
|
123
|
+
if parent == "" {
|
|
124
|
+
if found {
|
|
125
|
+
return nil
|
|
126
|
+
}
|
|
127
|
+
return fmt.Errorf("not a recorded forward continuation of %s; native sequence authorization required", controller)
|
|
128
|
+
}
|
|
129
|
+
if !devritespaths.ValidSlug(parent) {
|
|
130
|
+
return fmt.Errorf("sequence_parent %q is not a workspace slug", parent)
|
|
131
|
+
}
|
|
132
|
+
current = parent
|
|
133
|
+
}
|
|
134
|
+
return fmt.Errorf("sequence_parent chain exceeds %d workspaces", maxSequenceChain)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
type workspaceProducer struct {
|
|
138
|
+
workspace string
|
|
139
|
+
id string
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
type workspacePlan struct {
|
|
143
|
+
raw []byte
|
|
144
|
+
graph TaskGraphResult
|
|
145
|
+
built map[string]bool
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
type workspaceDependencies struct {
|
|
149
|
+
root string
|
|
150
|
+
plans map[string]*workspacePlan
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
func (d *workspaceDependencies) load(slug string) (*workspacePlan, error) {
|
|
154
|
+
if plan := d.plans[slug]; plan != nil {
|
|
155
|
+
return plan, nil
|
|
156
|
+
}
|
|
157
|
+
raw, err := readSequenceArtifact(d.root, slug, "tasks.md")
|
|
158
|
+
if err != nil {
|
|
159
|
+
return nil, fmt.Errorf("producer %s tasks.md: %w", slug, err)
|
|
160
|
+
}
|
|
161
|
+
graph := ParseTaskGraph(raw)
|
|
162
|
+
if len(graph.Problems) > 0 {
|
|
163
|
+
return nil, fmt.Errorf("producer %s tasks.md: %s", slug, strings.Join(graph.Problems, "; "))
|
|
164
|
+
}
|
|
165
|
+
built, err := builtSlicesFrom(func(name string) ([]byte, error) {
|
|
166
|
+
return readSequenceArtifact(d.root, slug, name)
|
|
167
|
+
})
|
|
168
|
+
if err != nil {
|
|
169
|
+
return nil, fmt.Errorf("producer %s checkpoints: %w", slug, err)
|
|
170
|
+
}
|
|
171
|
+
plan := &workspacePlan{raw: raw, graph: graph, built: built}
|
|
172
|
+
d.plans[slug] = plan
|
|
173
|
+
return plan, nil
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
func declaredWorkspaceDependencies(block string) ([]workspaceProducer, bool, error) {
|
|
177
|
+
structural, err := markdowntext.Structural([]byte(block))
|
|
178
|
+
if err != nil {
|
|
179
|
+
return nil, false, fmt.Errorf("workspace dependencies cannot be read from invalid Markdown")
|
|
180
|
+
}
|
|
181
|
+
block = string(structural)
|
|
182
|
+
fields := sliceFields(block)
|
|
183
|
+
value, declared := fieldValue(fields, "workspace dependencies")
|
|
184
|
+
count := 0
|
|
185
|
+
for _, field := range sliceFieldRe.FindAllStringSubmatch(block, -1) {
|
|
186
|
+
if strings.EqualFold(strings.TrimSpace(field[1]), "workspace dependencies") {
|
|
187
|
+
count++
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if count > 1 {
|
|
191
|
+
return nil, true, fmt.Errorf("duplicate Workspace dependencies; rerun native Plan/Vet")
|
|
192
|
+
}
|
|
193
|
+
if !declared || value == "none" {
|
|
194
|
+
return nil, declared, nil
|
|
195
|
+
}
|
|
196
|
+
var refs []workspaceProducer
|
|
197
|
+
seen := map[string]bool{}
|
|
198
|
+
for token := range strings.SplitSeq(value, ",") {
|
|
199
|
+
token = strings.TrimSpace(token)
|
|
200
|
+
slug, id, ok := strings.Cut(token, "/")
|
|
201
|
+
if !ok || !devritespaths.ValidSlug(slug) || !state.ValidSliceID(id) {
|
|
202
|
+
return nil, true, fmt.Errorf("malformed Workspace dependencies reference %q; use none or <slug>/SLICE-### and rerun native Plan/Vet", token)
|
|
203
|
+
}
|
|
204
|
+
if seen[token] {
|
|
205
|
+
return nil, true, fmt.Errorf("duplicate Workspace dependencies reference %q", token)
|
|
206
|
+
}
|
|
207
|
+
seen[token] = true
|
|
208
|
+
refs = append(refs, workspaceProducer{workspace: slug, id: id})
|
|
209
|
+
}
|
|
210
|
+
return refs, true, nil
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// validate follows local and workspace edges even across built nodes: a recorded
|
|
214
|
+
// checkpoint cannot make an unknown reference or a cyclic plan graph valid.
|
|
215
|
+
func (d *workspaceDependencies) validate(ref workspaceProducer, visiting, valid map[string]bool) error {
|
|
216
|
+
key := parallel.SliceKey(ref.workspace, ref.id)
|
|
217
|
+
if visiting[key] {
|
|
218
|
+
return fmt.Errorf("workspace dependencies cycle at %s; repair native Plan/Vet", key)
|
|
219
|
+
}
|
|
220
|
+
if valid[key] {
|
|
221
|
+
return nil
|
|
222
|
+
}
|
|
223
|
+
if len(visiting)+len(valid) >= 4096 {
|
|
224
|
+
return fmt.Errorf("workspace dependencies graph exceeds 4096 slices")
|
|
225
|
+
}
|
|
226
|
+
plan, err := d.load(ref.workspace)
|
|
227
|
+
if err != nil {
|
|
228
|
+
return err
|
|
229
|
+
}
|
|
230
|
+
var node *TaskSlice
|
|
231
|
+
for i := range plan.graph.Slices {
|
|
232
|
+
if plan.graph.Slices[i].ID == ref.id {
|
|
233
|
+
node = &plan.graph.Slices[i]
|
|
234
|
+
break
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if node == nil {
|
|
238
|
+
return fmt.Errorf("unknown Workspace dependencies producer %s", key)
|
|
239
|
+
}
|
|
240
|
+
block, _ := state.ExtractTaskSlice(plan.raw, ref.id)
|
|
241
|
+
refs, _, err := declaredWorkspaceDependencies(block)
|
|
242
|
+
if err != nil {
|
|
243
|
+
return fmt.Errorf("%s: %w", key, err)
|
|
244
|
+
}
|
|
245
|
+
for _, id := range node.Dependencies {
|
|
246
|
+
refs = append(refs, workspaceProducer{workspace: ref.workspace, id: id})
|
|
247
|
+
}
|
|
248
|
+
visiting[key] = true
|
|
249
|
+
defer delete(visiting, key)
|
|
250
|
+
for _, dependency := range refs {
|
|
251
|
+
if err := d.validate(dependency, visiting, valid); err != nil {
|
|
252
|
+
return err
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
valid[key] = true
|
|
256
|
+
return nil
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
func workspacePlanReady(root, slug string, requireDeclaration bool, read func(string) ([]byte, error)) ([]parallel.SlicePaths, []string, error) {
|
|
260
|
+
raw, err := read("tasks.md")
|
|
261
|
+
if err != nil {
|
|
262
|
+
return nil, nil, err
|
|
263
|
+
}
|
|
264
|
+
graph := ParseTaskGraph(raw)
|
|
265
|
+
if len(graph.Problems) > 0 {
|
|
266
|
+
return nil, nil, fmt.Errorf("tasks.md: %s", strings.Join(graph.Problems, "; "))
|
|
267
|
+
}
|
|
268
|
+
built, err := builtSlicesFrom(read)
|
|
269
|
+
if err != nil {
|
|
270
|
+
return nil, nil, err
|
|
271
|
+
}
|
|
272
|
+
deps := workspaceDependencies{root: root, plans: map[string]*workspacePlan{
|
|
273
|
+
slug: {raw: raw, graph: graph, built: built},
|
|
274
|
+
}}
|
|
275
|
+
paths, _ := sliceWritePaths(raw, graph)
|
|
276
|
+
var ready []parallel.SlicePaths
|
|
277
|
+
var notices []string
|
|
278
|
+
valid := map[string]bool{}
|
|
279
|
+
for _, node := range graph.Slices {
|
|
280
|
+
block, _ := state.ExtractTaskSlice(raw, node.ID)
|
|
281
|
+
if satisfies, _ := fieldValue(sliceFields(block), "satisfies"); strings.EqualFold(satisfies, "none") {
|
|
282
|
+
continue
|
|
283
|
+
}
|
|
284
|
+
if built[sliceNumber(node.ID)] || slicesUnbuilt(node.Dependencies, built) {
|
|
285
|
+
continue
|
|
286
|
+
}
|
|
287
|
+
key := parallel.SliceKey(slug, node.ID)
|
|
288
|
+
refs, declared, problem := declaredWorkspaceDependencies(block)
|
|
289
|
+
if problem == nil && requireDeclaration && !declared {
|
|
290
|
+
problem = fmt.Errorf("missing Workspace dependencies; native Plan/Vet must bind none or explicit producers before foreign admission")
|
|
291
|
+
}
|
|
292
|
+
if problem == nil {
|
|
293
|
+
problem = deps.validate(workspaceProducer{workspace: slug, id: node.ID}, map[string]bool{}, valid)
|
|
294
|
+
}
|
|
295
|
+
if problem != nil {
|
|
296
|
+
notices = append(notices, key+": "+problem.Error())
|
|
297
|
+
continue
|
|
298
|
+
}
|
|
299
|
+
waiting := false
|
|
300
|
+
for _, ref := range refs {
|
|
301
|
+
producer := deps.plans[ref.workspace] // validate loaded every referenced graph.
|
|
302
|
+
if !producer.built[sliceNumber(ref.id)] {
|
|
303
|
+
notices = append(notices, fmt.Sprintf("%s: waiting for durable BUILT/integrated producer %s", key, parallel.SliceKey(ref.workspace, ref.id)))
|
|
304
|
+
waiting = true
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if waiting {
|
|
308
|
+
continue
|
|
309
|
+
}
|
|
310
|
+
if len(paths[node.ID]) == 0 {
|
|
311
|
+
if requireDeclaration {
|
|
312
|
+
notices = append(notices, key+": no Writer allowlist or Files likely touched; repair native Plan/Vet")
|
|
313
|
+
continue
|
|
314
|
+
}
|
|
315
|
+
return nil, notices, fmt.Errorf("%s has no Writer allowlist or Files likely touched", node.ID)
|
|
316
|
+
}
|
|
317
|
+
external, _ := fieldValue(sliceFields(block), "external dependencies")
|
|
318
|
+
ready = append(ready, parallel.SlicePaths{ID: node.ID, Paths: withManifests(filepath.Dir(root), paths[node.ID], external)})
|
|
319
|
+
}
|
|
320
|
+
return ready, notices, nil
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
func slicesUnbuilt(ids []string, built map[string]bool) bool {
|
|
324
|
+
for _, id := range ids {
|
|
325
|
+
if !built[sliceNumber(id)] {
|
|
326
|
+
return true
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return false
|
|
330
|
+
}
|