Skip to content

fix(lease): reject a second live job on the same checkout path - #202

Open
rmems wants to merge 4 commits into
mainfrom
cursor/lease-live-path-uniqueness-00d2
Open

rmems wants to merge 4 commits into
mainfrom
cursor/lease-live-path-uniqueness-00d2

Conversation

@rmems

@rmems rmems commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

User description

Linear: RM-1412. Does not replace RM-825 / #203.

Why

LeaseStore::grant already refuses the same job id on a different live path. Different job ids could still share one unreleased worktree_path. An occupant SELECT followed by a separate INSERT is not atomic across independent SQLite connections: the mutex is per store/connection.

Change

  • Live-path uniqueness is one BEGIN IMMEDIATE grant plus a partial unique index on worktree_path WHERE released_at IS NULL.
  • Unique violations and occupant hits map to typed LEASE_CONFLICT (no silent seize).
  • Sequential release/re-register and historical released rows remain; lookup prefers the live row else the most recent released identity.
  • rusqlite query_row keeps the first row; query_one is what errors on extras (query_row_keeps_first_row_query_one_rejects_extras).
  • Two-connection tests: unconstrained SELECT+INSERT admits two live owners; LeaseStore::grant admits exactly one.

Analyzer follow-up

insert_or_refresh_writer takes a WriterRefresh bundle (two parameters) so CodeScene's four-argument limit is met. The two race tests are split under Codacy's 50-line method cap. Grant behavior is unchanged.

Head: c4763cfb4d5224448e6bdd2d988b01a1e454dcca.

Out of scope

