BOHICA-LABS / BOHICA-LABS/vsdd-factory
Phase-3 wave-close gate: require CI green before state-manager burst can advance state
- Dominant language
- Rust
- Stars
- 2
- Forks
- 1
- Avg merge
- 6h 43m
- Merged PRs (30d)
- 29
Description
## Summary
The Phase-3 wave-close gate currently marks a story CONVERGED when local `cargo test --workspace` is green and a PR is open. It does not require the PR's CI on GitHub Actions to be green before advancing state. This produced a false-convergence signal on STORY-017: 10 CLEAN adversarial passes, per-AC demo evidence recorded, PR opened — with CI red on macos-latest for 5 consecutive attempts. Only manual inspection surfaced the discrepancy; the state-manager burst was queued to close the story regardless.
## Observed instance
- Story: STORY-017 (akey — LOCAL_PEERPID peer PID capture on macOS)
- Adversarial: Pass 1..Pass 10 CLEAN
- Per-AC demos: recorded
- Local `cargo test --workspace`: green
- PR: open with `gh pr checks` reporting fail on macos-latest, 5 consecutive attempts
- State-manager burst: queued to advance the story to CONVERGED
- CI evidence: GHA run 28727397489 (AC-A1 integration test — `caller_pid = 0`)
- Downstream engine issue: see companion issue (tokio-worker starvation adversary rule)
The story looked ready to merge by every gate the engine checked. The only signal that would have caught the false convergence was `gh pr checks` on the PR — and the engine did not consult it.
## Root cause (engine)
The wave-close gate treats local test-suite success as sufficient evidence of runtime correctness. In practice, the release runs on GitHub Actions runners, not the developer's local machine. Scheduler behavior, kernel version, filesystem, resource contention, and macOS Gatekeeper posture all differ between local dev and CI. \"Green locally\" is a necessary but not sufficient condition for merge-readiness.
## Proposed engine rule
Add a `require-ci-green` gate to the `pr-manager` sub-flow. Gate contract:
1. Trigger: after PR is opened / updated by the story.
2. Command: `gh pr checks --watch` (or equivalent polling loop with a bounded timeout).
3. Success condition: all required checks report `SUCCESS` (or `NEUTRAL` where policy allows).
4. Failure condition: any required check reports `FAILURE`, `CANCELLED`, or `TIMED_OUT`.
5. On failure: block state-manager burst; return a pipeline error naming the failing check(s) and the run URL so the next agent can investigate.
6. On timeout: block with an explicit \"CI still running\" state rather than assuming success.
This gate is orthogonal to the story's own convergence criteria (adversarial passes, per-AC demos, local tests) — those measure the story's internal consistency. `require-ci-green` measures the story's compatibility with the runner the release actually uses. Both are required for correctness; neither substitutes for the other.
## Why this matters
Without this gate, the pipeline can produce a stream of \"CONVERGED\" stories whose PRs cannot be merged. This defeats the purpose of pipelined delivery: the state-manager tells downstream that the story is done, downstream schedules integration work, and the actual PR sits red for days. The engine's state and the repo's state diverge silently.
The fix is cheap: one `gh pr checks --watch` invocation gated behind PR-open. The cost is a delay proportional to CI runtime. The benefit is deterministic pipeline correctness.
## Cross-references
Precedents on engine methodology gaps discovered in the akey pipeline:
- #440
- #441
- #466
- #467
- #468
Companion issue in this batch: adversary rule for tokio-worker starvation (the substantive defect that STORY-017's CI-red PR exposed).
Contributor guide
Assessment
This issue has not been assessed yet.