Skip to content

Add the allocation gate: alloc-diff and assert --max-alloc-mb - #214

Closed
jantimon wants to merge 0 commit into
mainfrom
feat/alloc-gate
Closed

Add the allocation gate: alloc-diff and assert --max-alloc-mb#214
jantimon wants to merge 0 commit into
mainfrom
feat/alloc-gate

Conversation

@jantimon

@jantimon jantimon commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Stacked on #213 (assert --format json). Review only this PR's own diff; merge from the tip of the stack. The alloc gate is wired through #213's AssertView, hence the stack.

Problem

A GC-pressure regression that allocates hard but costs little CPU passed every wpd gate. In the dogfood, cpu-diff caught a +61% allocation regression only by accident (building the array also cost CPU); a pure large-buffer / retained-churn regression sails through counts, timing, slice, and CPU gates alike.

Change

Two owed surfaces, mirroring the existing CPU gate:

  • alloc-diff <baseline> <current> --fail-on-regression gates on net allocated bytes (the allocation analog of cpu-diff's net JS self-time), with per-package and per-function byte movers, a comparability refusal across an incompatible workload/lane/capture, and an AllocDiffResult under --format json|toon.
  • assert --max-alloc-mb <mb> gates the total sampled MB against a budget.

Both read a --target node --alloc recording's sidecar .alloc.json. A recording with no alloc model (a chrome or node-cpu capture) is a loud n/a-FAIL, never a silent pass; a run-group (no --alloc member exists) is an n/a-FAIL too.

The noise floor (measured, and consistent with the cpu-diff fix)

Sampled byte totals are the directional tier (~10-20%), so the gate floor is percentage-led, the same two-term shape as cpu-diff: net must clear max(--noise-floor MB, --noise-pct% of the baseline), default max(1 MB, 25%).

[measured, --target node --alloc, gate lock held] on a ~14 MB workload (examples/probes/allocates.mjs at --iterations 20, same module path both sides):

identical-code net +50% regression net
relative p50 6%, p95 15%, max 20% +33..78%

25% sits above the 20% identical-code ceiling with margin. Verified through the built CLI's exit code:

  • identical pairs: 0/90 false-red (100% green)
  • +50% regression pairs: 80/80 caught (100%)
  • 1 MB absolute floor covers a tiny-allocation workload where 25% would be a fraction of a sample; --noise-floor / --noise-pct tune each term.

Scope

  • src/commands/allocdiff.ts (new), src/model/query.ts (AllocDiffResult + delta types), src/cli.ts (alloc-diff + --max-alloc-mb), src/commands/assert.ts (the alloc axis, n/a-FAIL without a model), src/index.ts + README type table + public-types walker.
  • Docs: allocation-profiling.md gains a gating section with the measured floor; facts.md pins the 25% default; README CI-gating section gains the alloc gate + a baseline-management paragraph (where baselines live, what is lean to commit, the re-record-on-upgrade rule).
  • Tests: test/unit/alloc-diff.test.mjs (6: identical, scaling floor, +50% gate, absolute-floor, knob, comparability refusal) and 2 assert alloc-axis tests (gates the sibling total; n/a-FAIL without a model).

Gates: lint, format:check, build, unit (753), measurement (6), the 3 Chrome assert e2e tests all green.

Base automatically changed from feat/assert-json to main August 2, 2026 15:19
@jantimon jantimon closed this Aug 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant