Skip to content

FABRIC-MEM-GRANT-0: one memory grant carrier, one microVM sizing policy, one grain-parameterised rounder (reconciles #11883 + #11885) - #11992

Merged
briansrls merged 4 commits into
mainfrom
session/bold-wolf-254
Sep 21, 2026
Merged

briansrls merged 4 commits into
mainfrom
session/bold-wolf-254

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Summary

FABRIC-MEM-GRANT-0, reconciled from the two independent green implementations (#11883 session/bright-ram-63 @ 125659f and #11885 session/royal-moth-544 @ 80ec506). One carrier, one policy, one rounder, one witness suite. Both superseded PRs are closed with a comment saying which base won.

The defect this addresses is a bypass around the fabric transaction, not an absence of demand consumption: memory is screened before reservation and the runner reads the requirement, but memory is never converted into a grant, never atomically reserved against live host use, and never carried on CellReservation. This PR lands the first of those — the grant carrier and the policy that mints one — and nothing else (see "What this does NOT do").

Base chosen: session/royal-moth-544, and why

Both lanes converged on more than the brief recorded: both carry MemoryGrant<P, A> with a sole_constructor authority token constructed only inside the policy's issue fold, and both take the per-cell ceiling as a parameter. Re-derived, the differences that decided the base:

  1. The rounder fork is resolved, not repeated. royal-moth moves GrainRounding and round_up_to_grain(bytes, grain) to std.measure, reduces gunbc.floor_demand round_up_to_gibibyte_grain to its gibibyte binding, and re-points the three consumer imports (§3 replacement migration, cut at the root). bright-ram inlined a second grain-parameterised rounder in the policy beside floor_demand's — which is the fork.
  2. References are modeled, not nicknamed. royal-moth's policy reference and permit issuer are std.decl_ref DeclarationRef; bright-ram's are NonEmptyStr where brand(...) free text (§3: cite the symbol).
  3. The permit is a reasoned record carrying its default. royal-moth's MemoryCompatibilityPermit { default_grant, permitted_by, reason } rides inside the provenance, so "unstated axis without permit" has no constructor at the carrier and the policy refuses on its own typed arm. bright-ram carried compatibility_permit: Ref? beside a separate compatibility_default: ByteSize on the policy record — permit absent + default present is writable there, and the carrier needed a third refusal arm to validate it.

Ported from session/bright-ram-63

  • Every fleet quantity the policy needs arrives as a parameter. royal-moth imported gunbc.runner_microvm for the cache allowance and admitted in its own frontier note that the wiring item (runner consuming the policy) would then close an import cycle. bright-ram's acyclicity argument is right: the binding now takes (allowance, ceiling), imports nothing from the runner, and is total (grain constructed via gibibyte_grain(), reference and permit are the module's own rows — no Unavailable arm left for a consumer to answer). The witness keeps the pairing obligation by executing the real allowance producer gunbc_runner_microvm_guest_cache_allowance() and assembling the policy exactly as the wiring consumer will.
  • The unstated-axis-through-the-real-route claim (the_fleet_policy_binding_grants_an_unstated_axis_under_its_own_permit).
  • The executed authority-token wall — re-executed here, not cited (M3 below).

Not ported, with reason: bright-ram's token carrying policy: Ref (the fixture policy can set that ref to anything, so it adds no guarantee over the type identity); microvm_memory_grant_is_compatibility_default (no consumer but its witness — §3c dangling; the carrier's memory_grant_standing_is_requirement_checked already answers it).

Applied once: the ByteSize repair (review 69467, review 69468)

gunbc_microvm_memory_compatibility_default_bytes: Int = 4294967296 on both branches is now data gunbc_microvm_memory_compatibility_default: ByteSize = gibibyte_to_byte_size(g: gibibyte(count: 4)) — the unit in the type, the magnitude reached through std.measure gibibyte_scale_factor_bytes, and the witness compares through byte_size_count.

The four decided things, kept

  1. Representability is bounded against int_inclusive_max first (policy microvm_memory_grant_size), the ceiling second (carrier issue_memory_grant). M1 shows exactly one claim goes red when the order is flipped.
  2. A gibibyte-grain control cannot discriminate the checked-add rounder from the subtraction rounder; the discriminator uses grain 1000 (measure_grain_rounding_witness_test an_aligned_count_at_the_bound_is_its_own_ceiling). M2 re-measures it.
  3. Refusal-arm claims assert the arm and that the right inputs reach it (a_minimum_within_one_byte_of_the_bound_refuses_as_unrepresentable uses a small ceiling and still expects the unrepresentable arm).
  4. The carrier does not foreclose the per-host CAS-linearized ledger (FABRIC-HOST-MEMORY-0): a MemoryGrant names its Work and Attempt by FabricIdentity, carries no host, cell or ledger state, and is the value a CellReservation will carry and one CAS will commit alongside occupancy.

Topology precondition (a gate, not an item): exact per-Work sizing is valid only where Work is bound before the VM boots. Nothing here lets a guest discover its Work after boot.

What this carrier does NOT do

  • No production path consumes the policy. gunbc.runner_microvm runner_microvm_shape_after_cpu_admitted still reads the requirement as a fit gate and sizes the guest from the cell remainder. The wiring item is a declared frontier (§3c) at the foot of fabric_memory_grant_policy.dag, with the capability as its trigger: the microVM shape derives its guest memory from a MemoryGrant, with the remainder exposed as one nameable runner function and the runner's memory witnesses re-pointed at the granted size. Import direction for that wiring: runner → policy, never the reverse.
  • No host ledger, no atomic reservation, no field on CellReservation. Those are items 2+ of the program.
  • The witnesses do not run in CI. required_gate_prefixes has no test.claim.fabric row, so this suite is discovered and declined by the required gate; a green check says nothing about these files. Evidence is the local claim_batch run below.

Test plan — executed, at this head, with a binary built from it

Binary: claim_batch built locally (CTRL_BUILD_MODE=local cargo build --release --bin claim_batch, private target dir) from this branch's Rust tree, sha256 ee16009ead17190ef367c71b826d6737b36a09ed94ce04642d5956d8ec6aa611. The change is .dag-only, so the Rust tree at every head below is identical to the one the binary was built from. Recipe per entry: claim_batch --source-root dag --source-root src/v2 --entry <entry> --functions <all test fns>. Every log line carries the binary path, its sha256, git rev-parse HEAD and the dirty count.

Green at 0bbf7a163f3 (the semantic head; a65bcee222b adds one // annotation block only, and the fabric suite was re-run there — see the last row):

entry result
test.claim.fabric_memory_grant_witness_test 16/16 PASS
test.claim.measure_grain_rounding_witness_test 4/4 PASS
test.claim.floor_demand_witness_test — the two rounder consumers (gibibyte_grain_rounds_up_and_leaves_a_whole_gibibyte_alone, a_count_at_the_representable_bound_has_no_gibibyte_ceiling) 2/2 PASS
test.claim.runner_microvm_witness_test — the_guest_cache_allowance_derives_from_the_receipts_last_unstalled_beat (the re-pointed GrainRounded consumer) 1/1 PASS
test.claim.fabric_memory_grant_witness_test at a65bcee222b 16/16 PASS

Mutation controls, each executed at 0bbf7a163f3 (dirty=1) and the tree restored to dirty=0 before the next:

# mutation measured
M1 policy bounds representability by policy.ceiling instead of int_inclusive_max (the ceiling-first order) exactly ONE red: the_policy_carries_the_ceiling_refusal_out_rather_than_resizing; both sizing claims stay green — which is why they are not coverage for this distinction
M2 std.measure round_up_to_grain refuses n > max - (g-1) (the old checked-add pre-check restored) an_aligned_count_at_the_bound_is_its_own_ceiling (grain 1000) RED; a_gibibyte_aligned_count_at_the_bound_is_its_own_ceiling stays GREEN — the power-of-two control does not discriminate, as decided
M3 a fn returning MicroVmMemoryGrantAuthority { } appended to the witness module module REFUSED at resolve, no claim runs: fabric_memory_grant_witness_test.dag:416:3: error: sole_constructor type 'MicroVmMemoryGrantAuthority' cannot be constructed outside its defining module
M4 carrier clamps to the ceiling instead of refusing 4 red: a_grant_above_the_ceiling_refuses_and_does_not_clamp, a_demand_larger_than_the_cell_is_reported_against_the_ceiling, the_policy_carries_the_ceiling_refusal_out_rather_than_resizing, a_permit_default_above_the_ceiling_is_refused_by_the_ceiling_law
M5 policy representability guard deleted a_minimum_within_one_byte_of_the_bound_refuses_as_unrepresentable RED with runtime error [integer-overflow]: 9223372036854775807 + 1 does not fit in a 64-bit Int — the untyped abort the guard replaces
M6 carrier decides the minimum before the ceiling a_demand_larger_than_the_cell_is_reported_against_the_ceiling RED

Not run: the required floor. These modules are outside required_gate_prefixes, so a green check on this PR is not evidence about them (and the floor's own SUCCESS-over-refusal defect is open — docs/plans/microvm-and-floor-wind-down-state.md §1).

Superseded

🤖 Generated with Claude Code

gunbc-ci-auto-heal and others added 3 commits September 20, 2026 17:02
…grant carrier + microVM policy + one grain-parameterised rounder

Parked record, not a PR. Program is parked on operator instruction; this commit exists so the
work is durable. A second independent implementation is bright-ram-63 125659f.

- product.fabric.memory_grant: sole_constructor MemoryGrant<P, A>, authority as a type parameter;
  provenance holds requirement or permit so an unstated axis without a permit is unwritable;
  two laws (below stated minimum, above ceiling), neither clamps.
- gunbc.fabric_memory_grant_policy: fieldless sole_constructor MicroVmMemoryGrantAuthority token
  (DataRevealKey precedent) so the policy is the sole producer by construction; the ceiling is a
  PARAMETER of the fleet binding (no forked remainder subtraction, no invented fleet row);
  representability is bounded against int_inclusive_max FIRST and the ceiling SECOND, and the
  annotation says why the order is load-bearing.
- std.measure round_up_to_grain: the corpus's one rounder, grain a declared FiniteByteSize input,
  subtraction form (pad first, one comparison, no checked_add). gunbc.floor_demand
  round_up_to_gibibyte_grain is now its gibibyte binding; GrainRounding moved to std.measure and
  three consumer import lines re-pointed (runner_microvm, floor/runner witnesses).

Evidence (local claim_batch on the shared /cargo-target binary; these witnesses are NOT on the
required gate): test.claim.fabric_memory_grant_witness_test 14/14 PASS,
test.claim.measure_grain_rounding_witness_test 4/4 PASS (3 at first run; the fourth is the
power-of-two control added after the finding below), the four re-pointed floor_demand /
runner_microvm rounder claims PASS. Mutation controls: ceiling checked ahead of the sizing ->
a_minimum_within_one_byte_of_the_bound_refuses_as_unrepresentable FAILs; checked-add restored in
the rounder -> an_aligned_count_at_the_bound_is_its_own_ceiling (grain 1000) FAILs.

Finding: at any power-of-two grain the checked-add and subtraction rounders refuse the SAME set
(2^63 is a multiple of the grain), so a gibibyte-grain control cannot discriminate them; the
discriminator uses grain 1000. bright-tern-814's annotation claiming otherwise was wrong.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…cy, one grain-parameterised rounder (reconciles #11883 and #11885)

Base: session/royal-moth-544 @ 80ec506. Ported from session/bright-ram-63
@ 125659f: every fleet quantity the policy needs arrives as a parameter
(no import of gunbc.runner_microvm, so the wiring item closes no cycle), the
fleet binding is total, and the unstated-axis-through-the-real-route claim.
Applied once: the compatibility default is a ByteSize derived from the
gibibyte (review 69467, review 69468).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rting it

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…9638, DESIGN 3c)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Sep 21, 2026

Copy link
Copy Markdown
Contributor Author

review 69638 addressed in d08c9b8: memory_grant_standing_is_requirement_checked deleted from the carrier — verified its only call sites were the witness suite (DESIGN §3c: a witness is not a consumer). Each witness site now matches the MemoryGrantStanding arm through a witness-local helper. Re-run at head d08c9b8 with the same locally built claim_batch (sha ee16009e…): fabric suite 16/16 PASS, dirty=0.

@briansrls
briansrls added this pull request to the merge queue Sep 21, 2026
Merged via the queue into main with commit 132c780 Sep 21, 2026
4 checks passed
@briansrls
briansrls deleted the session/bold-wolf-254 branch September 21, 2026 19:45
gunbai-bot Bot pushed a commit that referenced this pull request Sep 22, 2026
Mirror-only, from the merged base. Fixed point proven by a second regen round
with a binary verified to carry the rework: round two reports drift in
std_measure.rs alone, so v1_compiler_emit_rust.rs is what the reworked emitter
itself emits.

std_measure.rs is excluded as before -- it is #11992's unmirrored grain-rounder,
and #12027 is the PR that repairs it.

EVIDENCE RE-ESTABLISHED AFTER THE REWORK, because the coproduct change touched
emit_native_freemonoid_match and every earlier behavioural claim described a
superseded revision:

  list_init             identical three-arm chain, __fm.len() == 1 preserved
  refusals in closure   0, unchanged
  __fm.len() conditions 13 (2 exact, 11 floor), unchanged
  probe                 5/5, exit 0
  red control           3/5 FAIL, exit 1

So the rework is a pure refactor of how the refusal is carried, measured rather
than asserted.

The four enrolled witness rows all return true:
nested_field_arm_and_its_successor_both_reach_the_emitted_chain,
the_ordinary_two_arm_shape_still_lowers_natively,
a_refutable_head_sub_pattern_refuses_rather_than_becoming_a_wildcard,
a_guarded_arm_refuses_rather_than_running_unguarded.

INSTRUMENT PROVENANCE, recorded because it nearly produced a false finding
against this change. /cargo-target is shared across worktrees and sessions. A
neighbouring session's build of v1-compiler overwrote the binary between the
moment I verified it carried the rework and the moment I measured with it, so
two witness rows reported false and a fixture emitted a textbook reproduction of
the original bug -- from a compiler that predated the fix. Caught only because
two greps of one file disagreed: the rework-only string counted 1 earlier and 0
later. Every measurement above was re-taken with a worktree-local
CARGO_TARGET_DIR whose binary was verified by a string that exists only in the
reworked code. The red control needs no such check: its artifact carries the
two-way split and zero length-conditions, and witness row one establishes that
the fixed emitter emits len() == 1 for that exact shape, so the output
identifies its own producer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 22, 2026
…r in agreement

dag/gunbc/plans/dag_v2_defork_audit.dag is restored byte-for-byte to main.

WHY, AND IT IS NOT THAT THE STALENESS WOULD GO UNCAUGHT. docs/plans/dag-v2-defork-audit.md
is a registered PlanArtifact (via plan_registry_batch_b) regenerated ONLY by the
whole-population claim_executor --required-regen. That round currently fails on
'generated surface drift: std_measure.rs' -- a real drift on main since #11992, already
repaired in gunbc#12027 and not mine to re-fix. So editing this .dag meant committing a
carrier whose mirror contradicts it.

THE ARGUMENT I DID NOT GET TO MAKE, refused before I made it: "no CI job here runs the
generated-artifact phase, so nothing gates it" is an argument that the lie would not be
CAUGHT, not an argument that it is not a lie. A registered artifact whose mirror does not
match its authority is a stale present-tense claim in a carrier a reader consults first --
the class gunbc.v2_compile_obligation_census filed itself. Ungated makes it worse, not
admissible: an ungated artifact is one nobody will ever correct.

NOTHING IS LOST. The substance the amendment carried already lives in
gunbc.guarantee_stall.coercion_two_algebras_answer_one_question_stall, which states that the
audit's coercion row rests on the two modules SHARING ZERO TYPE NAMES -- the right question
for a resolver collision guard and the wrong one for a concept fork, since zero shared names
is exactly what makes a fork invisible. The representation_boundary coercions row cites it
too. The prose mirror was the carrier; the fact survives without it.

AND THE MOVE NOT TAKEN: merging gunbc#12027's branch to unblock the regen locally. That
converts an unrelated drift into a dependency between two lanes and inherits its refusals
into this PR's evidence -- which is how a floor verdict was lost elsewhere today.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 22, 2026
… one missing declaration

FOUR FAILING LANES, ONE DEFECT. The consumer half of the mirror carried the new
diagnostic variant and the DECLARING half did not: compile_clean.rs referenced
SiblingOperandEffectOrderUndetermined while v1_std_core.rs did not declare it,
so the seed did not build -- compiler red, clippy cannot compile, floor cannot
run the binary, witnesses is the aggregator echoing them.

THE RULE THIS COST ME, WRITTEN DOWN: THE STAGE0 MIRROR IS TWO FILES FOR A NEW
.dag VARIANT -- the enum's declaring mirror and every consuming mirror -- and
the revert had taken v1_std_core.rs back to main state while compile_clean.rs
kept my hand-authored arms.

AND A SECOND ONE I CAUSED MYSELF: I PREDICTED THE INSTALL LIST INSTEAD OF TAKING
THE REGEN'S. The regen named six drifted files; my script hardcoded four, and
the one it missed was v1_compiler_infer_items.rs -- the mirror of the module
where this change DECLARES item_is_effectful_callee. Install what the regen
names, minus what other lanes own; never a predicted set.

BOOTSTRAP ORDER, because the cycle is real: the hand-authored arms name a
variant only the regen emits, so the seed cannot build to run the regen. Drop
the arms, build, emit, install, restore the arms, rebuild.

VERIFIED BY COUNT RATHER THAN BY A GREEN BUILD:
  src/v1/00_core.dag                           4
  src/v1/stage0/src/v1_std_core.rs             4
  src/v1/stage0/src/cli_run/compile_clean.rs   4
and item_is_effectful_callee present in 04_items.dag, its mirror, and the
consuming infer mirror. Generation 2 reports drift on std_measure.rs ALONE, so
every mirror this change owns is at a fixed point;
--required-regen-fixed-point answers fixed_point_equal=true.

std_measure.rs is PRE-EXISTING drift on main since #11992, owned by #12027, and
is deliberately not installed here. The peer resource wall is confirmed absent
from the mirrors: the revert took fully.

Co-Authored-By: Claude Opus 5 (1M context) <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