BOHICA-LABS / BOHICA-LABS/vsdd-factory
process-gap(orchestrator+per-story-delivery): parallel-worktree TDD branches contaminate each other's test-failure baseline; "pre-existing" mis-attribution propagates
- Dominant language
- Rust
- Stars
- 2
- Forks
- 1
- Avg merge
- 6h 43m
- Merged PRs (30d)
- 29
Description
**Pattern: parallel-worktree test-baseline contamination — branch A's RED test commit pollutes branch B's "pre-existing failures" count**
In a Phase-3 dispatch this session, the orchestrator ran 4 parallel TDD cycles via `git worktree`. Each branch was forked from the same `main` SHA and got its own stub + RED test commit. Implementers across all 4 worktrees reported "N pre-existing failures unchanged" numbers, but the N differed wildly across branches: 0, 5, 18, 41.
### Root cause
GUT's headless runner (`addons/gut/gut_cmdln.gd -gdir=res://test/ -ginclude_subdirs ...`) globs the entire `test/**/*.gd` tree of the **current** working tree. When branch A's test-writer commits new RED tests for BC-A (which test against stubs only present on branch A's stub commit), and branch B is forked from the same base, **branch B does not contain branch A's stubs OR branch A's tests** — so its test count is honestly different.
But when an implementer on branch B runs the suite, they see "N failing — pre-existing" and have no easy way to verify whether N reflects branches their work was supposed to leave alone. The mental model "all 4 worktrees baseline from the same SHA" is correct, but the test counts diverge because each worktree's test corpus grew by its own RED commit.
A subtler failure mode: if a test-writer commits a test that **imports** code that doesn't exist on `main` (because the stub-architect committed it on branch X), running that test on branch Y will produce a load error / parse failure that's counted as "pre-existing" if the implementer doesn't trace the line numbers carefully.
### Why it survives existing gates
- #294 requires a baseline-vs-main diff before claiming "pre-existing" — but `main` is the same SHA all branches forked from. The diff against `main` doesn't catch the contamination because the contamination is **within-branch** (each branch's own RED commit).
- #210, #273, #345 cover staging-area races and parallel-dispatch fanout on the **factory-artifacts** branch — not parallel worktrees on product branches.
### Mechanism
Implementers in this session each reported different failure counts:
- STORY-A: "879 passing, 5 failing" — 5 = branches X/Y/Z's tests that imported their own stubs.
- STORY-B: "873 passing, 18 failing" — 18 = different mix.
- STORY-C: "891/0" — accidentally clean because their stubs satisfied other branches' tests.
- STORY-D: "902/1" — 1 was an in-branch test-file syntax bug.
The implementer is asked to certify "no regressions" — but the baseline they're certifying against is unstable in a way that's not their fault and not visible from `git log`.
### Suggested intervention
Either:
(a) the orchestrator's per-story-delivery workflow snapshots the **post-stub, post-RED** test count and gives implementers a deterministic "your own pre-existing-failure list = these specific test names," computed before TDD begins, or
(b) the test runner is wrapped to filter `-gdir` by a per-branch manifest (only run BC-X tests on branch BC-X), or
(c) parallel TDD branches are forbidden when stub commits cross-import (detect via a static check).
Option (a) is least disruptive — just a deterministic JSON baseline written to `.factory/sprint-state.yaml` at RED-gate time and surfaced to the implementer.
### Provenance
Observed 2026-06-29 during a 4-way parallel TDD dispatch in Wave 2. Cleared via per-branch human triage of failure lists. Implementer dispatch prompts had to include phrases like "if main has regressions, STOP and report — do not implement on a regressed base" to compensate, which is brittle.
Contributor guide
Assessment
This issue has not been assessed yet.