Skip to content

[auto] #67 phase 1: stabilize fresh prompt-step startup on brand-new choir runs - #71

Merged
nutt-adam merged 3 commits into
mainfrom
auto/issue-67-20260319112626
Mar 19, 2026
Merged

[auto] #67 phase 1: stabilize fresh prompt-step startup on brand-new choir runs#71
nutt-adam merged 3 commits into
mainfrom
auto/issue-67-20260319112626

Conversation

@nutt-adam

@nutt-adam nutt-adam commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

Automated SDLC cycle for #67.

  • planner: completed
  • implementation: completed
  • tests: updated
  • docs/changelog: updated
  • version: bumped if required

Summary by CodeRabbit

  • New Features

    • Startup grace window to improve agent initialization timing.
    • Per-agent memory, merge-gate enforcement, permissions suggestion, orchestration state machine, resume baseline, and issue-claim leasing.
    • Codex SDLC integration, runtime diagnostics, resume intent logging, compensator preflight, and enhanced runtime prompts.
  • Improvements

    • Enhanced agent idle detection with configurable startup grace behavior and better recognition of ongoing work states.
    • Documentation updates and a minor version bump with compatibility notes.

nutt-adam and others added 2 commits March 19, 2026 11:34
Prevent fresh prompt steps from falsely completing before the agent
has consumed the prompt. The startup grace period (default 30s) gates
completion detection until real working activity is observed.

Key changes:
- wait_for_agent_idle accepts a startup_grace Duration parameter
- AgentStatus::Working counts as activity even without pane hash change,
  requiring 2+ consecutive polls to avoid flicker false positives
- First pane capture no longer counts as a hash "change"
- Completion signals before any activity are held until grace expires
- "Unravelling" added to claude-code working patterns
- startup_grace_secs field threaded through config and automation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…anges

Cover startup grace window (#67), persistent memory (#62/#63), merge gate
enforcement (#59), permissions suggest (#53), orchestration state machine
(#54/#55), and all fixes shipped since 0.2.0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 19, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a configurable startup grace window for Prompt steps, propagated through config, automation resolution/execution, health idle-wait logic, CLI send/run usage, and runtime status detection (adds "Unravelling" to Working patterns). Includes changelog entry and a new unit test.

Changes

Cohort / File(s) Summary
Changelog & Config
CHANGELOG.md, src/config/mod.rs
Adds 0.3.0 changelog entry; adds startup_grace_secs: Option<u64> to WorkflowStepConfig::Prompt with validation rejecting inconsistent wait settings.
Automation & CLI run
src/automation/mod.rs, src/cli/run.rs
Extends ResolvedStep::Prompt to include startup_grace_secs; introduces DEFAULT_STARTUP_GRACE_SECS usage (fallback 30s) and propagates the grace window through resolve/execute flows.
Health & CLI send
src/health/mod.rs, src/cli/send.rs
wait_for_agent_idle gains startup_grace: Duration param; adds WORKING_STATUS_CONSECUTIVE_THRESHOLD, consecutive-working tracking, nuanced pre/post-activity completion logic, and uses startup grace to avoid premature timeouts.
Runtime detection & tests
src/runtime/claude_code.rs, src/runtime/mod.rs
Adds "Unravelling" to recognized Working patterns and a unit test verifying detection from "Searching..." and "Unravelling..." messages.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI (run/send)
  participant Config as Config
  participant Automation as Automation/Executor
  participant Health as Health checker
  participant Runtime as Runtime adapter

  CLI->>Config: load workflow (may include startup_grace_secs)
  CLI->>Automation: start execution (resolved steps include startup_grace_secs)
  Automation->>Health: wait_for_agent_idle(startup_grace)
  Health->>Runtime: poll status & hashes
  Runtime-->>Health: status (Working/Idle), content like "Unravelling"
  Health-->>Automation: idle/detected activity (honors startup_grace & consecutive-working)
  Automation->>CLI: step completion / continue
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰
A gentle grace for agents at start,
Beats of thinking given heart-to-heart.
"Unravelling" whispers, patience kept,
No haste to mark the prompt as slept.
Hop—now the run begins with art.

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description is minimal but confirms key lifecycle items. However, it lacks required template sections: no explicit SemVer choice checkbox, no version number specified, and missing validation/release sections. Complete the required template sections: specify SemVer choice (MINOR is appropriate given new startup_grace_secs capability), document the version selected (appears to be 0.3.0 from CHANGELOG), and confirm validation/release steps.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly references issue #67 and describes the main feature being implemented: stabilizing fresh prompt-step startup behavior on new workflow runs.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch auto/issue-67-20260319112626
📝 Coding Plan
  • Generate coding plan for human review comments

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 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 (2)
src/automation/mod.rs (1)

455-469: Expose prompt wait settings in dry-run output too.

ResolvedStep::Prompt now carries behavior-affecting wait metadata, but tt run --dry-run/--json still strips prompt wait settings in src/cli/run.rs via .. matches. That makes a non-default startup_grace_secs override impossible to inspect before execution. Please thread these fields through the plan serializers while this model change is fresh.

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

In `@src/automation/mod.rs` around lines 455 - 469, The dry-run/json serializer is
dropping the new prompt wait metadata from ResolvedStep::Prompt (wait_for_idle,
wait_timeout_secs, startup_grace_secs) via a `..` match when converting resolved
steps to the plan/JSON representation; update the plan/serializer code that
transforms ResolvedStep::Prompt into the serializable step type (the mapping
function that handles Prompt variants and the target serializable Prompt struct)
to explicitly include and forward wait_for_idle, wait_timeout_secs, and
startup_grace_secs (add those fields to the serializable struct if missing) so
the dry-run and --json output reflect the runtime wait overrides.
src/health/mod.rs (1)

253-265: Consider resetting consecutive_working_polls when hash changes.

The counter increments when runtime_is_working && !changed and resets when !runtime_is_working, but it's not reset when changed is true. This means if the hash changes while working, the counter retains its previous value.

While this doesn't affect immediate correctness (since changed already triggers activity), it could lead to subtle issues: after a hash change, the counter may already be at 1, meaning only one more Working poll without hash change would cross the threshold instead of requiring two consecutive polls.

♻️ Suggested fix to reset counter on hash change
         if runtime_is_working && !changed {
             consecutive_working_polls += 1;
         } else if !runtime_is_working {
             consecutive_working_polls = 0;
+        } else if changed {
+            consecutive_working_polls = 0;
         }

Or more concisely:

         if runtime_is_working && !changed {
             consecutive_working_polls += 1;
         } else {
             consecutive_working_polls = 0;
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/health/mod.rs` around lines 253 - 265, The consecutive_working_polls
counter should be reset when the hash changes to avoid carrying prior counts
across a change; modify the logic around runtime_is_working/changed so that when
changed is true you set consecutive_working_polls = 0, otherwise keep the
existing behavior (increment when runtime_is_working && !changed and reset to 0
when !runtime_is_working). Update the block that currently checks
runtime_is_working and adjusts consecutive_working_polls (the variables
runtime_is_working, changed, consecutive_working_polls and the constant
WORKING_STATUS_CONSECUTIVE_THRESHOLD) so changed always clears the counter
before any increment logic.
🤖 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/config/mod.rs`:
- Around line 156-160: Add a validation check in the prompt/step config
validator (where the struct with fields wait_for_idle, wait_timeout_secs,
startup_grace_secs is validated) to reject configurations that set
wait_timeout_secs or startup_grace_secs when wait_for_idle is false or absent;
return a user-facing error that instructs to "set `wait_for_idle = true` or
remove the wait settings." Locate the validator (e.g., impl validate/try_from
for that config struct in src/config/mod.rs or the function that currently
checks wait_timeout_secs) and add an if condition that errors when
(wait_for_idle == Some(false) || wait_for_idle.is_none()) &&
(wait_timeout_secs.is_some() || startup_grace_secs.is_some()), using the
existing error type/flow so the message is surfaced to users.

---

Nitpick comments:
In `@src/automation/mod.rs`:
- Around line 455-469: The dry-run/json serializer is dropping the new prompt
wait metadata from ResolvedStep::Prompt (wait_for_idle, wait_timeout_secs,
startup_grace_secs) via a `..` match when converting resolved steps to the
plan/JSON representation; update the plan/serializer code that transforms
ResolvedStep::Prompt into the serializable step type (the mapping function that
handles Prompt variants and the target serializable Prompt struct) to explicitly
include and forward wait_for_idle, wait_timeout_secs, and startup_grace_secs
(add those fields to the serializable struct if missing) so the dry-run and
--json output reflect the runtime wait overrides.

In `@src/health/mod.rs`:
- Around line 253-265: The consecutive_working_polls counter should be reset
when the hash changes to avoid carrying prior counts across a change; modify the
logic around runtime_is_working/changed so that when changed is true you set
consecutive_working_polls = 0, otherwise keep the existing behavior (increment
when runtime_is_working && !changed and reset to 0 when !runtime_is_working).
Update the block that currently checks runtime_is_working and adjusts
consecutive_working_polls (the variables runtime_is_working, changed,
consecutive_working_polls and the constant WORKING_STATUS_CONSECUTIVE_THRESHOLD)
so changed always clears the counter before any increment logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 786ef039-f64a-42cd-9979-ff42a2007ab5

📥 Commits

Reviewing files that changed from the base of the PR and between 715c39c and 207a9bb.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • src/automation/mod.rs
  • src/cli/run.rs
  • src/cli/send.rs
  • src/config/mod.rs
  • src/health/mod.rs
  • src/runtime/claude_code.rs
  • src/runtime/mod.rs

Comment thread src/config/mod.rs
- Reduce DEFAULT_STARTUP_GRACE_SECS from 30 to 10 so the
  completion-before-activity path fires before typical wait timeouts
- Validate that wait_timeout_secs/startup_grace_secs are only set when
  wait_for_idle is true, failing fast with actionable guidance

Addresses CodeRabbit feedback on PR #71.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

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

🧹 Nitpick comments (2)
src/cli/send.rs (1)

13-13: Consider centralizing startup-grace defaults to prevent behavior drift.

Line 13 defines a send-specific default (10s), while automation uses a different default (30s in src/automation/mod.rs), so prompt-wait behavior diverges by entrypoint. Consider moving this default to a shared constant/config source and reusing it in both paths.

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

In `@src/cli/send.rs` at line 13, The send-specific constant
DEFAULT_STARTUP_GRACE_SECS (used in send) causes divergent prompt-wait behavior
vs the automation path (which uses its own 30s default); extract this value into
a shared constant or configuration (e.g., STARTUP_GRACE_SECS in a new or
existing config/module) and replace usages of DEFAULT_STARTUP_GRACE_SECS in send
and the hard-coded 30s in src/automation/mod.rs to reference that single shared
symbol so both entrypoints use the same startup grace default.
src/config/mod.rs (1)

665-673: Add a targeted regression test for the new wait-setting guard.

This new branch should be pinned with a unit test so config validation behavior doesn’t regress in future refactors.

Proposed test addition
 #[cfg(test)]
 mod tests {
     use super::*;
+    
+    #[test]
+    fn validate_prompt_wait_settings_require_wait_for_idle() {
+        let toml_str = r#"
+[workspace]
+name = "test"
+
+[[agent]]
+name = "backend"
+runtime = "claude-code"
+
+[[workflow]]
+name = "verify"
+
+[[workflow.step]]
+type = "prompt"
+agent = "backend"
+text = "check"
+wait_timeout_secs = 30
+"#;
+        let config: TuttiConfig = toml::from_str(toml_str).unwrap();
+        let err = config.validate().unwrap_err();
+        assert!(err.to_string().contains("set wait_for_idle = true or remove the wait settings"));
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/config/mod.rs` around lines 665 - 673, Add a unit test in the config
validation tests (e.g., inside the tests module in src/config/mod.rs) that
constructs a workflow/step with wait_for_idle = false while setting
wait_timeout_secs and/or startup_grace_secs, calls the configuration validation
function (the code path that can return TuttiError::ConfigValidation) and
asserts it returns Err(TuttiError::ConfigValidation) and the error message
mentions the workflow name and the offending step index; this pins the new guard
branch that checks wait_for_idle, wait_timeout_secs, and startup_grace_secs so
future changes will fail the test if the validation regresses.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/cli/send.rs`:
- Line 13: The send-specific constant DEFAULT_STARTUP_GRACE_SECS (used in send)
causes divergent prompt-wait behavior vs the automation path (which uses its own
30s default); extract this value into a shared constant or configuration (e.g.,
STARTUP_GRACE_SECS in a new or existing config/module) and replace usages of
DEFAULT_STARTUP_GRACE_SECS in send and the hard-coded 30s in
src/automation/mod.rs to reference that single shared symbol so both entrypoints
use the same startup grace default.

In `@src/config/mod.rs`:
- Around line 665-673: Add a unit test in the config validation tests (e.g.,
inside the tests module in src/config/mod.rs) that constructs a workflow/step
with wait_for_idle = false while setting wait_timeout_secs and/or
startup_grace_secs, calls the configuration validation function (the code path
that can return TuttiError::ConfigValidation) and asserts it returns
Err(TuttiError::ConfigValidation) and the error message mentions the workflow
name and the offending step index; this pins the new guard branch that checks
wait_for_idle, wait_timeout_secs, and startup_grace_secs so future changes will
fail the test if the validation regresses.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c6d137a7-3e2b-4353-969a-ca711fc83189

📥 Commits

Reviewing files that changed from the base of the PR and between 207a9bb and d257df1.

📒 Files selected for processing (2)
  • src/cli/send.rs
  • src/config/mod.rs

@nutt-adam
nutt-adam merged commit a1beda9 into main Mar 19, 2026
10 checks passed
@nutt-adam
nutt-adam deleted the auto/issue-67-20260319112626 branch March 19, 2026 08:01
nutt-adam added a commit that referenced this pull request Mar 19, 2026
Take main's idle detection (startup_grace, consecutive working polls)
from merged PR #71. Restore expanded Claude Code completion/idle
patterns (don't ask on, shift+tab to cycle) and working patterns
(Searching for, (thinking)) needed for reliable prompt-bar detection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
nutt-adam added a commit that referenced this pull request Mar 19, 2026
Take main's idle detection (startup_grace, consecutive working polls)
from merged PR #71. Restore expanded Claude Code completion/idle
patterns (don't ask on, shift+tab to cycle) and working patterns
(Searching for, (thinking)) needed for reliable prompt-bar detection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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