Skip to content

perf(profile): compile only selected benchmark modes - #361

Closed
andrii-lz wants to merge 1 commit into
codex/profile-bench-skip-regenerationfrom
codex/profile-bench-group-features
Closed

perf(profile): compile only selected benchmark modes#361
andrii-lz wants to merge 1 commit into
codex/profile-bench-skip-regenerationfrom
codex/profile-bench-group-features

Conversation

@andrii-lz

@andrii-lz andrii-lz commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add six narrow akita-pcs profile feature groups and condition the profile mode registry so release builds only monomorphize the concrete PCS configurations selected by that feature. The existing profile-ci feature remains the compatibility union.

This PR only adds the capability; the next stacked PR adopts it in CI.

Why

The profile registry held function pointers for all 11 CI modes. That made every configuration reachable, so rustc monomorphized all of them even when a matrix cell ran only one mode. In the fresh slow CI job, profile binary builds took about 4m47s–5m15s, while the benchmark itself took only about 29s.

Expected improvement

Cold local release measurements:

Build Wall time Binary
parallel,profile-ci union 187.9s 45.5 MB
new dense feature group 74s 19.9 MB
existing singleton control 64.9s 18.2 MB

The dense group is 61% faster and produces a 56% smaller binary than the full union locally. Single-mode CI cells should see a similar order-of-magnitude reduction once the next PR adopts these features; multi-mode groups should land between the singleton and union results.

Validation

  • cargo check with -D warnings for all six new groups, profile-ci, and the singleton feature
  • cargo fmt --all --check
  • profile linkage smoke check on a narrowed release binary

Stack

  1. Remove redundant schedule regeneration.
  2. This PR: add narrow profile feature groups.
  3. Switch each benchmark matrix group to its narrow feature.

@quangvdao

Copy link
Copy Markdown

This seems a bit too tailored to what the CI bench is exercising now - could we have a more generic solution?

@quangvdao

Copy link
Copy Markdown

Like in the future what if we want to change what's exercised in each ci bench shard and/or add new shards?

@andrii-lz
andrii-lz force-pushed the codex/profile-bench-group-features branch from 7df6f5f to bbe389f Compare August 7, 2026 00:07
@github-actions github-actions Bot added the no-spec PR has no spec file label Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

Documentation blast radius (advisory)

These regions may need doc/spec/book updates based on changed paths.
This is not a merge gate. See docs/documentation.md.

Changed files in this PR: 3

workspace-crates

Workspace membership and public crate surface

Code paths touched:

  • crates/akita-pcs/Cargo.toml

Consider updating:

  • README.md
  • docs/crate-graph.md
  • book/src/how/architecture.md

pcs-umbrella

Public PCS API, examples, integration tests

Code paths touched:

  • crates/akita-pcs/Cargo.toml
  • crates/akita-pcs/examples/profile/main.rs
  • crates/akita-pcs/examples/profile/modes.rs

Consider updating:

  • book/src/usage/**
  • README.md

Per-PR checklist: spec Status / acceptance criteria; book owning page; AGENTS.md if contracts changed; archive spec after fold.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

CI test timing

  • Report generated: 2026-08-07T00:22:02Z.
  • Source: ddb7ed3 on codex/profile-bench-group-features.
  • Workflow run: 31133543799.
  • Main baseline: c9ca8e9.

Run summary

Wall s Main wall s Main Δ Ratio Tests Skipped Failed Status
315.0 302.0 +4.3% 1.04x 1278 0 0 ok

Wall time spans 2 parallel nextest slice shards.

Slowest tests

Rank Duration s Test
1 11.9 akita-planner::schedule_params::tests::pruned_mixed_search_matches_unpruned_traversal_and_is_canonical
2 9.4 akita-pcs::akita_e2e::dense_d64_snap_regen_prove_verify_nv24
3 7.6 akita-planner::schedule_params::tests::mixed_nv36_benchmark_policy_selects_minimum_setup_schedule
4 6.1 akita-planner::schedule_params::tests::uniform_suffix_dp_matches_unpruned_exact_cutover_search
5 4.7 akita-sis-estimator::search_mode_parity::parallel_exhaustive_matches_serial_exhaustive_smoke
6 4.6 akita-prover::kernels::linear::tests::chunking::q128_many_blocks_digits_chunk_instead_of_unsafe_block_parallel
7 4.5 akita-sis-estimator::search_mode_parity::exhaustive_search_is_at_least_as_good_as_local_minimum_smoke
8 4.0 akita-pcs::single_poly_e2e::single_dense_nv18
9 3.6 akita-pcs::setup::d64_dense::same_size_passes
10 3.6 akita-pcs::batched_aggregated_e2e::aggregated_mixed_dense_and_onehot_under_dense_cfg
11 3.5 akita-pcs::scheme::tests::onehot::multi_group_root_allows_precommitted_arity_above_final_group
12 3.4 akita-pcs::setup::d64_dense::large_setup_nv_passes
13 3.3 akita-pcs::batched_aggregated_e2e::non_zk_aggregated_cases::aggregated_dense_nv17_batch4
14 3.2 akita-pcs::setup::d128_dense::large_setup_batch_passes
15 3.2 akita-planner::schedule_params::tests::recursive_exact_cutover_proof_size_is_documented
16 3.1 akita-pcs::setup::d128_dense::same_size_passes
17 3.1 akita-pcs::setup::d128_dense::large_setup_nv_passes
18 2.8 akita-pcs::scheme::tests::fp32_ext4::fp32_ext4_multi_group_uses_one_batched_eor_sumcheck
19 2.7 akita-pcs::setup::d128_dense::small_setup_nv_panics
20 2.7 akita-pcs::batched_aggregated_e2e::non_zk_aggregated_cases::aggregated_onehot_nv20_batch4

Regressions vs main

No per-test regressions above the threshold.

New slow tests

No new tests ≥30s vs main baseline.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

Benchmark Report

  • Latest run: bbe389f
  • Message: perf(profile): compile only selected benchmark modes
  • Ref: codex/profile-bench-group-features
  • Workflow run: run 31133544799 attempt 1
  • Report generated: 2026-08-07T00:23:47Z.
  • Main baseline: 910c22b from the merge-base benchmarked on this runner.
  • Binary: target/release/examples/profile.
  • Memory: maximum resident set size from /usr/bin/time on the benchmark process.
Status Workload Setup contribution Setup and preparation Setup vector size Prepared NTT cache size Verifier NTT cache size Commit Prove Verify Peak process RSS Proof size
ok Fp32 - nv28Onehot256 - D=128 direct 0.043 s
-0.84% vs main
36.0 MiB
+0.00% vs main
144.0 MiB
+0.00% vs main
1.2 MiB
+0.00% vs main
0.101 s
+3.78% vs main
1.552 s
+0.41% vs main
33.4 ms
-1.20% vs main
466.4 MiB
+1.27% vs main
77,834 bytes
+0.00% vs main
ok Fp64 - nv28Onehot256 - D=128 direct 0.036 s
-1.43% vs main
40.0 MiB
+0.00% vs main
120.0 MiB
+0.00% vs main
0.9 MiB
+0.00% vs main
0.082 s
-3.15% vs main
1.088 s
-0.73% vs main
32.0 ms
-0.89% vs main
560.1 MiB
+0.24% vs main
83,596 bytes
+0.00% vs main
ok Fp128 - nv24Dense - D=64 direct 0.151 s
-0.77% vs main
215.0 MiB
+0.00% vs main
537.5 MiB
+0.00% vs main
1.4 MiB
+0.00% vs main
1.721 s
-1.46% vs main
1.332 s
+1.05% vs main
18.4 ms
+3.52% vs main
1546.4 MiB
-0.23% vs main
83,562 bytes
+0.00% vs main
ok Fp128 - nv26Onehot256 - D=64 - Tensor direct 0.651 s
-0.60% vs main
1024.0 MiB
+0.00% vs main
2560.0 MiB
+0.00% vs main
1.4 MiB
+0.00% vs main
0.116 s
+0.87% vs main
1.264 s
+0.47% vs main
35.1 ms
+2.75% vs main
4141.9 MiB
-0.01% vs main
85,080 bytes
+0.00% vs main
ok Fp128 - nv32Onehot256 - D=64 direct 0.210 s
+0.77% vs main
320.0 MiB
+0.00% vs main
800.0 MiB
+0.00% vs main
1.4 MiB
+0.00% vs main
1.232 s
-0.26% vs main
1.188 s
-0.16% vs main
23.9 ms
+3.44% vs main
1695.1 MiB
-0.04% vs main
84,972 bytes
+0.00% vs main
ok Fp128 - nv32Onehot256 - D_a=256D_b=128D_d=128 - MixedD256ToD64 direct 0.139 s
-0.31% vs main
128.0 MiB
+0.00% vs main
608.5 MiB
+0.00% vs main
1.4 MiB
+0.00% vs main
0.978 s
-0.47% vs main
1.303 s
-1.24% vs main
19.6 ms
+0.18% vs main
1411.8 MiB
+0.24% vs main
85,080 bytes
+0.00% vs main
ok Fp128 - nv30Onehot256 - Batched4 - D=64 direct 0.210 s
+0.99% vs main
320.0 MiB
+0.00% vs main
800.0 MiB
+0.00% vs main
1.4 MiB
+0.00% vs main
1.141 s
-2.54% vs main
1.195 s
+0.02% vs main
24.3 ms
+2.07% vs main
1699.0 MiB
+0.26% vs main
84,970 bytes
+0.00% vs main
ok Fp128 - nv32Onehot256 - Batched4 - D=64 - MultiGroup direct 0.427 s
-0.92% vs main
1032.0 MiB
+0.00% vs main
1075.0 MiB
+0.00% vs main
1.4 MiB
+0.00% vs main
3.110 s
+0.00% vs main
1.613 s
+0.22% vs main
28.8 ms
-0.78% vs main
3019.1 MiB
+0.07% vs main
85,093 bytes
+0.00% vs main
ok Fp128 - nv32Onehot256 - Batched4 - D=64 - MultiGroup recursive 3.726 s
-0.49% vs main
1032.0 MiB
+0.00% vs main
1075.0 MiB
+0.00% vs main
1.4 MiB
+0.00% vs main
3.134 s
+0.01% vs main
3.415 s
+0.12% vs main
26.1 ms
-0.84% vs main
3782.6 MiB
+0.38% vs main
89,873 bytes
+0.00% vs main
ok Fp128 - nv32Onehot256 - Batched4 - D=64 - MultiGroupW8R2 recursive 1.883 s
+0.26% vs main
430.0 MiB
+0.00% vs main
1075.0 MiB
+0.00% vs main
1.4 MiB
+0.00% vs main
3.472 s
-0.25% vs main
10.744 s
+0.60% vs main
39.7 ms
+4.56% vs main
3579.6 MiB
+0.12% vs main
95,904 bytes
+0.00% vs main
ok Fp128 - nv32Onehot256 - D=64 - MultiChunkW2R2 direct 0.208 s
-0.87% vs main
320.0 MiB
+0.00% vs main
800.0 MiB
+0.00% vs main
1.4 MiB
+0.00% vs main
1.227 s
-0.15% vs main
1.542 s
+0.90% vs main
25.1 ms
-0.95% vs main
1849.4 MiB
+0.29% vs main
85,331 bytes
+0.00% vs main
ok Fp128 - nv32Onehot256 - D=64 - MultiChunkW4R2 direct 0.221 s
-0.08% vs main
344.0 MiB
+0.00% vs main
860.0 MiB
+0.00% vs main
1.4 MiB
+0.00% vs main
0.427 s
+0.39% vs main
1.809 s
+0.34% vs main
28.1 ms
+0.16% vs main
2022.6 MiB
+0.05% vs main
85,946 bytes
+0.00% vs main
ok Fp128 - nv32Onehot256 - D=64 - MultiChunkW8R2 direct 0.221 s
-0.14% vs main
344.0 MiB
+0.00% vs main
860.0 MiB
+0.00% vs main
1.4 MiB
+0.00% vs main
0.427 s
+0.13% vs main
2.542 s
+0.11% vs main
30.2 ms
+0.09% vs main
2265.1 MiB
-0.61% vs main
86,215 bytes
+0.00% vs main

Negative deltas are improvements for time, memory, and proof size.

Terminal response component breakdown

Workload Folded response (z) Opening values (e) Inner-commitment values (t) Total terminal response
Fp32 - nv28Onehot256 - D=128 21,406 bytes 3,072 bytes 24,576 bytes 49,054 bytes
Fp64 - nv28Onehot256 - D=128 21,460 bytes 7,168 bytes 28,672 bytes 57,300 bytes
Fp128 - nv24Dense - D=64 21,854 bytes 7,168 bytes 28,672 bytes 57,694 bytes
Fp128 - nv26Onehot256 - D=64 - Tensor 21,848 bytes 7,168 bytes 28,672 bytes 57,688 bytes
Fp128 - nv32Onehot256 - D=64 21,852 bytes 7,168 bytes 28,672 bytes 57,692 bytes
Fp128 - nv32Onehot256 - D_a=256D_b=128D_d=128 - MixedD256ToD64 21,848 bytes 7,168 bytes 28,672 bytes 57,688 bytes
Fp128 - nv30Onehot256 - Batched4 - D=64 21,850 bytes 7,168 bytes 28,672 bytes 57,690 bytes
Fp128 - nv32Onehot256 - Batched4 - D=64 - MultiGroup 21,861 bytes 7,168 bytes 28,672 bytes 57,701 bytes
Fp128 - nv32Onehot256 - Batched4 - D=64 - MultiGroup 21,825 bytes 7,168 bytes 28,672 bytes 57,665 bytes
Fp128 - nv32Onehot256 - Batched4 - D=64 - MultiGroupW8R2 21,868 bytes 7,168 bytes 28,672 bytes 57,708 bytes
Fp128 - nv32Onehot256 - D=64 - MultiChunkW2R2 21,875 bytes 7,168 bytes 28,672 bytes 57,715 bytes
Fp128 - nv32Onehot256 - D=64 - MultiChunkW4R2 21,850 bytes 7,168 bytes 28,672 bytes 57,690 bytes
Fp128 - nv32Onehot256 - D=64 - MultiChunkW8R2 21,831 bytes 7,168 bytes 28,672 bytes 57,671 bytes

The z column includes its per-segment length prefixes and Golomb payload; e and t are raw field bytes. These three columns sum exactly to the serialized terminal response.

Detailed schedule and proof-size breakdowns by fold level are available in the uploaded report.md benchmark artifact.

quangvdao added a commit that referenced this pull request Aug 10, 2026
…378)

* ci(profile): improve reports and narrow builds

Describe the exact public opening statements and split the compact report into readable timing, memory, and proof size tables.

Build each matrix group with its narrow feature while preserving the profile-ci fallback for older merge bases. Fold the current coverage contract into the Book and archive the stale coverage spec.

Adapts the useful changes from draft PRs #360, #361, and #362 to the current benchmark matrix.

* ci(profile): unify fold report layout

Join planner choices, witness geometry, and proof costs in one row per fold. Emit group-specific records for multi-group roots and setup offloads so distinct commitment parameters remain visible.

Keep percentage deltas for measured costs and exact merge-base values for discrete planner choices.

* fix(profile): correct multi-group report values

* feat(profile): compare verifier thread modes

* refactor(profile): clarify fold report cells

Group planner, work, and proof details into labeled blocks while preserving the side-by-side fold comparison. Keep multi-group precommitment, final-group, and setup-offload parameters visibly separate.

* fix(profile): remove persisted bench setup

Construct recursive benchmark setup in memory for every sample instead of enabling disk persistence. This prevents public matrix and prefix registry caches from entering per-group handoff artifacts and makes setup timing measure fresh construction.

* fix(profile): close benchmark report review gaps

* fix(ci): align recursive profile linkage

* fix(ci): restore balanced nextest shards
@quangvdao

Copy link
Copy Markdown

Closing this as superseded by #378, merged in e8d63c6. Current main now has six narrow profile feature groups, and profile-ci is their transitive compatibility union. The profile registry compiles only the modes selected for each group. The merged version also reflects the current adaptive profile modes and adds exact coverage and linkage checks. Thank you, Andrii, for the work and for driving this build time improvement.

@quangvdao quangvdao closed this Aug 10, 2026
quangvdao added a commit that referenced this pull request Aug 10, 2026
…375)

* perf(onehot): keep big blocks on the tiled column sweep; row-pass accumulators

- Oversized blocks (hot count beyond the wide accumulators' 2^15 headroom)
  are split into cap-respecting sub-blocks and swept through the bucketed
  tiled kernel, then re-merged per parent — the previous per-block safe
  fallback re-streamed n_a A rings per hot coefficient (~15 TB at a 2^26
  one-hot trace column group) and dominated trace-scale commits. Measured:
  2^26 K=256 jolt prove 333s -> 154s (commit ~252s -> ~80s).
- Row-pass accumulation (one wide ring per block live at a time) with the
  tile budget parameterized; sweep-structure and shift-accumulate
  microbenches added (ignored) for A/B iteration.
- In-place NEON AddAssign/SubAssign for Fp128x8i32 (no temp round-trip;
  measured neutral on M4 — kept for clarity of intent).
- inner_ajtai_wide_onehot_safe retained as the overflow-safety reference.

* perf(onehot): fused multi-polynomial commit sweep

Every polynomial of a committed group multiplies the same A matrix, but
the sweep ran per-poly, re-streaming A once per polynomial — the
dominant commit traffic at trace scale (~11 TB at 2^26/K256, ~28 s of
the ~82 s commit).

Adds a merge-based fused kernel (column_sweep_core_merge): blocks carry
cursors over their position-sorted entries and the kernel walks A
columns in L1-sized chunks, so one A pass serves every block of every
polynomial in the batch — and the counting/scatter pass (whose packed
buffer scales with tile size) disappears. Wiring:
CommitmentComputeBackend::onehot_commit_rows_multi (default loops the
single-poly path), RootCommitKernel::commit_inner_group (default
per-source), OneHotPoly::commit_inner_group, and the batched-prove
commit path groups the whole batch.

Byte-equal to per-poly sweeps (new equality test covers core-vs-core,
wrapper round-trip, and tile-size independence); 223 unit tests pass.

* perf(onehot): keep merge-sweep accumulator tile and column chunk L1-resident

The fused sweep ran its 58-block accumulator set (116 KB) plus a 64 KB
widened-column chunk out of L2, costing ~1.5x per accumulate (68 vs
28 ns in the tight-tile bench). Cap the merge tile at 32 blocks of
accumulators (64 KB) and halve the column chunk to 16 (32 KB) so both
live in L1; the extra A re-streaming this causes is negligible after
poly fusion. Also spans the fold grind (fold_grind_sample) for opening
attribution.

* fix(onehot): self-reduce merge-sweep accumulators at the cap; no block splitting

At trace scale every one-hot block exceeds the 2^15 wide-accumulator
cap (~2^19 accumulations at ppb 2^21), so the merge path inherited the
splitting wrapper's 16x sub-block explosion — which turned the L1 tile
cap into a 29x A re-stream and mostly-empty cursor scans (2^26 prove
regressed to 252s). Fold each block's wide accumulator into a canonical
partial whenever it reaches the cap instead: a handful of reduces per
block-row, no splitting, blocks keep dense full-range chunks, and small
L1 tiles are genuinely safe. New regression pins the self-reducing
kernel against the splitting wrapper on an oversized block.

* perf(onehot): bench-tuned merge-sweep defaults (tile 64 blocks, chunk 32 cols)

Full (tile x chunk) matrix at a trace-like sparse shape is flat within
5-30%; (64, 32) is the minimum at 61.4 ns/accum vs 64.4 at the previous
default. The kernel is at its practical floor for quarter-density
one-hot blocks — the 28 ns dense-shape bench figure does not transfer.
Adds the merge_sweep_bench tuning matrix (ignored).

* feat(onehot): expose clear_block_cache on OneHotPoly

The per-block storage is a pure cache over the retained hot indices
(blocks_for rebuilds it on demand), but it is trace-scale — ~8 bytes per
hot entry across every committed column — and otherwise lives from commit
until the opening fold. Callers that know the sweep is done can drop it
and pay one parallel rebuild inside the fold.

* perf(prover): build the setup NTT envelope slot lazily and let callers drop it between uses — 2^26 jolt e2e peak 87.7->81.3GB, prove 118.8->99.4s

Registration at prepare_setup now only reserves the slot cell and records
the CRT profile; with_shared_ntt builds single-flight on first use, and
drop_built_ntt_slots() returns built slots to the reserved state (next use
rebuilds, ~1.9s at the jolt 2^26 envelope). Keeps the ~28GiB transformed
matrix out of every window that doesn't touch it: unused setups never
build, and the caller can drop between the commit's terminal product and
the stage-8 fold.

* perf(prover): extent-sized NTT slots + streamed root-relation transforms — 2^26 jolt e2e peak 87.7->55.1GB, prove 118.8->95.6s

Three changes that together keep the transformed matrix out of the fold
window (it was ~30GiB of standing memory at the jolt 2^26 shape):

- with_shared_ntt(extent, f): consumers declare the rows x width extent
  they slice; slots build at the rounded request (smallest built cover
  reused, envelope-warmed setups unchanged). The commit's terminal
  product now builds 5GiB instead of 30.
- ring-switch relation/quotient rows above 2^21 rings stream per-element
  transforms from A's field form inside the tile loop (new cyc-only ring
  constructor; chunked z-quotient mirrors the cached path's bracketing;
  both paths bit-identical to the cache fill — equality tests included).
  The root relation reads each element once per prove, so caching its
  transform was pure standing memory.
- fold-entry envelope warms (prove.rs role/terminal, ring-switch
  commit_w/commit_terminal_w) skip the base ring dim: its consumers
  self-serve extent-sized, cross-D dims keep the eager warm.

AKITA_NTT_BUILD_BACKTRACE=1 dumps a backtrace per slot build for future
residency diagnosis.

* perf(prover): drop built NTT slots after the root fold level — fold window 51.3->49.3GiB sampled at 2^26, prove unchanged

Root-level slots dwarf every deeper level's; releasing them keeps the
fold tail (where sumcheck transients spike) off root-scale caches, and
deeper levels rebuild their own sub-GiB slots on first use. Peak-neutral
on its own (the stage-3/4 transient now binds at ~51 GiB sampled) —
rides with the stage-window items.

* perf(prover): releasable setup matrix with seed re-derivation — 2^26 jolt e2e peak 55.1->47.1GB, prove 95.6->99.3s

The field-form matrix is a pure function of the public seed, so its
backing store is cache. AkitaExpandedSetup.shared_matrix becomes
SharedSetupMatrix: seed-backed shape metadata (envelope keys and
validation never shrink), covering_at_dyn/full accessors over a swappable
Arc store, release_to_prefix, and a per-element MatrixElementDeriver
(same XOF stream as derive_public_matrix_flat — bit-identical values,
equality-tested). Derivation is captured as monomorphized fn pointers at
construction, so consumers need no extra bounds.

After the commit sweep (its last full-width reader) the store releases
to a 2^21-ring prefix that serves slot rebuilds and small setup reads;
wide readers stream per element: the ring-switch relation kernels take a
StreamedASource (materialized pre-release, seed-derived after), and the
relation weight events read per-column ring slices through
SetupRowFamily instead of full row views. Setup-contribution scans cover
only the rows they read, not padded view lengths. A full-width covering
re-caches the store (the verifier's root-level scan legitimately reads
the whole matrix; later proves re-release), so within one process the
~2.4s derive amortizes to once per prove/verify cycle — first-verify
cost 0.2->2.6s, standalone verifiers already pay full derivation at
setup.

* perf(prover): build commit-sweep block tiles lazily from index columns — 2^26 jolt e2e peak 47.1->44.1GB, commit window 43.7->35.1GiB

The fused group commit materialized every polynomial's block entries
(~200 B/cycle across a 29-poly batch) before sweeping. Blocks partition
the ring-element index space contiguously, so from_indices gains
block-range variants reading exactly a tile's slice of the retained
index columns; per-tile builds across the sweep sum to the same single
pass. commit_inner_group hands the sweep LazyOneHotBlocks builders
(OneHotCommitBlocks::{SingleChunk,MultiChunk}Lazy) and each thread
materializes one L2 tile at a time (~2 GiB in flight for the batch),
dropping it after the pass. The tile pass is extracted from the merge
kernel and shared, so lazy results are byte-equal to eager
(equality-tested). Side effect: later windows drop ~6-9 GiB too — the
cache's freed pages no longer linger in the allocator. Single-poly and
small-batch paths keep the eager cache.

* perf(prover): stream fold blocks from index columns — per-block builds in fold_blocks/_ring, per-(block,position-window) builds in the tensor accumulate

The fold's opening-claim evaluation was the sole builder of the full
per-block entry cache (probe-verified: every blocks_for build flowed
through fold_kernels::evaluate_claims_at_prepared_point), and the tensor
decompose reused it. Both consumers visit each entry range exactly once:
fold_blocks/_ring build one block at a time, and
onehot_accumulate_tensor_lazy builds one (block, position-window) at a
time (LazyOneHotBlocks generalized to ring-range builds; pos_in_block
stays absolute). Total build work equals one pass over the retained
index columns; the eager tensor kernel stays as the reference for the
lazy-equality test. 2^26 measurement pending a quiet machine (first
attempt voided by mid-run user activity).

* refactor: shrink the perf-branch diff before upstreaming

- delete measured-dead code: Fp128Lazy (negative A/B result), the
  row-outer sweep variant + bench entry, inner_ajtai_wide_onehot_safe
- delete perf-campaign scaffolding: planner candidate dump, three
  env-gated backtrace blocks
- from_indices delegates to the ring-range builders; one view_layout
  helper replaces triplicated validation in OneHotPoly; lazy fold arms
  collapse into a macro; base-dim NTT warm skip moves into
  ensure_envelope_ntt (one home instead of five call sites)
- fix two real residency leaks the review found: the tensor decompose
  layout probe rebuilt+cached a full block set inside the fold, and two
  setup-prefix readers materialized the full matrix post-release
- export NTT_STREAM_THRESHOLD_RING_ELEMENTS + a pinned
  release_setup_matrix_to_streaming_prefix so the retained prefix and
  the streaming threshold cannot drift apart
- fix two doc comments stranded on the wrong item by earlier insertions

2^26 validation: prove 101.3s / peak 44.09GB (unchanged).

* perf(algebra): fuse fixed-size wide ring shifts

* perf(algebra): expose wide ring coefficients

* perf(prover): consume decompose witness rows without copies

* perf(prover): release root opening storage after fold

* fix(profile): propagate commit accumulator bounds

* perf(prover): cache only required commit transform

* perf(prover): stream CRT-chunked quotient roles

* perf(prover): parallelize relation setup columns

* perf(prover): coalesce aligned relation events

* perf(prover): parallelize exact-prefix folds

* fix(prover): preserve group-local relation dimensions

* perf(planner): trade payload slack for narrower roots

* fix(planner): preserve scalar rank policy through recursion

* fix(planner): emit rustfmt-stable catalog imports

* fix(planner): remove stale lint expectation

* fix(types): size released setup without rebuilding

* test(prover): drop local tuning probes

* fix(pcs): update releasable setup call sites

* test(pcs): align mixed-D cache test with lazy setup

* test(prover): split oversized backend test modules

* revert(planner): drop payload-slack schedule selection

Removes the rank-aware selection policy (payload slack for narrower
roots) per review feedback: the planner is being reworked upstream and
this policy should not bake into catalog identity. Restores
akita-planner, akita-config, and akita-schedules to their origin/main
state; the prover optimizations in this branch are unaffected.

* fix(ci): repair doc links and glue trait bound

Rustdoc denies public docs linking private items; the trusted-artifact
glue impl needs RandomSampling for seed re-derived setup construction.

* fix(tests): drop tensor-kernel test and port oracle to flat views

* fix(compute): restore onehot_chunk_size on RootPolyMeta

Downstream root-poly adapters key one-hot commit planning on the
chunk size; the reconciliation dropped it with the tensor cleanup.

* fix(compute): restore one-hot chunk-size metadata on root polys

OneHotPoly and MultilinearPolynomial expose their K through
RootPolyMeta again; downstream commit packaging derives the group's
one-hot flavor from it.

* fix(prover): close optimization review gaps

Route root release and grouped one-hot commitments through their inner implementations. Share quotient planning and one-hot storage dispatch, and split ring-switch execution from the CPU backend.

Allow expected profile cache releases, remove the orphan schedule, and add Q32, concurrency, and path-specific regression coverage.

* fix(onehot): make block cache caller-owned

Keep persistent block storage under explicit caller control. Ordinary commits stream from canonical indices, while opening operations borrow prepared blocks or use operation-local materialization. Remove the protocol-wide release hook so proving cannot evict state shared by downstream clones.

* fix(cache): make tensor and NTT retention explicit

Keep tensor-root projections operation-local unless callers prepare them explicitly. Retain shared NTT state by default and expose an open root-fold lifecycle hook plus an opt-in release wrapper. Propagate release failures and deduplicate aliased cache owners.

* refactor(profile): split workload module

Move proof sizing, profile data, claims, cache checks, and each execution scenario into focused modules. Preserve the existing workload facade and runtime behavior while keeping every Rust file below the CI line cap.

* docs(spec): define PR 375 end state

* fix(cache): align NTT prewarm and release

Remove released cache keys so smaller requests rebuild their exact extent. Route prewarming and planned memory through the backend retention policy used by CPU ring-switch streaming. Document lifecycle and concurrency rules, and complete local unsafe safety arguments.

* refactor(onehot): unify sparse block representation

* refactor(commit): finish source-typed kernel cutover

* perf(onehot): unify commit sweep scheduling

Use one group driver for range materialization, worker partitioning, scratch-bounded tiling, and source-ordered output.

Retain only the measured bucketed and merge production sweeps. Keep direct arithmetic as a test oracle, expose route statistics in tracing, and document the exact selector and 8 MiB per-worker budget.

* fix(commit): restore group source parallelism

Run independent dense and sparse-ring sources through the existing feature-gated parallel iterator inside their group kernels. One-hot groups keep their fused scheduler.

Addresses review discussion #3742146391.

* refactor(onehot): remove mutable derived caches

* ci(profile): improve reports and narrow builds

Describe the exact public opening statements and split the compact report into readable timing, memory, and proof size tables.

Build each matrix group with its narrow feature while preserving the profile-ci fallback for older merge bases. Fold the current coverage contract into the Book and archive the stale coverage spec.

Adapts the useful changes from draft PRs #360, #361, and #362 to the current benchmark matrix.

* refactor(ring-switch): unify quotient planning

Remove the temporary fixed ring-switch backend trait and row-plan wrappers so source-typed kernels own the CPU implementation directly.

Make cached and streamed quotient paths share validated matrix geometry, bounds, and CRT chunk planning. Strengthen exact-prefix and wide-accumulation boundary tests, and remove unused public wide-ring helpers.

* ci(profile): unify fold report layout

Join planner choices, witness geometry, and proof costs in one row per fold. Emit group-specific records for multi-group roots and setup offloads so distinct commitment parameters remain visible.

Keep percentage deltas for measured costs and exact merge-base values for discrete planner choices.

* chore(pr375): complete validation slice

Repair the explicit D64 root commitment benchmark without weakening production schedule checks. Record one hot route decisions in profile reports and validate the parser against the isolated CI artifact.\n\nReplace the optimization book stub, align backend and ownership docs, and close the PR 375 spec with benchmark, compatibility, and lifecycle evidence.

* fix(prover): close independent review gaps

Preserve exact NTT operation requirements through backend routing, join retained cache requests by physical owner, and batch homogeneous projection groups through their child kernels.

Remove leaked commitment-only bounds and the streamed source wrapper, split oversized modules, add routing regressions, and archive the implemented PR specification.

* fix(profile): correct multi-group report values

* feat(profile): compare verifier thread modes

* refactor(profile): clarify fold report cells

Group planner, work, and proof details into labeled blocks while preserving the side-by-side fold comparison. Keep multi-group precommitment, final-group, and setup-offload parameters visibly separate.

* fix(profile): remove persisted bench setup

Construct recursive benchmark setup in memory for every sample instead of enabling disk persistence. This prevents public matrix and prefix registry caches from entering per-group handoff artifacts and makes setup timing measure fresh construction.

* docs(pr375): reopen CPU policy spec

Define configurable CPU resource limits on the existing backend, complete NTT release semantics, and the downstream Jolt validation slices.

* feat(compute): configure CPU resource limits

* fix(compute): release all CPU NTT caches

* fix(compute): retain compression NTT cache

* feat(profile): report CPU resource limits

* fix(ntt): fail closed on unsafe streaming

Reject ring-switch work that exceeds the streamed CRT capacity before entering the retained-cache path. This preserves the configured memory bound and adds a regression proving no cache slot is built on failure.

* fix(profile): close benchmark report review gaps

* fix(prover): resolve routed cache review findings

* fix(ci): align recursive profile linkage

* fix(ci): align recursive profile linkage

* fix(ci): restore balanced nextest shards

* fix(profile): address benchmark review follow-ups

Resolve schedule features transitively across crate boundaries and derive profile linkage allowlists from that canonical graph.\n\nThread the exact final group layout into benchmark reporting, reject incomplete public group metadata, and simplify compact report tables.\n\nAlso make workflow-step test failures explicit.

---------

Co-authored-by: Markos Georghiades <mgeorghiades@a16z.com>
Co-authored-by: sumchecker <241190306+sumchecker@users.noreply.github.com>
quangvdao added a commit that referenced this pull request Aug 10, 2026
* perf(onehot): keep big blocks on the tiled column sweep; row-pass accumulators

- Oversized blocks (hot count beyond the wide accumulators' 2^15 headroom)
  are split into cap-respecting sub-blocks and swept through the bucketed
  tiled kernel, then re-merged per parent — the previous per-block safe
  fallback re-streamed n_a A rings per hot coefficient (~15 TB at a 2^26
  one-hot trace column group) and dominated trace-scale commits. Measured:
  2^26 K=256 jolt prove 333s -> 154s (commit ~252s -> ~80s).
- Row-pass accumulation (one wide ring per block live at a time) with the
  tile budget parameterized; sweep-structure and shift-accumulate
  microbenches added (ignored) for A/B iteration.
- In-place NEON AddAssign/SubAssign for Fp128x8i32 (no temp round-trip;
  measured neutral on M4 — kept for clarity of intent).
- inner_ajtai_wide_onehot_safe retained as the overflow-safety reference.

* perf(onehot): fused multi-polynomial commit sweep

Every polynomial of a committed group multiplies the same A matrix, but
the sweep ran per-poly, re-streaming A once per polynomial — the
dominant commit traffic at trace scale (~11 TB at 2^26/K256, ~28 s of
the ~82 s commit).

Adds a merge-based fused kernel (column_sweep_core_merge): blocks carry
cursors over their position-sorted entries and the kernel walks A
columns in L1-sized chunks, so one A pass serves every block of every
polynomial in the batch — and the counting/scatter pass (whose packed
buffer scales with tile size) disappears. Wiring:
CommitmentComputeBackend::onehot_commit_rows_multi (default loops the
single-poly path), RootCommitKernel::commit_inner_group (default
per-source), OneHotPoly::commit_inner_group, and the batched-prove
commit path groups the whole batch.

Byte-equal to per-poly sweeps (new equality test covers core-vs-core,
wrapper round-trip, and tile-size independence); 223 unit tests pass.

* perf(onehot): keep merge-sweep accumulator tile and column chunk L1-resident

The fused sweep ran its 58-block accumulator set (116 KB) plus a 64 KB
widened-column chunk out of L2, costing ~1.5x per accumulate (68 vs
28 ns in the tight-tile bench). Cap the merge tile at 32 blocks of
accumulators (64 KB) and halve the column chunk to 16 (32 KB) so both
live in L1; the extra A re-streaming this causes is negligible after
poly fusion. Also spans the fold grind (fold_grind_sample) for opening
attribution.

* fix(onehot): self-reduce merge-sweep accumulators at the cap; no block splitting

At trace scale every one-hot block exceeds the 2^15 wide-accumulator
cap (~2^19 accumulations at ppb 2^21), so the merge path inherited the
splitting wrapper's 16x sub-block explosion — which turned the L1 tile
cap into a 29x A re-stream and mostly-empty cursor scans (2^26 prove
regressed to 252s). Fold each block's wide accumulator into a canonical
partial whenever it reaches the cap instead: a handful of reduces per
block-row, no splitting, blocks keep dense full-range chunks, and small
L1 tiles are genuinely safe. New regression pins the self-reducing
kernel against the splitting wrapper on an oversized block.

* perf(onehot): bench-tuned merge-sweep defaults (tile 64 blocks, chunk 32 cols)

Full (tile x chunk) matrix at a trace-like sparse shape is flat within
5-30%; (64, 32) is the minimum at 61.4 ns/accum vs 64.4 at the previous
default. The kernel is at its practical floor for quarter-density
one-hot blocks — the 28 ns dense-shape bench figure does not transfer.
Adds the merge_sweep_bench tuning matrix (ignored).

* feat(onehot): expose clear_block_cache on OneHotPoly

The per-block storage is a pure cache over the retained hot indices
(blocks_for rebuilds it on demand), but it is trace-scale — ~8 bytes per
hot entry across every committed column — and otherwise lives from commit
until the opening fold. Callers that know the sweep is done can drop it
and pay one parallel rebuild inside the fold.

* perf(prover): build the setup NTT envelope slot lazily and let callers drop it between uses — 2^26 jolt e2e peak 87.7->81.3GB, prove 118.8->99.4s

Registration at prepare_setup now only reserves the slot cell and records
the CRT profile; with_shared_ntt builds single-flight on first use, and
drop_built_ntt_slots() returns built slots to the reserved state (next use
rebuilds, ~1.9s at the jolt 2^26 envelope). Keeps the ~28GiB transformed
matrix out of every window that doesn't touch it: unused setups never
build, and the caller can drop between the commit's terminal product and
the stage-8 fold.

* perf(prover): extent-sized NTT slots + streamed root-relation transforms — 2^26 jolt e2e peak 87.7->55.1GB, prove 118.8->95.6s

Three changes that together keep the transformed matrix out of the fold
window (it was ~30GiB of standing memory at the jolt 2^26 shape):

- with_shared_ntt(extent, f): consumers declare the rows x width extent
  they slice; slots build at the rounded request (smallest built cover
  reused, envelope-warmed setups unchanged). The commit's terminal
  product now builds 5GiB instead of 30.
- ring-switch relation/quotient rows above 2^21 rings stream per-element
  transforms from A's field form inside the tile loop (new cyc-only ring
  constructor; chunked z-quotient mirrors the cached path's bracketing;
  both paths bit-identical to the cache fill — equality tests included).
  The root relation reads each element once per prove, so caching its
  transform was pure standing memory.
- fold-entry envelope warms (prove.rs role/terminal, ring-switch
  commit_w/commit_terminal_w) skip the base ring dim: its consumers
  self-serve extent-sized, cross-D dims keep the eager warm.

AKITA_NTT_BUILD_BACKTRACE=1 dumps a backtrace per slot build for future
residency diagnosis.

* perf(prover): drop built NTT slots after the root fold level — fold window 51.3->49.3GiB sampled at 2^26, prove unchanged

Root-level slots dwarf every deeper level's; releasing them keeps the
fold tail (where sumcheck transients spike) off root-scale caches, and
deeper levels rebuild their own sub-GiB slots on first use. Peak-neutral
on its own (the stage-3/4 transient now binds at ~51 GiB sampled) —
rides with the stage-window items.

* perf(prover): releasable setup matrix with seed re-derivation — 2^26 jolt e2e peak 55.1->47.1GB, prove 95.6->99.3s

The field-form matrix is a pure function of the public seed, so its
backing store is cache. AkitaExpandedSetup.shared_matrix becomes
SharedSetupMatrix: seed-backed shape metadata (envelope keys and
validation never shrink), covering_at_dyn/full accessors over a swappable
Arc store, release_to_prefix, and a per-element MatrixElementDeriver
(same XOF stream as derive_public_matrix_flat — bit-identical values,
equality-tested). Derivation is captured as monomorphized fn pointers at
construction, so consumers need no extra bounds.

After the commit sweep (its last full-width reader) the store releases
to a 2^21-ring prefix that serves slot rebuilds and small setup reads;
wide readers stream per element: the ring-switch relation kernels take a
StreamedASource (materialized pre-release, seed-derived after), and the
relation weight events read per-column ring slices through
SetupRowFamily instead of full row views. Setup-contribution scans cover
only the rows they read, not padded view lengths. A full-width covering
re-caches the store (the verifier's root-level scan legitimately reads
the whole matrix; later proves re-release), so within one process the
~2.4s derive amortizes to once per prove/verify cycle — first-verify
cost 0.2->2.6s, standalone verifiers already pay full derivation at
setup.

* perf(prover): build commit-sweep block tiles lazily from index columns — 2^26 jolt e2e peak 47.1->44.1GB, commit window 43.7->35.1GiB

The fused group commit materialized every polynomial's block entries
(~200 B/cycle across a 29-poly batch) before sweeping. Blocks partition
the ring-element index space contiguously, so from_indices gains
block-range variants reading exactly a tile's slice of the retained
index columns; per-tile builds across the sweep sum to the same single
pass. commit_inner_group hands the sweep LazyOneHotBlocks builders
(OneHotCommitBlocks::{SingleChunk,MultiChunk}Lazy) and each thread
materializes one L2 tile at a time (~2 GiB in flight for the batch),
dropping it after the pass. The tile pass is extracted from the merge
kernel and shared, so lazy results are byte-equal to eager
(equality-tested). Side effect: later windows drop ~6-9 GiB too — the
cache's freed pages no longer linger in the allocator. Single-poly and
small-batch paths keep the eager cache.

* perf(prover): stream fold blocks from index columns — per-block builds in fold_blocks/_ring, per-(block,position-window) builds in the tensor accumulate

The fold's opening-claim evaluation was the sole builder of the full
per-block entry cache (probe-verified: every blocks_for build flowed
through fold_kernels::evaluate_claims_at_prepared_point), and the tensor
decompose reused it. Both consumers visit each entry range exactly once:
fold_blocks/_ring build one block at a time, and
onehot_accumulate_tensor_lazy builds one (block, position-window) at a
time (LazyOneHotBlocks generalized to ring-range builds; pos_in_block
stays absolute). Total build work equals one pass over the retained
index columns; the eager tensor kernel stays as the reference for the
lazy-equality test. 2^26 measurement pending a quiet machine (first
attempt voided by mid-run user activity).

* refactor: shrink the perf-branch diff before upstreaming

- delete measured-dead code: Fp128Lazy (negative A/B result), the
  row-outer sweep variant + bench entry, inner_ajtai_wide_onehot_safe
- delete perf-campaign scaffolding: planner candidate dump, three
  env-gated backtrace blocks
- from_indices delegates to the ring-range builders; one view_layout
  helper replaces triplicated validation in OneHotPoly; lazy fold arms
  collapse into a macro; base-dim NTT warm skip moves into
  ensure_envelope_ntt (one home instead of five call sites)
- fix two real residency leaks the review found: the tensor decompose
  layout probe rebuilt+cached a full block set inside the fold, and two
  setup-prefix readers materialized the full matrix post-release
- export NTT_STREAM_THRESHOLD_RING_ELEMENTS + a pinned
  release_setup_matrix_to_streaming_prefix so the retained prefix and
  the streaming threshold cannot drift apart
- fix two doc comments stranded on the wrong item by earlier insertions

2^26 validation: prove 101.3s / peak 44.09GB (unchanged).

* perf(algebra): fuse fixed-size wide ring shifts

* perf(algebra): expose wide ring coefficients

* perf(prover): consume decompose witness rows without copies

* perf(prover): release root opening storage after fold

* fix(profile): propagate commit accumulator bounds

* perf(prover): cache only required commit transform

* perf(prover): stream CRT-chunked quotient roles

* perf(prover): parallelize relation setup columns

* perf(prover): coalesce aligned relation events

* perf(prover): parallelize exact-prefix folds

* fix(prover): preserve group-local relation dimensions

* perf(planner): trade payload slack for narrower roots

* fix(planner): preserve scalar rank policy through recursion

* fix(planner): emit rustfmt-stable catalog imports

* fix(planner): remove stale lint expectation

* fix(types): size released setup without rebuilding

* test(prover): drop local tuning probes

* fix(pcs): update releasable setup call sites

* test(pcs): align mixed-D cache test with lazy setup

* test(prover): split oversized backend test modules

* feat(planner): decouple inner commitment basis

Search inner and opening decomposition bases independently across dense, setup-prefix, and recursive commitments.

Add exact i16 commitment support, wider SIS buckets, padded-prefix-aware selection, and dense nv26 schedule coverage.

* fix(planner): bound independent-basis search

Keep distinct next-witness classes so recursive feasibility remains exact, while dropping only dominated one-digit inner bases.

Bound suffix memoization and catalog workers to prevent schedule regeneration from exhausting memory after the search-domain expansion.

* refactor(prover): split CPU backend by role

* perf(planner): evict bounded memo entries

* fix(planner): skip discarded sweep work

* test(config): expect independent dense basis

* fix(planner): decouple precommit inner basis

* refactor(planner): tighten candidate context

* feat(planner): preserve partial regen rows

* chore(schedules): restore D64 onehot rows

* refactor(prover): isolate CPU prepared setup

* ci(planner): avoid redundant table regeneration

* fix(planner): preserve unsupported regen rows

* feat(planner)!: complete independent basis search

Decouple raw inner commitment bases from opening bases while preserving exact one-hot and recursive balanced-digit sources.

Add padded-prefix Pareto planning, profile-native precommits, canonical signed-digit support, bounded exact suffix search, atomic catalog publishing, and full SIS policy audit artifacts.

Preserve the established complete-schedule selection objectives while refining recursive setup scoring to physical padded capacity.

* fix(ci): refresh precommit registries

Remove the stale all-schedules test import and regenerate standalone precommit profiles with the merged independent-basis planner so catalog coverage matches runtime lookup.

* fix(sis): harden table publication

Require the canonical proven-pruned profile and mandatory validation for production Rust artifacts. Correct certificate provenance and table digests, align the parallel exhaustive diagnostic profile with the quantum LGSA model, and split oversized estimator/type test modules.

* fix(schedules): refresh SIS table identity

Propagate the corrected SIS provenance digest into all generated catalog identities and precommitted descriptors. Recompute the four affected catalog key digests so validation remains fail closed without changing schedules or numeric SIS rows.

* chore(sis): remove obsolete audit CSV

Keep generated_sis_table/policy_audit.csv as the only canonical production SIS certificate. Direct full comparison jobs to temporary output and align the book and estimator documentation with the proven-pruned shared-digest policy.

* revert(planner): drop payload-slack schedule selection

Removes the rank-aware selection policy (payload slack for narrower
roots) per review feedback: the planner is being reworked upstream and
this policy should not bake into catalog identity. Restores
akita-planner, akita-config, and akita-schedules to their origin/main
state; the prover optimizations in this branch are unaffected.

* fix(ci): repair doc links and glue trait bound

Rustdoc denies public docs linking private items; the trusted-artifact
glue impl needs RandomSampling for seed re-derived setup construction.

* fix(tests): drop tensor-kernel test and port oracle to flat views

* fix(compute): restore onehot_chunk_size on RootPolyMeta

Downstream root-poly adapters key one-hot commit planning on the
chunk size; the reconciliation dropped it with the tensor cleanup.

* fix(compute): restore one-hot chunk-size metadata on root polys

OneHotPoly and MultilinearPolynomial expose their K through
RootPolyMeta again; downstream commit packaging derives the group's
one-hot flavor from it.

* fix(prover): close optimization review gaps

Route root release and grouped one-hot commitments through their inner implementations. Share quotient planning and one-hot storage dispatch, and split ring-switch execution from the CPU backend.

Allow expected profile cache releases, remove the orphan schedule, and add Q32, concurrency, and path-specific regression coverage.

* fix(onehot): make block cache caller-owned

Keep persistent block storage under explicit caller control. Ordinary commits stream from canonical indices, while opening operations borrow prepared blocks or use operation-local materialization. Remove the protocol-wide release hook so proving cannot evict state shared by downstream clones.

* fix(cache): make tensor and NTT retention explicit

Keep tensor-root projections operation-local unless callers prepare them explicitly. Retain shared NTT state by default and expose an open root-fold lifecycle hook plus an opt-in release wrapper. Propagate release failures and deduplicate aliased cache owners.

* refactor(profile): split workload module

Move proof sizing, profile data, claims, cache checks, and each execution scenario into focused modules. Preserve the existing workload facade and runtime behavior while keeping every Rust file below the CI line cap.

* docs(spec): define PR 375 end state

* fix(cache): align NTT prewarm and release

Remove released cache keys so smaller requests rebuild their exact extent. Route prewarming and planned memory through the backend retention policy used by CPU ring-switch streaming. Document lifecycle and concurrency rules, and complete local unsafe safety arguments.

* refactor(onehot): unify sparse block representation

* refactor(commit): finish source-typed kernel cutover

* perf(onehot): unify commit sweep scheduling

Use one group driver for range materialization, worker partitioning, scratch-bounded tiling, and source-ordered output.

Retain only the measured bucketed and merge production sweeps. Keep direct arithmetic as a test oracle, expose route statistics in tracing, and document the exact selector and 8 MiB per-worker budget.

* fix(commit): restore group source parallelism

Run independent dense and sparse-ring sources through the existing feature-gated parallel iterator inside their group kernels. One-hot groups keep their fused scheduler.

Addresses review discussion #3742146391.

* refactor(onehot): remove mutable derived caches

* ci(profile): improve reports and narrow builds

Describe the exact public opening statements and split the compact report into readable timing, memory, and proof size tables.

Build each matrix group with its narrow feature while preserving the profile-ci fallback for older merge bases. Fold the current coverage contract into the Book and archive the stale coverage spec.

Adapts the useful changes from draft PRs #360, #361, and #362 to the current benchmark matrix.

* perf(planner): reduce recursive sizing overhead

Add exact scalar witness sizing, reuse bounded checked compression plans, and reject non-contracting recursive split bodies before B/D construction. Preserve the exhaustive candidate domain and verify against the unpruned planner oracle.\n\nKnown limitation: fp128_onehot_recursive still does not finish catalog generation within the measured five-minute window, so this checkpoint does not resolve the stale recursive catalog blocker.

* refactor(ring-switch): unify quotient planning

Remove the temporary fixed ring-switch backend trait and row-plan wrappers so source-typed kernels own the CPU implementation directly.

Make cached and streamed quotient paths share validated matrix geometry, bounds, and CRT chunk planning. Strengthen exact-prefix and wide-accumulation boundary tests, and remove unused public wide-ring helpers.

* ci(profile): unify fold report layout

Join planner choices, witness geometry, and proof costs in one row per fold. Emit group-specific records for multi-group roots and setup offloads so distinct commitment parameters remain visible.

Keep percentage deltas for measured costs and exact merge-base values for discrete planner choices.

* chore(pr375): complete validation slice

Repair the explicit D64 root commitment benchmark without weakening production schedule checks. Record one hot route decisions in profile reports and validate the parser against the isolated CI artifact.\n\nReplace the optimization book stub, align backend and ownership docs, and close the PR 375 spec with benchmark, compatibility, and lifecycle evidence.

* fix(prover): close independent review gaps

Preserve exact NTT operation requirements through backend routing, join retained cache requests by physical owner, and batch homogeneous projection groups through their child kernels.

Remove leaked commitment-only bounds and the streamed source wrapper, split oversized modules, add routing regressions, and archive the implemented PR specification.

* fix(profile): correct multi-group report values

* feat(profile): compare verifier thread modes

* perf(planner): retain hot suffix cache entries

Use bounded second-chance eviction within the existing direct and prefixed suffix quotas. A 700,000-insertion census reduced recomputations from about 218,000 to 145,179 without changing candidate coverage.\n\nShare setup and payload frontier keys only in states that retain both projections, and use binary search over monotone SIS rank rows. The exact planner and unpruned oracle suite passes all 21 tests.

* refactor(profile): clarify fold report cells

Group planner, work, and proof details into labeled blocks while preserving the side-by-side fold comparison. Keep multi-group precommitment, final-group, and setup-offload parameters visibly separate.

* perf(planner): bound recursive split frontier

Keep recursive split enumeration exact through twelve reduced variables. For larger multi-candidate suffix states, retain both extremes and a five-point window around the analytic balance point. Ordinary single-winner direct search still checks the complete split domain.

Move prefix-only rejection before child recursion, avoid retaining unused prefix frontiers, and compact present setup lengths with NonZeroUsize. Regenerate both recursive catalog families.

This intentionally trades global optimality for large frontier states for a practical, explicit search policy. Full 14-family generation now completes in 36 seconds.

* fix(sis): restore generated table identity

Reconnect the split artifact digest test and make the generated digest constants the single runtime source of truth. Refresh the q128 Inner/512 extension digest for the checked-in rows and regenerate every catalog identity.

Also replace the compression planner's manual loop counter so all configured CI Clippy graphs pass.

* fix(profile): remove persisted bench setup

Construct recursive benchmark setup in memory for every sample instead of enabling disk persistence. This prevents public matrix and prefix registry caches from entering per-group handoff artifacts and makes setup timing measure fresh construction.

* fix(prover): preserve i16 opening digits

* docs(pr375): reopen CPU policy spec

Define configurable CPU resource limits on the existing backend, complete NTT release semantics, and the downstream Jolt validation slices.

* refactor(planner): resolve review findings

* feat(compute): configure CPU resource limits

* fix(planner): preserve terminal basis winners

* fix(compute): release all CPU NTT caches

* fix(compute): retain compression NTT cache

* feat(profile): report CPU resource limits

* perf(ntt): use exact tail for quotients

Route centered relation quotients through the existing five-prime CRT prefix plus the 12289 exactness tail when one base term cannot fit. Prewarm only the affected A prefixes and keep scalar arithmetic as the final capacity fallback.

Parallelize independent exact-i16 commitment blocks and restore the advertised setup-first objective for direct grouped schedule generation.

* test(ntt): guard small-field cache plans

Lock the fp32 and fp64 dense nv26 schedules to their ordinary cached NTT domains and verify that catalog planning agrees with field-typed runtime tail selection across every modulus profile.

Remove the stale profile label that described shipped D128 catalogs as runtime-DP schedules.

* ci(profile): clarify dense benchmark suite

Rename the existing three-field dense benchmark leg instead of duplicating runner work.

Show the resolved A/B/D fold schedule in compact reports and update the active profiling documentation to explain why fp128 uses D256 only for the root A role.

* fix(ntt): fail closed on unsafe streaming

Reject ring-switch work that exceeds the streamed CRT capacity before entering the retained-cache path. This preserves the configured memory bound and adds a regression proving no cache slot is built on failure.

* test(pcs): dispatch adaptive opening dimensions

* fix(pcs): generalize adaptive opening helper

* fix(profile): close benchmark report review gaps

* refactor(planner): centralize admission and pruning

Route precommit admission, scalar sizing, Pareto insertion, recursive split traversal, and generated-family providers through their canonical owners. Harden descriptor validation, entropy coverage, SIS limits, output isolation, and exact i16 composition tests in response to review.

* fix(prover): resolve routed cache review findings

* fix(ci): align recursive profile linkage

* fix(ci): align recursive profile linkage

* fix(ci): restore balanced nextest shards

* test(pcs): pin adaptive W8R2 schedule shape

* fix(profile): address benchmark review follow-ups

Resolve schedule features transitively across crate boundaries and derive profile linkage allowlists from that canonical graph.\n\nThread the exact final group layout into benchmark reporting, reject incomplete public group metadata, and simplify compact report tables.\n\nAlso make workflow-step test failures explicit.

* fix(ci): isolate recursion build cache

Key the recursion smoke target cache by the exact source revision. This prevents path dependencies outside the recursion workspace from restoring stale artifacts across PRs.

---------

Co-authored-by: Markos Georghiades <mgeorghiades@a16z.com>
Co-authored-by: sumchecker <241190306+sumchecker@users.noreply.github.com>
quangvdao added a commit that referenced this pull request Aug 10, 2026
* perf(onehot): keep big blocks on the tiled column sweep; row-pass accumulators

- Oversized blocks (hot count beyond the wide accumulators' 2^15 headroom)
  are split into cap-respecting sub-blocks and swept through the bucketed
  tiled kernel, then re-merged per parent — the previous per-block safe
  fallback re-streamed n_a A rings per hot coefficient (~15 TB at a 2^26
  one-hot trace column group) and dominated trace-scale commits. Measured:
  2^26 K=256 jolt prove 333s -> 154s (commit ~252s -> ~80s).
- Row-pass accumulation (one wide ring per block live at a time) with the
  tile budget parameterized; sweep-structure and shift-accumulate
  microbenches added (ignored) for A/B iteration.
- In-place NEON AddAssign/SubAssign for Fp128x8i32 (no temp round-trip;
  measured neutral on M4 — kept for clarity of intent).
- inner_ajtai_wide_onehot_safe retained as the overflow-safety reference.

* perf(onehot): fused multi-polynomial commit sweep

Every polynomial of a committed group multiplies the same A matrix, but
the sweep ran per-poly, re-streaming A once per polynomial — the
dominant commit traffic at trace scale (~11 TB at 2^26/K256, ~28 s of
the ~82 s commit).

Adds a merge-based fused kernel (column_sweep_core_merge): blocks carry
cursors over their position-sorted entries and the kernel walks A
columns in L1-sized chunks, so one A pass serves every block of every
polynomial in the batch — and the counting/scatter pass (whose packed
buffer scales with tile size) disappears. Wiring:
CommitmentComputeBackend::onehot_commit_rows_multi (default loops the
single-poly path), RootCommitKernel::commit_inner_group (default
per-source), OneHotPoly::commit_inner_group, and the batched-prove
commit path groups the whole batch.

Byte-equal to per-poly sweeps (new equality test covers core-vs-core,
wrapper round-trip, and tile-size independence); 223 unit tests pass.

* perf(onehot): keep merge-sweep accumulator tile and column chunk L1-resident

The fused sweep ran its 58-block accumulator set (116 KB) plus a 64 KB
widened-column chunk out of L2, costing ~1.5x per accumulate (68 vs
28 ns in the tight-tile bench). Cap the merge tile at 32 blocks of
accumulators (64 KB) and halve the column chunk to 16 (32 KB) so both
live in L1; the extra A re-streaming this causes is negligible after
poly fusion. Also spans the fold grind (fold_grind_sample) for opening
attribution.

* fix(onehot): self-reduce merge-sweep accumulators at the cap; no block splitting

At trace scale every one-hot block exceeds the 2^15 wide-accumulator
cap (~2^19 accumulations at ppb 2^21), so the merge path inherited the
splitting wrapper's 16x sub-block explosion — which turned the L1 tile
cap into a 29x A re-stream and mostly-empty cursor scans (2^26 prove
regressed to 252s). Fold each block's wide accumulator into a canonical
partial whenever it reaches the cap instead: a handful of reduces per
block-row, no splitting, blocks keep dense full-range chunks, and small
L1 tiles are genuinely safe. New regression pins the self-reducing
kernel against the splitting wrapper on an oversized block.

* perf(onehot): bench-tuned merge-sweep defaults (tile 64 blocks, chunk 32 cols)

Full (tile x chunk) matrix at a trace-like sparse shape is flat within
5-30%; (64, 32) is the minimum at 61.4 ns/accum vs 64.4 at the previous
default. The kernel is at its practical floor for quarter-density
one-hot blocks — the 28 ns dense-shape bench figure does not transfer.
Adds the merge_sweep_bench tuning matrix (ignored).

* feat(onehot): expose clear_block_cache on OneHotPoly

The per-block storage is a pure cache over the retained hot indices
(blocks_for rebuilds it on demand), but it is trace-scale — ~8 bytes per
hot entry across every committed column — and otherwise lives from commit
until the opening fold. Callers that know the sweep is done can drop it
and pay one parallel rebuild inside the fold.

* perf(prover): build the setup NTT envelope slot lazily and let callers drop it between uses — 2^26 jolt e2e peak 87.7->81.3GB, prove 118.8->99.4s

Registration at prepare_setup now only reserves the slot cell and records
the CRT profile; with_shared_ntt builds single-flight on first use, and
drop_built_ntt_slots() returns built slots to the reserved state (next use
rebuilds, ~1.9s at the jolt 2^26 envelope). Keeps the ~28GiB transformed
matrix out of every window that doesn't touch it: unused setups never
build, and the caller can drop between the commit's terminal product and
the stage-8 fold.

* perf(prover): extent-sized NTT slots + streamed root-relation transforms — 2^26 jolt e2e peak 87.7->55.1GB, prove 118.8->95.6s

Three changes that together keep the transformed matrix out of the fold
window (it was ~30GiB of standing memory at the jolt 2^26 shape):

- with_shared_ntt(extent, f): consumers declare the rows x width extent
  they slice; slots build at the rounded request (smallest built cover
  reused, envelope-warmed setups unchanged). The commit's terminal
  product now builds 5GiB instead of 30.
- ring-switch relation/quotient rows above 2^21 rings stream per-element
  transforms from A's field form inside the tile loop (new cyc-only ring
  constructor; chunked z-quotient mirrors the cached path's bracketing;
  both paths bit-identical to the cache fill — equality tests included).
  The root relation reads each element once per prove, so caching its
  transform was pure standing memory.
- fold-entry envelope warms (prove.rs role/terminal, ring-switch
  commit_w/commit_terminal_w) skip the base ring dim: its consumers
  self-serve extent-sized, cross-D dims keep the eager warm.

AKITA_NTT_BUILD_BACKTRACE=1 dumps a backtrace per slot build for future
residency diagnosis.

* perf(prover): drop built NTT slots after the root fold level — fold window 51.3->49.3GiB sampled at 2^26, prove unchanged

Root-level slots dwarf every deeper level's; releasing them keeps the
fold tail (where sumcheck transients spike) off root-scale caches, and
deeper levels rebuild their own sub-GiB slots on first use. Peak-neutral
on its own (the stage-3/4 transient now binds at ~51 GiB sampled) —
rides with the stage-window items.

* perf(prover): releasable setup matrix with seed re-derivation — 2^26 jolt e2e peak 55.1->47.1GB, prove 95.6->99.3s

The field-form matrix is a pure function of the public seed, so its
backing store is cache. AkitaExpandedSetup.shared_matrix becomes
SharedSetupMatrix: seed-backed shape metadata (envelope keys and
validation never shrink), covering_at_dyn/full accessors over a swappable
Arc store, release_to_prefix, and a per-element MatrixElementDeriver
(same XOF stream as derive_public_matrix_flat — bit-identical values,
equality-tested). Derivation is captured as monomorphized fn pointers at
construction, so consumers need no extra bounds.

After the commit sweep (its last full-width reader) the store releases
to a 2^21-ring prefix that serves slot rebuilds and small setup reads;
wide readers stream per element: the ring-switch relation kernels take a
StreamedASource (materialized pre-release, seed-derived after), and the
relation weight events read per-column ring slices through
SetupRowFamily instead of full row views. Setup-contribution scans cover
only the rows they read, not padded view lengths. A full-width covering
re-caches the store (the verifier's root-level scan legitimately reads
the whole matrix; later proves re-release), so within one process the
~2.4s derive amortizes to once per prove/verify cycle — first-verify
cost 0.2->2.6s, standalone verifiers already pay full derivation at
setup.

* perf(prover): build commit-sweep block tiles lazily from index columns — 2^26 jolt e2e peak 47.1->44.1GB, commit window 43.7->35.1GiB

The fused group commit materialized every polynomial's block entries
(~200 B/cycle across a 29-poly batch) before sweeping. Blocks partition
the ring-element index space contiguously, so from_indices gains
block-range variants reading exactly a tile's slice of the retained
index columns; per-tile builds across the sweep sum to the same single
pass. commit_inner_group hands the sweep LazyOneHotBlocks builders
(OneHotCommitBlocks::{SingleChunk,MultiChunk}Lazy) and each thread
materializes one L2 tile at a time (~2 GiB in flight for the batch),
dropping it after the pass. The tile pass is extracted from the merge
kernel and shared, so lazy results are byte-equal to eager
(equality-tested). Side effect: later windows drop ~6-9 GiB too — the
cache's freed pages no longer linger in the allocator. Single-poly and
small-batch paths keep the eager cache.

* perf(prover): stream fold blocks from index columns — per-block builds in fold_blocks/_ring, per-(block,position-window) builds in the tensor accumulate

The fold's opening-claim evaluation was the sole builder of the full
per-block entry cache (probe-verified: every blocks_for build flowed
through fold_kernels::evaluate_claims_at_prepared_point), and the tensor
decompose reused it. Both consumers visit each entry range exactly once:
fold_blocks/_ring build one block at a time, and
onehot_accumulate_tensor_lazy builds one (block, position-window) at a
time (LazyOneHotBlocks generalized to ring-range builds; pos_in_block
stays absolute). Total build work equals one pass over the retained
index columns; the eager tensor kernel stays as the reference for the
lazy-equality test. 2^26 measurement pending a quiet machine (first
attempt voided by mid-run user activity).

* refactor: shrink the perf-branch diff before upstreaming

- delete measured-dead code: Fp128Lazy (negative A/B result), the
  row-outer sweep variant + bench entry, inner_ajtai_wide_onehot_safe
- delete perf-campaign scaffolding: planner candidate dump, three
  env-gated backtrace blocks
- from_indices delegates to the ring-range builders; one view_layout
  helper replaces triplicated validation in OneHotPoly; lazy fold arms
  collapse into a macro; base-dim NTT warm skip moves into
  ensure_envelope_ntt (one home instead of five call sites)
- fix two real residency leaks the review found: the tensor decompose
  layout probe rebuilt+cached a full block set inside the fold, and two
  setup-prefix readers materialized the full matrix post-release
- export NTT_STREAM_THRESHOLD_RING_ELEMENTS + a pinned
  release_setup_matrix_to_streaming_prefix so the retained prefix and
  the streaming threshold cannot drift apart
- fix two doc comments stranded on the wrong item by earlier insertions

2^26 validation: prove 101.3s / peak 44.09GB (unchanged).

* perf(algebra): fuse fixed-size wide ring shifts

* perf(algebra): expose wide ring coefficients

* perf(prover): consume decompose witness rows without copies

* perf(prover): release root opening storage after fold

* fix(profile): propagate commit accumulator bounds

* perf(prover): cache only required commit transform

* perf(prover): stream CRT-chunked quotient roles

* perf(prover): parallelize relation setup columns

* perf(prover): coalesce aligned relation events

* perf(prover): parallelize exact-prefix folds

* fix(prover): preserve group-local relation dimensions

* perf(planner): trade payload slack for narrower roots

* fix(planner): preserve scalar rank policy through recursion

* fix(planner): emit rustfmt-stable catalog imports

* fix(planner): remove stale lint expectation

* fix(types): size released setup without rebuilding

* test(prover): drop local tuning probes

* fix(pcs): update releasable setup call sites

* test(pcs): align mixed-D cache test with lazy setup

* test(prover): split oversized backend test modules

* feat(planner): decouple inner commitment basis

Search inner and opening decomposition bases independently across dense, setup-prefix, and recursive commitments.

Add exact i16 commitment support, wider SIS buckets, padded-prefix-aware selection, and dense nv26 schedule coverage.

* fix(planner): bound independent-basis search

Keep distinct next-witness classes so recursive feasibility remains exact, while dropping only dominated one-digit inner bases.

Bound suffix memoization and catalog workers to prevent schedule regeneration from exhausting memory after the search-domain expansion.

* refactor(prover): split CPU backend by role

* perf(planner): evict bounded memo entries

* fix(planner): skip discarded sweep work

* test(config): expect independent dense basis

* fix(planner): decouple precommit inner basis

* refactor(planner): tighten candidate context

* feat(planner): preserve partial regen rows

* chore(schedules): restore D64 onehot rows

* refactor(prover): isolate CPU prepared setup

* ci(planner): avoid redundant table regeneration

* fix(planner): preserve unsupported regen rows

* feat(planner)!: complete independent basis search

Decouple raw inner commitment bases from opening bases while preserving exact one-hot and recursive balanced-digit sources.

Add padded-prefix Pareto planning, profile-native precommits, canonical signed-digit support, bounded exact suffix search, atomic catalog publishing, and full SIS policy audit artifacts.

Preserve the established complete-schedule selection objectives while refining recursive setup scoring to physical padded capacity.

* fix(ci): refresh precommit registries

Remove the stale all-schedules test import and regenerate standalone precommit profiles with the merged independent-basis planner so catalog coverage matches runtime lookup.

* fix(sis): harden table publication

Require the canonical proven-pruned profile and mandatory validation for production Rust artifacts. Correct certificate provenance and table digests, align the parallel exhaustive diagnostic profile with the quantum LGSA model, and split oversized estimator/type test modules.

* fix(schedules): refresh SIS table identity

Propagate the corrected SIS provenance digest into all generated catalog identities and precommitted descriptors. Recompute the four affected catalog key digests so validation remains fail closed without changing schedules or numeric SIS rows.

* chore(sis): remove obsolete audit CSV

Keep generated_sis_table/policy_audit.csv as the only canonical production SIS certificate. Direct full comparison jobs to temporary output and align the book and estimator documentation with the proven-pruned shared-digest policy.

* revert(planner): drop payload-slack schedule selection

Removes the rank-aware selection policy (payload slack for narrower
roots) per review feedback: the planner is being reworked upstream and
this policy should not bake into catalog identity. Restores
akita-planner, akita-config, and akita-schedules to their origin/main
state; the prover optimizations in this branch are unaffected.

* fix(ci): repair doc links and glue trait bound

Rustdoc denies public docs linking private items; the trusted-artifact
glue impl needs RandomSampling for seed re-derived setup construction.

* fix(tests): drop tensor-kernel test and port oracle to flat views

* fix(compute): restore onehot_chunk_size on RootPolyMeta

Downstream root-poly adapters key one-hot commit planning on the
chunk size; the reconciliation dropped it with the tensor cleanup.

* fix(compute): restore one-hot chunk-size metadata on root polys

OneHotPoly and MultilinearPolynomial expose their K through
RootPolyMeta again; downstream commit packaging derives the group's
one-hot flavor from it.

* fix(prover): close optimization review gaps

Route root release and grouped one-hot commitments through their inner implementations. Share quotient planning and one-hot storage dispatch, and split ring-switch execution from the CPU backend.

Allow expected profile cache releases, remove the orphan schedule, and add Q32, concurrency, and path-specific regression coverage.

* fix(onehot): make block cache caller-owned

Keep persistent block storage under explicit caller control. Ordinary commits stream from canonical indices, while opening operations borrow prepared blocks or use operation-local materialization. Remove the protocol-wide release hook so proving cannot evict state shared by downstream clones.

* fix(cache): make tensor and NTT retention explicit

Keep tensor-root projections operation-local unless callers prepare them explicitly. Retain shared NTT state by default and expose an open root-fold lifecycle hook plus an opt-in release wrapper. Propagate release failures and deduplicate aliased cache owners.

* refactor(profile): split workload module

Move proof sizing, profile data, claims, cache checks, and each execution scenario into focused modules. Preserve the existing workload facade and runtime behavior while keeping every Rust file below the CI line cap.

* docs(spec): define PR 375 end state

* fix(cache): align NTT prewarm and release

Remove released cache keys so smaller requests rebuild their exact extent. Route prewarming and planned memory through the backend retention policy used by CPU ring-switch streaming. Document lifecycle and concurrency rules, and complete local unsafe safety arguments.

* refactor(onehot): unify sparse block representation

* refactor(commit): finish source-typed kernel cutover

* perf(onehot): unify commit sweep scheduling

Use one group driver for range materialization, worker partitioning, scratch-bounded tiling, and source-ordered output.

Retain only the measured bucketed and merge production sweeps. Keep direct arithmetic as a test oracle, expose route statistics in tracing, and document the exact selector and 8 MiB per-worker budget.

* fix(commit): restore group source parallelism

Run independent dense and sparse-ring sources through the existing feature-gated parallel iterator inside their group kernels. One-hot groups keep their fused scheduler.

Addresses review discussion #3742146391.

* refactor(onehot): remove mutable derived caches

* ci(profile): improve reports and narrow builds

Describe the exact public opening statements and split the compact report into readable timing, memory, and proof size tables.

Build each matrix group with its narrow feature while preserving the profile-ci fallback for older merge bases. Fold the current coverage contract into the Book and archive the stale coverage spec.

Adapts the useful changes from draft PRs #360, #361, and #362 to the current benchmark matrix.

* perf(planner): reduce recursive sizing overhead

Add exact scalar witness sizing, reuse bounded checked compression plans, and reject non-contracting recursive split bodies before B/D construction. Preserve the exhaustive candidate domain and verify against the unpruned planner oracle.\n\nKnown limitation: fp128_onehot_recursive still does not finish catalog generation within the measured five-minute window, so this checkpoint does not resolve the stale recursive catalog blocker.

* refactor(ring-switch): unify quotient planning

Remove the temporary fixed ring-switch backend trait and row-plan wrappers so source-typed kernels own the CPU implementation directly.

Make cached and streamed quotient paths share validated matrix geometry, bounds, and CRT chunk planning. Strengthen exact-prefix and wide-accumulation boundary tests, and remove unused public wide-ring helpers.

* ci(profile): unify fold report layout

Join planner choices, witness geometry, and proof costs in one row per fold. Emit group-specific records for multi-group roots and setup offloads so distinct commitment parameters remain visible.

Keep percentage deltas for measured costs and exact merge-base values for discrete planner choices.

* chore(pr375): complete validation slice

Repair the explicit D64 root commitment benchmark without weakening production schedule checks. Record one hot route decisions in profile reports and validate the parser against the isolated CI artifact.\n\nReplace the optimization book stub, align backend and ownership docs, and close the PR 375 spec with benchmark, compatibility, and lifecycle evidence.

* fix(prover): close independent review gaps

Preserve exact NTT operation requirements through backend routing, join retained cache requests by physical owner, and batch homogeneous projection groups through their child kernels.

Remove leaked commitment-only bounds and the streamed source wrapper, split oversized modules, add routing regressions, and archive the implemented PR specification.

* fix(profile): correct multi-group report values

* feat(profile): compare verifier thread modes

* perf(planner): retain hot suffix cache entries

Use bounded second-chance eviction within the existing direct and prefixed suffix quotas. A 700,000-insertion census reduced recomputations from about 218,000 to 145,179 without changing candidate coverage.\n\nShare setup and payload frontier keys only in states that retain both projections, and use binary search over monotone SIS rank rows. The exact planner and unpruned oracle suite passes all 21 tests.

* refactor(profile): clarify fold report cells

Group planner, work, and proof details into labeled blocks while preserving the side-by-side fold comparison. Keep multi-group precommitment, final-group, and setup-offload parameters visibly separate.

* perf(planner): bound recursive split frontier

Keep recursive split enumeration exact through twelve reduced variables. For larger multi-candidate suffix states, retain both extremes and a five-point window around the analytic balance point. Ordinary single-winner direct search still checks the complete split domain.

Move prefix-only rejection before child recursion, avoid retaining unused prefix frontiers, and compact present setup lengths with NonZeroUsize. Regenerate both recursive catalog families.

This intentionally trades global optimality for large frontier states for a practical, explicit search policy. Full 14-family generation now completes in 36 seconds.

* fix(sis): restore generated table identity

Reconnect the split artifact digest test and make the generated digest constants the single runtime source of truth. Refresh the q128 Inner/512 extension digest for the checked-in rows and regenerate every catalog identity.

Also replace the compression planner's manual loop counter so all configured CI Clippy graphs pass.

* fix(profile): remove persisted bench setup

Construct recursive benchmark setup in memory for every sample instead of enabling disk persistence. This prevents public matrix and prefix registry caches from entering per-group handoff artifacts and makes setup timing measure fresh construction.

* fix(prover): preserve i16 opening digits

* docs(pr375): reopen CPU policy spec

Define configurable CPU resource limits on the existing backend, complete NTT release semantics, and the downstream Jolt validation slices.

* refactor(planner): resolve review findings

* feat(compute): configure CPU resource limits

* fix(planner): preserve terminal basis winners

* fix(compute): release all CPU NTT caches

* fix(compute): retain compression NTT cache

* feat(profile): report CPU resource limits

* perf(ntt): use exact tail for quotients

Route centered relation quotients through the existing five-prime CRT prefix plus the 12289 exactness tail when one base term cannot fit. Prewarm only the affected A prefixes and keep scalar arithmetic as the final capacity fallback.

Parallelize independent exact-i16 commitment blocks and restore the advertised setup-first objective for direct grouped schedule generation.

* test(ntt): guard small-field cache plans

Lock the fp32 and fp64 dense nv26 schedules to their ordinary cached NTT domains and verify that catalog planning agrees with field-typed runtime tail selection across every modulus profile.

Remove the stale profile label that described shipped D128 catalogs as runtime-DP schedules.

* ci(profile): clarify dense benchmark suite

Rename the existing three-field dense benchmark leg instead of duplicating runner work.

Show the resolved A/B/D fold schedule in compact reports and update the active profiling documentation to explain why fp128 uses D256 only for the root A role.

* refactor(planner): enumerate exact role tuples

* feat(config)!: adapt small-field schedule profiles

* feat(planner): adapt direct grouped schedules

* feat(config): expand small-field dimensions

Certify and dispatch fp64 through D512 and fp32 through D1024 for the inner commitment role. Keep outer and opening search bounded at D256, regenerate every affected schedule family, and cover the exact NTT requirements and runtime dispatch paths.

* fix(catalog): harden adaptive runtime wiring

Unify dispatch, SIS coverage, runtime capability, and generated-family ownership around canonical policy tables. Reject non-monotone terminal dimensions, remove dead runtime obligations and duplicate routing, strengthen drift/oracle coverage, and align live documentation.

* fix(ntt): fail closed on unsafe streaming

Reject ring-switch work that exceeds the streamed CRT capacity before entering the retained-cache path. This preserves the configured memory bound and adds a regression proving no cache slot is built on failure.

* test(sis): align role-specific D512 coverage

* test(pcs): dispatch adaptive opening dimensions

* fix(pcs): generalize adaptive opening helper

* test(config): clean all-schedules feature graph

* fix(profile): close benchmark report review gaps

* refactor(planner): centralize admission and pruning

Route precommit admission, scalar sizing, Pareto insertion, recursive split traversal, and generated-family providers through their canonical owners. Harden descriptor validation, entropy coverage, SIS limits, output isolation, and exact i16 composition tests in response to review.

* fix(profile): report benchmark shards exactly

Record each workflow shard in benchmark artifacts, render field-first shard ownership separately from public opening statements, and make partial merge-base coverage explicit so missing base modes never produce false deltas.

* fix(prover): resolve routed cache review findings

* fix(ci): align recursive profile linkage

* fix(ci): check adaptive profile linkage

* fix(config): drop stale recursive import

* fix(ci): align recursive profile linkage

* fix(ci): restore balanced nextest shards

* test(pcs): pin adaptive W8R2 schedule shape

* fix(profile): address benchmark review follow-ups

Resolve schedule features transitively across crate boundaries and derive profile linkage allowlists from that canonical graph.\n\nThread the exact final group layout into benchmark reporting, reject incomplete public group metadata, and simplify compact report tables.\n\nAlso make workflow-step test failures explicit.

* fix(ci): isolate recursion build cache

Key the recursion smoke target cache by the exact source revision. This prevents path dependencies outside the recursion workspace from restoring stale artifacts across PRs.

---------

Co-authored-by: Markos Georghiades <mgeorghiades@a16z.com>
Co-authored-by: sumchecker <241190306+sumchecker@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-spec PR has no spec file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants