revert: "fix(native): read mtime via BigInt nanoseconds (#1079)"#1080
revert: "fix(native): read mtime via BigInt nanoseconds (#1079)"#1080carlos-alm merged 2 commits intomainfrom
Conversation
… truncation (#1079)" This reverts commit 3575880. #1079 paid a real perf cost (BigInt-mode statSync on every file in change detection) for what is in practice a no-op: at large epoch values, JS Math.floor(stat.mtimeMs) can read N+1 where Rust wrote N, busting the fast-skip optimization. But fast-skip only gates whether to re-hash the file — when it misses, the hash is recomputed from contents and matches what's stored, so the graph is byte-identical either way. The fix changes optimization hit rate, not correctness. The 0.026% miss-rate window the fix targeted does not justify the constant-cost BigInt overhead applied to 100% of stat calls on the change-detection hot path. Post-merge benchmark gate confirmed the regression: no-op rebuild went from +70% (warning) to +108% (fail). Reopens #1075. The right path is documenting that fast-skip is best-effort (the on-disk hash is the source of truth for graph correctness) rather than chasing exact integer parity with Rust.
|
Claude finished @carlos-alm's task —— View job Reviewing PR #1080Conducting thorough review of this revert PR following the 5-phase review process. Todo List
Root Cause AnalysisProblem Being Solved: The revert addresses a performance regression introduced in #1079. The original fix used BigInt nanosecond precision to match Rust's Why This Approach: The author correctly identifies that the original issue (#1075) was an optimization problem, not a correctness bug. When the fast-skip optimization misses due to f64 rounding, files are re-hashed from contents and produce identical graph results. The fix targeted ~0.026% of cases but imposed overhead on 100% of stat calls. Risk Assessment: LOW RISK - This is a clean revert to a known-good state. The benchmark gate confirmed the performance regression, making this a data-driven decision. Backlog Compliance
Critical ConcernsNone. This is an exemplary revert with:
Code Quality ReviewThe changes are mechanically sound:
Technical AssessmentThe original #1079 fix targeted a narrow edge case where JavaScript's f64
The cost/benefit analysis clearly favors the revert. The author's proposal to document fast-skip as "best-effort" is the right architectural approach. Final Recommendation
|
Greptile SummaryThis PR reverts #1079, which had switched
Confidence Score: 5/5Safe to merge — this is a clean, well-scoped revert with consistent internal logic and no correctness regression. The change is a straightforward revert confirmed by benchmark data. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[fileStat called] --> B["fs.statSync(filePath)"]
B --> C["Math.floor(s.mtimeMs)"]
C --> D["return { mtime: integer, size: number }"]
D --> E{Consumer}
E --> F["detect-changes.ts\nstat.mtime used directly\n(already integer)"]
E --> G["insert-nodes.ts buildFileHashes\nitem.stat.mtime used directly\n(Math.floor removed)"]
E --> H["insert-nodes.ts updateFileHashes\nitem.stat.mtime used directly\n(Math.floor removed)"]
F --> I[(file_hashes DB\ninteger mtime column)]
G --> I
H --> I
Reviews (2): Last reviewed commit: "refactor(builder): floor mtime inside fi..." | Re-trigger Greptile |
Codegraph Impact Analysis3 functions changed → 15 callers affected across 5 files
|
Encapsulate `Math.floor(stat.mtimeMs)` inside the `fileStat` helper so every consumer of the integer DB column gets a pre-floored value by default. Eliminates the risk that a future call site reads `stat.mtimeMs` and stores it un-floored, which would silently write a non-integer (or rounded-up integer) into the DB and cause spurious fast-skip misses on the next build. All six existing call sites simplified from `Math.floor(stat.mtimeMs)` to `stat.mtime`. Behaviour unchanged. Addresses Greptile P2 feedback on the revert PR.
|
Addressed Greptile P2 feedback ("
This eliminates the forward-looking concern that a future call site could store an un-floored |
Summary
stat.mtimeMs. Investigation showed it was not a correctness bug — when fast-skip misses, the file is re-hashed from contents and the resulting graph is byte-identical either way. The fix only changed the optimization hit rate.Number(mtimeNs) / 1e6rounds across a millisecond boundary). The fix paid a constant-costfs.statSync(path, { bigint: true })overhead on 100% of stat calls in the change-detection hot path to recover that 0.026% miss rate.Reopens #1075. The right path forward is to document that fast-skip is a best-effort optimization (the on-disk hash is the source of truth for graph state) rather than chase exact integer parity with Rust's
Duration::as_millis().Test plan
npx vitest run tests/builder/detect-changes.test.ts— passes (10/10).npm run lint— clean (only pre-existing warnings unrelated to this revert).Pre-publish benchmark gaterun on main to confirm the no-op rebuild metric returns to its pre-fix(native): read mtime via BigInt nanoseconds to match Rust truncation #1079 level.