Skip to content

fix(item): defer claim release until after push_and_open_pr - #183

Merged
getappz merged 2 commits into
masterfrom
task/37
Jul 14, 2026
Merged

getappz merged 2 commits into
masterfrom
task/37

Conversation

@getappz

@getappz getappz commented Jul 14, 2026 •

Copy link
Copy Markdown
Owner

Fixes item #37 (flagged by CodeRabbit reviewing PR #179): item::claim_done released the claim lease and moved the item to completed in one transaction; push_and_open_pr then ran after that transaction committed, outside the backend DB lock. In the window between release and the push/PR finishing, another agent could claim() the same now-completed item, silently reassigning item.assignee_agent mid-flight.

Fix

Split item::claim_done into item::mark_completed (state transition only — verifies the caller still holds the claim, does not touch the ledger) plus a deferred claim::done call in the done MCP arm that only runs after push_and_open_pr has been attempted (success or soft-fail, it never blocks). The lease stays held for the entire publish window, so a concurrent claim() correctly returns Held instead of Acquired.

Added ClaimLedger::is_owner (checks current ownership without mutating the claim row) to support the split.

Tests

  • mark_completed_moves_to_completed_state_and_a_later_release_makes_it_reclaimable — proves a concurrent claim is rejected (Held) while the lease is still held post-mark_completed, and only becomes Acquired after the lease is actually released
  • mark_completed_is_a_noop_when_owner_does_not_hold_the_claim
  • Updated heartbeat_release_done_are_owner_scoped for the new split call sequence

432/432 tests pass, clippy clean (-D warnings -A unsafe_code -A clippy::pedantic), fmt clean.

Summary by CodeRabbit

  • New Features
    • Added ownership checks when marking items as completed.
    • Items can now transition to the completed state without releasing their claim lease immediately.
    • The “done” workflow refreshes the claim lease before the pull request workflow, and releases afterward.
  • Bug Fixes
    • Non-owners can no longer complete or release another owner’s claimed item.
    • Prevented concurrent claims from succeeding while completion is in progress, ensuring correct reclaim behavior after completion is finalized.

…the done-arm race

item::claim_done released the claim lease and moved the item to
completed in one transaction; push_and_open_pr then ran after that
transaction committed, outside the backend DB lock. In the window
between release and the push/PR finishing, another agent could claim()
the same now-completed item, silently reassigning item.assignee_agent
mid-flight.

Split into item::mark_completed (state transition only, verifies the
caller still holds the claim, does not touch the ledger) plus a
deferred claim::done call in the done MCP arm that only runs after
push_and_open_pr has been attempted. The lease stays held for the
entire publish window, so a concurrent claim() correctly returns Held
instead of Acquired.

Added ClaimLedger::is_owner (ownership check without mutating the
claim) to support the split. New/updated backend tests cover: a
concurrent claim is rejected while the lease is still held post-
mark_completed, and mark_completed no-ops for a non-owning caller.
@coderabbitai

coderabbitai Bot commented Jul 14, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 416ae18c-ca24-48da-847d-0ce956fa0b22

📥 Commits

Reviewing files that changed from the base of the PR and between 4ae22c3 and ba8055e.

📒 Files selected for processing (1)
  • src/mcp_server.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/mcp_server.rs

📝 Walkthrough

Walkthrough

The PR adds claim ownership checks, replaces claim_done with mark_completed, preserves the lease during completion, and defers lease release in the MCP done flow until after PR handling.

Changes

Completion and claim lease flow

Layer / File(s) Summary
Claim ownership lookup
crates/agentflare-db-kit/src/claim.rs, crates/agentflare-backend/src/claim.rs
Adds ledger and backend helpers that determine whether an owner holds an item claim.
Owned completion without lease release
crates/agentflare-backend/src/item.rs
Adds mark_completed, which transitions an owned item to completed while retaining the claim, with tests covering ownership and later release.
Deferred MCP lease release
src/mcp_server.rs
The done action completes the item, refreshes the lease, handles PR publication, and releases the claim afterward.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: rust

Sequence Diagram(s)

sequenceDiagram
  participant MCP_item_tool
  participant mark_completed
  participant push_and_open_pr
  participant claim_done
  MCP_item_tool->>mark_completed: Mark item completed
  mark_completed-->>MCP_item_tool: Completion result
  MCP_item_tool->>push_and_open_pr: Push changes and open PR
  push_and_open_pr-->>MCP_item_tool: PR result
  MCP_item_tool->>claim_done: Release claim lease
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately describes the main change: deferring claim release until after push_and_open_pr.
Description check ✅ Passed The description clearly explains the change, rationale, and testing, though it doesn't fully follow the repo's template headings.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 task/37

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

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

Caution

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

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

2635-2675: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Keep the claim lease alive through publish, and surface release failures.

  • push_and_open_pr can run long enough for the claim to expire before claim::done runs.
  • claim::done(...) is discarded; log or handle false/errors so an owner mismatch or DB failure doesn't disappear.
🤖 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 `@src/mcp_server.rs` around lines 2635 - 2675, The completion flow around
push_and_open_pr must refresh or otherwise keep the claim lease alive throughout
publishing, then surface any claim::done failure instead of discarding it.
Update the done-claim release block to handle both false results and database
errors with appropriate logging or propagation, preserving the existing owner
and timestamp semantics.
🤖 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.

Outside diff comments:
In `@src/mcp_server.rs`:
- Around line 2635-2675: The completion flow around push_and_open_pr must
refresh or otherwise keep the claim lease alive throughout publishing, then
surface any claim::done failure instead of discarding it. Update the done-claim
release block to handle both false results and database errors with appropriate
logging or propagation, preserving the existing owner and timestamp semantics.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a24fd575-3ea4-4abd-a393-c12d27c940b0

📥 Commits

Reviewing files that changed from the base of the PR and between 184a560 and 4ae22c3.

📒 Files selected for processing (4)
  • crates/agentflare-backend/src/claim.rs
  • crates/agentflare-backend/src/item.rs
  • crates/agentflare-db-kit/src/claim.rs
  • src/mcp_server.rs

Addresses CodeRabbit on PR #183:
- push_and_open_pr can run long enough that a short custom
  AGENTFLARE_BACKEND_CLAIM_TTL_SECS could let the lease go stale
  mid-publish. Refresh the heartbeat right before the publish step
  starts, immediately after mark_completed succeeds.
- The final claim::done release call discarded its result entirely.
  Now logs (eprintln, matching this file's other soft-fails) on an
  owner mismatch, a DB error, or a with_backend_db lock failure,
  instead of silently swallowing it.
@getappz
getappz merged commit 0b0d19c into master Jul 14, 2026
14 checks passed
@getappz
getappz deleted the task/37 branch July 14, 2026 12:19
getappz added a commit that referenced this pull request Jul 14, 2026
* feat(mcp): consolidate 6 tools into action-dispatch pattern

- Merge skill/search+load, gateway/search+execute, claim/5-actions,
  review/5-actions, artifact/6-actions, memory/6-actions into one
  consolidated #[tool(...)] method each with action dispatch
- Reconcile with #182 (fetch target branch before branching) and
  #183 (deferred claim release, mark_completed split)

* fix(mcp): finish artifact/skill/gateway test migration, fix consolidation regressions

CI was red: ~35 test call sites in mcp_server.rs still called the old
per-action methods (artifact_publish/get/list/delete/diff/search,
skill_search/load, gateway_search/execute) that this consolidation removed.
Migrated them all to the unified action-dispatch tools.

Also fixes real bugs the consolidation introduced along the way:
- artifact()'s get/diff/search arms called store methods with a signature
  they no longer have (get takes no version, diff's to is a required u32,
  and there's no store.search at all) — restored the pre-consolidation
  logic (get_version fallback, latest-version resolution, inline
  list+filter+snippet search).
- review()'s "consensus" arm called crate::review::consensus with the wrong
  arguments entirely (a Connection/ids instead of findings+changed-lines);
  now loads findings and computes the diff/changed-lines first, matching
  "record"'s already-correct pattern. Also dropped record's dead base/head
  locals that shadowed the actual req.base/req.head usage.
- memory()'s "curate" arm passed the outer "curate" action into
  CurateInput.action, so update/delete/pin/unpin could never be reached;
  added a dedicated curate_action field.
- mark_completed's ownership check and completion write weren't in the
  same transaction, leaving a window for a concurrent release+claim by a
  different owner to complete the item out from under its new owner.

Also ran cargo fmt across the branch (had never been formatted).

* fix(fmt): collapse tool() signature onto one line per rustfmt
getappz pushed a commit that referenced this pull request Aug 22, 2026
…ut false positives (#183)

cursor-agent was dispatched with its default text output format, same as
the pre-#489 Claude Code behavior: run_captured's idle-timeout (default
300s) writes nothing to stdout until the run finishes, so any real,
longer cursor-agent task gets killed as a false-positive hang.

build_extra_args now also passes --output-format stream-json for
Agent::Cursor (without the Claude-Code-only --verbose/--max-turns/
--max-cost-usd flags, unconfirmed for cursor-agent), and clean_agent_reply
parses cursor-agent's stream-json transcript the same way as Claude
Code's. New test lives in its own file (cli/work/cursor_dispatch_tests.rs)
since src/cli/work.rs is frozen at the LOC gate's limit.

Agentflare-Agent: claude-code
Agentflare-Branch: task/183-fix-cursor-agent-stream-json-idle-timeout
Agentflare-Item: 183
getappz added a commit that referenced this pull request Aug 22, 2026
…ut false positives (#183) (#594)

cursor-agent was dispatched with its default text output format, same as
the pre-#489 Claude Code behavior: run_captured's idle-timeout (default
300s) writes nothing to stdout until the run finishes, so any real,
longer cursor-agent task gets killed as a false-positive hang.

build_extra_args now also passes --output-format stream-json for
Agent::Cursor (without the Claude-Code-only --verbose/--max-turns/
--max-cost-usd flags, unconfirmed for cursor-agent), and clean_agent_reply
parses cursor-agent's stream-json transcript the same way as Claude
Code's. New test lives in its own file (cli/work/cursor_dispatch_tests.rs)
since src/cli/work.rs is frozen at the LOC gate's limit.

Agentflare-Agent: claude-code
Agentflare-Branch: task/183-fix-cursor-agent-stream-json-idle-timeout
Agentflare-Item: 183

Co-authored-by: shiva <shiva@gosysinfo.tech>
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