Crash prepare/reconcile/tombstone (RM-825 / #203), coord messages/handoff, Foremerge/transport rewrites.

Linear Issue: RM-1412

Open in Web Open in Cursor 

Summary by cubic

Rejects granting a lease when another unreleased row already holds the same checkout path, so different job IDs can no longer share an active worktree. Enforcement is atomic across connections via a BEGIN IMMEDIATE transaction and a partial unique index on unreleased worktree_path, returning a typed LEASE_CONFLICT on either conflict. Path lookup now prefers the live row over released ones, fixing unregister/WorktreeRemove errors after sequential path reuse. Race regression tests were consolidated into lease/tests/grant.rs during the merge with main; grant behavior is unchanged.

Written for commit 4439ecf. Summary will update on new commits.

View guided diff Turn on auto-fix


CodeAnt-AI Description

Prevent multiple jobs from claiming the same active checkout

What Changed

  • A checkout already held by one job now rejects registration by another job, including simultaneous attempts.
  • After a checkout is released, another job can claim it; lookups return the active owner.

Impact

✅ Prevents shared active checkouts
✅ Clear lease-conflict errors
✅ Checkout paths reusable after release

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no actionable issue was identified in the changed code.

Summary

The PR adds tests for concurrent checkout-path claims and clarifies lease-conflict and row-query behavior.

  • The new two-connection test checks that only one grant succeeds and the other receives a typed conflict.
  • The unconstrained-table test demonstrates the race that the lease store must prevent.
  • Greptile automatically discovered a related ticket that helped explain the purpose of this PR: verifying atomic live-checkout ownership while preserving release and history behavior.

Reviews (1) · Last reviewed commit: "Merge origin/main into cursor/lease-live..." · Reviewed by Greptile

@coderabbitai

coderabbitai Bot commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Repository: rmems/writ/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b7fd1bb4-6ce7-4f65-ab6b-b54417199d3a
  • Autofix · 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.

@linear-code

linear-code Bot commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

RM-1412

@codecov

codecov Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codacy-production

codacy-production Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 2 duplication

Metric Results
Duplication 2

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

cursor Bot pushed a commit that referenced this pull request Sep 23, 2026
…queness

Refresh #203 onto current main so status/watchlist Unknown/mode_raw/row_id
and Attribution/Watchlist CLI stay intact next to prepare/reconcile/tombstone
and generation-matched handoff.

Consume the #202 live-checkout uniqueness invariant at the register/grant
boundary: unique partial index on live worktree_path, occupant check inside
BEGIN IMMEDIATE, constraint mapped to LEASE_CONFLICT, find_by_path prefers
the live row. Do not seize WIP or grant duplicate live ownership when the
binding store is available.

Refs: RM-825, RM-1412, #202, #136

Agent: Cursor Grok 4.6

Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>
cursor Bot pushed a commit that referenced this pull request Sep 23, 2026
finalize_by_path looked up by worktree_path without preferring the live
row, so a second job on a reused checkout could be skipped and left
ACTIVE. Select the live row (same order as find_by_path) and update by
row id.

Adapt watchlist view tests to the coord schema that LeaseStore::open now
installs; missing-table overlay remains covered in coord_read tests.

Refs: RM-825, RM-1412, #202

Agent: Cursor Grok 4.6

Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>
Comment thread crates/writ-core/src/lease.rs Outdated
@rmems

rmems commented Oct 1, 2026

Copy link
Copy Markdown
Owner Author

Analyzer follow-up on draft PR #202. Still draft. Not merged.

HEAD: c4763cfb4d5224448e6bdd2d988b01a1e454dcca

  • CodeScene Excess Number of Function Arguments on insert_or_refresh_writer: the writer insert now takes a WriterRefresh bundle (2 arguments; limit is 4). Replied and resolved discussion 4078097756.
  • Codacy method-length findings: select_then_insert_without_constraint_admits_two_live_owners (58) and concurrent_grants_admit_one_live_owner (51) are split into helpers, each under the 50-line cap.
  • Live-path uniqueness is unchanged: BEGIN IMMEDIATE, partial unique index leases_live_worktree_path, typed LEASE_CONFLICT.

Local gates on this HEAD: cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings, and cargo test --workspace passed (writ-core 344 tests, including both race tests).

Agent: Cursor

codescene-access[bot]

This comment was marked as outdated.

@linear-code
linear-code Bot marked this pull request as ready for review October 1, 2026 01:28
@codeant-ai

codeant-ai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Incremental review completed 4439ecf Oct 09, 2026 · 07:23 07:23
✅ Incremental review completed 0981b8b Oct 01, 2026 · 03:01 03:01
✅ Reviewed your PR c4763cf Oct 01, 2026 · 01:28 01:30

@codeant-ai

codeant-ai Bot commented Oct 1, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Oct 1, 2026

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Devin Review

Comment thread crates/writ-core/src/lease.rs Outdated
Comment on lines +404 to +405
CREATE UNIQUE INDEX IF NOT EXISTS leases_live_worktree_path
ON leases(worktree_path) WHERE released_at IS NULL;

@devin-ai-integration devin-ai-integration Bot Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Legacy lease collisions block store startup

When an existing store has two live jobs on one path, LeaseStore::open fails while creating the unique index. Registration, unregister, and hooks cannot open that store to resolve the collision.

Learn more

The previous schema permits distinct job IDs to hold unreleased rows for one checkout path. LeaseStore::open now runs the new unique-index statement against every existing database. SQLite rejects the index when such rows exist, so the store cannot open for writes; unregister also needs a writable store to release a lease. A migration must address existing duplicates before enforcing uniqueness, while preserving the identities needed for recovery.

Example: A pre-upgrade database contains live job-a and job-b rows for /checkouts/shared. After upgrade, the first writ worktree unregister /checkouts/shared fails opening the database, rather than releasing the collision.

Recommended fix: Add a migration that detects conflicting live rows before CREATE UNIQUE INDEX, resolves or explicitly quarantines them without silently granting either job ownership, and then creates the index. Provide a focused upgrade test using a database built with the previous schema and duplicate active paths.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread crates/writ-core/src/lease.rs Outdated
Comment on lines +294 to +297
ORDER BY CASE WHEN released_at IS NULL THEN 0 ELSE 1 END,
COALESCE(released_at, 0) DESC,
id DESC
LIMIT 1",

@devin-ai-integration devin-ai-integration Bot Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Rapid checkout reuse reports wrong released job

When a lower-ID job reuses and releases a checkout within the same second as a higher-ID job, find_by_path selects the higher ID. release_by_path then reports the wrong job as released.

Learn more

The database keeps released lease rows so different jobs can reuse one path. release_by_path stamps its updated row with Unix seconds, then calls find_by_path to return the released lease. If another row at that path was released in the same second, sorting by id DESC does not identify which row was updated. The row IDs represent initial insertion, not release order.

Example: job-a has ID 1 and job-b has ID 2. Both release /checkouts/shared at timestamp 100; job-a releases last after reclaiming it, but release_by_path returns job-b because its ID is larger.

Recommended fix: Return the row actually updated by release_by_path, preferably with an atomic UPDATE ... RETURNING or by retaining its row ID inside a transaction. Do not infer the last released row from second-resolution timestamps and insertion IDs.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread crates/writ-core/src/lease.rs Outdated
Comment on lines +293 to +297
where_sql: "WHERE worktree_path = ?1
ORDER BY CASE WHEN released_at IS NULL THEN 0 ELSE 1 END,
COALESCE(released_at, 0) DESC,
id DESC
LIMIT 1",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: After release_by_path updates its row, a concurrent registration can claim the path before this lookup, so unregister returns the new live lease instead of the lease it released.

Assessment: 🟠 Major · 🔁 Occurrence: Rarely · 🏷️ Api mismatch

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** crates/writ-core/src/lease.rs
**Line:** 293:297
**Comment:**
	*Api Mismatch: After `release_by_path` updates its row, a concurrent registration can claim the path before this lookup, so unregister returns the new live lease instead of the lease it released.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment thread crates/writ-core/src/lease.rs Outdated
Comment on lines +404 to +405
CREATE UNIQUE INDEX IF NOT EXISTS leases_live_worktree_path
ON leases(worktree_path) WHERE released_at IS NULL;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Opening an existing database containing duplicate live paths now fails while creating this index, so all writable lease operations become unavailable instead of migrating the old state.

Assessment: 🔴 Critical · 🔁 Occurrence: Sometimes · 🏷️ Api mismatch

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** crates/writ-core/src/lease.rs
**Line:** 404:405
**Comment:**
	*Api Mismatch: Opening an existing database containing duplicate live paths now fails while creating this index, so all writable lease operations become unavailable instead of migrating the old state.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment thread crates/writ-core/src/lease.rs Outdated
)
.map_err(|e| lease_err("grant lease", e))?;
let mut conn = self.lock()?;
grant_on(&mut conn, grant)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Another connection can release or re-register this job after grant_on commits but before find_job, causing grant to return a different or released lease.

