Skip to content

fix(GenesisHub): a link's commit range that ends in commits the PR's checkout has not pushed yet opens that range from the checkout, with a note, instead of the whole MR - #595

Merged
genesiscz merged 2 commits into
masterfrom
fix/2026-10-26-hub-local-commit-range
Oct 26, 2026
Merged

genesiscz merged 2 commits into
masterfrom
fix/2026-10-26-hub-local-commit-range

Conversation

@genesiscz

Copy link
Copy Markdown
Owner

A hub link such as commit=<from>..<to> can name commits an agent made but did not push yet. The forge does not list them, so the hub fell back to the whole PR. Now it looks in the PR's checkout first.

What it changes

  • HubLocalCommits.resolve reads both ends from the checkout's git, off the main thread. It accepts the range only when the last commit descends from the PR's pushed head, and the first is one of the PR's commits or comes after that head. A commit from before the PR would show the base's changes, so it is refused.
  • The diff then comes from the checkout: the PR's own base when the range starts at the PR's first commit, else the first commit's first parent from git (the rule rangeScope follows). The commits list marks the pushed commits the range covers.
  • A note says how many commits of the link are not pushed yet. It is shown as information, not as an error.

This commit was split out of #590. It was written on the unified branch against the older linkedRange: DiffScope?, so on master it is adapted to PRLinkedRange (scope plus the shas it marks).

Checks

  • swift test --package-path src/macos/GenesisTools --disable-build-manifest-caching --filter HubLogicTests: 63 tests, 0 failures, including testALinkRangeOfUnpushedCommitsResolvesFromTheCheckout.
  • check-commits.ts: 1 commit, 0 to fix. Personal-data probe: no matches.
  • Not checked live: the installed app was not rebuilt from this branch.

@eve-bot-lovinka

eve-bot-lovinka Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

🐉 eve review — ✅ APPROVE · 2 findings

→ review · run

  • Queued 01:21:30Z
  • Reading diff — 134 files
  • Building repo map
  • Analyzing (find → verify) — 2 candidates → 2 survivors · reviewed by find codex/gpt-6.1-sol + codex/gpt-6-luna, verify codex/gpt-6-luna
  • Posting review
  • Review posted 01:32:10Z (10m 41s)

run wrun_01M5TWRVYNVTTC8ZBTHER1SPY5

Previous runs (2)
run head outcome findings took
2 437ff28 ✅ APPROVE 0 9m 20s
1 9a3f2be ✅ APPROVE 3 2m 10s

@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Next included review available in 3 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 3 included reviews currently available. Your 43 included PR review attempts over the past 7 days set your current allowance at 3 reviews per hour.

Learn how review limits work.

Review configuration:

Run configuration
Commits

Reviewing files that changed from the base of the PR and between 47713be and 4c75a85.

Files selected for processing: 3
  • src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubCommitLink.swift
  • src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubPRs.swift
  • src/macos/GenesisTools/Tests/HubLogicTests.swift
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@eve-bot-lovinka eve-bot-lovinka 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.

🐉 eve review — 🟡 Review comments

9a3f2be · 3 actionable findings · reviewed by find codex/gpt-6.1-sol, verify codex/gpt-6-luna · view run ↗

Severity Count
🟡 Medium 2
🔵 Low 1

Blast radius

  • git (+) → 3 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Host/App/ChildEnvironment.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubWorktrees.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubComponents.swift
  • graph truncated by caps — dependents above are a lower bound

ℹ️ Claims vs diff — 6 claims could not be checked from the diff (c1, c2, c3, c4, c5, c6).

Comment thread src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubCommitLink.swift Outdated
Comment thread src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubPRs.swift
Comment thread src/macos/GenesisTools/Tests/HubLogicTests.swift Outdated
genesiscz added a commit that referenced this pull request Oct 26, 2026
@genesiscz

Copy link
Copy Markdown
Owner Author

Review fixes 2026-10-26 02:07 from GPT-6.1 Sol judged by Claude Opus 5.5 (fable-judge)

Round 1. 3 open threads (eve 3, CodeRabbit 0). 3 fixed, 0 rejected, 0 already done. Full PR self-review found no additional defects. Only the PR's three existing Swift files changed. Commit 437ff28 completed before the lead changed this worker to fixes only. Swift tests: not run (the lead verifies at integration).

Count only unpushed commits within the linked inclusive range (eve-bot-lovinka)

  • Context: The head..last query counted earlier unpushed commits before the link's first endpoint. Later single-commit links and local subranges therefore overstated the notice.
  • Commit(s): 437ff289e
  • Verdict: accepted
  • Code before:
    let unpushed = Int(git(repo, ["rev-list", "--count", head + ".." + last])?
        .trimmingCharacters(in: .whitespacesAndNewlines) ?? "") ?? 0
  • Code after:
    let unpushedAfterFirst = Int(git(repo, ["rev-list", "--count", "--ancestry-path=" + first, first + ".." + last, "--not", head])?
        .trimmingCharacters(in: .whitespacesAndNewlines) ?? "") ?? 0
    let unpushed = unpushedAfterFirst + (isAncestor(first, of: head, repo: repo) ? 0 : 1)
  • How was this fixed: Count descendants of the first endpoint through the last endpoint, explicitly anchor Git's ancestry path at first, exclude commits reachable from the pushed head, and include the first endpoint once if unpushed. Extended testALinkRangeOfUnpushedCommitsResolvesFromTheCheckout for later single commits, equal endpoints, all-local and later subranges, reversed endpoints, pushed-only commits, and a merged side commit outside the first endpoint's ancestry path. Swift tests: not run (the lead verifies at integration).
  • Confidence: 92%

Discard superseded local lookups before applying either outcome (eve-bot-lovinka)

  • Context: A second link to the same PR can reuse the ReviewModel. Checking only PR and review identity allowed an older local lookup to replace the newer scope or reset it to the whole PR.
  • Commit(s): 437ff289e
  • Verdict: accepted
  • Code before:
    guard let self, self.reviewPRID == shown.id, self.review === review else { return }
    switch found {
  • Code after:
    guard let self, self.reviewPRID == shown.id, self.review === review else { return }
    self.finishRangeLookup(lookup) {
        switch found {
  • How was this fixed: Local lookup starts now take a fresh rangeLookup token. Both local-commit and parent lookups use beginRangeLookup/finishRangeLookup, and request() invalidates that shared token. Every local success and failure is inside the guarded completion. Added testANewPRLinkDiscardsBothOutcomesOfAnOlderLocalLookup for single, range, invalid and whole-PR requests, rejection of stale completions while a newer lookup runs, and one-time application of the current completion. Swift tests: not run (the lead verifies at integration).
  • Confidence: 91%

Isolate fixture commits from machine signing and hooks (eve-bot-lovinka)

  • Context: The checkout fixture supplied an invented author but inherited global signing and hook settings, which could fail commits or invoke developer hooks.
  • Commit(s): 437ff289e
  • Verdict: accepted
  • Code before:
    process.arguments = ["-C", repo, "-c", "user.name=Fixture", "-c", "user.email=fixture@example.com"] + args
  • Code after:
    process.arguments = ["-C", repo, "-c", "user.name=Fixture", "-c", "user.email=fixture@example.com",
                         "-c", "core.hooksPath=/dev/null", "-c", "commit.gpgsign=false"] + args
  • How was this fixed: The existing fixture's Git helper now passes core.hooksPath=/dev/null and commit.gpgsign=false on every command, matching the adjacent fixtures. The existing and expanded testALinkRangeOfUnpushedCommitsResolvesFromTheCheckout uses that helper. Swift tests: not run (the lead verifies at integration).
  • Confidence: 95%

Threads: t1 accepted · t2 accepted · t3 accepted

@eve-bot-lovinka eve-bot-lovinka 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.

🐉 eve review — ✅ Approved

437ff28 · 0 actionable findings · reviewed by find codex/gpt-6.1-sol, verify codex/gpt-6-luna · view run ↗

…checkout has not pushed yet opens that range from the checkout, with a note, instead of the whole MR
@genesiscz
genesiscz force-pushed the fix/2026-10-26-hub-local-commit-range branch from 437ff28 to 4c75a85 Compare October 26, 2026 01:21
@genesiscz
genesiscz merged commit 4c75a85 into master Oct 26, 2026
5 checks passed

@eve-bot-lovinka eve-bot-lovinka 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.

🐉 eve review — 🟡 Review comments

4c75a85 · 2 actionable findings · reviewed by find codex/gpt-6.1-sol + codex/gpt-6-luna, verify codex/gpt-6-luna · view run ↗

Severity Count
🟡 Medium 1
🔵 Low 1

Blast radius

  • git (+) → 3 dependent(s) outside this PR: src/macos/GenesisTools/Tests/HubMenuButtonTests.swift, src/macos/GenesisTools/Tests/HubPollGateTests.swift, src/macos/GenesisTools/Tests/ReviewVersionsTests.swift
  • graph truncated by caps — dependents above are a lower bound

} catch {
return nil
}
let data = out.fileHandleForReading.readDataToEndOfFile()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚡ Performance | 🟡 Medium · confidence 92/100

⚠️ Potential issue

Bound the local git subprocess waits with a deadline

The new local lookup blocks on both readDataToEndOfFile() and waitUntilExit() without any deadline or cancellation. Moving this to a detached task protects the UI thread, but a stalled git process (for example on an unavailable filesystem) leaves the link unresolved indefinitely, and subsequent links can accumulate more blocked tasks and children. Invalidating rangeLookup only discards the eventual answer; it does not stop the process. This violates the project review-memory rule that every wait needs a deadline and an explicit expiry outcome. Bound the entire subprocess operation, terminate/reap it on expiry, and surface a lookup failure rather than leaving it pending.

🧩 Analysis

Grep evidence: readDataToEndOfFile\(|waitUntilExit\(|HubLocalCommits.resolve

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Accepted. The follow-up will bound the local git subprocess waits with a deadline. The pull request was merged after its fix rounds, so this finding waits for a follow-up, and this thread stays open until then.

let pushed = Set(shas[1 ... 2])
let range = try XCTUnwrap(try? HubLocalCommits.resolve(
ends: [String(shas[2].prefix(10)), String(shas[4].prefix(10))], repo: repo, head: pushedHead, pushed: pushed).get())
XCTAssertEqual(range, HubLocalCommits(first: shas[2], last: shas[4], count: 3, unpushed: 2, title: "commit 4"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧪 Tests | 🔵 Low · confidence 93/100

⚠️ Potential issue

Test application of a resolved local range to the review

The new fixture verifies HubLocalCommits.resolve, and the other new test verifies request-token invalidation, but neither exercises showLocalCommits. Consequently the user-visible half of this fix—the PR-base versus first-parent scope choice, PRLinkedRange pushed-sha marking, and informational notice—is not asserted. Existing rangeScope tests exercise the separate forge-listed path, not the new implementation. Add model-level coverage applying local results for a range starting at the PR's first commit, a later pushed commit, and a local-only commit, asserting scope, linkedRange.shas, and notice.isError/count. These are explicit promises in the PR description and can regress while the resolver fixture continues passing.

🧩 Analysis

Grep evidence: showLocalCommits|testALinkRangeOfUnpushedCommitsResolvesFromTheCheckout|testANewPRLinkDiscardsBothOutcomesOfAnOlderLocalLookup

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Accepted. The follow-up will test application of a resolved local range to the review. The pull request was merged after its fix rounds, so this finding waits for a follow-up, and this thread stays open until then.

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