Skip to content

fix(automation): poll artifact_glob after wait_for_idle settles - #124

Merged
nutt-adam merged 5 commits into
mainfrom
codex/pr-121-artifact-capture-poll
May 4, 2026
Merged

fix(automation): poll artifact_glob after wait_for_idle settles#124
nutt-adam merged 5 commits into
mainfrom
codex/pr-121-artifact-capture-poll

Conversation

@nutt-adam

@nutt-adam nutt-adam commented May 4, 2026

Copy link
Copy Markdown
Contributor

Supersedes #121 from Brian's fork so the required repository CI can attach normally after the branch protection updates. This preserves Brian's original fix plus the two CodeRabbit-requested follow-ups that were already reviewed on #121.

Fixes #120.

Versioning

  • SemVer: PATCH
  • Version bump: none in this PR; queued for the normal release flow.
  • Release tag: none.

Validation

  • cargo fmt --all -- --check
  • cargo check
  • cargo test --bin tt artifact
  • HOME=/private/tmp/tutti-test-home CARGO_HOME=/Users/adamnutt/.cargo cargo test --bin tt -- --test-threads=1

bketelsen and others added 3 commits May 4, 2026 11:56
The post-step artifact capture in the wait_for_idle = true branch was a
single-shot check after a 2s sleep. wait_for_agent_idle can return as
soon as the runtime adapter detects a completion signal (Claude Code
emits this at end-of-turn), which can fire before the agent's last
file write is flushed to disk — or before the agent has even started
writing the file referenced in its final response.

Replace the sleep+check with a bounded polling loop (1s cadence,
window = max(wait_timeout_secs / 30, 5s)..60s). The artifact-polling
mode branch (active when wait_for_idle = false) already uses this
pattern at lines 1080-1255; this aligns the wait_for_idle = true
path with that proven approach.

Fixes #120
@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@nutt-adam has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 45 minutes and 50 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b52379be-0b27-464b-8715-6558b4a1a150

📥 Commits

Reviewing files that changed from the base of the PR and between b98d2fe and 8fb86e4.

📒 Files selected for processing (1)
  • src/automation/mod.rs
📝 Walkthrough

Walkthrough

The pull request replaces fixed-sleep artifact capture with bounded polling in src/automation/mod.rs. A new helper function polls for artifact materialization with a timeout-derived duration across three capture points: the implement_code early-success path, its retry variant, and general post-step capture. Error handling now propagates poll failures into step results.

Changes

Artifact Capture Polling

Layer / File(s) Summary
Polling Helpers
src/automation/mod.rs
New post_idle_artifact_poll_secs(wait_timeout_secs) computes a bounded poll window; capture_artifact_with_poll(...) retries artifact capture with configurable interval until success or timeout.
Early-Success Capture
src/automation/mod.rs
In implement_code early-success and retry paths, replaces fixed sleep(2) + one-shot capture_artifact with capture_artifact_with_poll, using post_idle_poll_secs; failures now push failed StepResult and abort.
Post-Step Capture
src/automation/mod.rs
General post-step artifact capture replaces brief settle sleep + immediate capture with bounded polling via capture_artifact_with_poll, avoiding false failures when filesystem flush lags process completion.
Tests & Verification
src/automation/mod.rs
Unit tests verify that capture_artifact_with_poll waits for late-created files and that post_idle_artifact_poll_secs correctly clamps durations (e.g., 30s → 5s, large values → 60s).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 A bounded poll, not a sleepy wait,
No more false fails from filesystem late—
With clamped durations and retries so keen,
Artifacts dance at the edge in-between!
Capture and retry, the race is now tame, 🎯

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive PR description covers key points (issue reference, versioning choice, validation steps) but lacks explicit details required by template sections (changelog, release tag rationale). Clarify whether CHANGELOG.md was updated and explicitly document why no version bump is needed in this specific PR, despite the bug fix.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: replacing a settle sleep with polling for artifact capture after idle detection.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/pr-121-artifact-capture-poll

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
Review rate limit: 0/1 reviews remaining, refill in 45 minutes and 50 seconds.

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