Assessment: 🟠 Major · 🔁 Occurrence: Rarely · 🏷️ Race condition

Use CodeAnt Skill Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** crates/writ-core/src/lease.rs
**Line:** 193:199
**Comment:**
	*Race Condition: Another connection can release or re-register this job after `grant_on` commits but before `find_job`, causing `grant` to return a different or released lease.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

cubic-dev-ai[bot]

This comment was marked as resolved.

@rmems rmems added bug Something isn't working core safety rust labels Oct 1, 2026 — with Cursor
cursoragent and others added 3 commits October 1, 2026 03:01
Same-job path conflicts already fail closed. Different job ids could still
share an unreleased worktree_path, after which find_by_path used query_row
and unregister/WorktreeRemove could error. Prefer the active row on lookup
so sequential reuse after release still returns one identity.

Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>
The occupant SELECT plus INSERT was not a single SQLite decision: the
store mutex is per connection, so two LeaseStore::open handles could both
observe an empty path. Grant now uses BEGIN IMMEDIATE and a partial unique
index on unreleased worktree_path, mapping unique violations to
LEASE_CONFLICT.

Document rusqlite query_row (first row) versus query_one (errors on extras).
Sequential release/re-register and Unknown modes are unchanged.

Refs RM-1412; consumed by RM-825/#203.

Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>
Bundle the writer refresh inputs so insert_or_refresh_writer stays under
the four-argument limit, and split the two race tests that exceeded
Codacy's 50-line method cap. Live-path uniqueness is unchanged.

