* fix(#2772): only disable worktree isolation when planned paths touch submodules
The previous guard in execute-phase.md and quick.md unconditionally set
USE_WORKTREES=false whenever .gitmodules existed, penalising every plan in
a submodule project even when no plan touched a submodule path.
Replace with submodule-path parsing + per-plan path intersection:
- Parse SUBMODULE_PATHS once from .gitmodules via
`git config --file .gitmodules --get-regexp '^submodule\..*\.path$'`.
- In execute-phase.md, intersect SUBMODULE_PATHS with each plan's
files_modified frontmatter; disable worktree isolation only for plans
with non-empty intersection. Fall back to safe-disable for that plan
when files_modified is missing/unparseable, with a log line explaining
why.
- In quick.md (no pre-declared paths), keep submodule-path parsing and
document a fail-loud commit-time guard so the executor aborts only when
it actually stages a submodule path.
Add tests/bug-2772-gitmodules-path-intersection.test.cjs covering both
files: no unconditional disable, submodule paths are parsed, intersection
logic exists in execute-phase, fallback path is documented.
Full suite: 5680 / 5680 pass.
Closes#2772
* test(#2772): replace source-grep with behavioral test of submodule path intersection
* fix(#2772): wire USE_WORKTREES_FOR_PLAN into dispatch + fix glob matcher + add quick.md commit guard
Address CodeRabbit review on PR #2779 — the original fix computed
USE_WORKTREES_FOR_PLAN but never read it, so the per-plan submodule
intersection was dead code. Dispatch sites still branched on the
project-level USE_WORKTREES.
Changes:
1. execute-phase.md (CRITICAL — dispatch wiring): Move per-plan
computation into execute_waves as sub-step 2.5, run it for each plan
before its dispatch, and gate all four dispatch sites on
USE_WORKTREES_FOR_PLAN: worktree-mode header, sequential-mode header,
"worktrees disabled" sequential rule, and post-wave cleanup. Document
PLAN_FILES extraction via jq from the phase-plan-index JSON. Track
WAVE_WORKTREE_PLANS so post-wave cleanup only runs when at least one
plan in the wave actually used worktrees.
2. Per-plan gate matcher (MAJOR — glob safety): Strip leading "./" and
trailing "/" from both submodule and planned paths. Match
bidirectionally (pf inside sm AND sm inside pf). Handle globby
planned paths like "vendor/**/*.c" by extracting the literal prefix
before the first glob metachar and re-checking. Wrap the iteration
in set -f / set +f so glob expansion does not corrupt patterns.
Extracted the gate (~92 lines) into
workflows/execute-phase/steps/per-plan-worktree-gate.md to keep
execute-phase.md under the 1700-line XL budget.
3. quick.md (CRITICAL — fail-loud guard): Inject SUBMODULE_PATHS into
the executor Task prompt and add a <submodule_commit_guard> bash
block the executor must run before every git commit. The guard
inspects staged paths via `git diff --cached --name-only`, normalizes
paths, and aborts with a clear ABORT message + recovery instruction
("re-run with workflow.use_worktrees=false") when any staged path
falls inside a submodule.
4. tests/bug-2772-gitmodules-path-intersection.test.cjs: 25 tests total.
Updated GATE_SNIPPET to match the new bash matcher. Added
normalization tests (./ prefix, trailing /, glob "vendor/**/*.c",
parent directory, ./ in .gitmodules). Added workflow-markdown
wiring assertions for all 4 dispatch sites + per-plan gate file
extraction. Added quick.md guard tests: prompt injection assertion +
behavioral fixture-repo tests that stage a submodule path and assert
the guard exits non-zero with the ABORT message.
Test count: 5701 pass / 0 fail (was 5698/1 before).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>