@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: 1

🧹 Nitpick comments (1)
src/automation/mod.rs (1)

2887-2908: ⚡ Quick win

Make the poll-expiry error actionable.

When the deadline expires, this helper returns the last capture_artifact(...) error verbatim, so callers only surface a generic “matched no new files” message. Wrapping that case with the poll window and a hint to verify artifact_glob or increase the timeout would make these failures much easier to diagnose.

Suggested change
 fn capture_artifact_with_poll(
     pre_snapshot: &HashSet<PathBuf>,
     pattern: &str,
     artifact_name: &str,
     poll_secs: u64,
     poll_interval: Duration,
 ) -> Result<PathBuf> {
     let poll_deadline = Duration::from_secs(poll_secs);
     let poll_start = std::time::Instant::now();

     loop {
         match capture_artifact(pre_snapshot, pattern, artifact_name) {
             Ok(path) => break Ok(path),
-            Err(err) => {
+            Err(_) => {
                 if poll_start.elapsed() >= poll_deadline {
-                    break Err(err);
+                    break Err(TuttiError::ConfigValidation(format!(
+                        "artifact '{}' did not appear within {}s after completion; verify artifact_glob '{}' or increase wait_timeout_secs",
+                        artifact_name, poll_secs, pattern
+                    )));
                 }
                 std::thread::sleep(poll_interval);
             }
         }
     }
 }

As per coding guidelines, "User-facing errors should include actionable guidance".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/automation/mod.rs` around lines 2887 - 2908, In
capture_artifact_with_poll wrap the Err returned when poll_start.elapsed() >=
poll_deadline into a new, more actionable error that mentions the poll window
expired and suggests verifying the artifact_glob/pattern and increasing
poll_secs; preserve or attach the original capture_artifact error details (from
capture_artifact(...)) so callers still see the underlying cause. Update the
return at the timeout branch to construct that wrapped error instead of
returning err verbatim, keeping the Ok path unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/automation/mod.rs`:
- Around line 1565-1627: The current code bails out of prompt-step success paths
with early continues so artifact capture (artifact_pre_snapshot/artifact_name ->
capture_artifact_with_poll -> store_artifact_output) is skipped for some exits;
refactor so every successful prompt-step funnels through a single post-step
artifact-capture routine instead of returning/continuing early. Concretely:
remove or replace the early continue/return in the prompt-step completion
branches and call a shared helper (e.g., implement a new function like
finalize_prompt_step_artifacts that takes &self, run_id, step_index, started,
artifact_pre_snapshot, artifact_name, post_idle_poll_secs, output_files,
outputs, step_results, failed_steps) which runs capture_artifact_with_poll and
store_artifact_output and pushes to output_files/outputs or records failures
into step_results/failed_steps; invoke that helper from all success exit points
(including where implement_code previously returned) so artifact capture always
runs once per successful prompt-step.

---

Nitpick comments:
In `@src/automation/mod.rs`:
- Around line 2887-2908: In capture_artifact_with_poll wrap the Err returned
when poll_start.elapsed() >= poll_deadline into a new, more actionable error
that mentions the poll window expired and suggests verifying the
artifact_glob/pattern and increasing poll_secs; preserve or attach the original
capture_artifact error details (from capture_artifact(...)) so callers still see
the underlying cause. Update the return at the timeout branch to construct that
wrapped error instead of returning err verbatim, keeping the Ok path unchanged.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6f6fe5e9-771f-4cf6-8ec6-6442de5f569e

📥 Commits

Reviewing files that changed from the base of the PR and between ada9ad7 and b98d2fe.

📒 Files selected for processing (1)
  • src/automation/mod.rs

Comment thread src/automation/mod.rs
@nutt-adam
nutt-adam merged commit 417381f into main May 4, 2026
11 checks passed
@nutt-adam
nutt-adam deleted the codex/pr-121-artifact-capture-poll branch May 4, 2026 02:18
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.

wait_for_idle = true + artifact_glob race: post-step capture is single-shot, fails when agent finishes faster than the filesystem flushes

2 participants