Refs RM-1412.

Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>
@rmems
rmems force-pushed the cursor/lease-live-path-uniqueness-00d2 branch from c4763cf to 0981b8b Compare October 1, 2026 03:01
codescene-access[bot]

This comment was marked as outdated.

rmems added a commit that referenced this pull request Oct 6, 2026
#203)

* feat(lease): crash-consistent registration for harness-owned checkouts

Salvage the RM-825 prepare/inspect/reconcile, tombstone, TTL, and
fix_cycles journal from #185 onto the #199 register path. Writ no longer
treats git worktree add as the mutation boundary; identity is persisted
before ownership grant. Same-host coord claims/messages/handoff from
#198 sit on the same leases.db.

Closes #136. Linear: RM-825.

Agent: Cursor Grok 4.6

Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* fix(lease): release the live path holder after sequential reuse

finalize_by_path looked up by worktree_path without preferring the live
row, so a second job on a reused checkout could be skipped and left
ACTIVE. Select the live row (same order as find_by_path) and update by
row id.

Adapt watchlist view tests to the coord schema that LeaseStore::open now
installs; missing-table overlay remains covered in coord_read tests.

Refs: RM-825, RM-1412, #202

Agent: Cursor Grok 4.6

Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* refactor(coord): flatten analyzer criticals without behavior change

Split classify/register/overlapping_paths into helpers, share Display residuals,
exclude coordination surfaces from Codacy complexity like checkout.rs, and move
writ coord CLI into its own module with a shared job_field for Show/Inbox.

Agent: Cursor
Cited by: Writ Kernel Steward (Grok Bot)

Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* refactor: clear CodeScene gates and qlty init_repo clone

Share CLI test init_repo, split lease into schema/classify/occupant
modules, and flatten remaining CodeScene gate findings without changing
lease or coord behavior.

Agent: Cursor
Cited by: Writ Kernel Steward (Grok Bot)

Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* refactor(lease): split crash recover and tests for CodeScene health

Extract types/query/fix_cycle/recover modules and shared CLI/test helpers
so lease/mod.rs drops under the file-size gate and remaining Large Method,
duplication, and cohesion findings on the 2fc279a CodeScene run clear.
Lease and coord behavior is unchanged.

Agent: Cursor
Cited by: Writ Kernel Steward (Grok Bot)

Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* refactor(lease): split store surfaces and unify recover updates

Move grant/allocate/agents/util out of lease/mod.rs to drop Low Cohesion,
and fold promote/attention SQL plus abort/attention entrypoints in recover
so CodeScene duplication and qlty similar-code on apply_* clear.

Agent: Cursor
Cited by: Writ Kernel Steward (Grok Bot)

Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* fix(core): enforce lease transitions and scope overlaps by repository

Repair legacy migrations and recovery; preserve unknown states and allow released leases to be tombstoned.

Agent: Codex
Co-authored-by: Codex <noreply@openai.com>

* fix(core): mill Codex P1/P2 lease and coord recovery findings

Validate checkout identity before resume, enforce the owner allowlist on
lease/coord, and prove git common-dir identity before promote. Close the
remaining mailbox, inspect, grant, and recovery gaps with tests.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(core): mill CodeScene hotspot and new-file health on #203

