Repository navigation
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
⏭️ Performance benchmarks were skippedPerf benchmarks (CodSpeed) are opt-in on pull requests — they no longer run on every push. They always run automatically after merge to To run them on this PR, do any of the following, then push a commit (or re-run CI):
|
Binary size checks passed✅ 7 passed
Generated by |
…nifest fragments, not unit payloads The warm path spent most of a no-op invocation re-proving its own cache validity: the serve-time throws gate re-derived package_items (re-parsing every file) to convert types for a comparison, and plan_reuse read + hashed + decoded every clean unit payload just to extract the tiny callable-throws fragments it seeds from. At a 295k LOC project that was ~7.2s to conclude "nothing changed" — the same wall time as recompiling from scratch. - No-delta gate skip: when the dirty partition finds no changed, added, or removed files, the gate is provably a tautology — the seeds it would validate are byte-for-byte the values the manifest was stored with (store persists file_throw_facts verbatim; units are content-addressed and written before the manifest), and the solve + runtime conversion are deterministic pure functions of those inputs. Any real delta still takes the full gate. - Manifest-resident fragments: ManifestFile now carries a verbatim copy of each unit's CallableThrowsFragment blob, and the callable_throws seeds project from that copy — so a no-delta invocation opens zero unit payloads. Units are loaded (now in parallel, manifest order preserved) only when a delta means something will be re-emitted or relinked. Both verify oracles (the BAML_CACHE_VERIFY full compare and the 1-in-32 sampled re-derive) now check the manifest copy — exactly the artifact that is served. - The gate path (and every warm collection) primes per-file semantic indexes across workers first, so the package_items derivation the gate and package-level diagnostics demand is a parallel-fed fold instead of a serial parse of the project. - bex_cache: unit_key is derived from the payload's integrity digest, which entry validation already computes — load_unit_shared now reuses that digest instead of hashing the payload a second time. Behavior change, deliberate: a unit file deleted out from under a warm cache is no longer detected on a no-op invocation (nothing reads it); the next compile that needs it falls back to a byte-identical full compile. Slower once, never wrong. Old manifests (without the fragment field) fail borsh decode and are treated as absent — one full recompile re-seeds them. Measured (Apple Silicon): warm no-op check at 295k LOC 7.2s -> 2.0s (zero unit reads, gate skipped); at 59k LOC 0.54s -> 0.30s. Warm leaf-edit check is emit-bound (it seeds the cache for later run/pack hits) and unchanged. Verified: 66 cache tests, BAML_CACHE_VERIFY honest-recompile compare (no-op + after-edit), forced sampled verify across 7 warm invocations, diagnostics byte-identity cold + warm. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01V4oee6wrCHzXH6mM2h8eJo
c2da018 to
f214619
Compare
dc5828e to
5573885
Compare
…itor latency (BoundaryML#4105) Consolidated stack (supersedes BoundaryML#4098, BoundaryML#4100, BoundaryML#4101 — their commits are all contained here, rebased onto current canary). Seven commits, reviewable independently, in dependency order. ## What this does A ground-up performance pass on the compiler driven by head-to-head benchmarking against tsgo (native TypeScript) and `go build` on semantically identical generated corpora (1.5k–295k LOC), followed by root-cause profiling of every gap found. ### 1. `perf(compiler2)`: kill the two cold-compile quadratics; parallelize the cache-path check - The package-wide Jinja type environment was rebuilt inside every `check_file` call (O(N²)) — and twice per compile via `get_bytecode`'s error gate. Now a memoized salsa query (`jinja_base_types`) + skipped entirely for files with no prompts. - `ProjectDatabase` handle clones deep-copied two N-entry PathBuf maps; the parallel drivers clone ~1.55N handles per compile (quadratic CPU + peak RSS). Now Arc-wrapped, O(1). - `baml check`/`run` routed through a serial diagnostics collector while the parallel one sat unreachable next to it. Now shared. - The LSP proves the project error-free once (`get_bytecode_unchecked`), and its diagnostics candidate now includes package-level diagnostics — cross-file name conflicts previously **never reached the editor at all**. ### 2. `feat(cli)`: `baml pack` uses the bytecode cache; `baml check` seeds it Pack was fully cold on every invocation (no cache participation at all); check reused but never wrote, so check-only workflows never warmed. Now one warm cache serves check → run → test → pack. ### 3–4. `build` + `fix(ci)`: hardware SHA-2 (`sha2/asm`, gated off MSVC), doc-link fix The warm path hashes ~hundreds of MB of unit payloads per run; it was on the software SHA fallback. ### 5. `perf(compiler2)`: prime wave, bulk project load, parallel LSP sweep Cold parallel check scaled 1.18× on 12 cores: every file's check demands whole-package aggregates, and the first worker to claim that memo computed parse+index for the entire project inline while all other workers parked on the sync slot (diagnosed against ty/ruff's salsa usage; interventionally verified). Per-file indexes are now primed across workers before fan-out. Project load stops re-writing the file list per file (O(files²)) and reads sources in parallel (FileId order preserved). The LSP candidate uses the shared order-preserving parallel checker. ### 6. `perf(cache)`: warm no-op checks stop re-proving the cache A warm no-op check cost the same as a full recompute: the throws-gate safety compare re-parsed every file, and seeding read+hashed 78MB of unit payloads for metadata. Now: the gate is skipped when the dirty partition is provably empty (a value compared against itself), throws fragments live verbatim in the manifest so a no-op check opens **zero** unit payloads, and units load in parallel (manifest order preserved) only when a delta means relink will need them. Both verify oracles (`BAML_CACHE_VERIFY` full compare + always-on 1-in-32 sampled re-derive) now check the manifest copy — exactly what is served. Design was adversarially reviewed; the unsound variant (fact-space throws compare) was rejected and every real edit still takes the full runtime-space gate. ### 7. `refactor(cli)`: one shared `ProjectSession` for every project-loading command check/run/test/pack/describe/grep/generate each hand-rolled a drifting subset of the same preamble — the root cause of "pack forgot the cache" and "describe never primes." One implementation; commands declare `CacheUse::{ReadWrite, ReadWriteTests, ReadOnly, Off}`. Introspection installs seeds only on a no-delta plan (provable tautology) and derives honestly otherwise. ## Measured impact (Apple Silicon, 12 cores, hyperfine) | | before | after | |---|--:|--:| | cold check, 295k LOC | 21–46 s (126 s CPU, 5.3 GB RSS) | **6.6 s** (~13 s CPU, 2.7 GB) | | cold check, 59k LOC | 3.3 s | **1.24 s** | | warm no-op check, 295k / 59k | 7.2 s / 3.2 s | **2.0–2.6 s / 0.4–0.6 s** | | `run` after check (59k / 295k) | full compile | **0.12 s / 0.65 s** (cache hit) | | `pack` after check (59k / 295k) | 1.7 s / 40.5 s (always cold) | **0.19 s / 0.87 s** (cache hit) | | LSP edit→diagnostics (250/500/1000 files) | 0.46 / 1.7 / 5.5 s | **179 / 192 / 216 ms** (flat) | | `describe`, 295k / 59k LOC | 6.3 s / 716 ms | **2.6 s / 402 ms** | Cold compile scaling is now ~linear in project size (was quadratic: 5× code cost 33× CPU), verified to 8000 modules. ## Verification - Diagnostics byte-identical to the pre-change binary (error-heavy corpus, cold + warm) at each stage. - Cache soundness: `BAML_CACHE_VERIFY=1` honest-recompile compare (no-op + after-edit) and forced `BAML_CACHE_SAMPLED_VERIFY=1` across edit sequences — all pass; 43 bytecode-cache oracle tests updated and green. - LSP load-tested: 50-edit multi-file burst storms + sustained ~17 edits/s churn at 250/1000 files — zero crashes, stable RSS, convergence after every storm. - Full stack green in CI (doc, Windows incl. MSVC sha2 gating, size gate, all SDK matrices). ## Deliberate trade-offs - Cold `check` at mid-size projects (~15–30k LOC) is ~10% slower than before: it now emits + stores once to warm the cache; every later check/run/pack is served warm. - A warm *edit* check re-emits and stores (that is what buys the instant run/pack); at 295k LOC the edit path remains ~6–9 s — the known remaining floor, tracked separately. - A unit file deleted out from under a warm cache is not detected on a no-op run; the next compile that needs it falls back to a byte-identical full compile. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01V4oee6wrCHzXH6mM2h8eJo <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * CLI commands now share a consistent, cache-aware project session workflow, including lenient read-only sessions for inspection when configuration is missing. * **Performance** * Faster project loading and diagnostics checking via parallel per-file processing. * Improved bytecode-cache reuse by avoiding unnecessary payload hashing/loading, including a fast “no-delta” warm path. * **Bug Fixes** * Fixed callable-throws fragment seeding and verification for warm “no-delta” runs. * Improved package-level diagnostics handling during compilation and error-gating behavior. * **Chores** * Improved build robustness for cryptography acceleration on MSVC targets. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Fable 5 <[email protected]>
Draft on purpose — this touches cache-soundness invariants; walk through the risk section below before merging. Stacked on #4100.
The problem
A warm no-op
baml checkat 295k LOC cost 7.2s — identical to a full recompute — because the warm path re-proved its own cache validity from scratch every run: the serve-time throws gate re-parsed every file (viapackage_items) just to convert types for a comparison, andplan_reuseread+hashed+decoded 78MB of unit payloads just to extract the tiny throws fragments it seeds from. Profiled: 70% gate, 20% unit loads.The fix (adversarially reviewed design)
The naive fix (compare throws in "fact space") was killed in adversarial review — it was either circular or unsound (alias-retarget hole). What's implemented is the reviewed survivor:
ManifestFilecarries a verbatim copy of each unit's throws-fragment blob; seeding reads that. A no-op invocation opens zero unit files. Units load (in parallel, order preserved) only when a delta means relink/re-emit will need them.package_itemsderivation (still needed on edits and for package-level diagnostics) is a parallel fold, not a serial parse.bex_cache: unit content-key is derived from the integrity digest entry-validation already computed — one hash pass per unit instead of two.Measured
run/packthen hit in ~0.7 s at 295k LOC)Risk analysis (what to scrutinize)
dirty == added == removed == ∅) reuses the same dirty-partition logic every warm compile already trusts; a bug there was already a soundness bug before this PR. The new failure surface is manifest-fragment drift from the unit copy — mitigated by copying from the same in-memory bytes at store time, and by re-pointing both verify oracles (fullBAML_CACHE_VERIFYcompare + always-on 1-in-32 sampled re-derive) at the manifest copy, i.e. exactly what is served.Verification run
BAML_CACHE_VERIFY=1honest-recompile byte-compare: PASS on no-op and after-edit.BAML_CACHE_SAMPLED_VERIFY=1forced on 7 consecutive warm invocations across edits: PASS.🤖 Generated with Claude Code
https://claude.ai/code/session_01V4oee6wrCHzXH6mM2h8eJo