Skip to content

(MOT-4202) fix(harness): reseed a turn when the finalize drain delivers a parked message - #577

Merged
andersonleal merged 4 commits into
mainfrom
fix/harness-finalize-reseed
Jul 23, 2026
Merged

(MOT-4202) fix(harness): reseed a turn when the finalize drain delivers a parked message#577
andersonleal merged 4 commits into
mainfrom
fix/harness-finalize-reseed

Conversation

@andersonleal

@andersonleal andersonleal commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Problem

A message that parks while a turn's final step is in flight is drained into the transcript by finalize_completed/finalize_failed, but no turn is ever seeded to react to it. An autonomous run that ends its turn expecting a notification to wake it strands forever — observed live 2026-07-22: a scan coordinator's child-completion notification landed in the finalize window and the session went permanently idle.

Fix

drain_queued_best_effort now reports whether it delivered a MODEL-VISIBLE row (custom-role status rows don't count — regenerating over an assistant-tailed context is a guaranteed provider prefill rejection). When it did, the finalizing turn reseeds a fresh turn via send::seed_new, reusing the finalized turn's frozen options and registry generation — the same outcome an external harness::send produces against a now-terminal session. Applies to finalize_completed and finalize_failed; finalize_cancelled drains without reseeding (the user cancelled). The reseed runs after the terminal put_turn, since the turn slot is keyed per session.

Coverage

  • Unit: finalize_reseed_gate_counts_only_model_visible_rows pins the reseed gate (custom-only queue must not wake a turn).
  • E2E-003 (reseed-parked-message): deterministic public-path regression test. The completed finalize can't be pinned externally — a park during a completing terminal generation is always delivered by the steering check first — so the scenario routes through the failed finalize (no steering check, same drain-and-reseed): generation 1 steers a message mid-generation (it parks durably) and then fails; the finalize drain delivers the parked row and the reseeded turn's :0 request over [user, empty assistant residue, parked follow-up] is matched exactly, with the follow-up keeping its durable e_q_ queue entry id. Verified both directions: passes with the fix (~3.3s), times out with the reseed disabled.
  • Framework support added for the scenario: scripted generation failures, declared per-turn terminal statuses enforced positionally by the floor, driver-derived expected trace count (harness-seeded turns chain into the originating send's trace), latest-terminal-turn evidence binding.

E2E-001/002/003 pass, harness-integration unit tests and clippy -D warnings clean, all 5 fixtures validate.

Summary by CodeRabbit

  • New Features

    • Added support for automatically continuing a turn when a queued notification arrives during finalization.
    • Added scenario support for testing multiple terminal turns with distinct outcomes.
    • Added scripted scenarios for queued follow-ups and generation failures.
  • Bug Fixes

    • Prevented queued notifications from being stranded after a completed or failed turn.
    • Cancelled turns no longer restart automatically because of queued notifications.
  • Documentation

    • Documented the new queued-message continuation scenario and expected outcomes.

… message

A notification or steer that parked during a turn's final step was drained to the transcript by the finalize drain but had no turn to react to it, so an autonomous run that ended its turn expecting the fire to wake it would stall.

finalize_completed/finalize_failed now seed a fresh turn when the finalize drain delivered a model-visible row; custom-only rows never reseed and a cancelled turn drains but does not reseed. Gated on the drain actually delivering a row, so a redelivered finalize cannot double-seed and a racing external send is resolved by run_step's stale-turn guard.
…ed (E2E-003)

A message parked during a completing terminal generation is always
delivered by the turn loop's steering check, so the completed-finalize
drain cannot be reached deterministically from the public boundary. The
failed finalize has no steering check and shares the same drain-and-
reseed, so E2E-003 steers a message mid-generation and then fails that
generation with a scripted router error: the failed finalize drains the
parked row and must reseed a fresh turn, pinned by generation 2
matching a new turn's :0 request over [user, empty assistant residue,
parked follow-up] and by the follow-up keeping its durable e_q_ queue
entry id. With the reseed disabled the scenario times out.

Framework support: scripted generation failures (fails()/failure),
declared per-turn terminal statuses enforced positionally by the floor,
driver-derived expected trace count (harness-seeded turns chain into
the originating send's trace), and latest-terminal-turn evidence
binding for multi-turn direct scenarios.
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
workers Ready Ready Preview, Comment Jul 23, 2026 6:08pm
workers-tech-spec Ready Ready Preview, Comment Jul 23, 2026 6:08pm

Request Review

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

skill-check — worker

0 verified, 48 skipped (no docs/).

Layer Result
structure
vale
ai
render

Four for four. Nicely done.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@andersonleal, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ff236e0d-c8bb-4870-ab79-7a803b9e745f

📥 Commits

Reviewing files that changed from the base of the PR and between df2a992 and a319140.

📒 Files selected for processing (5)
  • harness/src/turn_loop.rs
  • harness/tests/e2e/src/scenario/floor.rs
  • harness/tests/e2e/src/scenario/phases/completion.rs
  • harness/tests/e2e/src/scenarios/reseed_parked_message.rs
  • harness/tests/e2e/src/scripted_router.rs
📝 Walkthrough

Walkthrough

The turn loop now conditionally reseeds after finalization drains model-visible parked messages. The E2E harness adds serve-time steering, scripted failures, ordered terminal-status expectations, and scenario E2E-003 coverage for a failed turn followed by a reseeded completed turn.

Changes

Parked message reseed flow

Layer / File(s) Summary
Finalize drain and reseed runtime
harness/src/functions/send.rs, harness/src/turn_loop.rs
Finalization drains now identify model-visible messages, reseed completed or failed turns when needed, and avoid reseeding cancelled turns.
Scripted steering and failure contract
harness/tests/e2e/src/types/script.rs, harness/tests/e2e/src/scenarios/dsl.rs, harness/tests/e2e/src/scripted_router.rs
Scripted generations can steer on serve and fail without streaming frames; the router executes steering before returning scripted failures.
Multi-turn fixture and evidence validation
harness/tests/e2e/src/fixtures/loading.rs, harness/tests/e2e/src/scenario/floor.rs, harness/tests/e2e/src/scenario/phases/*
Fixtures declare ordered terminal statuses and trace counts, and evidence validation checks positional lifecycle status and trace expectations.
Reseed scenario coverage
harness/tests/e2e/src/scenarios/*, harness/tests/e2e/src/fixtures/tests.rs, harness/tests/e2e/README.md
E2E-003 validates a failed parked-message turn followed by deterministic reseeding and completion.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ScriptedRouter
  participant IIIClient
  participant harness_send
  participant turn_loop
  ScriptedRouter->>IIIClient: execute on_serve steer
  IIIClient->>harness_send: send parked follow-up
  harness_send->>turn_loop: queue notification during finalization
  turn_loop->>turn_loop: drain model-visible parked row
  turn_loop->>turn_loop: reseed next turn
  turn_loop-->>ScriptedRouter: run reseeded generation
Loading

Possibly related PRs

  • iii-hq/workers#540: Both changes modify finalize/completion handling in harness/src/turn_loop.rs.

Suggested reviewers: ytallo

Poem

I’m a rabbit with a queue full of cheer,
A parked little message hops near.
One turn fails, then seeds anew,
The next turn knows just what to do.
Two terminal hops, one trace in sight—
Reseeded magic, working right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main harness fix: reseeding a turn when finalize drain delivers a parked message.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/harness-finalize-reseed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@andersonleal andersonleal changed the title fix(harness): reseed a turn when the finalize drain delivers a parked message (MOT-4202) fix(harness): reseed a turn when the finalize drain delivers a parked message Jul 23, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
harness/src/turn_loop.rs (1)

1073-1098: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Preserve the wake signal after a partial drain.

If a model-visible row appends successfully but a later append or delete_queued fails, this returns Err; drain_queued_best_effort converts that to false, so no turn is reseeded even though input reached the transcript. Track successfully appended model-visible rows through the loop and return that outcome despite a subsequent best-effort error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@harness/src/turn_loop.rs` around lines 1073 - 1098, The drain_queued flow
currently loses the wake signal when a later append or delete fails after
model-visible input was appended. Track successfully appended model-visible rows
within drain_queued, and ensure drain_queued_best_effort preserves and returns a
true outcome when any such row reached the transcript, even if a subsequent
operation returns an error.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@harness/src/turn_loop.rs`:
- Line 1286: Make terminalization atomic with the final queue drain and reseed
decision in the turn-loop completion path around drain_queued_best_effort and
the failed-finalization path at harness/src/turn_loop.rs:1286-1286 and
harness/src/turn_loop.rs:1337-1337. Coordinate both paths with harness::send
using a shared session lock or equivalent CAS/recheck protocol so no message can
be accepted as queued after the final sweep without triggering a reseed;
preserve the existing woke behavior once the terminal transition and queue
decision are linearized.

In `@harness/tests/e2e/src/scripted_router.rs`:
- Around line 462-482: Update perform_serve_effect to wrap the client.trigger
call in the same outer tokio::time::timeout used by Client::call_with_timeout,
preserving DEFAULT_CALL_TIMEOUT_MS as the timeout duration. Handle timeout
errors through the existing Error::Handler path so an unconnected steer cannot
remain parked indefinitely.

---

Outside diff comments:
In `@harness/src/turn_loop.rs`:
- Around line 1073-1098: The drain_queued flow currently loses the wake signal
when a later append or delete fails after model-visible input was appended.
Track successfully appended model-visible rows within drain_queued, and ensure
drain_queued_best_effort preserves and returns a true outcome when any such row
reached the transcript, even if a subsequent operation returns an error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f23e6385-30a2-4c77-ba38-4c6117a674b3

📥 Commits

Reviewing files that changed from the base of the PR and between 1853bc1 and df2a992.

📒 Files selected for processing (13)
  • harness/src/functions/send.rs
  • harness/src/turn_loop.rs
  • harness/tests/e2e/README.md
  • harness/tests/e2e/src/fixtures/loading.rs
  • harness/tests/e2e/src/fixtures/tests.rs
  • harness/tests/e2e/src/scenario/floor.rs
  • harness/tests/e2e/src/scenario/phases/completion.rs
  • harness/tests/e2e/src/scenario/phases/evidence.rs
  • harness/tests/e2e/src/scenarios/dsl.rs
  • harness/tests/e2e/src/scenarios/mod.rs
  • harness/tests/e2e/src/scenarios/reseed_parked_message.rs
  • harness/tests/e2e/src/scripted_router.rs
  • harness/tests/e2e/src/types/script.rs

Comment thread harness/src/turn_loop.rs
Comment thread harness/tests/e2e/src/scripted_router.rs
…al sweep

Review follow-up (CodeRabbit). A send racing a finalize could enqueue
after the finalize drain and recheck the turn record before the
terminal write landed, concluding queued against a turn that would
never drain again. A second drain sweep after the terminal put_turn
pairs with try_enqueue's post-enqueue recheck: a recheck that still saw
Running implies the row landed before the sweep; a recheck that sees
the terminal record seeds its own turn. Applied to completed, failed,
and cancelled finalize (the latter still drain-only).

Also wrap the scripted router's steer trigger in the same outer
timeout Client::call_with_timeout uses, so a connection that never
establishes cannot park the chat handler.
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