Extract the lease CLI from main.rs, bundle excess query/grant/coord/view
arguments, and split large allocate/grant/dispatch methods. Behavior is
unchanged; this is extract/dedupe only for the required CodeScene gate.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(core): mill Windows path assert, CodeScene, and Codex P2s on #203

Use OS-correct Path::ends_with for the interrupted-resume checkout test.
Bundle seed/announce test args, split coord CLI write handlers, and shrink
grant/announce. Canonicalize declared `.`/`..` paths, match worktrees via
NUL porcelain -z, require MUTATE before fix-cycle commit, store detached
HEAD as HEAD, and print lease payloads in human mode.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(core): extract coord declared-path helpers below CodeScene file limit

Move encode/normalize of declared paths into coord/declared_paths.rs so
writ-core coord production LOC and normalize_one complexity sit under the
CodeScene thresholds from HEAD 80d7f26. Overlap canonicalization is unchanged.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli): collapse coord show/inbox clone that blocked qlty

Show and Inbox now share load_coord_read so qlty similar-code mass=52
is one JobKey lookup plus a claim vs inbox load. Envelope behavior is
unchanged.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(codacy): exclude modularized coord/ from complexity engines

Coord lives at crates/*/src/coord/** after the file-to-module split, so
the old coord.rs glob no longer covered mod.rs. Complexity/metric/lizard
now use the directory glob; security engines stay enabled.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli): extract execute_announce so execute_offer is under Codacy LOC

Codacy flagged execute_offer at 51 lines (limit 50). Announce is its own
helper; envelopes are unchanged.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(core): mill Codex P1/P2 findings on handoff, classify, and watchlist

Validate handoff ACK owner/repo/job before transferring. Require stored
repo identity before Retryable classify. Default watchlist lists live
nonterminal leases, overlays blockers, and drops stale-generation
handoffs. Announce reloads the ACTIVE lease inside the write txn; coord
show/list/inbox open the store read-only.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(lease): match inspect --repo against stored git common dir

Registration stores the checkout common dir as lease.repo, while inspect
passes the working-tree root. Compare both spellings so Retryable still
requires stored-repo identity without classifying live registrations as
needs-attention.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(codescene): split coord/mod.rs and flatten classify retryable

Move coord types, row access, announce/overlap, and tests out of
coord/mod.rs so the new-file Lines of Code gate no longer fails.
Extract retryable_without_git_mutation so classify_terminal_or_retryable
has no compound match-guard. Behavior is unchanged.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(codescene): split coord ACK path and collapse lease-lookup dup

access.rs failed CodeScene (duplication + complex conditional, health
9.10) after the first split. Move ACK/handoff checks into ack.rs and
share require_active between live_lease and the in-txn lookup. Behavior
is unchanged.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli): share read-only lease store open for coord and inspect

qlty similar-code (mass 111) flagged the identical metadata/open_read_only
match arms in coord show/list/inbox and lease inspect. One helper in
store.rs; envelopes and missing-file vs non-file errors are unchanged.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(core): mill remaining CodeRabbit correctness threads

1. Alias legacy SELECT crash-consistency columns in a subquery so
   list_active/find_by_path work on an unmigrated parent leases.db.
2. grant only Active/Released rows; interrupted states need reconcile.
3. Scope broadcast ACKs to the sender owner and repository.
4. Reject absolute or repo-escaping declared paths instead of dropping.
5. Tombstoned leases report recovery_needed false.
6. Watchlist maps NEEDS_ATTENTION/Unknown to Conflicted, matching status.
7. coord show/list/inbox already open via open_existing_read_only_store
   (4b31715); keep that path and the absent-store CLI test.

Agent: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(lease): guard recovery writes against stale state

Require recovery updates and aborts to match the allocation state that was inspected so a newer transition is preserved for reconciliation.

Agent: Codex
Co-authored-by: Codex <noreply@openai.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* fix(lease): serialize legacy schema migration

Configure SQLite before taking an immediate transaction so concurrent legacy-store opens cannot race the conditional column additions.

Agent: Codex
Co-authored-by: Codex <noreply@openai.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* fix(lease): retry concurrent WAL setup

Concurrent legacy-store opens can receive SQLITE_BUSY or SQLITE_LOCKED while another connection enables WAL mode, even after installing a busy timeout. Retry only those transient results before the already-serialized schema migration.

Agent: Codex
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f

* fix(coord): close stale assignment races

Bind coordination reads and writes to current lease and owner generations, invalidate stale handoffs on regrant, and keep legacy read-only stores usable. Fail closed when fix-cycle or checkout reconciliation evidence is replaced concurrently.

Agent: Codex
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f

* refactor(coord): simplify consistency guards

Keep the transactional pause checks and reconciliation identity binding unchanged while extracting focused helpers and deduplicating regression fixtures.

Agent: Codex
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f

* test(coord): isolate consistency regressions

Keep operation replacement and source-generation cases focused while sharing only their fixture setup.

Agent: Codex
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f

* refactor(watchlist): reuse coordination identity

Represent message sources and recipients with the existing JobId value type instead of parallel identity fields.

Agent: Codex
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f

* fix(coord): close transactional consistency gaps

Revalidate message senders under the write lock and assemble watchlist lease and coordination data from one SQLite snapshot.

Agent: Codex
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f

* test(watchlist): consolidate message fixtures

Keep blocker and stale-handoff expectations in one table-driven test so the quality gate does not treat their setup as duplicated logic.

Agent: Codex
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f

* fix(lease): verify interrupted checkout branch

Require a named interrupted allocation to remain checked out on its recorded symbolic branch before classifying the registration as matching.

Agent: Codex
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Blocks Task Runner <montoyaraul34@gmail.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* fix(coord): close stale identity gaps

Invalidate stale coordination state, bind mutations to current lease identity, and keep recovery and checkout classification fail-closed.

Co-authored-by: Blocks Task Runner <montoyaraul34@gmail.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* refactor(coord): simplify ack and crash tests

Keep acknowledgement behavior transactional while separating its validation and persistence steps. Group crash-consistency tests by allocation, identity, and recovery concerns.

Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* refactor(coord): trim ack builder arguments

Build the existing NewMessage value separately so ACK insertion stays focused and below the advisory argument threshold.

Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* fix(coord): keep assignment state current

Publish overlap notices to both affected jobs, remove pending overlap state when a lease is finalized, and reject active registration after checkout identity changes. Align the README architecture summary with implemented same-host coordination.

Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* refactor(coord): clear code health gates

Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

* docs: describe implemented coordination

Amp-Thread-ID: https://ampcode.com/threads/T-01a0fff8-02d8-744b-8ccf-be23a0e6f79f
Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Amp <amp@ampcode.com>
Resolve modify/delete on lease.rs by keeping main's lease/ module and
porting PR-only live-path race regression tests into lease/tests/grant.rs.

Resolve checkout.rs by keeping both register_second_job_for_same_path_fails
and register_keeps_unknown_allocation_state_non_retryable.

Co-authored-by: Raul Cardenas Montoya <montoyaraul34@gmail.com>

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

Gates Passed
6 Quality Gates Passed

See analysis details in CodeScene

Quality Gate Profile: Pay Down Tech Debt
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.

@codeant-ai

codeant-ai Bot commented Oct 9, 2026

Copy link
Copy Markdown

CodeAnt PR Risk: Medium Risk

  • The PR needs attention before merging: the visible tests do not resolve credible lease-store migration and concurrency concerns.
  • Verify that existing databases with duplicate live paths remain usable if live-path uniqueness is enforced.
  • The concurrent-grant test checks competing grants, but not whether grant or unregister can return a lease changed by another connection.

Assessed commit: 4439ecf10d42

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working core rust safety size:L This PR changes 100-499 lines, ignoring generated files

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants