Skip to content

fix: preserve running status while a job starts - #17

Merged
Boulea7 merged 1 commit into
mainfrom
ln-cx/supervisor-startup-status
Oct 3, 2026
Merged

Boulea7 merged 1 commit into
mainfrom
ln-cx/supervisor-startup-status

Conversation

@Boulea7

@Boulea7 Boulea7 commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

Concurrent Python calls to Supervisor.start() and Supervisor.status() on the same instance could mark a job failed before its worker starts. The job could then complete successfully with a stale crash error. Check the existing startup reservation and fresh record ownership under the registry lock before reconciling an absent worker.

Regression tests pause startup after metadata creation and before Thread.start(), then verify normal completion without the false diagnostic. A duplicate-start test checks that orphan reconciliation resumes once the reservation is released. Foreign-owner and terminal handling are preserved. Standard synchronous stdio handling does not interleave these calls.

Validation: 150 selected Supervisor, MCP and session-store tests passed on Linux/Python 3.12, plus Ruff, an offline wheel/sdist build and the release artifact audit. Local full-suite, native Windows and real-provider E2E runs were not performed.

CI for e9da634 passed all five code jobs and 48 steps, including required lint/test/build/artifact checks and Linux/macOS compatibility tests on Python 3.11 and 3.13: CI run.

Follow-up to the startup race identified in #16.

Summary by Sourcery

Preserve running job state while local workers are starting and reconcile genuine orphaned jobs after startup reservations are released.

Bug Fixes:

  • Prevent status checks from falsely marking locally starting jobs as failed before their worker begins.
  • Preserve orphan reconciliation for duplicate starts after the startup reservation is released.

Tests:

  • Add regression coverage for status checks during startup and duplicate-start orphan reconciliation.

Summary by cubic

Fixes a race where concurrent Supervisor.start() and Supervisor.status() calls on the same instance could mark a job failed before its worker started, leaving a stale crash error on a job that later completed successfully.

  • status() now checks the job's local startup reservation and fresh record ownership under the registry lock before reconciling an absent worker.
  • Orphan reconciliation is preserved for foreign-owned records and resumes once a duplicate start releases its reservation.
  • Adds regression tests for status checks during startup and for duplicate-start orphan reconciliation.

Written for commit e9da634. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Job status now remains accurate while a job is starting, rather than incorrectly showing it as failed.
    • Cancellation requests during startup correctly indicate when the job cannot yet be cancelled.
    • Duplicate job starts are reconciled to a failed status when the start attempt returns.

Signed-off-by: boulea7 <zln1905391059@163.com>
@sourcery-ai

sourcery-ai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

The PR fixes a startup race by having status() recognize a locally owned startup reservation before reconciling an absent worker, while preserving existing ownership and terminal-state behavior. Regression tests cover both startup timing windows and confirm duplicate-start orphan reconciliation still occurs after the reservation is released.

Sequence diagram for preserving running status during job startup

sequenceDiagram
    participant Start as Supervisor.start()
    participant Status as Supervisor.status()
    participant Registry as Registry lock
    participant Worker as Thread.start()
    participant Store as Job store

    Start->>Registry: Create startup reservation and running metadata
    par Concurrent status check
        Status->>Registry: Read _starting_jobs and fresh record
        alt Local startup reservation exists
            Registry-->>Status: Local owner identity, worker may be absent
            Status-->>Start: Return running record
        else Reservation not present
            Registry-->>Status: No local reservation
            Status->>Store: finalize_job(job_id)
            Store-->>Status: Reconciled terminal record
        end
    and Worker startup
        Start->>Worker: Thread.start()
    end
    Worker-->>Start: Worker runs and completes normally
Loading

File-Level Changes

Change Details Files
Prevent status reconciliation from failing a job during its local startup reservation.
  • Inspect the fresh record’s owner identity while holding the registry lock.
  • Treat a locally reserved job as still running until startup completes.
  • Preserve existing handling for foreign owners, live workers, and terminal records.
src/agy_mcp/supervisor.py
Add regression coverage for startup/status races and duplicate-start orphan reconciliation.
  • Pause startup before registration and before thread start, then verify status and successful completion.
  • Verify duplicate starts eventually release the reservation and allow orphan reconciliation.
  • Assert cancellation, cleanup, terminal status, and absence of stale crash diagnostics.
tests/test_supervisor.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 660c769a-07c8-4d46-83f3-1cae01395ea9
📥 Commits

Reviewing files that changed from the base of the PR and between 6bffbf0 and e9da634.

📒 Files selected for processing (2)
  • src/agy_mcp/supervisor.py
  • tests/test_supervisor.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Supervisor.status now preserves a fresh running record for a locally owned job during startup. Tests cover status and cancellation during startup, successful completion after startup, and reconciliation after a duplicate start fails.

Changes

Startup status handling

Layer / File(s) Summary
Preserve running status during startup
src/agy_mcp/supervisor.py, tests/test_supervisor.py
Supervisor.status preserves the running record when the job is in _starting_jobs and its fresh owner identity matches this supervisor. Tests cover two startup windows and verify that a duplicate start is reconciled as failed after it returns.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to e9da6

No actionable issue remains from this review; the change is mergeable after normal checks.

Security Architecture Review

Security architecture risk: ⚪ Minimal · up to e9da6

The fix preserves startup status without adding execution authority or weakening ownership checks. No security issue introduced or materially worsened by this change was identified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed preservation behavior is bounded to job records with an active reservation in the same Supervisor instance and matching persisted instance ownership. It changes status visibility, not the authority to execute or cancel jobs.

Trust Boundaries and Controls

  • observed — A foreign-owned record cannot satisfy the new local-startup condition. Existing live-foreign-owner and changed-owner safeguards remain before failure reconciliation, and terminal records return without reconciliation. These are lifecycle ownership controls, not evidence of tenant-level authorization.

Resilience and Maintainability Implications

  • observed — Existing handled startup failures release capacity and clean unstarted resources. Thread.start RuntimeError also removes the handle and attempts to persist failure. Worker cleanup removes its handle and releases capacity even if finalization fails. Existing retry tests exercise store, factory, and thread-start failures; these containment mechanisms are unchanged by this PR.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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 summarizes the main change: preserving a job’s running status while startup is in progress.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-03T09:58:33.937560Z e9da634 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

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

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Needs a human reviewer. If a local start remains marked in _starting_jobs after its worker fails to register or start, status() will continue reporting the persisted job as running and skip orphan reconciliation. Reverting restores the old behavior, but any stale running record created meanwhile would need a bounded cleanup or re-run.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 2 files

Re-trigger cubic

@Boulea7

Boulea7 commented Oct 3, 2026

Copy link
Copy Markdown
Owner Author

On the startup reservation concern: start() removes its reservation in a finally when the call returns or raises. The start-failure controls exercise this cleanup, and the new duplicate-start regression verifies that orphan reconciliation resumes after refusal. A call that is still pending intentionally defers reconciliation of its own record; this change does not add a startup deadline.

Both startup windows now preserve the running record and complete without the false crash diagnostic. CI on e9da634 passed all five code jobs and 48 steps.

@Boulea7
Boulea7 merged commit c418175 into main Oct 3, 2026
9 checks passed
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