Skip to content

Auto-official finalize respects the open-protest gate (#338)#344

Merged
ryan-johnson2 merged 1 commit into
develfrom
auto-official-protest-gate
Jul 3, 2026
Merged

Auto-official finalize respects the open-protest gate (#338)#344
ryan-johnson2 merged 1 commit into
develfrom
auto-official-protest-gate

Conversation

@ryan-johnson2

Copy link
Copy Markdown
Contributor

Fixes #338 (adversarially-verified release-review finding, user-approved fix).

The auto-official protest-window driver appended Finalized directly via state.append, bypassing the #330 open-protest guard on the Finalize command path — a protest filed during the window was silently finalized over, defeating the window's purpose.

Fix: open_protest_count (filed minus non-reversed resolutions, RulingReversed-aware) is promoted to the shared predicate for BOTH finalize paths; after the window sleep the driver re-reads the log and stands down if protests are open (or the log can't be read — fail closed), leaving the heat Unofficial for the RD. No retry loop, deliberately: the driver is a one-shot task per Unofficial entry, and once a protest pulls a human in, an auto-finalize racing the RD's follow-up rulings would be worse than requiring their manual Finalize (which re-checks the same gate).

Tests: first integration coverage for this driver — happy path (window expiry auto-finalizes) + stand-down path (open protest → stays Unofficial → manual Finalize blocked → resolve → manual Finalize lands).

855 workspace tests green, clippy clean.

🤖 Generated with Claude Code

The auto-official protest-window driver (spawn_auto_official_driver in
crates/app/src/source.rs) appended its Finalized transition directly to
the log, bypassing the command handler — so the #330 "cannot finalize:
resolve open protests first" guard (P1-4) never applied to it. A protest
filed during the protest window could be auto-finalized over, defeating
the point of the window.

Fix: at window expiry the driver now checks the SAME predicate the
manual Finalize command is gated on. open_protest_count (filed protests
minus non-reversed resolutions) is promoted to pub in
gridfpv_server::control_handler and reused by the driver — one
definition of "still contested" for both finalize paths, no duplicated
count logic. A log read failure at expiry also stands down (fail closed,
never finalize blind).

Chosen behavior when protests ARE open at expiry: the driver appends
nothing and leaves the heat Unofficial for the RD — no retry loop.
Rationale: a filed protest pulls a human into the loop, and the RD's
follow-up is often several rulings (resolve, then a penalty, then
finalize); an auto-finalize firing at the surprising instant the last
protest resolves could race those. The driver is a one-shot task per
Unofficial entry (cancelled by the bridge on any transition), so
standing down fits its structure with no new lifecycle; the RD's manual
Finalize — re-checked by the same gate on the command path — closes the
heat with one click.

Adds the driver's first integration tests (bridge harness over
Practice, as the failover tests):
- auto_official_finalizes_after_the_window_with_no_protests: pins the
  happy path — deadline fact logged, window elapses, heat folds Final.
- auto_official_stands_down_on_an_open_protest_until_resolved: window
  expiry with an open protest appends no Finalized (heat stays
  Unofficial), manual Finalize is blocked by the same gate, and
  resolving the protest unblocks the manual Finalize to Final.

Gate: cargo test --workspace (855 passed, 0 failed), cargo fmt,
cargo clippy --all-targets -- -D warnings clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ryan-johnson2 ryan-johnson2 merged commit 79d2c8d into devel Jul 3, 2026
3 checks passed
@ryan-johnson2 ryan-johnson2 deleted the auto-official-protest-gate branch July 3, 2026 11:21
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.

Auto-official (protest-window) runtime driver bypasses the open-protest Finalize gate

1 participant