Skip to content

Rungs 3 and 4 of the bank ladder: κ = 7.11175695867958e-4, and the top of the complex ledger (priced target, not a witness) - #232

Closed
maxime-fleury wants to merge 11 commits into
CrocSwap:mainfrom
maxime-fleury:research/complex-bank-run3
Closed

maxime-fleury wants to merge 11 commits into
CrocSwap:mainfrom
maxime-fleury:research/complex-bank-run3

Conversation

@maxime-fleury

@maxime-fleury maxime-fleury commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

A scheduled target, not a witness. kappa = 711599961413937/10^18 = 7.11599961413937e-4
-- +0.4671% over #224's rung 2 and +4.1584% over the #207 frontier -- conditional on
the same open obligations rung 2 carries, plus two new inventories. The bank schedule those
rungs need is built here, not merely owed: every bank exactly filled, every item in a block,
the remainder padded from a retained bin.

Package: research/complex-bank-run3/, self-contained on main: it vendors #219's rung-1
package byte-identically under references/pr219-run1/ and #207's frontier certificate, and
pins 27 files by sha256.

cd research/complex-bank-run3 && python3 -B verify.py

The ladder, and where it stops

Rung 2 (#224) absorbs the complex word's rank-11 family and lands on the complex branch's
ceiling, so every further rung has to raise the complex coarse saving. The criterion that
makes such an absorption free is that the family's own volume is a whole number of width-66
banks (66 | rank * children), and exactly three families of that ledger satisfy it:

rung what leaves the ledger per bank banks complex coarse kappa vs rung 2
2 (#224) complex rank 11 6 rank-11 blocks 531 7.08793603125109e-4 0.000708291570590726 —
3, volume criterion + complex rank 16 — 192 7.11077971348264e-4 0.000710572698755137 +0.3221%
3, padded schedule + complex rank 16 4 blocks + 2 registers 198 7.11289982558164e-4 0.000710784408728476 +0.3520%
4, volume criterion + complex rank 20 — 60 7.11681826686289e-4 0.000711175695867958 +0.4072%
4, padded schedule (the top) + complex rank 20 3 blocks + 6 registers 66 7.12106696511698e-4 0.000711599961413937 +0.4671%

The two "volume criterion" rows are the accounting the criterion gives and are kept because
they are what the ledger arithmetic produces -- but a width-66 bank cannot host them (192 and
60 are below the capacity bounds 198 and 66, and no uniform tiling absorbs two bins at
once). The padded rows are the schedule a bank admits, and they price higher, so the padded
rung 4 is the top this PR claims.

After rung 4 no family of the remaining 17 has a whole-bank volume (the check is
machine-asserted), so the accounting criterion the built rungs use is exhausted: 795 banks in
total (531 + 198 + 66), top row W = 35,361, rank mass 2,329,866, 634,473 children, largest
child 19. Each step keeps the row identity 66 * W - rank_mass = 3,960 and drops the stock by
exactly the bank count (531, 198, 66).

Two consequences fall out of the same arithmetic, and they are the useful part:

Status (unchanged blocker, two new items)

obligations.json states C1-C7 and inherits #219's R1-R4; T1, which this PR carried as an
obligation, is settled below. Read from the pins rather
than asserted: the complex supplier's certificate carries no key containing bank at all,
and the only banked word in the pins is the bit word's entrance-gauge pack (#205, 45,842
banks of width 72 over rank-60 exteriors). Nothing enumerates the complex word's rank-11,
rank-16 or rank-20 children, so the item-to-block map has no starting inventory (C6, C7). And
because 66 = 4 * 16 + 2 = 3 * 20 + 6, the two new families cannot tile a bank alone.

T1 is now enumerated, and the answer is negative (schedule66.py, schedule66.json,
re-run by verify.py). A uniform pattern -- the same pattern in every bank, as the certified
bit-side construction uses -- forces one common bank count B with k_f = n_f / B, so B
divides gcd(n_f) and sum_f k_f * f <= 66. That is exhaustive:

family blocks per bank banks by volume criterion banks its capacity needs uniform patterns
11 (rung 2) 6 (66 = 6 * 11) 531 531 4, tightest 531
16 (rung 3) 4 (66 = 4 * 16 + 2) 192 198 4, smallest 198
20 (rung 4) 3 (66 = 3 * 20 + 6) 60 66 3, smallest 66

No subset of two or three families admits a uniform tiling at all; {16, 20} comes closest,
its common divisor 198 giving four rank-16 and one rank-20 block per bank -- 84 registers into
a 66-wide bank. The volume criterion and the capacity criterion coincide only when the rank
divides the width, which is why rung 2's 531 is consistent and the unpadded 192 and 60
are not.

T1 is settled, at the schedule level (prototype66.py, checked by verify.py, recorded in
certificate.json -> padded_schedule). A bank the family cannot fill alone is filled by the
family plus a fixed pattern of retained blocks:

rung banks per bank padding per bank chosen draw
11 531 6 rank-11 blocks 0 none
16 198 4 rank-16 blocks 2 2 rank-1 blocks per bank (396 rank-1 children of 262,602)
20 66 3 rank-20 blocks 6 6 rank-1 blocks per bank (396 rank-1 children)

Every bank is exactly full, every family item lands in a block with no slot unused
(4 * 198 = 792, 3 * 66 = 198, 6 * 531 = 3,186), the item-to-block map is explicit (item
i -> bank i // k_f, block i % k_f), and the padding is a partial draw from a bin the
ledger keeps, so the retained histogram carries the reduced count. Because the mass leaving is
banks * 66 by construction, the row identity holds and the stock falls by exactly the bank
count at every step. All padding options are enumerated and compared (rank 16: two; rank 20:
eleven), and the best is the one claimed. What this is not: the normalizer, frames, charts and
prime witnesses remain C1-C7, and the padding blocks are ordinary retained children -- no new
frame family is introduced.

Is the bank width a lever? No -- and the scan says which lever is one

The bank width is not a schedule parameter, it is the word's own modulus. The pinned
bit-side schedule fixes it: M = 72, its rank-22 bin's 20,016 occurrences carrying
22 * 20,016 = 440,352 registers into 440,352 / 72 = 6,116 banks, with the stock dropping
by exactly the bank count. So a width scan is a word scan (widths66.py), and it answers:

  • nothing narrower exists. The engine's contraction is rank mass < W * modulus, and the
    pinned row has rank mass / W = 65.8905..., so every w <= 65 leaves the row unposeable
    (recorded at 48, 54, 58, 60, 63, 64, 65). 66 is the smallest modulus this ledger admits.
  • nothing wider is comparable. Holding the ledger fixed while raising w leaves a row whose
    rank mass fills only mass / (W * w) of its capacity: 99.834% at 66, 95.5% at 69, 91.5% at
    72, 68.6% at 96
    -- a different word, which is why only the pinned width is priced, and where
    the scan reproduces this PR's own top exactly as its calibration.
  • the criterion is not the cap, the density is. At w = 54, nine of the 20 families would
    tile whole banks and 1,549,098 registers (65% of the rank mass) could leave, against
    52,470 (2.2%) here. A less dense complex word -- more stock per unit of rank mass -- would
    admit a narrower modulus where far more of its ledger tiles at once. That is what to look for
    in a new supplier, measured rather than guessed.

What is instanced, and what is still owed

The schedule's items are now addressed (instantiate66.py -> occurrences66.json), which is
C1's combinatorial half and the C5-C7 inventories: item i -> bank i // k_f, block
i % k_f, offset (i % k_f) * rank.

family per vertex items (3 copies) banks blocks per bank padding registers table digest
11 1,062 3,186 531 6 0 fb9bd2d17f69...
16 264 792 198 4 396 f96efd45d9d9...
20 66 198 66 3 396 f9d9567b4b41...

4,176 items over 795 banks, 792 registers of padding (0.30% of the kept rank-1 bin), every
bank exactly filled, every block exactly one item, a per-family digest over the whole table, and
the ledger re-derived with the stock falling by exactly the bank count. What stays owed is read
from the pins rather than asserted: the complex supplier's certificate has no key containing
bank
and its own status line says a literal globally renumbered operation program is not
exported
, so the residual projectors the normalizer must move (C1's physical half) are not
there, and C2-C4 plus each child's frame/chain identity (C5-C7) follow the same gap. The shape
owed is pinned for the bit word at references/pr219-run1/inputs/absorbed-occurrences.json.

Verification

Scope and limits

  • Not a witness: the accounting, the padded bank schedule and the item addresses are
    certified; C1's physical half, C2-C4 and the inherited R1-R4 are open, so no normalizer, chart
    or physical witness is built. Not an unconditional multiplication theorem, not a practical
    multiplier, not a Lean certificate.
  • T1 is settled (enumeration plus the padded schedule), and what it settles is a schedule:
    the bank geometry, the item-to-block map and the padding draw are checked, the normalizer,
    frames, charts and prime witnesses are C1-C7.
  • The whole-bank volume condition is necessary and is what the built rungs use; it is not
    sufficient -- for the two new families it is not even compatible with a width-66 tiling at
    the bank count it prices, which is why the padded schedule exists.
  • Nothing here bounds any other complex-side lever: this ladder is over this supplier's child
    ledger at this bank width. A different word, width or frame layout is not priced.
  • The 10^-10 supplier field is priced too (certificate.json -> conservative_variant)
    rather than ignored.

Credits: rung 1, its schedule, the interval-moment engine and the 47-constraint assembly are
#219 (vendored, imported, not re-implemented); the frontier and the complex ledger's shape
are #207; rung 2 and the ceiling argument are #224; the ladder and the 10^-10 replica
convention are #208; the bank proof and engine chain are #200/#205 (Chafik Boukhalfa and
the #197/#205 line) and #184/#168-v4 (icekylinx, eumemic) as inherited through them. This
package adds the rank-16 and rank-20 absorptions and their prices, the exhaustion proof and
the next-step arithmetic. Apache-2.0; no existing file is changed.

Prepared by Maxime Fleury with Codebuff assistance.

🤖 Generated with Codebuff

maxime-fleury and others added 7 commits October 9, 2026 23:02
…and the complex ledger's top

Rung 2 binds on the complex supplier and lands on its ceiling, so the ladder can
only continue there. Exactly three families of that ledger fill whole width-66
banks: rank 11 (rung 2), rank 16 and rank 20. Pricing the other two with the
pinned engine through the unchanged 47-constraint assembly gives rung 3 at
7.10572698755137e-4 and rung 4 at 7.11175695867958e-4 -- +0.4072% over rung 2
and +4.0963% over the CrocSwap#207 frontier -- after which no remaining family has a
whole-bank volume, so the accounting ladder terminates. The next wall is the bit
word: the rung-1 leaf caps kappa at 7.277251e-4. A priced target, not a witness:
C1-C7 and T1 are open, plus CrocSwap#219's inherited R1-R4.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
The three absorptions occupy 783 width-66 banks (531 + 192 + 60); the table gave
them separately but the total was only in the certificate.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
…their negative result

A uniform bank pattern absorbing a set of families forces one common bank count, so the
scan is over the gcd of the item counts rather than over partitions of 66 -- exhaustive
and therefore a decision. It shows rank 11 tiles alone four ways (rung 2's 531 is the
tightest), that ranks 16 and 20 tile alone only above the bank counts their own volume
criterion prices (198 and 66 against 192 and 60, six three-copy banks short each), and
that no mixture tiles at all: {16,20} comes closest at 84 registers into a 66-wide bank.
The two top rungs are therefore priced on bank counts no admissible tiling realises, a
stronger caveat than "not constructed", so it is recorded in the certificate, the
obligations file and both documents rather than left implied.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
…ladder onto it

The T1 enumeration left exactly one repair: pad the bank. A bank the family cannot fill
alone can be filled by the family plus a fixed pattern of retained blocks, so rank 16 fits
198 banks of (4 blocks + 2 registers) and rank 20 fits 66 banks of (3 blocks + 6), every
bank exactly full, every item in a block with no slot unused, and the padding drawn as a
partial removal from a retained bin (396 rank-1 children of 262,602). Because the mass that
leaves is banks * 66 by construction, the row identity and stock-drop-equals-bank-count rule
both survive, every padding option can be enumerated and priced, and the padded schedule
prices above the volume-criterion rows it replaces: the top of the ladder is now the padded
rung 4 at kappa = 711599961413937/10^18, +4.1584% over the frontier.

T1 is therefore settled at the schedule level rather than merely owed, and the certificate,
the obligations file and both documents say what is still open: C1-C7, the normalizer,
frames, charts and prime witnesses, since the padding blocks are ordinary retained children
and no new frame family is introduced.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
… dial

Two questions the last commit left open, both answered by measurement rather than by
argument. The bank width is the word's own modulus -- the pinned bit-side schedule fixes
M = 72, banks = volume/72 and stock drop = bank count -- so a width scan is a word scan:
the pinned ledger's rank mass over stock is 65.8905, which makes every modulus of 65 or
under unposeable (66 is the smallest it admits), and every wider modulus leaves a row whose
density has moved (95.5% at 69, 91.5% at 72), i.e. a different word, so only the pinned
width is priced -- where the scan reproduces this package's top exactly, as its own
calibration. The scan also shows the criterion is not the cap: at modulus 54 nine families
would tile 1,549,098 registers (65% of the rank mass) whole, against 52,470 here, so the
dial to turn is the supplier's density, not the bank layout.

Then the schedule is instanced: all 4,176 items of the three families get a bank, a block
and an offset under item i -> bank i//k, block i%k, with per-family table digests, every
bank exactly filled, the padding named, and the ledger re-derived with the stock falling by
exactly the bank count. That instantiates C1's combinatorial half and the C5-C7 inventories;
what stays owed is stated from the pins rather than in prose -- the complex supplier's
certificate has no bank key and its own status line says the operation program is not
exported, so the residual projectors the normalizer must move are simply not there.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
…gets onto both branches

The width scan left one question open and it decided the next step: the bank criterion is not
what caps the ladder, the ledger's density is. So this asks it over the tree instead of guessing.
Every ledger-bearing certificate in the repository is scored on the same four numbers (modulus,
density, the smallest modulus the row admits, the mass share tiling there), keeping only rows
that satisfy m*W - mass = D with every child inside the width: 20 distinct poseable ledgers are
found and none is less dense than the complex word, which is itself the least dense one in the
repository. A narrower modulus cannot be reused, it has to be built.

So the same module prices the word that would take it: holding the pinned shape and occupancy and
varying only the modulus, the cheapest stock that poses the row. The width-66 point is its
calibration -- there the required stock is exactly the pinned stock, 12,052, and it reproduces
this package's top kappa. At widths 48 and 60 the complex branch stops binding and the kappa
rises to the budget the pinned bit leaf allows (+2.2655%, the whole of the complex headroom
left); at 72 nothing tiles and every wider word is strictly worse.

Finally the targets invert onto both branches. kappa is read off min(bit leaf, (1-beta)C - weak),
so a target needs both branches above its budget, and the cap must clear the budget after the
beta and weak haircuts, which costs one 10^-18 grid step. Per target: 7.5e-4 needs a bit leaf
+3.064% and a complex coarse saving +5.400% over the top rung; 8e-4 needs +9.940% and +12.433%;
1e-3 needs +37.453% and +40.569%; only 7.2e-4 is short on the complex branch alone, and the
complex ceiling the density curve finds above is still below all of them. This also fixes the
target list itself, which read 8/10^3 where the package documents 8e-4.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
…s closed by the pins

Asked whether C1-C7 and R1-R4 can be discharged and whether the kappa can then be made
unconditional. The first is yes and the second is no, and both are readings of pinned bytes
rather than positions, so the answer is now recorded with its evidence and checked back by
verify.py.

The eleven items are one missing artifact seen from eleven rungs: the literal operation program,
then the columns, charts, witnesses and envelope re-run on the word it banks. The supplier this
whole ladder is priced on certifies its flow and all-column fresh identity and states in the same
breath that a literal globally renumbered operation program is not exported, with its receipts
calling the literal program a downstream integration task. So C1's normalizer has to move
projectors that exist only there, C2 re-runs a word that program defines, C3 charts the frames it
creates, and C5-C7 need each child's frame/chain identity where the pins export a count per bin
and not an identity. C4 is the one item closable from the pins alone once C1's completion
children are named; R1 is the exception on the other side, with a pinned precedent to extend.

Unconditional is closed three times over: the supplier is published as a PASS conditional finite
witness, the vendored CrocSwap#219 package states that discharging R1-R4 buys a completed finite witness
and that the result is not an unconditional multiplication theorem in any case, and this
package's own scope says the same of the finite bridge and all-size interfaces it inherits.
Discharging the eleven raises the kappa from a scheduled target to the house-standard conditional
finite witness, which is the whole of what the work buys.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
maxime-fleury and others added 4 commits October 10, 2026 00:09
… against the pins

C1-C7 and R1-R4 reduce to one missing artifact: the literal operation program, then the columns,
charts, witnesses and envelope re-run on the word it banks. This turns that into an interface the
importer can accept or refuse, instead of a hoped-for construction.

The contract names six required exports -- the operation program, the frame bodies behind the
three published cache digests, the exact lift and witness pair, the chronology tables, the
per-child occurrence inventory, and the envelope plus integrity manifest -- each with the digest
it must reproduce, so it asks for bodies behind hashes the supplier already publishes rather than
for new trust. Seven acceptance tests carry the bounds and a reject control each, and every export
maps to the obligations it unblocks (all eleven are covered).

Two readings shape it. The exports address the lift/witness pair and not the flow block, because
the supplier's own flow.status says "Not an exact supplier certificate". And the per-child export
is asked in the exact shape of the bit word's absorbed-occurrences.json, since our side of that
bijection already exists in occurrences66.json: 4,176 items over 795 banks.

verify.py -> check_export_contract resolves every citation against the pinned bytes -- the digests,
the column and read counts, the status strings and the precedent values of the banked word and the
occurrence inventory -- and asserts the state the contract declares: 0 of 6 bodies exported today,
so the import fails closed and the kappa keeps its conditional flag.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
check_export_contract now derives the bodies the contract waits for from the contract itself
(the lift certificate, the three cache bodies) and asserts none of them is in the pin manifest,
nor any path under the supplier's own workspace. So "no body export exists in the pins" is read
back from the pinned file list rather than restated in prose, which is the one claim in the
contract that a reader should not have to take on trust.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
…ntil the bodies arrive

The contract named the six exports; this runs them. importer66.py consumes the exports, applies
the seven acceptance tests with their bounds, and today -- when no body exists -- refuses cleanly
with exit code 2 after naming all ten bodies it waits for, so no obligation moves on an empty
import.

The module keeps apart two things that are easy to confuse. The gate is decidable from what the
bodies declare: hashes anchored to the digests the supplier already published, cardinalities, the
published bounds, the two bijections (the frame id map, and the occurrence families against this
package's own occurrences66.json) and the counts that must come out of the exported tables rather
than out of the certificate. The replay is the physics, and it is the supplier's own checker: the
contract pins its digest, so the harness requires that file by digest and stops at "gate green,
replay not run" until it arrives, rather than reimplementing or claiming the columns.

It is proven to work while the data is absent. --self-test builds synthetic bodies, patches the
anchored digests to their synthetic hashes and then breaks each check in turn: a tampered body, a
wrong cardinality, a denominator above the bound, counts that do not come from the tables, a
foreign family and bin, an accepted colouring conflict, a repeated prime witness, an absent body,
a checker the contract does not pin, and the pinned checker passing. All twelve cases pass, and
verify.py now runs them, so the refusals the harness will perform on the real drop are
demonstrated rather than promised.

Writing the harness found two real bugs in the contract's gate model, both fixed here: an export's
declared checks were being applied to every body it owns instead of its primary body (so the
colouring and witness bounds were demanded of graph.json and record.json), and the integrity
manifest was required to declare its own digest, which no file can contain.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
Adding importer66.py to the package changes the manifest the certificate embeds as source_pins,
so the certificate is regenerated rather than left describing a pin set that no longer exists.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@maxime-fleury maxime-fleury changed the title Rungs 3 and 4 of the bank ladder: kappa = 7.11175695867958e-4, and the top of the complex ledger (priced target, not a witness) Rungs 3 and 4 of the bank ladder: κ = 7.11175695867958e-4, and the top of the complex ledger (priced target, not a witness) Oct 10, 2026
@maxime-fleury

Copy link
Copy Markdown
Contributor Author

Superseded by #246, which carries this same package plus the rank-3 rung on #233's row (κ = 1819302815717/25·10^14 = 7.277211262868e-4, bit-bound) and its mergeable form: head 545665b, +194,111/−0 over 70 new files, no existing file edited, with the package's own path-filtered workflow green on 3.11/3.13/3.14 and the full matrix green in the fork (52/52 jobs). Closing this one so the queue has a single head for this ladder; the history here stays as submitted.

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