Skip to content

feat(loop): fail-closed gate preflight — never start work a broken gate can't accept (v0.33.0)#73

Merged
protoquinn[bot] merged 4 commits into
mainfrom
feat/gate-preflight
Jul 7, 2026
Merged

feat(loop): fail-closed gate preflight — never start work a broken gate can't accept (v0.33.0)#73
protoquinn[bot] merged 4 commits into
mainfrom
feat/gate-preflight

Conversation

@mabry1985

Copy link
Copy Markdown
Contributor

Why

The board loop's per-PR local gate (_run_local_gate) intentionally fails open — a gate that can't run degrades to "pass" so a flaky/misconfigured gate never blocks good work (CI is the backstop). Correct for the per-PR edge, but it means a coder happily generates against a gate that cannot execute (e.g. the build tool isn't installed), burning generations on work no gate could ever accept.

Surfaced dogfooding the roxy→protoContent delivery loop: a coder burned 5 generations producing test files against a pnpm -r build gate whose pnpm wasn't installed in the image.

What

The fail-closed complement. Before dispatching ANY work, smoke-run local_gate_cmd on the clean base checkout (the main repo — coders only touch worktrees, so it stays at base):

gate result on clean base action
exits 0 runnable → dispatch (cached for the run)
exits non-zero base doesn't pass → hold all ready work
can't launch (missing tool) broken env → hold all ready work
times out indeterminate → allow (never wedge on a slow gate)
  • Held features are flag_blocked with the reason, so the stall is visible on the board — not a silent stop.
  • Re-checks each cycle (throttled) and releases the holds the moment the gate goes green.
  • Default on when a gate is configured (a healthy repo passes instantly — no behavior change). Opt out with preflight: false.

Tests

7 new tests (pass/non-zero/launch-error/timeout classification, _spawn_ready hold, recovery release). Full suite: 303 passed (test_packaging.py skipped — pre-existing tomllib/py3.10 env issue, unrelated).

🤖 Generated with Claude Code

…te can't accept (v0.33.0)

The board loop's per-PR local gate (_run_local_gate) fails OPEN: a gate that
can't run degrades to 'pass' so a flaky/misconfigured gate never blocks good
work (CI is the real backstop). That's correct for the per-PR edge, but it means
a coder will happily generate against a gate that CANNOT EXECUTE — e.g. the build
tool isn't installed — burning generations on work no gate could ever accept.

Add the fail-CLOSED complement: before dispatching ANY work, smoke-run
local_gate_cmd on the CLEAN base checkout (the main repo — coders only touch
worktrees, so it stays at base).
- gate exits 0            → runnable; dispatch normally (cached for the run)
- gate exits non-zero     → base doesn't pass; HOLD all ready work
- gate can't launch       → broken env (missing tool); HOLD all ready work
- gate times out          → indeterminate; ALLOW (never wedge on a slow gate)

Held features are flag_blocked with the reason so the stall is visible on the
board, not silent; the preflight re-checks each cycle (throttled) and releases
the holds the moment the gate goes green. Default on when a gate is configured
(a healthy repo passes instantly — no behavior change); opt out with
preflight:false.

Surfaced dogfooding the roxy→protoContent delivery loop: a coder burned 5 gens
producing test files against a 'pnpm -r build' gate whose pnpm wasn't installed.
This makes that a one-line board hold with a clear reason instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@protoquinn

protoquinn Bot commented Jul 7, 2026

Copy link
Copy Markdown

👀 Quinn is reviewing — verdict (PASS / WARN / FAIL) + findings to follow.

@protoquinn protoquinn Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA Audit — PR #73 | feat(loop): fail-closed gate preflight — never start work a broken gate can't accept (v0.33.0)

VERDICT: WARN (CI pending — test queued)


CI Status

  • test: queued

Diff Review

  • 3 files, +231/-1: loop.py (preflight gate mechanism), pyproject.toml (0.32.0 → 0.33.0), tests/test_loop.py (7 new tests)
  • Design is sound: fail-closed preflight on clean base complements the existing fail-open per-PR gate. Timeout → allow (never wedge), missing tool → hold, non-zero exit on clean base → hold with board-visible flag_blocked. Recovery re-checks throttled and releases holds automatically. preflight: false opt-out available. Default-on when local_gate_cmd is configured.
  • Clawpatch structural review: zero findings on changed files.

Observations

  • LOW: CI test is still queued — approve-on-green policy promotes this review to APPROVED automatically once every check settles terminal-green. No blocking issues identified in diff or structural review.

— Quinn, QA Engineer

@protoquinn

protoquinn Bot commented Jul 7, 2026

Copy link
Copy Markdown

Submitted COMMENT review on protoLabsAI/projectBoard-plugin#73.

@protoquinn protoquinn Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA Audit — PR #73 | feat(loop): fail-closed gate preflight — never start work a broken gate can't accept (v0.33.0)

VERDICT: WARN (CI pending — test queued)


CI Status

  • test: queued

Incremental delta since prior review (13c8f43e184c3d)

  • 4 files, +391/-3: loop.py adds _resolve_gate_cmd() (auto-discovery from package.json/Makefile/justfile), README.md documents the auto sentinel and preflight config, pyproject.toml bumps to 0.33.0, tests/test_loop.py carries forward 7 preflight tests
  • Clawpatch structural review: zero findings on changed files.
  • No unresolved CodeRabbit threads. Design is clean: gate resolution favors a single repo-declared entrypoint (ci/check/verify script → pnpm run <it>) whose own CI targets the same thing, so local == CI by construction. Falls back to pnpm -r --if-present typecheck build test only when nothing is declared.

Observations

  • LOW: CI test is still queued — the approve-on-green policy promotes this review to APPROVED automatically once every check settles terminal-green. No blocking issues identified.

— Quinn, QA Engineer

@protoquinn

protoquinn Bot commented Jul 7, 2026

Copy link
Copy Markdown

Submitted COMMENT review on #73.

…repo

Hard-coding one repo's check steps into the orchestrator (or the operator's
dispatch) is a footgun: the repo's CI changes and the transcription silently
goes stale (green-locally / red-in-CI), or the team is pointed at a different
repo and the gate is just wrong.

"auto" resolves the pre-PR gate from the checkout instead, favoring a single
repo-DECLARED entrypoint (package.json ci/check/verify → `pnpm run <it>`;
Makefile/justfile ci|check target → `make/just <it>`) so a repo whose OWN CI
calls that same target keeps local == CI by construction. Falls back to the
`pnpm -r --if-present typecheck build test` superset for an undeclared node
repo, and to "" (gateless, fail-open, warns) when nothing is recognized.

Resolved once at construction, so every downstream reader (coder_solve_test_cmd,
_run_local_gate, _preflight, candidate preference) sees the concrete command
with no further plumbing. Explicit command passes through; blank still = no
gate (auto is opt-in, never inferred from blank). Composes with the fail-closed
preflight: auto-resolve the gate, then smoke it on clean base before dispatch.

9 resolver unit tests; full suite 312 green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mabry1985 mabry1985 force-pushed the feat/gate-preflight branch from e184c3d to 732ccdb Compare July 7, 2026 03:10

@protoquinn protoquinn Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA Audit — PR #73 | feat(loop): fail-closed gate preflight — never start work a broken gate can't accept (v0.33.0)

VERDICT: WARN (CI pending — test in_progress)


CI Status

  • test: in_progress

Incremental delta since prior review (e184c3d732ccdb)

  • 4 files, +387/-3 (down 4 lines from prior): loop.py_resolve_gate_cmd() auto-discovery + preflight mechanism, README.md docs for auto sentinel + preflight config, pyproject.toml → 0.33.0, tests/test_loop.py — 7 preflight tests.
  • Clawpatch structural review: zero findings on changed files.
  • No unresolved CodeRabbit threads.

Observations

  • LOW: CI test is still in_progress — the approve-on-green policy promotes this review to APPROVED automatically once every check settles terminal-green. No blocking issues identified on the current head.

— Quinn, QA Engineer

@protoquinn

protoquinn Bot commented Jul 7, 2026

Copy link
Copy Markdown

Submitted COMMENT review on #73.

…anifest to 0.33.0

Two CI-only failures on this branch:

- _release_preflight_holds() built the store (get_store → needs the `br` beads
  CLI) even with zero holds to release, so a PASSING preflight called it, and on
  a host without `br` the error was swallowed by _preflight's outer except and
  masqueraded as a gate failure (_preflight_state = "gate command could not run:
  beads CLI 'br' not on PATH"). It passed locally only because the dev host has
  `br`. Short-circuit before building the store: a clean preflight (the common
  path) never touches it.

- protoagent.plugin.yaml still said 0.32.0 while pyproject moved to 0.33.0
  (test_manifest_and_pyproject_versions_agree). Bump to 0.33.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@protoquinn protoquinn Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA Audit — PR #73 | feat(loop): fail-closed gate preflight — never start work a broken gate can't accept (v0.33.0)

VERDICT: WARN (CI pending — test queued)


CI Status

  • test: queued

Incremental delta since prior review (732ccdbd55d00b)

  • 5 files, +393/-4 (+1 file, +6 lines from prior): added protoagent.plugin.yaml; minor adjustments to loop.py on top of the _resolve_gate_cmd() + preflight mechanism reviewed previously.
  • Clawpatch structural review on d55d00b: zero findings on changed files.
  • No unresolved CodeRabbit threads.

Observations

  • LOW: CI test is queued — the approve-on-green policy promotes this review to APPROVED automatically once every check settles terminal-green. No blocking issues identified on the current head.

— Quinn, QA Engineer

@protoquinn

protoquinn Bot commented Jul 7, 2026

Copy link
Copy Markdown

Submitted COMMENT review on #73.

test_preflight_recovery_releases_holds pre-set a failed _preflight_state but
left _last_preflight=0.0, so whether the throttled recheck fired depended on
time.monotonic()'s absolute value — large on a dev host (passed), small in a
fresh CI container (< the 60s throttle → recheck skipped → stale state, flaky
fail). Anchor _last_preflight well in the past so the recheck always fires.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@protoquinn

protoquinn Bot commented Jul 7, 2026

Copy link
Copy Markdown

✅ CI went terminal-green with no blockers on the prior review — promoting it to APPROVED per the approve-on-green policy (#748).

@protoquinn protoquinn Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI terminal-green, no blockers on prior review — auto-approving on green (#748).

@protoquinn protoquinn Bot merged commit 30dcfc4 into main Jul 7, 2026
1 check passed
@protoquinn protoquinn Bot deleted the feat/gate-preflight branch July 7, 2026 03:22

@protoquinn protoquinn Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QA Audit — PR #73 | feat(loop): fail-closed gate preflight — never start work a broken gate can't accept (v0.33.0)

VERDICT: WARN (CI pending — test in_progress)


CI Status

  • test: in_progress

Incremental re-review (d55d00b98858a5)

  • +4 net lines on top of the prior-reviewed head. Clawpatch structural review on 98858a5: zero findings on changed files (18 mapped, 0 reviewed — no features touched by the diff that weren't already covered).
  • No unresolved CodeRabbit threads.
  • Prior review findings carry forward — no new blocking issues on this head.

Observations

  • LOW: CI test is still settling. The approve-on-green policy promotes this review to APPROVED automatically once every check completes terminal-green. No blocking issues identified.

— Quinn, QA Engineer

@protoquinn

protoquinn Bot commented Jul 7, 2026

Copy link
Copy Markdown

Submitted COMMENT review on protoLabsAI/projectBoard-plugin#73.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant