Repository navigation
fix(GenesisKit, markdown, git): the git sidebar's Changes list shows moves as renames, the newest change first, and scrolls 3 to 5 times cheaper - #572
Conversation
|
🐉 eve review — ⏭️ superseded → run
run Previous runs (10)
|
|
Warning Review limit reachedEnable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. Next included review available in 14 minutes. View limit details
Comment |
There was a problem hiding this comment.
🐉 eve review — ✅ Approved
fe82f85· 0 actionable findings · reviewed by codex/gpt-6.1-sol + codex/gpt-6-luna · view run ↗
Blast radius
Keyed(+) → 12 dependent(s) outside this PR: src/macos/GenesisKit/Sources/GenesisKitCharts/TreemapView.swift, src/macos/GenesisKit/Sources/GenesisKitCharts/HealthBar.swift, src/macos/GenesisKit/Sources/GenesisKit/Sessions/Transcript/TranscriptBus.swift, +9 morereadKitFixtureJson(Δsig) → 9 dependent(s) outside this PR: src/macos/commands/clones/reclaim.test.ts, src/macos/commands/clones/optimize.test.ts, src/macos/lib/kit-fixtures.test.ts, +3 moreRecent(+) → 9 dependent(s) outside this PR: src/macos/GenesisKit/Tests/GenesisKitTests/Markdown/MarkdownRecentsTests.swift, src/macos/GenesisKit/Sources/GenesisKit/Sessions/Transcript/TranscriptScrollAnchor.swift, src/macos/GenesisKit/Sources/GenesisKit/Flow/FlowWidget.swift, +6 morecontrols(~) → 8 dependent(s) outside this PR: native/ax-tool/Sources/main.swift, native/ax-tool/Sources/IsolatedCapture.swift, native/ax-tool/Sources/commands/Harness.swift, +5 morerunGit(+) → 8 dependent(s) outside this PR: scripts/ci/pre-commit-hook.test.ts, plugins/genesis-tools/skills/git/evals/fixtures/build.ts, src/scripts/commands/git.ts, +5 moreKey(~) → 7 dependent(s) outside this PR: native/ax-tool/Sources/main.swift, native/ax-tool/Sources/Record.swift, native/ax-tool/Sources/commands/Harness.swift, +4 morepair(+) → 7 dependent(s) outside this PR: native/ax-tool/Sources/SnapshotWorkflow.swift, native/ax-tool/SnapshotSupport/VisualCapture.swift, native/ax-tool/SnapshotSupport/OcrReuse.swift, +4 moreupdate(~) → 7 dependent(s) outside this PR: native/ax-tool/Sources/Record.swift, native/ax-tool/Sources/IsolatedCapture.swift, native/ax-tool/Sources/utils/Output.swift, +4 moreContract(+) → 6 dependent(s) outside this PR: src/macos/commands/clones/optimize.ts, src/benchmark/lib/baseline.ts, src/utils/fs/disk-usage.test.ts, +3 moreIdentity(+) → 6 dependent(s) outside this PR: native/ax-tool/SnapshotSupport/IsolatedComposition.swift, src/macos/GenesisKit/Sources/GenesisKit/Settings/KitSettingsBackend.swift, src/macos/GenesisKit/Sources/GenesisKit/Clicky/ClickyPacks.swift, +3 more- +28 more changed symbol(s) with outside dependents
ℹ️ Claims vs diff — 8 claims could not be checked from the diff (c1, c2, c3, c4, c5, c6, c7, c8).
fe82f85 to
18b40f5
Compare
b37dcf5 to
f7c6aed
Compare
There was a problem hiding this comment.
🐉 eve review — 🟡 Review comments
f7c6aed· 5 actionable findings · reviewed by find codex/gpt-6.1-sol + codex/gpt-6-luna, verify codex/gpt-6-luna · view run ↗
| Severity | Count |
|---|---|
| 🟡 Medium | 4 |
| 🔵 Low | 1 |
Blast radius
Keyed(+) → 12 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Host/Notify.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubSessionInsights.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubTimeline.swift, +9 morecontrols(~) → 9 dependent(s) outside this PR: native/ax-tool/Sources/commands/Harness.swift, native/ax-tool/SnapshotSupport/HierarchySource.swift, src/macos/GenesisTools/Package.swift, +6 moreKey(~) → 9 dependent(s) outside this PR: native/ax-tool/Sources/commands/Annotate.swift, native/ax-tool/Sources/commands/Harness.swift, native/ax-tool/Sources/main.swift, +6 morereadKitFixtureJson(Δsig) → 9 dependent(s) outside this PR: src/du/lib/index/index.test.ts, src/macos/commands/clones/reclaim.test.ts, src/macos/commands/clones/optimize.test.ts, +3 moreRecent(+) → 9 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubNotify.swift, src/macos/GenesisTools/Sources/Parts/Features/Settings/DaemonSettings.swift, src/macos/GenesisKit/Sources/GenesisKit/Markdown/Document/VaultIndex.swift, +6 morepair(+) → 8 dependent(s) outside this PR: native/ax-tool/Sources/SnapshotWorkflow.swift, native/ax-tool/SnapshotSupport/FrameSampler.swift, native/ax-tool/SnapshotSupport/ContextMenu.swift, +5 morerunGit(+) → 8 dependent(s) outside this PR: scripts/ci/pre-commit-hook.test.ts, src/utils/agent-sessions/testing/fixture-world.ts, src/utils/git/test-repo.ts, +5 moreheader(+) → 7 dependent(s) outside this PR: native/ax-tool/Sources/commands/Annotate.swift, src/macos/GenesisTools/Tests/ReviewScopeChipShots.swift, src/macos/GenesisTools/Tests/HubNavigationTests.swift, +4 moreupdate(~) → 7 dependent(s) outside this PR: native/ax-tool/Sources/Record.swift, native/ax-tool/Sources/IsolatedCapture.swift, native/ax-tool/Sources/utils/Output.swift, +4 moreapply(+) → 6 dependent(s) outside this PR: native/ax-tool/Sources/SnapshotWorkflow.swift, native/ax-tool/SnapshotSupport/ContextMenu.swift, native/ax-tool/SnapshotSupport/VisualCapture.swift, +3 more- +26 more changed symbol(s) with outside dependents
ℹ️ Claims vs diff — 7 claims could not be checked from the diff (c1, c2, c3, c4, c5, c6, c7).
e1c71e7 to
bc86241
Compare
…section, rename identity uses every candidate, date invalidation waits for its result, and staged files keep their index paths
f7c6aed to
47dae8a
Compare
Review fixes 2026-10-26 03:14 from GPT-6.1 Sol judged by Claude Opus 5.5 (fable-judge)Round 1. 5 open threads (eve 5, CodeRabbit 0). All 5 fixed, 0 rejected, 0 already done. Full self-review of the 32 changed files added 2 fixed findings. Fixed in 802af50; the lead ran the tests and committed. Reveal unfolds the file's containing section (eve-bot-lovinka)
Resolve file rename identity from the complete candidate set (eve-bot-lovinka)
Keep date invalidation pending until its result is applied (eve-bot-lovinka)
Keep staged files at their index paths when moved outside git (eve-bot-lovinka)
Update the public repository panel example (eve-bot-lovinka)
Keep quote-prefixed paths literal in the hash batch (self-review, no thread)
Follow shared environment and diagnostic contracts (self-review, no thread)
Threads: t1 accepted · t2 accepted · t3 accepted · t4 accepted · t5 accepted |
…section, rename identity uses every candidate, date invalidation waits for its result, and staged files keep their index paths
47dae8a to
efcd6de
Compare
241716b to
d5ea372
Compare
There was a problem hiding this comment.
🐉 eve review — 🟡 Review comments
efcd6de· 3 actionable findings · reviewed by find codex/gpt-6.1-sol + codex/gpt-6-luna, verify codex/gpt-6-luna · view run ↗
| Severity | Count |
|---|---|
| 🟡 Medium | 2 |
| 🔵 Low | 1 |
ℹ️ Checks (advisory — CI is authoritative) — typecheck timed out (tsconfig.json): out of memory, then its 6144 MiB retry ran out of time
Blast radius
Keyed(+) → 12 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubTimeline.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubWindow.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubWorktrees.swift, +9 morereadKitFixtureJson(Δsig) → 9 dependent(s) outside this PR: src/doctor/tests/reclaim-analyzers.test.ts, src/doctor/tests/act.test.ts, src/macos/lib/kit-fixtures.test.ts, +3 moreRecent(+) → 9 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubNotify.swift, src/macos/GenesisTools/Sources/Parts/Features/Settings/DaemonSettings.swift, src/macos/GenesisKit/Sources/GenesisKit/Flow/FlowWidget.swift, +6 morerunGit(+) → 8 dependent(s) outside this PR: src/utils/agent-sessions/testing/fixture-world.ts, src/utils/git/origins/pr-fetch.test.ts, src/utils/git/test-repo.ts, +5 morecontrols(~) → 7 dependent(s) outside this PR: src/macos/GenesisTools/Package.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubHandoffComposer.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubBench.swift, +4 moreContract(+) → 6 dependent(s) outside this PR: src/benchmark/lib/baseline.ts, src/utils/fs/disk-usage.test.ts, src/utils/fs/disk-usage.ts, +3 morepair(+) → 6 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubWindow.swift, src/macos/GenesisTools/Sources/Parts/Hub/Review/ReviewWindow.swift, src/macos/GenesisTools/Sources/Parts/Hub/Review/ReviewSessionState.swift, +3 moresection(+) → 6 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubPRs.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubPanelFind.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubLaunch.swift, +3 moreIdentity(+) → 5 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubInbox.swift, src/macos/GenesisTools/Sources/Host/VaultRecipient.swift, src/macos/GenesisTools/Sources/Host/VaultUnlock.swift, +2 moreKey(~) → 5 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubWindow.swift, src/macos/GenesisTools/Tests/ReviewSessionStateTests.swift, src/macos/GenesisKit/Sources/GenesisKitPosture/Pose/PoseSample.swift, +2 more- +26 more changed symbol(s) with outside dependents
ℹ️ Claims vs diff — 5 claims could not be checked from the diff (c2, c3, c4, c5, c8).
…section, rename identity uses every candidate, date invalidation waits for its result, and staged files keep their index paths
efcd6de to
a2b2b0e
Compare
d5ea372 to
407c989
Compare
…section, rename identity uses every candidate, date invalidation waits for its result, and staged files keep their index paths
…alize line endings and clean filters before pairing, and the file history follows the review
a2b2b0e to
d4b94d1
Compare
Review fixes 2026-10-26 04:07 from GPT-6.1 Sol judged by Claude Opus 5.5 (fable-judge)Round 2. 3 unresolved threads (eve 3, CodeRabbit 0): 3 fixed, 0 rejected. Two threads describe the same missing repository-history failure notice. Fixed in d4b94d1; the lead ran the tests and committed. Show repository history failures and retry in the Commits tab (eve-bot-lovinka)
Check Git normalization before using the raw-size shortcut (eve-bot-lovinka)
Restore the repository commit-log failure notice (eve-bot-lovinka)
Threads: t1 accepted · t2 accepted · t3 accepted |
There was a problem hiding this comment.
🐉 eve review — 🟡 Review comments
a2b2b0e· 3 actionable findings · reviewed by find codex/gpt-6.1-sol + codex/gpt-6-luna, verify codex/gpt-6-luna · view run ↗
| Severity | Count |
|---|---|
| 🟡 Medium | 3 |
ℹ️ This pass reviewed the full PR diff: the incremental delta since
f7c6aedbwas unusable after a base-branch merge saturated GitHub's compare API (300+ files, 271 of them merge noise, list truncated).
Blast radius
Keyed(+) → 12 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Parts/Hub/Review/ReviewSessionState.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubWindow.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubSessionDetail.swift, +9 morereadKitFixtureJson(Δsig) → 9 dependent(s) outside this PR: src/du/lib/index/index.test.ts, src/doctor/tests/reclaim-analyzers.test.ts, src/doctor/tests/act.test.ts, +3 moreRecent(+) → 9 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubNotify.swift, src/macos/GenesisTools/Sources/Parts/Features/Settings/DaemonSettings.swift, src/macos/GenesisKit/Tests/GenesisKitTests/Markdown/MarkdownRecentsTests.swift, +6 morebefore(+) → 8 dependent(s) outside this PR: src/browser-router/native/Router.swift, src/du/native/cloudctl.swift, src/macos/GenesisTools/Tests/ReviewQueueTests.swift, +5 morefile(+) → 8 dependent(s) outside this PR: src/browser-router/native/Router.swift, src/du/native/cloudctl.swift, src/macos/GenesisClickyPreview/Sources/PreviewWidgetRoster.swift, +5 morerunGit(+) → 8 dependent(s) outside this PR: src/scripts/lib/store.ts, src/scripts/commands/git.ts, src/gitlab/lib/git.ts, +5 morefind(+) → 7 dependent(s) outside this PR: src/macos/GenesisTools/Tests/HubTimelineRowIdentityTests.swift, src/macos/GenesisTools/Tests/LocalNetworkWatchTests.swift, src/macos/GenesisTools/Tests/HubLogicTests.swift, +4 moreactivate(+) → 6 dependent(s) outside this PR: src/macos/GenesisTools/Tests/HubLogicTests.swift, src/macos/GenesisTools/Tests/HubPollGateTests.swift, src/macos/GenesisTools/Tests/ReviewSessionStateTests.swift, +3 moreapply(+) → 6 dependent(s) outside this PR: src/browser-router/native/Router.swift, src/macos/GenesisTools/Tests/HubTimelineRowIdentityTests.swift, src/macos/GenesisTools/Tests/HubInboxTimelineTests.swift, +3 moreapply(~) → 6 dependent(s) outside this PR: src/browser-router/native/Router.swift, src/macos/GenesisTools/Tests/HubTimelineRowIdentityTests.swift, src/macos/GenesisTools/Tests/HubInboxTimelineTests.swift, +3 more- +26 more changed symbol(s) with outside dependents
ℹ️ Claims vs diff — 8 claims could not be checked from the diff (c1, c2, c3, c4, c5, c6, c7, c8).
There was a problem hiding this comment.
🐉 eve review — 🟡 Review comments
d4b94d1· 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 | 2 |
ℹ️ This pass reviewed the full PR diff: the incremental delta since
efcd6de6was unusable after a base-branch merge saturated GitHub's compare API (300+ files, 270 of them merge noise, list truncated).
Blast radius
Keyed(+) → 12 dependent(s) outside this PR: src/macos/GenesisKit/Sources/GenesisKitCharts/HealthBar.swift, src/macos/GenesisKit/Sources/GenesisKitCharts/TreemapView.swift, src/macos/GenesisKit/Sources/GenesisKit/Markdown/Window/MarkdownDocumentsModel.swift, +9 morereadKitFixtureJson(Δsig) → 9 dependent(s) outside this PR: src/macos/commands/clones/reclaim.test.ts, src/macos/commands/clones/optimize.test.ts, src/macos/lib/kit-fixtures.test.ts, +3 moreRecent(+) → 9 dependent(s) outside this PR: src/macos/GenesisKit/Tests/GenesisKitTests/Markdown/MarkdownRecentsTests.swift, src/macos/GenesisKit/Sources/GenesisKit/Widgets/AgentWidgetModels.swift, src/macos/GenesisKit/Sources/GenesisKit/Markdown/Document/VaultIndex.swift, +6 morecontrols(~) → 8 dependent(s) outside this PR: src/macos/GenesisKit/Tests/GenesisKitTests/Markdown/MarkdownPathsTests.swift, src/macos/GenesisKit/Tests/GenesisKitTests/ImageViewerTests.swift, src/macos/GenesisKit/Tests/GenesisKitTests/RecordingTests.swift, +5 morerunGit(+) → 8 dependent(s) outside this PR: src/scripts/commands/git.ts, src/scripts/lib/store.ts, src/utils/git/origins/pr-fetch.test.ts, +5 morefile(+) → 7 dependent(s) outside this PR: src/browser-router/native/Router.swift, src/macos/GenesisClickyPreview/Sources/PreviewWidgetRoster.swift, src/macos/GenesisClickyPreview/Sources/ClickyPreview.swift, +4 moreContract(+) → 6 dependent(s) outside this PR: src/dev-dashboard/contract/client.test.ts, src/benchmark/lib/baseline.ts, src/macos/commands/clones/optimize.ts, +3 moreheader(+) → 6 dependent(s) outside this PR: src/macos/GenesisKit/Tests/GenesisKitTests/Markdown/MarkdownDocumentWindowTests.swift, src/macos/GenesisKit/Tests/GenesisKitTests/Markdown/MarkdownContentViewTests.swift, src/macos/GenesisKit/Tests/GenesisKitTests/Markdown/MarkdownBlocksTests.swift, +3 moreIdentity(+) → 6 dependent(s) outside this PR: src/macos/GenesisKit/Sources/GenesisKit/Settings/KitSettingsBackend.swift, src/macos/GenesisKit/Sources/GenesisKit/Clicky/ClickyPacks.swift, src/macos/GenesisTools/Tests/VaultUnlockTests.swift, +3 moreKind(+) → 5 dependent(s) outside this PR: src/macos/GenesisKit/Tests/GenesisKitTests/Markdown/MarkdownDocumentWindowTests.swift, src/macos/GenesisKit/Tests/GenesisKitTests/ForgeBadgeTests.swift, src/macos/GenesisKit/Tests/GenesisKitTests/Alerts/AlertPolicyTests.swift, +2 more- +25 more changed symbol(s) with outside dependents
ℹ️ Claims vs diff — 3 claims could not be checked from the diff (c4, c5, c7).
| load() | ||
| let gitFolder = root.appendingPathComponent(".git").path | ||
| workingTree = DirectoryWatcher(paths: [root.path], latency: 1, fileEvents: false, | ||
| accepts: { $0 != gitFolder && !$0.hasPrefix(gitFolder + "/") }) { [weak self] _ in |
There was a problem hiding this comment.
⚡ Performance | 🟡 Medium · confidence 99/100
Normalize the Git-folder exclusion to the watcher's path spelling
The exclusion compares real-path root paths against paths that DirectoryWatcher has already rewritten. GitQueries.root resolves symlinks, so repositories under /tmp or /var have roots under /private/tmp or /private/var, while DirectoryWatcher.normalizedEventPath strips /private before calling accepts (DirectoryWatcher.swift:49,71–75). Consequently no .git event in those repositories matches this exclusion. Commits, fetches and other Git-only activity unnecessarily schedule the working-tree status/hash/date reads, including a second refresh after the existing Git-directory watcher. Normalize gitFolder with the same function before capturing it in accepts.
🧩 Analysis
Grep evidence: normalizedEventPath|let gitFolder = root|accepts: \{ \$0 != gitFolder|resolvingSymlinksInPath
There was a problem hiding this comment.
Valid. For a repository under /tmp or /var the watcher hands accepts() a path without /private, so the .git exclusion never matches and git-only activity schedules an extra working-tree read. The cost is an extra refresh, not a wrong result; the fix normalizes gitFolder with DirectoryWatcher.normalizedEventPath and adds a test under /tmp. The pull request has had its three fix rounds, so this finding waits for a follow-up, and this thread stays open until then.
| const proc = Bun.spawn(["git", "-C", root, ...args], { | ||
| stdout: "pipe", | ||
| stderr: "pipe", | ||
| env: { |
There was a problem hiding this comment.
🧪 Tests | 🟡 Medium · confidence 98/100
Isolate fixture Git processes from inherited repository and user config
The new fixture runner copies the entire parent environment and only overrides author identity. In a hook or rebase --exec, inherited GIT_DIR/GIT_WORK_TREE/GIT_INDEX_FILE can redirect these add, mv and commit calls away from the temporary directory into the outer checkout; user hooks, signing and template configuration are also still active. This violates the project rule to sandbox external user-data configuration read by tests. The repository already provides src/utils/git/test-repo.ts:hermeticGitEnv (and isolatedGitEnv), which removes repository selectors and disables global/system config. Use that environment consistently for fixture mutations and the production readers exercised by these tests; the new Swift fixture helper likewise inherits user Git configuration and should be isolated.
🧩 Analysis
Grep evidence: process\.env|function hermeticGitEnv|function isolatedGitEnv|GIT_INDEX_FILE|GIT_CONFIG_GLOBAL
There was a problem hiding this comment.
Valid. The fixture copies the whole environment, so GIT_DIR or GIT_INDEX_FILE from a hook would point its commands at the outer checkout. The fix uses hermeticGitEnv from src/utils/git/test-repo.ts for the fixture and the readers it exercises. The pull request has had its three fix rounds, so this finding waits for a follow-up, and this thread stays open until then.
…ounts follow an edit that keeps the same git status, and the table measures its row height on the first file row
Review fixes 2026-10-26 04:33 from GPT-6.1 Sol judged by Claude Opus 5.5 (fable-judge)Round 3. 3 unresolved Eve threads: 2 fixed with small source changes, 1 already addressed by the verified round-2 commit d4b94d1. No findings deferred. Fixed in 0b55281; the lead ran the tests and committed. Refresh content-derived followers when porcelain status stays equal (eve-bot-lovinka)
Normalized blob hashes already bypass the file-identity cache (eve-bot-lovinka)
Defer row-height measurement until an actual file row appears (eve-bot-lovinka)
Threads: t1 accepted · t2 already done · t3 accepted |
There was a problem hiding this comment.
🐉 eve review — ✅ Approved
5a5e7a2· 1 actionable finding · reviewed by find codex/gpt-6.1-sol + codex/gpt-6-luna, verify codex/gpt-6-luna · view run ↗
| Severity | Count |
|---|---|
| 🔵 Low | 1 |
Blast radius
panel(+) → 9 dependent(s) outside this PR: native/ax-tool/SnapshotSupport/OcrReuse.swift, native/ax-tool/SnapshotSupport/DrawnCheck.swift, native/ax-tool/SnapshotSupport/WorkflowArguments.swift, +6 moretable(+) → 6 dependent(s) outside this PR: native/ax-tool/SnapshotSupport/BulkHierarchy.swift, src/macos/GenesisTools/Sources/Host/VaultRecipient.swift, src/macos/GenesisTools/Sources/Host/App/GenesisToolsApp.swift, +3 more- graph truncated by caps — dependents above are a lower bound
| let deadline = Date().addingTimeInterval(3) | ||
| while mounted.numberOfRows != 2, Date() < deadline { | ||
| host.layoutSubtreeIfNeeded() | ||
| try await Task.sleep(for: .milliseconds(20)) |
There was a problem hiding this comment.
🧪 Tests | 🔵 Low · confidence 78/100
Use an event-driven wait for the hosted table update
The new regression test polls the hosted table every 20 ms, repeatedly forcing layout until SwiftUI applies the update. This directly violates the project review-memory rule “Give every wait a deadline and expiry outcome; use event-driven waits, avoid … sub-100-ms polling.” The three-second deadline bounds the wait, but does not address the prohibited polling. Fulfill an XCTest expectation from the representable/table update (or an injected update callback) and await it with a timeout before asserting the row count and height.
🧩 Analysis
Grep evidence: Task.sleep\(for: \.milliseconds\(20\)\)
There was a problem hiding this comment.
Valid. The test should wait on an expectation fulfilled by the table update, keeping the 3 s deadline. The pull request has had its three fix rounds, so this finding waits for a follow-up, and this thread stays open until then.
Review fixes 2026-10-26 04:41 from Claude Opus 5.5 judged by Claude Opus 5.5 (fable-judge)After round 3, on 5a5e7a2. 2 new eve threads (both Medium): valid, deferred under the three-round limit; their threads stay open. No code change in this pass. The .git exclusion compares a real path with the watcher's normalized path (eve-bot-lovinka)
The fixture's git calls inherit the parent's repository and user config (eve-bot-lovinka)
Threads: t1 belongs to another PR · t2 belongs to another PR |
…ounts follow an edit that keeps the same git status, and the table measures its row height on the first file row
359497d to
a935db9
Compare
Review fixes 2026-10-26 06:05 from Claude Opus 5.5 judged by Claude Opus 5.5 (fable-judge)After round 3, on the restacked head. 1 more eve thread (Low): deferred under the three-round limit; its thread stays open. The table-height test polls every 20 ms instead of waiting on an event (eve-bot-lovinka)
Threads: t1 belongs to another PR |
There was a problem hiding this comment.
🐉 eve review — 🟡 Review comments
359497d· 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 |
ℹ️ This pass reviewed the full PR diff: the incremental delta since
5a5e7a21was unusable after a base-branch merge saturated GitHub's compare API (300+ files, 266 of them merge noise, list truncated).
Blast radius
Keyed(+) → 12 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Host/Notify.swift, src/macos/GenesisTools/Sources/Parts/Hub/Review/ReviewSessionState.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubSessionDetail.swift, +9 moreKey(~) → 9 dependent(s) outside this PR: native/ax-tool/SnapshotSupport/CursorFeedback.swift, native/ax-tool/Sources/commands/Harness.swift, native/ax-tool/Sources/commands/Annotate.swift, +6 morepair(+) → 9 dependent(s) outside this PR: native/ax-tool/SnapshotSupport/OcrReuse.swift, native/ax-tool/SnapshotSupport/VisualCapture.swift, native/ax-tool/SnapshotSupport/FrameSampler.swift, +6 morepanel(−) → 9 dependent(s) outside this PR: native/ax-tool/SnapshotSupport/OcrReuse.swift, native/ax-tool/SnapshotSupport/WorkflowArguments.swift, native/ax-tool/SnapshotSupport/WindowEvents.swift, +6 morereadKitFixtureJson(Δsig) → 9 dependent(s) outside this PR: src/doctor/tests/reclaim-analyzers.test.ts, src/doctor/tests/act.test.ts, src/du/lib/index/index.test.ts, +3 moreRecent(+) → 9 dependent(s) outside this PR: src/macos/GenesisTools/Sources/Parts/Features/Settings/DaemonSettings.swift, src/macos/GenesisTools/Sources/Parts/Hub/Hub/HubNotify.swift, src/macos/GenesisKit/Sources/GenesisKit/Flow/FlowWidget.swift, +6 morecontrols(~) → 8 dependent(s) outside this PR: native/ax-tool/SnapshotSupport/HierarchySource.swift, native/ax-tool/Sources/commands/Harness.swift, native/ax-tool/Sources/IsolatedCapture.swift, +5 morefind(+) → 8 dependent(s) outside this PR: native/ax-tool/SnapshotSupport/WindowChoice.swift, native/ax-tool/SnapshotSupport/SnapshotToken.swift, native/ax-tool/SnapshotSupport/SnapshotDigest.swift, +5 morerunGit(+) → 8 dependent(s) outside this PR: scripts/ci/pre-commit-hook.test.ts, src/gitlab/lib/git.ts, src/scripts/lib/store.ts, +5 moreupdate(~) → 7 dependent(s) outside this PR: native/ax-tool/SnapshotSupport/OcrReuse.swift, native/ax-tool/SnapshotSupport/IsolatedComposition.swift, native/ax-tool/SnapshotSupport/PermissionRefusal.swift, +4 more- +25 more changed symbol(s) with outside dependents
ℹ️ Claims vs diff — 7 claims could not be checked from the diff (c1, c2, c3, c4, c5, c6, c8).
Not line-anchorable (review without the full diff context)
- 🔵 Low
src/macos/GenesisKit/Sources/GenesisKit/Diff/Views/GitRepoPanel.swift:897· confidence 90/100 — Keep relative file ages ticking while the repository is idle: The new age label computes a plain String from Date() only when its hosted cell is rebuilt. Unlike the previous LiveAgo label, it has no clock. Equal status/date reads deliberately do not rebuild cells, so a file shown as seconds old can keep that label indefinitely, even across manual refreshes that find unchanged dates. Scrolling it out and back or changing the sort makes the age jump. Keep a clock local to the age view (as LiveAgo/LiveTime does), without invalidating the whole table.
| stderr: "pipe", | ||
| env: { ...env.getProcessEnv(), GIT_OPTIONAL_LOCKS: "0" }, | ||
| }); | ||
| const [stdout, stderr, code] = await Promise.all([ |
There was a problem hiding this comment.
🧹 Quality | 🟡 Medium · confidence 93/100
Bound the rename-query subprocess waits
runGit awaits both output streams and proc.exited without a deadline or cancellation. This is now on the tools git changes read path, and hash-object intentionally invokes configured clean filters: a stuck filter can prevent the command from ever returning, rather than falling back to the original status entries. This violates the project review rule that every wait has a deadline and defined expiry outcome. Add a bounded subprocess lifetime, terminate/reap it on expiry (including filter descendants as appropriate), and return the existing failure result so rename detection remains optional.
🧩 Analysis
Grep evidence: proc.exited|hash-object|pairStatusRenames\(root, status.entries\)
There was a problem hiding this comment.
Valid. runGit should end a subprocess after a deadline, reap it, and return the existing failure result, so rename detection stays optional. A hang needs a clean filter that never exits; with none configured the calls end on their own. The pull request has had its three fix rounds, so this finding waits for a follow-up, and this thread stays open until then.
Review fixes 2026-10-26 06:06 from Claude Opus 5.5 judged by Claude Opus 5.5 (fable-judge)After round 3, on the restacked head. 1 more eve thread (Medium): deferred under the three-round limit; its thread stays open. The rename query's git subprocesses have no deadline (eve-bot-lovinka)
Threads: t1 belongs to another PR |
…oved away opens its deleted diff instead of "not in a git repository", a folder moved outside git shows as renames in the repository panel, the Changes pane and the hub's working-tree diff, and the Repository tab keeps the last repository for a file outside one - GitQueries.root(of:) starts git in the nearest folder that exists: git cannot start in a deleted file's folder when the whole folder moved, so every lookup, history, diff and file state of such a file said "This file is not in a git repository" (Martin, 2026-10-25: compiler.ts in a moved perf-deep folder). - GitWorktreeRenames pairs a deleted file with an untracked file of the same blob (same name, then most equal trailing folders, then leading ones, then byte order; empty files never pair). Git itself pairs a rename only when both sides are in the index. Used by GitQueries.repoStatus (repository panel, tree marks) and GitWorkingTreeSource (hub review, Changes); the Changes pane reads a moved file's old side at its old path and says "Moved from … without changes". - Real vault (650 deleted, 4,906 untracked): 142 renames, 508 real deletions stay deleted; 98-165 ms wall, 58-65 ms thread CPU off the main thread (GIT_RENAMES_REAL=<repo> swift test --filter GitWorktreeRenamesTests). Git's own detection through a scratch index took 3.9 s. - The cases live in GenesisKitFixtures/Git/contract-worktree-renames.json; the CLI's twin passes the same file.
…nto renames dated by the new file, instead of 650 deletions counted as touched in the last hour pairWorktreeRenames / findWorktreeRenames / pairStatusRenames in @genesiscz/utils/git, the twin of GenesisKit's GitWorktreeRenames: both pass GenesisKitFixtures/Git/contract-worktree-renames.json. Real vault: 650 D + 4,925 untracked → 142 R + 508 D, 50-92 ms wall, 29 ms CPU.
…ollow edits by other programs, at most every 3 s, instead of waiting for the next git event while the panel's Last update showed a note from 5 h ago GitRepoModel watches its working tree (DirectoryWatcher, folder events, 1 s latency, the .git folder excluded) and refreshes no sooner than workingTreeInterval (3 s) after the last read, so an agent writing a file a second costs one status every few seconds. Before, only git's folder events and the viewer's own saves refreshed it (Martin, 2026-10-25: 4,836 untracked files up to 1 min old, the panel's newest row 5 h 15 m). Test: a file written with no refresh call shows up; a planted break (watcher callback dropped) times out.
…al window with the notes as tabs and the git sidebar on Repository, measuring main-thread CPU, busy time, longest pass, bodies and publishes for open, unrelated publishes, tab switches, filter typing, sort, fold and Show more, status refresh and 45 pt scrolling, plus the off-main status read, dates and derived lists; env-gated (MARKDOWN_REPO_BENCH), JSONL out with a summary over every run, in-bench sample
…difference: the same unrelated publish, tab switch and status refresh with the git sidebar on Repository, on This file and closed, interleaved step by step (phase ab), since a sample cannot name the panel's share of SwiftUI's layout
…e on either sidebar tab (MARKDOWN_REPO_BENCH_SAMPLE_TAB=file), so a sample of This file is the baseline for one of Repository
…wakes no follower unless git's folder, a save or a retry asked, status lookups by path are O(1), moved files are hashed once per file identity, and a moved file's status says "Moved from …" - GitRepoModel.generation bumps only for a changed status or a read git's own folder, a save or a retry asked for; working-tree events read with wake: false. A new `reads` counter bumps on every read for the repository panel's dates. Every wake reloads each open note's agent blame and the panel; before, every read woke them (gt-native-fixes: blame is one run per repository at most every 5 s, now fewer). - GitRepoStatus.entry(for:) uses a path index built with the status (off main): GitFileMark walked 5,650 entries per render, 30 samples in a sort sample of the repository panel. - GitWorktreeRenames remembers blob ids by (inode, size, mtime ns), bounded at 50,000: a read no longer hashes the same 222 candidates again. - GitQueries.fileState pairs an untracked file with a deleted one (tracked-only status, one hash): the status bar says "Moved from <old>" instead of "new file, not in git". Tests: GitWorktreeRenamesTests.testAMovedFilesStateSaysWhereItCameFrom; GitReposTests (the empty-commit wake still holds).
…pKit table over the sidebar and refill in place, the sidebar and panel skip unrelated model publishes, an equal git read changes nothing, and Last update is one newest-first list; scroll 9.4 → 4.5 ms per step, publish 22.9 → 8.4 ms, tab switch 142 → 92 ms, equal refresh 134 → 49 ms, sort 68 → 39 ms on a 5,650-entry vault Bench MarkdownRepoPanelBenchTests (vault, 39 tabs, debug, main-thread CPU medians; before = 4 rounds at 33430fc + bench, after = 4 rounds at the first table build, sort/filter/fold from one probe of this commit). Report: the notes vault, folder 2026-10-25-RepositoryPanel/. - GitRepoTable: an NSTableView of hosted SwiftUI cells laid over the sidebar (MarkdownOverlaySlot, as the file tree). The LazyVStack re-placed its rows inside the window root's layout on every scroll step (743 of 984 busy samples under MarkdownRootHostingView.layout, 0 bodies). Scroll 9.4 → 4.5 ms, with a 600-row folder open 12.2 → 4.0 ms. - One row height and in-place refills (enumerateAvailableRowViews) instead of reloadData: a reload rebuilt every row view, re-running AppKit's key-view loop and moving each SwiftUI host into the window (2,000 of 2,172 busy samples of a sort). Sort 68 → 39 ms, filter clear 72 → 70 ms, fold open 56 → 74 ms (one run), filter key 56 → 72 ms (every matching file is listed now). - No Show more pages: the table builds only the rows on screen. - MarkdownGitSidebar and GitRepoPanel are Equatable (closures excluded) and the sidebar no longer observes the documents model: publish 22.9 → 8.4 ms (panel share +13.9 → +0.2), tab switch 142 → 92 ms. - No .focusable()/.focused over the rows (FocusBridge.updateDefaultKeyViewLoop: 26% of opening the tab, 31.6 ms per tab switch); the keyboard is the table's, same order and keys (Esc ignored when nothing is keyed). - GitRepoPanelLists: dates by lstat (76 → 13 ms off main), one off-main pass, derive only when status, dates or inputs changed, publish only when the lists changed; equal refresh 134 → 49 ms main. - Last update: changes, untracked files and untracked folders (by newest file) in one list newest first (Martin: the newest change row was 5 h old while untracked files were a minute old). Rename rows' tooltip "old → new". - Durable profiling: spans git.panel.derive, git.panel.table; PerfMainBusy git.panel.open/sort/filter/fold/untracked; RenderProbe git.row. Tests: keyboard order and keys, Last update order, equal read publishes nothing, a new root drops late dates, reveal lookup; bench adapted to the new types.
…on screen through a reload of the same diff instead of flashing away on every status refresh of a busy repository GitFileDiffModel keeps the shown result while it reloads the same question (file, scope, pick, rename, compare) and shows loading only for a new one. Martin, 2026-10-25: "flashes every few seconds" in GenesisTools' own repository, where other sessions' git activity refreshes the status often. Test: three reloads of an empty diff never pass through .loading; the old code fails it with loading/empty flips.
…d's row with its own ring instead of the system focus ring, which the scroll view clipped and drew off the rows Martin, 2026-10-25: the blue box around the first file sat above and beside the row. The list keeps its Up/Down keys; .focusEffectDisabled() drops the clipped ring, and the picked row draws an accent outline while the list has focus.
…d Commits tabs: Changes is the former Repository tab with its files only, Commits lists the repository's last 50 commits, and the changes table rebuilds only the cells whose row changed - Martin, 2026-10-25: the Repository tab must show the changed files as before; commits get a tab of their own. The stored tab value "repo" opens Changes, so a saved choice keeps working. - GitRepoTable rebuilds only the row views whose row changed (by id after an animated insert/remove, by index after an in-place refill), and the open file (revealPath) is no longer part of the cells' revision: a tab switch rebuilt every visible cell, +51 ms per switch in the 4-round after-run (ab.tabs repo 129 ms vs This file 78 ms); now only the old and new open file's rows are refreshed.
… and Untracked sections A click on a heading, or Return, Left and Right on it, folds and unfolds its section; the fold survives a restart (`genesiskit.gitRepoPanel.folded`). The heading carries a chevron, a tooltip, the header trait and Expanded/Collapsed for VoiceOver. A filter shows its matches in every section, as it opens every folder. The keyboard now stops on headings too, so a section can be folded without the mouse. Busy time of a fold is written to perf.log as `git.panel.section`. Tests: GitRepoPanelKeyboardTests (key order with headings, Left/Right/Return on a section, a folded section in both layouts keeps only its heading).
…o a rewrite that keeps the size and the mtime is hashed again The performance skill's freshness rule: a file's identity is inode, size, mtime and ctime; the mtime alone misses a rewrite that puts it back. Test: GitWorktreeRenamesTests.testARewriteThatKeepsSizeAndMtimeIsHashedAgain.
… hosted-cell tables without reloadData, Equatable children, wake-on-change counters, git from a deleted folder, renames as one row, one Last update list, foldable sections, size-then-hash pairing, event sources that miss writers
…finding, foldable sections only for long lists with the outline keys, and the viewer rule says the change lists have no pages since 2026-10-25
…: Left on a file or a closed folder keys the row it belongs to, Left folds an open folder or section, Right opens a folded one (gt-native-ux's review)
…section, rename identity uses every candidate, date invalidation waits for its result, and staged files keep their index paths
…e it became a table, so the history failure notice from the restack goes
…alize line endings and clean filters before pairing, and the file history follows the review
…ounts follow an edit that keeps the same git status, and the table measures its row height on the first file row
a935db9 to
f010b18
Compare
Stacked on #581: it changes
GitFileDiffModel's failure states andGitRepoPanel's keyed rows, which #581 adds (ee708a5); #581 sits on #563.What Martin reported (2026-10-25 19:06) and what changed
GitQueries.root(of:)now starts in the nearest existing folder, so the deleted diff opens (02b5a96)..gitevents, so edits by other programs never reached it; a working-tree watcher now refreshes it at most every 3 s (c6b4b56). Untracked files had their own section below the tracked edits; Last update is now one newest-first list (5787bf9).tools git changes, with one fixture both languages read (02b5a96, 6a29a2b). On the vault: 142 renames and 508 real deletions.GitWorktreeRenames) and insrc/utils/git/worktree-renames.ts, withcontract-worktree-renames.jsonas the shared contract.Added during the work, at Martin's request: the git sidebar's tabs are This file / Changes / Commits (4866f98); "No unstaged changes in this file." no longer flashes on every refresh (c85a5ac); the commit sheet's keyboard ring sits on its row (38199e7); the Changes sections fold (d2c252e) with the outline keys gt-native-ux asked for (f7c6aed). The rename hash cache keys on the ctime too (793cd77).
Changed from Martin's 2026-10-13 call: the change lists no longer page with "Show more". The table builds only the rows on screen.
.claude/rules/markdown-viewer.mdsays so.Numbers
Bench
MarkdownRepoPanelBenchTests(MARKDOWN_REPO_BENCH=<repo>), the notes vault with 5,650 status entries, debug build, main-thread CPU medians in ms. "after2" is 4 interleaved rounds; "probe3" is one run of the later commits (an observation).The installed release viewer (Genesis Markdown, the vault, git sidebar on Changes, load 18 to 29 in both), 360 wheel events from
tools control scroll … --repeat 4 --alternate, CPU fromps:MarkdownRootHostingView.layoutNot better: filter typing (a filter opens every folder, and with no pages it shows every match).
How the speed was found
LazyVStackinside the window's SwiftUI root to anNSTableViewof hosted cells over the sidebar (GitRepoTable, the file tree's pattern), with one row height.reloadDatare-running the key-view loop for every row (1,159 samples) and moving every host into the window (892). Rows now refill in place; only changed cells rebuild.Equatableand stopped observing the whole documents model; no.focusable()over the rows.generationon change,readsfor the dates); status lookups by path are O(1).git.worktreeRenames,git.repoStatusspans,git.row/git.repoPanelbody probes, andgit.panel.*main-busy windows inperf.log.The lessons are in the swift, ux and performance skills (631b6ec, 65804ba), reviewed and cleared by gt-native-ux.
Moved out of this PR
The swift/ux/performance skill lessons are here except the eight
performance/references/patterns.mdlines: that file is added by gt-native-ux's docs branchdocs/2026-10-25-ux-swift-audit-skills, which carries them (0fcd26d).Tests
swift test --filter 'GitRepoPanelKeyboardTests|GitReposTests|GitFileDiffTests|GitWorktreeRenamesTests': 40 tests, 0 failures, 1 skipped (the env-gated real-repository test).bun test src/utils/git/worktree-renames.test.tsfor the TS twin.Not yet checked by hand on the installed key window: key repeat, the keyed row scrolling into view, reveal under Reduce Motion, VoiceOver reading.