Conversation
…icate-item reuse, assignee freeze Item #236 (handoff hardening, QuorumGit adoption): - HandoffRequest gains last_commit: verified via `git cat-file -e` and, when the item's task/<seq> branch already exists, `git merge-base --is-ancestor` -- a fabricated or unreachable OID is rejected, not trusted. - HandoffRequest gains required completed/remaining and optional blockers fields, stored in the asset's metadata. - A handoff without item_id now reuses an existing open item assigned to the recipient (matched by name or thread_id) instead of blindly creating a duplicate; genuinely new work still auto-creates. - agentflare_backend::item::claim gains a BlockedByAssignee outcome: a freshly handed-off, never-claimed item can only be claimed by its assignee until accepted, excluding completed/cancelled items. Deferred: shim-side branch-push denial for open handoffs (spec's own review already downgraded this to defense-in-depth, covered in large part by #234's scope enforcement and the opencode branch-guard plugin).
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe PR adds explicit claim outcomes with assignee-based blocking, updates MCP claim responses, and extends handoffs with structured progress fields, item reuse, commit continuity validation, and expanded asset metadata. ChangesClaim and handoff flow
Sequence Diagram(s)sequenceDiagram
participant MCPClient
participant HandoffImpl
participant GitRepository
participant ItemStore
MCPClient->>HandoffImpl: submit structured handoff
HandoffImpl->>GitRepository: verify last_commit reachability
GitRepository-->>HandoffImpl: validation result
HandoffImpl->>ItemStore: reuse or create open item
ItemStore-->>HandoffImpl: item identifier
HandoffImpl-->>MCPClient: persist handoff asset metadata
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (2)
src/mcp_server/handoff.rs (1)
79-92: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winName match wins over an explicit
thread_idmismatch.The
findpredicate short-circuits oni.name == name, so a handoff carryingthread_id: Some("t-2")can be attached to an item whose metadata thread ist-1purely because the names collide. Consider preferring a thread match and only falling back to name whenthread_idisNone(or the thread agrees).🤖 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/handoff.rs` around lines 79 - 92, Update the handoff item predicate in the find call so an explicit thread_id takes precedence: require the item metadata thread to match when thread_id is Some, allowing a name match only when the thread agrees; when thread_id is None, retain name-based matching. Ensure a matching name cannot override a conflicting thread ID.src/mcp_server/tests/artifact_tests.rs (1)
589-611: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueThis test requires the source tree to be a live git checkout.
worktree_repo_root()falls back to a path-walk when.gitis absent, so running the suite from an exported/vendored tree (crates.io tarball, distro packaging) makesrev-parse HEADfail and the test panics rather than skipping. Consider initializing a throwaway repo in the temp dir, or gating onrun_in(..., ["rev-parse","HEAD"]).is_ok().🤖 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/tests/artifact_tests.rs` around lines 589 - 611, The test handoff_accepts_an_existing_last_commit_oid must not panic when the source tree is not a live Git checkout. Before requiring HEAD, probe rev-parse through worktree_repo_root() and return early when it fails, or initialize an isolated temporary repository; preserve the existing assertion for checkout environments.
🤖 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 `@crates/agentflare-backend/src/item.rs`:
- Around line 633-670: Update the assignee comparison in claim to canonicalize
both the owner and assignee agent identities before checking for a mismatch.
Adjust agent_part or the comparison around claim so aliases such as “claude:1”
resolve to the same canonical form as assignee_agent, while preserving the
existing BlockedByAssignee behavior for genuinely different agents.
In `@src/mcp_server/handoff.rs`:
- Around line 52-54: The handoff flow performs blocking Git work while the
backend DB mutex is held. Update the surrounding with_backend_db logic to
resolve and retain item.sequence_id under the lock, then call
verify_continuation_commit after the closure completes, preserving the existing
continuation and error behavior.
- Around line 135-152: Update the validation guards in handoff_impl to reject
empty completed and remaining values after trimming, matching the existing
required-field checks for recipient, name, and content. Perform this validation
before constructing the metadata in the handoff flow so empty progress fields
cannot be accepted.
- Around line 264-282: Validate the caller-controlled oid in the handoff
validation flow before using it with git: reject leading-dash values and require
it to resolve specifically to a commit, not merely any existing Git object.
Update the cat-file check near the existing last_commit error and ensure the
same validated commit-only value is used by the later merge-base call.
In `@src/mcp_server/types.rs`:
- Around line 238-243: Update the handoff prompt and its request examples to
explicitly include the required completed and remaining fields, matching the
fields defined on the structured payload in the relevant handoff types. Ensure
generated handoff requests contain both fields so they deserialize successfully.
---
Nitpick comments:
In `@src/mcp_server/handoff.rs`:
- Around line 79-92: Update the handoff item predicate in the find call so an
explicit thread_id takes precedence: require the item metadata thread to match
when thread_id is Some, allowing a name match only when the thread agrees; when
thread_id is None, retain name-based matching. Ensure a matching name cannot
override a conflicting thread ID.
In `@src/mcp_server/tests/artifact_tests.rs`:
- Around line 589-611: The test handoff_accepts_an_existing_last_commit_oid must
not panic when the source tree is not a live Git checkout. Before requiring
HEAD, probe rev-parse through worktree_repo_root() and return early when it
fails, or initialize an isolated temporary repository; preserve the existing
assertion for checkout environments.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 642210e0-0c4e-4695-b430-f0e29def2515
📒 Files selected for processing (5)
crates/agentflare-backend/src/item.rssrc/mcp_server/handoff.rssrc/mcp_server/item.rssrc/mcp_server/tests/artifact_tests.rssrc/mcp_server/types.rs
…oad off the DB lock (#366) - cargo fmt (item.rs claim closure, types.rs schemars doc attr) - item::claim: canonicalize both sides of the assignee/owner comparison so an alias owner (claude:1) isn't wrongly BlockedByAssignee against its own canonical handoff assignee (claude-code) - verify_continuation_commit: resolve the target branch under the backend DB lock, then run all git subprocess checks after releasing it, matching the existing item_claim split; validate oid is a plain hex id and force commit-type resolution (oid^{commit}) so a non-hex/flag-like value or a blob/tree/tag can't pass as a continuation commit - handoff_impl: reject empty completed/remaining instead of silently accepting an empty structured payload - mcp_prompts: document completed/remaining as required handoff fields so generated requests don't fail deserialization
…rning from racing concurrent with_temp_home callers The assertion read AGENTFLARE_HOME_OVERRIDE outside GLOBAL_STATE_LOCK, the lock that guards every set/remove of it. A concurrent thread's own correctly-scoped with_temp_home call could be transiently holding the var set at the exact moment this test read it, flaking the check on a var this test was never entitled to observe in the first place. Fix: acquire the same lock before reading.
Summary
Item #236 (Handoff hardening, QuorumGit adoption) — narrowed scope per the spec artifact's own 2026-07-28 review update:
HandoffRequest.last_commitis verified against the repo (git cat-file -e) and, when the item's owntask/<seq>branch already exists, checked for reachability from it (git merge-base --is-ancestor). A fabricated/typo'd OID is rejected — verified, not trusted.completed/remainingare now required fields,blockersoptional — all stored in the attached asset's metadata.handoffwithoutitem_idnow checks the recipient's existing open items for a name or thread match and reuses it instead of blindly creating a new one. Genuinely new work (no match) still auto-creates.agentflare_backend::item::claimgains aBlockedByAssigneeoutcome — a freshly handed-off, never-claimed item can only be claimed by its assignee until accepted. Excludes completed/cancelled items so reopening old work still works normally.Deferred, not silently dropped: the shim-side "deny push/commit to the handoff's branch by non-parties" half of the freeze spec. It needs new branch→item→assignee resolution wiring in
flare-git-shimmirroring the existing scope-check (#234), and the spec's own review note already downgraded it to defense-in-depth since the motivating incident (opencode stray-diff-on-main) is covered by #234's scope enforcement plus the opencode branch-guard plugin.Test plan
cargo test --workspace— 1676 tests, 0 failedcargo clippy --workspace --all-features -- -D warnings— cleanSummary by CodeRabbit
completed,remaining, optionalblockers, and optional commit references, and return these in handoff metadata.item_idisn’t provided, handoffs can reuse an existing matching open item (by name or thread).