* test(#4254): sequential executor root pin — failing-first regression + matrix
The new suite executes the shipped supplied-root-pin guard against real git
fixtures (drifted primary-checkout cwd halts before the write and the FATAL
names both roots; matching cwd permits it; unexpanded/empty pins halt;
normalization forms; submodule and sibling boundaries; metacharacter quoting;
drive-letter form gate) and locks the dispatch contract across execute-phase.md,
its sequential-root-pin step fragment, and worktree-path-safety.md. The #2772
per-plan serialization assertion retargets to the fragment that now carries
those rules (ADR-857 Phase 6 ceiling), plus the host-step wiring.
* fix(#4254): pin sequential executor to the orchestrator's validated root
Sequential-mode dispatch told the executor to self-derive PROJECT_ROOT from its
own cwd; every existing guard is worktree-mode-only or self-referential, so an
executor spawned with a drifted cwd committed onto the wrong checkout silently.
- worktree-path-safety.md step 0p: mode-agnostic supplied-root pin guard,
composed by the orchestrator at build time with the literal $ORCHESTRATOR_WT
(git-vs-git comparison on both sides — representation-safe on Windows, the
#4296 lesson), fail-closed on empty/unexpanded pins, registered-submodule
allowance, warn-and-proceed only when the dispatch carries no pin block.
- execute-phase.md sequential branch: build-time embed of the bound
<project_root_pin> via the new execute-phase/steps/sequential-root-pin.md
fragment (ADR-857 Phase 6 frozen ceiling — the host step cannot grow; the
wave serialization rules move with the fragment, verbatim in substance) plus
the per-write/commit pin instruction in <sequential_execution>. Worktree-mode
dispatch untouched (its self-derived toplevel IS correct there).
- INVENTORY rows (5 locales) + INVENTORY-MANIFEST + install-tree goldens
regenerated for the new fragment; changeset added.
* chore(#4254): backfill changeset PR number
* fix(#4254): accept backslash-separated Windows drive pins
CI on windows-latest showed every permit-path test failing with
"Actual root: <none>": pins composed from Node's path.join arrive in the
backslash drive form (C:\Users\RUNNER~1\...), which the guard's absolute-form
gate rejected before the cwd-side root was ever computed — a legitimate
matching pin could never pass. The gate now accepts either separator
([A-Za-z]:[\\/]); git -C resolves both forms (and 8.3 short names) to the
same canonical toplevel, so the git-vs-git comparison is unaffected. Form-gate
tests cover the emitted (C:/…) and produced (C:\…) spellings plus short names.
* fix(#4254): portable drive-form gate for MSYS bash
The bracket class [\\/] that accepted backslash drive pins parses
inconsistently on MSYS bash (the Windows CI leg still rejected C:\ pins —
every permit-path test red with "Actual root: <none>"). Replace it with
standard pattern escaping outside brackets: [A-Za-z]:/*|[A-Za-z]:\\* —
the escape form is version- and build-portable. Verified across all forms:
both drive spellings accepted; bare "C:", relative, empty, and unexpanded
rejected.
* fix(#4254): runtime-generated backslash comparator + self-describing FATAL
The Windows CI legs failed every #4254 permit-path row with
'Actual root: <none>' across two prior pattern spellings ([\\/] and \\*).
Stage misattribution: <none> appears whenever the FATAL fires BEFORE the
cwd-side capture assigns ACTUAL_ROOT — the absolute-form gate was what fired.
Mechanism: the test harness spawns bash -c <script> through the Windows
command-line boundary; that round-trip applies one extra shell-quoting pass
with double-quote semantics — a backslash written twice in the script text
arrives halved, while a lone backslash survives (the pin displays intact;
row 9's pure-bash gate independently showed the halved pattern rejecting
C:\ while C:/ still passed its surviving arm). On windows-latest every pin
carries backslashes (os.tmpdir() is the 8.3 short form C:\Users\RUNNER~1\...),
so the gate ate every pin before the actual root was ever computed.
Fix, robust by construction:
- the drive-form gate generates its backslash comparator at RUNTIME
(BS=$(printf '\134'); match [A-Za-z]:"$BS"*) — the shipped guard now
contains no doubled backslash anywhere, enforced by a regression
assertion on the extracted guard text;
- the FATAL self-describes: Guard stage (pin-unbound / form-gate /
actual-capture / pinned-capture / root-mismatch) plus a Diagnostic line
carrying git's own stderr for capture failures and both compared values
for mismatches — future platform failures name their stage in the log;
- row 9's hand-rolled duplicate case gate (transit-fragile copy, #4296
Minor 1 duplication smell) is replaced by driving the SHIPPED guard and
asserting the stage; rows 2/4 pin the new stage machinery.
Validated on darwin across drift/match/relative/unbound/empty/bare-drive/
forward-and-backslash drive forms, each also re-run under a simulated
Windows transit (every doubled backslash halved) with identical outcomes.
* fix(#4254): close the empty-comparator fail-open seam in the drive-form gate
Self-review of the runtime-generated backslash comparator: if printf's
octal escape ever returned empty, the drive arm [A-Za-z]:"$BS"* would
widen to drive-RELATIVE pins (C:foo) — the construction's one theoretical
fail-open path. Fail closed with a self-describing diagnostic instead of
trusting the shell's printf.
---------
Co-authored-by: sim <sim@local>