feat(git-native): in-process gitoxide blob reads for the diff panel (Rust core, PR 1)#9312
feat(git-native): in-process gitoxide blob reads for the diff panel (Rust core, PR 1)#9312ioitiki wants to merge 16 commits into
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gence Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rd clarity Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…utral) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on poisoning Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…wiring Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughAdds a Rust N-API addon for bounded Git blob reads by revision and index path, with async JavaScript bindings and repository tests. Adds build, packaging, benchmark, and CI integration for the addon. Introduces native module loading, experimental settings, telemetry, CLI fallback, shadow verification, sampled parity checks, and session fallback on divergence. Updates Git status blob reads to use the shared abstraction and documents the experimental behavior. 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: adeba08b-037d-4139-b5ac-9d999c33e5b2
⛔ Files ignored due to path filters (1)
native/git-native/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (23)
.github/workflows/pr.yml.gitignoreconfig/electron-builder.config.cjsconfig/scripts/build-git-native.mjsconfig/scripts/build-native-for-platform.mjsdocs/reference/git-compatibility.mdnative/git-native/Cargo.tomlnative/git-native/build.rsnative/git-native/src/blob_read.rsnative/git-native/src/lib.rsnative/git-native/tests/blob_read.rspackage.jsonsrc/main/git/blob-reader.parity.test.tssrc/main/git/blob-reader.test.tssrc/main/git/blob-reader.tssrc/main/git/git-native-module.test.tssrc/main/git/git-native-module.tssrc/main/git/status.tssrc/main/index.tssrc/shared/constants.tssrc/shared/telemetry-events.tssrc/shared/types.tstools/benchmarks/git-native-blob-read-bench.mjs
…verify before poisoning Addresses CodeRabbit review on stablyai#9312. - blob_read.rs/lib.rs: operational gix failures (repo open, rev resolution, object read) now return Err and the N-API call rejects, so the TS seam falls back to the git CLI instead of serving an empty diff on a repo feature gix cannot handle. Genuine missing paths still resolve as Ok(NotFound). - git-native-module.ts: guard the load-failure track() so a throwing telemetry call cannot escape loadGitNativeModule and abort the read; the prior comment overclaimed the never-throw contract. - blob-reader.ts: re-verify a detected divergence before poisoning. A concurrent HEAD move or index stage between the native read and the CLI verify was a false divergence that permanently disabled native reads and emitted misleading telemetry; poisoning now requires the mismatch to reproduce on a fresh read. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Why
Discussion #6314 asked whether Orca should move to a Rust core. After a deep review of the codebase, the highest-leverage, lowest-risk first target isn't the terminal plane (which @nwparker's team is already experimenting on) — it's git, where Orca shells out to the
gitCLI for everything and the measured cost is process-spawn churn (themain-thread-churn-probeexists precisely for this, per #7576/#7225).This is the first slice: diff blob reads. Opening a source-control review currently spawns two
git showprocesses per file (git show <oid>:<path>+git show :<path>); a 50-file review is ~100 process spawns. This PR serves those reads from an in-process gitoxide reader instead.@nwparker set the bar as "PRs welcome if they can guarantee zero regressions." That bar is the organizing principle of this PR — the design makes zero-regression structural, not a promise (see Safety below).
What this does
A new Rust crate
native/git-native(napi-rs +gix) exposes two async blob reads. A strategy layer insrc/main/git/blob-reader.tsdecides per-read whether to use native or the existing CLI path;status.ts's two blob readers become thin mappers over it. Off by default.Measured (200 iters,
git show HEAD:package.jsonvs native, this repo):The CLI cost is dominated by process spawn — which is the real per-read cost being eliminated. The native side fully materializes the same blob bytes (it isn't doing less work); if anything the benchmark is conservative (it re-opens the repo every call, and the CLI's earlier run warms the OS cache in native's favor). Byte-for-byte equality is proven separately by the parity suite below, not by the benchmark.
Safety: zero-regression is structural
The CLI path is never modified in behavior — Task "blob-reader seam" is a behavior-neutral refactor proven by the entire existing
src/main/gitsuite passing with zero test changes, and the twostatus.tsreaders preserve their exact prior result semantics (verified branch-by-branch in review). With the flag off, native is never even loaded — the feature is provably inert.When the flag is on, a fallback ladder guarantees a user can only ever get slower, never wrong:
git_native_load_failedtelemetry event, then silent)wslDistro/\\wsl.localhost) or SSH repoShadow verification: in
onmode the first few reads plus a 1/128 sample are re-run through the CLI in the background and compared byte-for-byte; a single divergence permanently reverts the process to CLI-only and emits a cappedgit_native_shadow_divergenceevent.ORCA_NATIVE_GIT=shadowdual-runs every read (serving the trusted CLI result) for dogfooding. So even an unsampled gix/git disagreement self-heals the moment the sampler catches it.Kill switch:
ORCA_NATIVE_GIT=0/off/false. Env always overrides the setting.Correctness: differential parity suite (the un-bypassable gate)
blob-reader.parity.test.tsruns the real native reader against the realgitCLI — the CLI is the oracle — over a fixture matrix: loose and packed objects, CRLF (raw object bytes, no smudge), nested unicode paths, binary blobs, empty (0-byte) files, the exact 10 MB size boundary (limit → served, limit+1 → too-large, on both), explicit commit OIDs, bad revs, staged-content-≠-HEAD, linked-worktree private index, and unmerged (no stage-0) paths. 18 tests, zero divergence. CI builds the addon and runs this suite underORCA_REQUIRE_GIT_NATIVE=1, so a missing addon fails the build loudly rather than silently skipping the gate.The Rust crate additionally has 21 hermetic
cargo tests (mutation-tested in review) covering the gix logic in isolation.cargo testand the parity suite are complementary — the former can't catch N-API marshaling or CLI-divergence bugs; the latter does.Documented intentional divergences (excluded from the oracle, unreachable in production): gitlink/submodule and sparse-dir entries return not-found while
git showpretty-prints a locally-resolvable gitlink — Orca already routes submodules away before blob reads (status.tsloadDiff). Also on the shadow watchlist:git replacerefs, sparse-index repos.Scope cuts (intentional, called out for review)
ORCA_NATIVE_GITenv only. A renderer checkbox is deliberately out of scope for PR 1.release-mac-build.ymletc.) are not touched, because that path involves signing/notarization and mac universal-arch packaging that deserves its own maintainer-reviewed change. Until then, packaged release builds simply omit the addon (the packaging entry is conditional on the artifact existing) and the runtime degrades to CLI — safe by construction. The build script already supports the mac dual-arch lipo path for when that lands.Reviewer notes / conscious choices
dtolnay/rust-toolchain@stable(matching the repo's floating-tag action pins; the crate declaresrust-version = "1.95"). A pinned toolchain would be more deterministic at the cost of forward-compat signal — happy to change if you prefer.default-features = false, features = ["revision", "index"]— dropping its network/credentials stack (213→175 crates) and structurally removinggix-filter, so the "raw object bytes, no smudge" contract can't be violated by accident.ubuntu-latestjob). macOS/Windows parity leans onshadowtelemetry rather than a per-platform CI gate — gix is platform-agnostic and paths are forward-slash-normalized before the read. The recommendation (documented ingit-compatibility.md) is to flip the flag on for real users only after clean cross-platform shadow results.Cargo.lockis committed (application crate).Follow-ups (PR 2+)
The natural next slice is the status bundle — replacing the 3–9 spawns per status poll (porcelain + ahead/behind + numstat) with a single in-process gitoxide call, which is the actual #7576/#7225 churn kill-shot and reuses this crate's foundation. Then branch-compare, then a native relay for SSH.
Smaller follow-ups when this graduates from experimental: a settings-UI toggle in
ExperimentalPane(read-path is already wired), which will also needexperimentalNativeGitadded toSETTINGS_CHANGED_WHITELIST; and Rust wiring in the release workflows so packaged builds ship the addon.🤖 Generated with Claude Code