Skip to content

Rework CI floor allocation: bound concurrency to the live container cgroup memory limit, retire the static per_shard scalar - #5877

Merged
briansrls merged 5 commits into
mainfrom
session/sharp-cat-505
Jun 28, 2026
Merged

briansrls merged 5 commits into
mainfrom
session/sharp-cat-505

Conversation

@briansrls

@briansrls briansrls commented Jun 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes the stale-per_shard → silent-OOM failure mode (3 recurrences: #5867 context, #5875 refresh).

Root cause: spawn_width = min(shard_count, hw_threads, floor(budget / per_shard_committed)). The budget term already reads the live cgroup memory.max. But per_shard_committed (a static ByteSize scalar) drifts low as the corpus grows — the last staleness was 2.1 GiB at real 3.0 GiB, giving width=3, 3×3.0=9 GiB > 8 GiB cap → exit-137.

Construction wall: Replace the floor(budget / per_shard_committed) term with an honest 3-case formula:

  1. budget ≤ 0 → conservative fallback width (unchanged)
  2. budget < per_shard_committed → width=1 (single-shard guard: budget too small for even one shard)
  3. else → min(cpu_bound, confirmed_safe_width)

gunbc_ci_floor_confirmed_safe_width = 2 is a new committed integer: the largest concurrency confirmed safe (VmHWM=6.0 GiB at width=2 with 8 GiB runner cap, 2 GiB headroom, main HEAD 6461042). Stale per_shard_committed can no longer raise width beyond this ceiling — the failure mode is structurally closed.

Honest labeling: This is NOT container-scaling. confirmed_safe=2 on a 16 GiB box still gives width=2 (conservative but correct). Width scales up only when a larger confirmed run updates the integer. The proper scaling path is resource-aware-scheduler Node B/C (docs/plans/resource-aware-scheduler.md) where Runnable.cost.space replaces this scaffold.

per_shard_committed role: Vestigial in the width formula (width=1 guard + ResourceEnvelope memory estimate). Marked in gunbc_ci_floor_per_shard_rss_source Disposition. confirmed_safe_width is a Scaffold dissolving to std.realization_schedule.Runnable when Node B/C lands.

Residual risk (documented, not fixed here): per_shard_committed is not fully inert — it still drives case 2 (single-shard guard). Both scalars can therefore go stale: if a single shard's real peak exceeds the runner cap while per_shard_committed lags low, case 2 won't fire AND confirmed_safe_width=2 still permits width=2 → latent OOM. This is the same staleness class one level up. The dissolution trigger (resource-aware-scheduler Node B/C, live per-shard measurement) covers both. The [calibration] hygiene line must be checked against BOTH scalars when staleness is suspected, not just confirmed_safe_width.

Changed files

  • dsl/gunbc/ci_floor_measurement.dag — add gunbc_ci_floor_confirmed_safe_width: Int = 2 + Scaffold disposition; update per_shard source disposition to mark it vestigial in width path
  • src/v2/workflow/ci_floor_plan.dag — replace gunbc_ci_floor_spawn_width_for_budget with 3-case formula; simplify gunbc_ci_floor_run_envelope to parallel_run_demand_envelope(width, committed_per_shard); add 2 new witnesses
  • src/v2/test/claim/ci_floor_plan_witness_test.dag — import + call new witnesses in new test fn ci_floor_confirmed_safe_width_ceiling_witnesses
  • dsl/test/claim/ci_floor_measurement_per_shard_test.dag — import confirmed_safe_width; add witness_confirmed_safe_width_is_positive_and_small + witness_per_shard_fits_within_confirmed_safe_shards

Test plan

  • cargo test --workspace (no Rust changes; floor witness correctness proven below)
  • witness_floor_confirmed_safe_width_bounds_actual_width: 8 GiB budget → width=2 ≤ confirmed_safe=2 ✓
  • witness_floor_ceiling_clamps_stale_per_shard: stale 2.1 GiB → raw_width=3 > safe=2; capped=min(3,2)=2 ≤ safe=2 ✓
  • witness_per_shard_fits_within_confirmed_safe_shards: 3226056704 × 2 = 6452113408 ≤ 8589934592 ✓
  • All existing floor witnesses verified unaffected (zero budget fallback, tight budget backoff, fail-open envelope exceeds, budget-tree governance)

🤖 Generated with Claude Code

Brian Searls and others added 3 commits June 27, 2026 19:27
Replace the stale-per_shard → silent-OOM path with a construction wall:
spawn_width = min(cpu_bound, confirmed_safe_width) where confirmed_safe_width=2
is a committed integer reflecting the largest concurrency confirmed to fit
within the runner cap (VmHWM=6.0 GiB at width=2 on an 8 GiB runner).

The old formula (floor(budget / per_shard_committed)) was the failure mode:
per_shard_committed drifted low (2.1 GiB at real 3.0 GiB) → formula picked
width=3 → 3 × 3.0 = 9 GiB > 8 GiB cap → exit-137 (three recurrences).

The new formula:
  if budget <= 0:  conservative_fallback (unchanged)
  if budget < per_shard_committed:  width=1 (single-shard guard)
  else:  min(cpu_bound, confirmed_safe_width)

per_shard_committed is now vestigial in the width path — its role reduced to
the width=1 guard (budget too small for even one shard) and the ResourceEnvelope
memory estimate. The Disposition on gunbc_ci_floor_per_shard_rss_source is
updated to mark this explicitly.

confirmed_safe_width is a Scaffold dissolving to resource-aware-scheduler
Node B/C (docs/plans/resource-aware-scheduler.md) when Runnable.cost.space
replaces it. It is NOT container-scaling (confirmed_safe=2 on a 16 GiB box
still gives width=2 — that's honest; wider requires a confirmed larger run).

Witnesses:
- witness_floor_confirmed_safe_width_bounds_actual_width: cap budget → width ≤ 2
- witness_floor_ceiling_clamps_stale_per_shard: stale 2.1 GiB raw=3 > safe, capped=2 ≤ safe
- witness_per_shard_fits_within_confirmed_safe_shards: 3 GiB × 2 ≤ 8 GiB cap

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review June 27, 2026 19:33
Brian Searls and others added 2 commits June 27, 2026 19:37
@gunbai-bot

gunbai-bot Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Re: witness_floor_ceiling_clamps_stale_per_shard — agreed the split is worth documenting. The two witnesses serve different roles:

  • witness_floor_confirmed_safe_width_bounds_actual_width exercises the real function path end-to-end (the execution proxy for the ceiling property).
  • witness_floor_ceiling_clamps_stale_per_shard is a mathematical witness that the stale scalar value (2.1 GiB, the value that historically caused exit-137) would produce raw_width=3, and the ceiling reduces it to ≤2. It intentionally avoids calling through the function so it can't be trivially satisfied by a bug in the formula that also affects the inline math.

In other words: one witness tests the implementation; the other tests the mathematical invariant the implementation is supposed to maintain. That said, the inline clamp duplicates some logic and your point that the second witness could pass while the function is broken stands. Will tighten in a follow-up once CI is green.

— sent from sharp-cat-505

@briansrls
briansrls merged commit 2ca4a6d into main Jun 28, 2026
2 checks passed
@briansrls
briansrls deleted the session/sharp-cat-505 branch June 28, 2026 00:54
gunbai-bot Bot pushed a commit that referenced this pull request Jun 28, 2026
Drop the abandoned v1_interpreter.rs bulk-eviction (PR #5886 closed: sustained-RSS
only, did not move the per-shard resolve peak). Record the Lever C design outcome in
the plan .dag authority + regenerate the .md projection (main_wet):
- §2 finding (floor consumes the resolved Node tree, not type_env/func_env;
  teeth-proven) and extend-not-fork (aligns to v2 ResolvedTree/InferredTree, no new
  type);
- the v2-surviving root is a frontier-bounded RETENTION POLICY over InferredTree.facts
  (OWED at v2 00_compile, which holds it whole today);
- A3-default conditional with an explicit flip-to-A1 trigger (implement v1
  frontier-evict only if a residual per-shard peak survives over cap after the
  cheaper fixes — alloc-clamp #5877 landed + Rc-shared sigs #5884 pending).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Jun 28, 2026
…und; A3-default + flip trigger) (#5892)

* WIP: Lever C: stream/evict resolved-module envs (representation-minimization

* WIP: Lever C: stream/evict resolved-module envs (representation-minimization

* Lever C: evict resolved-module envs the interpreter never reads

Project each TypedModule into a fresh one keeping module/items/item_registry
but pointing type_env/func_env at shared empty singletons, so the floor path
releases the never-read envs once the source ResolvedGraph drops. Remove probe
scaffold; untrack scratchpad.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WIP: Lever C: stream/evict resolved-module envs (representation-minimization

* WIP: Lever C: stream/evict resolved-module envs (representation-minimization

* Restore clean #5886 (revert teeth perturbation; items/item_registry kept, only envs evicted)

The teeth perturbation (items emptied) was auto-committed/pushed; it served its
purpose as the discriminating control (rust_tests RED with items evicted vs GREEN
with only type_env/func_env evicted), proving the reflection path consumes
items/item_registry. Restoring the intended change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* WIP: Lever C: stream/evict resolved-module envs (representation-minimization

* Lever C (item 2): record design-note disposition in the plan authority

Drop the abandoned v1_interpreter.rs bulk-eviction (PR #5886 closed: sustained-RSS
only, did not move the per-shard resolve peak). Record the Lever C design outcome in
the plan .dag authority + regenerate the .md projection (main_wet):
- §2 finding (floor consumes the resolved Node tree, not type_env/func_env;
  teeth-proven) and extend-not-fork (aligns to v2 ResolvedTree/InferredTree, no new
  type);
- the v2-surviving root is a frontier-bounded RETENTION POLICY over InferredTree.facts
  (OWED at v2 00_compile, which holds it whole today);
- A3-default conditional with an explicit flip-to-A1 trigger (implement v1
  frontier-evict only if a residual per-shard peak survives over cap after the
  cheaper fixes — alloc-clamp #5877 landed + Rc-shared sigs #5884 pending).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* Lever C: record RESOLVED A3 verdict in the plan note (measured, not data-gated)

Official call (manager stern-moth-225): A3, robust. Post-#5873-cutover floor
measurement (claim_executor per-shard VmHWM × spawn_width=2, sccache excluded):
co-resident 5.98 GiB, 1.82 GiB UNDER the ~7.8 GiB safety threshold below the 8 GiB
host cap, +0.7% vs the 5.94 GiB pre-cutover baseline (noise). The cheaper fixes
already hold the floor under cap; frontier-evict is NOT written into the doomed v1
seed — the ~4 GiB prize is captured durably in v2 streaming-infer. Flip-to-A1
trigger kept documented but marked UN-tripped (re-auditable if the corpus grows).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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