# T3 per-window covert-channel budget bound

**Ticket**: #000036 — **closed 2026-05-11**.
**Source analysis**: `docs/soft-hash-channel-analysis.md`
**Date**: 2026-05-10 (dav1d review pass + Option-B + KAT-regen tooling 2026-05-11)
**Status**: formal derivation + calculator landed; **dav1d review
returned 2026-05-11** → Tier-1 polish + Tier-2 (Option B: the
conservative `max_envelope` B1 model, applied in v1 — no v2 fork)
+ KAT-regen tooling (`scripts/generate_t3_bound_kat.py`) all landed
2026-05-11; **#000036 closed**. KAT fixture is 12 entries, active
(`test_t3_bound_known_answer_tests` runs, not skips). The default
B1 model is `max_envelope` (§3.1); `effective_control_v1` /
`fraction_channels` / `aggregate_bias` reachable via `--b1-model`.
The named C_B* constants are conservative starting estimates that
empirical tightening — **continued under #000043** — can replace
without changing call sites. (#000043 parks on v7 deployment
data.) Landing the bound's framing into a v7 plastic-training spec
parks on that spec gaining a deployment target.

---

## §0. Reviewer brief (dav1d review returned 2026-05-11)

This document derives an upper bound on the per-window mutual
information a T3 (hyperparameter) adversary can steer into the
SHA-256 commitment `C(M_{t+1})`. The framework decomposes the
channel across T3's three control surfaces (gradient bias,
LR selection, batch order) and combines them into a closed-form
bound consumed by `bench/scripts/t3_bound_calculator.py`.

**dav1d's 2026-05-11 review** (`RESPONSE_1` + `RESPONSE_2`)
findings and how they were resolved:

1. **§2 decomposition** — accepted. Markov-chain DPI on
   `A → Θ_{t+1} → C(M_{t+1})` correctly applied; T1+T2 baseline
   cleanly separated from the T3 capacity term.
2. **§4 (C_B2 LR selection)** — accepted. Clean categorical-channel
   capacity bound.
3. **§5 (C_B3 batch order)** — accepted *as a model-bound, not a
   theorem* (§5's "model-bound" note reflects this).
4. **§3 (C_B1 gradient bias)** — was the closure blocker. `g`
   appeared twice in the per-window expression, only sound under
   the `effective_control_v1` reading. **Resolved 2026-05-11**:
   Option B applied in v1 — the default `b1_model` is now
   `max_envelope` = `max(fraction_channels, aggregate_bias)`,
   genuinely upper-bounding across both interpretations of `g`
   (§3.1). `effective_control_v1` stays reachable for backward
   comparison. All three B1 variants are reported in every output.
5. Wording / validation / output-schema fixes — applied (§10.1).

**What's *not* being asked**: empirical validation against an
actual adversarial-training run (out of scope per §10 item 5;
opens as a future ticket once v7 plastic-training has a deployment
target).

The headline numeric example in §7 + §11 now yields
`I_window ≈ 6183 bits/window` for the default deployment config
**under the default `max_envelope` B1 model** (`B1 = aggregate_bias`
= 5849.6 bits dominates `fraction_channels` = 1729.7 bits;
`effective_control_v1` would have been 292.5 bits) — well above
the 256-bit threshold, so `certification_status = NOT_CERTIFIED_BY_BOUND`.
That is the correct conservative reading: at W=10000 with these
inputs, the bound cannot certify M2 residual safety. The
calculator's `--b1-model` flag lets operators inspect the other
models if they want the effective-control risk score for
comparison.

---

## §1. T3 model restatement

From `docs/soft-hash-channel-analysis.md` §6, threat model T3
(hyperparameter adversary) extends T2 (gradient adversary) with
control over:

- **Learning-rate scheduling**: choosing the LR at each scheduled
  decision point from a constrained range (e.g. log-grid of `R`
  levels).
- **Batch ordering**: permuting batches within an epoch.

Combined with T2's gradient bias (controlling a `g`-fraction of
training-step gradient computations), T3 is a strict superset of
T2. The §4 reduction in `soft-hash-channel-analysis.md` bounds T1
+ T2 channels at the SHA-256 random-oracle baseline assuming φ is
independent of parameter geometry; T3 breaks the implicit
"published schedule" assumption so the §4 reduction does not
directly apply.

M2 mitigation (per-checkpoint anchor nonce, soft-hash-channel
analysis §5.3) re-randomizes the anchor every checkpoint. T3's
exploitation window is thus **bounded to one nonce-window** of
length `W` steps before the anchor re-randomizes. This document
bounds the bits T3 can steer into `C(M_{t+1})` within a single
window.

The bound's intended use: operators choose `W` (the nonce-window
length) such that `I_window` stays below their target residual
(e.g. < 1 bit per window means the adversary needs ≥ 2^256 windows
to steer `C(M)` to a specific 256-bit target).

---

## §2. Per-window channel — formal definition

For a single nonce window of length `W` steps starting at
checkpoint `t`:

```
I_window := I( A ; C(M_{t+1}) | H_{≤t}, n_t )
```

where:

- `A` is the joint random variable over T3's adversary inputs
  during the window: `A = (g_1, …, g_W, lr_1, …, lr_⌈W/K⌉, π)`
  where `g_s` is the adversary-controlled gradient signal at
  step `s`, `lr_d` is the LR at decision point `d`, `π` is the
  batch-ordering permutation.
- `C(M_{t+1})` is the SHA-256 hard-hash committed at the next
  checkpoint.
- `H_{≤t}` is the public history before the window opens.
- `n_t` is the published per-checkpoint nonce (M2 mitigation).

This is the standard mutual-information upper bound on
distinguishing-from-baseline channel capacity. Conditional on
`(H_{≤t}, n_t)`, the random variables form a Markov chain:

```
A  →  Θ_{t+1}  →  C(M_{t+1})
```

— T3's window inputs `A` affect the commitment only through the
parameter state `Θ_{t+1}`. Markov-chain data-processing inequality
gives the single-source bound:

```
I( A ; C(M_{t+1}) | H_{≤t}, n_t )  ≤  I( A ; Θ_{t+1} | H_{≤t}, n_t )
```

The right-hand side — T3's per-window capacity to encode adversarial
bits into the parameter state — is what this document bounds in
§§ 3-5.

**Inherited T1 + T2 baseline.** Independent of T3, the φ-mapping
`Θ → C(M)` itself admits a constant random-oracle baseline channel
under the §4 reduction in `soft-hash-channel-analysis.md` (when φ
is φ_PRG per #000035, or φ_linear under the NO_ALIGNMENT verdict
per #000034). That baseline is bounded by SHA-256 partial-preimage
hardness and is independent of A. Threat-model-additive (T3 capacity
+ T1+T2 baseline = total per-window leak budget) but not
information-additive in the same MI sense — the two contributions
come from disjoint adversary surfaces:

```
total per-window bits  ≤  I( A ; Θ_{t+1} | H_{≤t}, n_t )   ← T3, this doc
                        + (T1 + T2 baseline)               ← § 4, inherited
```

The baseline term is constant-bounded by §4 unchanged; the per-
window adversarial capacity is the first term, which we now bound
by decomposing across T3's three control surfaces.

---

## §3. C_B1 — gradient-bias bandwidth

**Setup.** Each step `s ∈ {1, …, W}`, the adversary controls a
`g`-fraction of gradient computations. The contributed
adversarial signal `g_s` is bounded in norm by `g · ‖∇L_max‖`
where `‖∇L_max‖` is the per-step gradient-norm cap (gradient
clipping, in practice).

**Information bound.** Per-step parameter-shift channel
capacity by discrete-distinguishability counting.

For one SGD step with learning rate `lr_s`:

```
Δ Θ_s = lr_s · (1 - g) · ∇L_honest + lr_s · g · ∇L_adv
```

The adversarial component `lr_s · g · ∇L_adv` is the parameter
shift in the adversary's chosen direction. The honest stochastic
gradient contributes noise of standard deviation `σ_grad`. At each
step the parameter shift falls in one of approximately
`SNR_grad + 1` distinguishable buckets — the noise-only level plus
`SNR_grad` adversarial-signal levels resolvable above the noise
floor. The single-symbol channel-capacity bound on a discrete
channel with `K` distinguishable outputs is `log₂ K`:

```
I( g_s ; Δ Θ_s ) ≤ log₂( ‖adversarial step‖ / ‖noise step‖ + 1 )
                ≤ log₂( g · lr_s · ‖∇L_max‖ / (lr_s · σ_grad) + 1 )
                = log₂( g · ‖∇L_max‖ / σ_grad + 1 )
```

The `+1` corresponds to the noise-only level (no signal injected);
it keeps the log finite when the adversarial step is below the
noise floor. (The `lr_s` factor cancels — LR scales signal and
noise identically per-step, so the bound is LR-independent at the
per-step level. LR's distinct channel contribution is the §4
LR-selection capacity, not double-counted here.)

Define:

```
SNR_grad := g · ‖∇L_max‖ / σ_grad
```

Then per-step gradient-bias capacity is bounded by
`log₂(SNR_grad + 1)` bits.

**Per-window.** Adversarial signals across steps are
information-additive (each step's signal can in principle target
a different parameter direction):

```
C_B1 · g · W · log₂(N_dir)
```

where the ticket's `log₂(N_dir)` factor is the per-step bit
**budget** (capped at log₂(SNR_grad + 1) per the discrete
channel-capacity bound above, which by data-processing-inequality
is much smaller than log₂ of the full direction count `2^256`).
Replace the ticket sketch's `log₂(N_dir)` with `log₂(SNR_grad + 1)`:

```
B1 contribution ≤ C_B1 · g · W · log₂( SNR_grad + 1 )

with C_B1 = 1 (data processing inequality; tight).
```

For typical deployments `g · ‖∇L_max‖ / σ_grad = 0.05 · 1 / 0.1
= 0.5`, so `log₂(1.5) ≈ 0.5850 bits/step`. With `W = 10000` and
`g = 0.05`: `1 · 0.05 · 10000 · 0.5850 ≈ 292.48 bits/window`.

### §3.1 The B1 model — `max_envelope` (default) vs the alternatives

`g` enters the naive per-window B1 expression **twice**: once as
the outer multiplier `g · W` (number of adversary-controlled
steps) and once inside `log₂(SNR_grad + 1)` where
`SNR_grad = g · ‖∇L_max‖ / σ_grad`. dav1d's 2026-05-11 review
flagged that this double use is only sound under a *narrow*
interpretation of `g`. The calculator now offers four B1 models
(`--b1-model` flag), with `max_envelope` as the **default**:

| `b1_model` | Reading of `g` | Formula | Baseline B1 (`g=0.05, G=1, σ=0.1, W=10000`) |
|---|---|---|---|
| `fraction_channels` | fraction of steerable directions; each carries full per-channel SNR `G/σ` | `C_B1 · g · W · log₂(1 + G/σ)` | 1 729.7 bits |
| `aggregate_bias` | aggregate adversarial amplitude shrinkage; one effective channel carries SNR `g·G/σ` | `C_B1 · W · log₂(1 + g·G/σ)` | 5 849.6 bits |
| **`max_envelope`** (default) | take the worse of the two — no assumption about which interpretation holds | `max(fraction_channels, aggregate_bias)` | **5 849.6 bits** (`aggregate_bias` selected) |
| `effective_control_v1` | `g` simultaneously bounds *both* direction fraction AND amplitude shrinkage — an operational risk score, NOT a worst-case bound | `C_B1 · g · W · log₂(1 + g·G/σ)` | 292.5 bits |

Every calculator output reports all three concrete variants
(`B1_fraction_channels`, `B1_aggregate_bias`,
`B1_effective_control_v1`), the selected one (`b1_selected`), and
both SNR readings (`snr_grad = g·G/σ`, `snr_per_channel = G/σ`),
regardless of which `b1_model` was requested — so a reader can
always see the spread.

**Why `max_envelope` is the default.** A security bound that may
be optimistic under some interpretation of its own inputs is not a
bound. `max_envelope` is upper-bounding across both readings of
`g`, so `certification_status` under the default is a genuine
certification. `effective_control_v1` is kept reachable for
operators who specifically want the older effective-control risk
score for comparison — it should never be used to *certify*.

**Implementation note (dav1d Option B, applied in v1 2026-05-11).**
Per fox's direction, this was applied by changing the v1
calculator's default rather than forking a v2 — `CALCULATOR_VERSION`
stays `t3-bound-v1-bottou-refinement` (the "bottou-refinement"
descriptor still names the unchanged B3 term). The `b1_model` field
appears in both the output and the echoed `inputs`, so KAT replays
are unambiguous about which model produced a given row. The KAT
fixture was regenerated 2026-05-11 (12 entries: the §7 worked
examples under `max_envelope` plus explicit `effective_control_v1`
/ `fraction_channels` / `aggregate_bias` mode pins and a `g=0`
edge case).

---

## §4. C_B2 — learning-rate selection

**Setup.** T3 picks LR from a log-grid of `R` levels at each
LR-decision point. With decision interval `K` steps, the window
of length `W` contains `⌈W/K⌉` decision points.

**Information bound.** Each decision contributes at most
`log₂(R)` bits to the channel under uniform prior. By
data-processing inequality, the LR choice's effect on `Θ_{t+1}`
is bounded by what the LR can change about gradient steps it
applies to — which is at most a multiplicative factor in the
parameter-step magnitude.

The categorical-channel capacity of `R` symbols is `log₂(R)`
bits per decision. The mapping from LR symbol to effective
parameter shift is a finite function (each LR level corresponds
to a fixed step magnitude), so:

```
B2 contribution ≤ C_B2 · ⌈W / K⌉ · log₂ R

with C_B2 = 1 (data processing inequality; tight).
```

For typical deployments `K = 100`, `R = 8`, `W = 10000`:
`1 · 100 · log₂(8) = 100 · 3 = 300 bits/window`.

**Tightening note.** `C_B2 = 1` assumes every LR choice
maps to an *information-distinguishable* parameter trajectory.
In practice many LR choices produce trajectories that converge
to similar `Θ` (the loss surface's basin geometry damps
small-LR perturbations). A tighter bound would measure the
LR-trajectory diversity empirically; the framework above
admits substituting `C_B2 < 1` when measured.

---

## §5. C_B3 — batch-order bandwidth

**Setup.** T3 reorders batches within an epoch. With `N_b` batches
per epoch, the naive bound is `log₂(N_b!)` bits per epoch — but
this drastically overestimates the **steering** capacity because
batch-order effects on final `Θ` are bounded by gradient noise,
not by permutation entropy.

**Information bound — the Bottou-Bousquet refinement.** Per
Bottou-Bousquet (2008), Hardt-Recht-Singer (2016), and the
broader random-shuffle SGD analysis:

- Random-shuffle SGD: order has `O(1/√N_b)` effect on final
  `Θ` distribution. Channel bits ≈ 0.
- Cyclic-shuffle SGD: order has `O(1)` effect (consistent
  bias). Channel bits ≈ `O(log₂ N_b)` per epoch.
- Adversarial-order SGD: order can amplify directional bias
  by at most a factor of `√N_b` over random-shuffle. Channel
  bits ≈ `log₂( σ_grad · √N_b / ‖∇L_max‖ )` per epoch =
  `0.5 · log₂(N_b) + log₂(σ_grad / ‖∇L_max‖)`.

The window of length `W` contains `⌈W / E⌉` epochs where
`E = N_b` (steps per epoch). Each epoch contributes at most:

```
log₂( N_b · σ_grad / ‖∇L_max‖ ) / 2  bits  (adversarial-order)
```

For `N_b = 1024`, `σ_grad/‖∇L_max‖ ≈ 0.1`: `0.5 · log₂(102.4) ≈
3.34 bits/epoch`.

```
B3 contribution ≤ C_B3 · ⌈W / E⌉ · log₂( N_b · σ_grad / ‖∇L_max‖ ) / 2

with C_B3 = 1 (data-processing inequality; tight under the
adversarial-order assumption made in this section).
```

Tightening to the random-shuffle baseline gives `C_B3 →
O(1/√N_b)` — substantially below 1 for typical `N_b`. That
tightening is **deferred to §10** + #000043; the headline bound
above stays at the adversarial-order ceiling so operators
choosing `W` get the upper-bound conservative number unless
they explicitly opt into the random-shuffle constant via
`--c-b3` on the calculator.

For `W = 10000`, `E = 1024`, the contribution is `1 · 9.77 · 3.34
≈ 32.6 bits/window` — substantially less than the naive
`log₂(N_b!)` bound of `~8000+ bits/epoch`.

**B3 is a model-bound, not a directly-quoted theorem (dav1d
review 2026-05-11).** The expression above is a *gradient-noise-
scale conservative modelling term* inspired by Bottou-Bousquet /
Hardt-Recht-Singer shuffle-stability arguments. It is **not** a
statement that "the Bottou-Bousquet theorem proves every
batch-order adversary is bounded by this exact expression." The
calculator's `test_b3_exact_formula` pins the implementation to
the model; it does not prove the model. The floor at 0 (when
`N_b · σ_grad / ‖∇L_max‖ ≤ 1`) does not mean batch order has
literally zero effect — it means this upper-bound formula gives
no positive distinguishable capacity above the noise floor in
that regime. Empirical tightening (random-shuffle classification)
remains Phase 2 / #000043.

---

## §6. Combined per-window bound

Combining §3-§5, with the **default `b1_model = max_envelope`**
(§3.1):

```
B1 = C_B1 · max(  g · W · log₂( 1 + ‖∇L_max‖ / σ_grad ),       ← fraction_channels
                      W · log₂( 1 + g·‖∇L_max‖ / σ_grad ) )    ← aggregate_bias

I_window ≤ B1
         + C_B2 · ⌈W / K⌉ · log₂( R )
         + C_B3 · ⌈W / E⌉ · log₂( N_b · σ_grad / ‖∇L_max‖ ) / 2
```

with conservative constants `C_B1 = C_B2 = C_B3 = 1` (each by
data-processing inequality; #000043 may tighten any of them based
on empirical measurement). For typical deployments `aggregate_bias`
dominates `fraction_channels` (because `1/g ≫ log₂(1+G/σ) /
log₂(1+g·G/σ)`), so `B1 ≈ W · log₂(1 + g·‖∇L_max‖/σ_grad)`.

Other `b1_model` choices (`--b1-model`): `effective_control_v1` =
`C_B1 · g · W · log₂(1 + g·‖∇L_max‖/σ_grad)` — the older
non-worst-case effective-control risk score, ~`g`× smaller than
`aggregate_bias`; never use it to *certify*.

---

## §7. Numeric examples

All numbers are the calculator's closed-form output under the
default `b1_model = max_envelope`, not rounded estimates; see
`bench/scripts/t3_bound_calculator.py`, `tests/test_t3_bound_calculator.py`,
and the pinned KAT fixture `bench/fixtures/t3-bound/known-answer-tests.jsonl`.
The `effective_control_v1` column shows what the older
non-worst-case model would have produced, for comparison.

### §7.1 Small deployment

```
g = 0.05, ‖∇L_max‖ = 1.0, σ_grad = 0.1
K = 100, R = 8, W = 10000, N_b = 1024, E = 1024
snr_grad = g·G/σ = 0.5    snr_per_channel = G/σ = 10.0

B1_fraction_channels = 0.05 · 10000 · log₂(11)    ≈ 1729.72 bits
B1_aggregate_bias    =        10000 · log₂(1.5)   ≈ 5849.63 bits  ← selected (max)
B1 (max_envelope)                                  ≈ 5849.63 bits
B2 = ⌈10000/100⌉ · log₂(8)                          = 300.00 bits
B3 = ⌈10000/1024⌉ · log₂(102.4) / 2                ≈  33.39 bits
total                                               ≈ 6183.02 bits/window
                                  → NOT_CERTIFIED_BY_BOUND
(effective_control_v1 B1 would be ≈ 292.48 → total ≈ 625.87)
```

### §7.2 Medium deployment (longer window)

```
g = 0.05, ‖∇L_max‖ = 1.0, σ_grad = 0.1
K = 1000, R = 16, W = 100000, N_b = 8192, E = 8192
snr_grad = 0.5    snr_per_channel = 10.0

B1_aggregate_bias = 100000 · log₂(1.5)             ≈ 58496.25 bits  ← selected
B2 = ⌈100000/1000⌉ · log₂(16)                       = 400.00 bits
B3 = ⌈100000/8192⌉ · log₂(819.2) / 2               ≈  62.91 bits
total                                                ≈ 58959.16 bits/window
                                  → NOT_CERTIFIED_BY_BOUND
(effective_control_v1 B1 would be ≈ 2924.81 → total ≈ 3387.72)
```

### §7.3 Hardened deployment (lower g, smaller R)

```
g = 0.01, ‖∇L_max‖ = 1.0, σ_grad = 0.1
K = 100, R = 4, W = 10000, N_b = 1024, E = 1024
snr_grad = 0.1    snr_per_channel = 10.0

B1_fraction_channels = 0.01 · 10000 · log₂(11)     ≈  345.94 bits
B1_aggregate_bias    =        10000 · log₂(1.1)    ≈ 1375.04 bits  ← selected
B1 (max_envelope)                                   ≈ 1375.04 bits
B2 = ⌈10000/100⌉ · log₂(4)                           = 200.00 bits
B3 = ⌈10000/1024⌉ · log₂(102.4) / 2                ≈  33.39 bits
total                                                ≈ 1608.43 bits/window
                                  → NOT_CERTIFIED_BY_BOUND
(effective_control_v1 B1 would be ≈ 13.75 → total ≈ 247.14)
```

Note: under the conservative `max_envelope` model, even the
"hardened" config exceeds 256 bits at W=10000 — the `aggregate_bias`
term `W · log₂(1 + g·G/σ)` grows with `W` regardless of how small
`g` is. Certifying M2 residual safety under this model requires a
**much smaller W** than the effective-control numbers suggested
(see §8).

---

## §8. Operator guidance — choosing window length

The operator picks `W` such that `I_window ≤ B_target` where
`B_target` is the desired residual. Under the default
`max_envelope` model with the small-deployment constants
(`g=0.05, G=1, σ=0.1, K=100, R=8, E=1024`), `aggregate_bias`
dominates B1, so:

```
I_window ≈ W · log₂(1.5)        +  (W/100) · 3      +  (W/1024) · 3.34/2
         = 0.5850 W             +  0.0300 W         +  0.00163 W
         ≈ 0.6166 W   bits/window
```

**Target = 1 bit/window** (very conservative; adversary needs
`≥ 2^256` windows for a specific target):

```
1 ≥ 0.6166 W   →   W ≤ 1.6 steps   (impractical — re-anchor essentially every step)
```

**Target = 256 bits/window** (the SHA-256 hard-hash output size):

```
256 ≥ 0.6166 W   →   W ≤ 415 steps
```

This is the practical operating range under the conservative
model: re-anchor approximately every **400 SGD steps** to keep
T3's per-window steerage at the SHA-256 baseline. (The earlier
effective-control numbers gave ~4196 steps; the conservative
envelope is ~10× tighter, which is the price of not assuming
which interpretation of `g` holds. An operator who can *measure*
that the effective-control model applies to their deployment can
run `--b1-model effective_control_v1` and use the looser W —
but that is a calibration claim they must justify, not a default.)

**Target = 2^16 = 65536 bits/window** (much larger window,
adversary still needs ~2^240 windows to brute-force):

```
W ≤ 1.06 × 10^5 steps
```

This admits roughly day-long training runs between anchor
rotations under the conservative model.

Use `python -m bench.scripts.t3_bound_calculator` with your
deployment's `g / G / σ / K / R / W / N_b / E` to read off the
exact `certification_status` and per-bandwidth breakdown rather
than working the algebra above by hand.

---

## §9. Closure of `soft-hash-channel-analysis.md` §9.3

§9.3 of the analysis posed the open question:

> What is the explicit per-window bound on T3 channel capacity
> under M2?

This document answers it. §6's closed-form bound, parametrized in
operator-measurable inputs `(g, K, R, W, N_b, σ_grad, ‖∇L_max‖)`,
is the explicit form. Reference: this doc §6.

---

## §10. Open questions + future work

**Closure-blocker status.** dav1d's 2026-05-11 review flagged two
blockers — the B1 model not being worst-case, and the KAT fixture
being skip-if-missing. **Both resolved 2026-05-11** (§10.1):
Option B applied *in v1* (per fox's direction — no v2 fork), so
the default `b1_model` is now `max_envelope` (§3.1); the KAT
fixture was regenerated (12 entries) and `test_t3_bound_known_answer_tests`
now runs rather than skips. What remains for closure is fox's
final close-or-iterate call (optionally a dav1d re-review of the
envelope formula itself).

Items 1-5 below are tightening paths that refine the bound
without invalidating it:

1. **C_B1 below the data-processing limit.** The discrete
   channel-capacity bound `log₂(SNR_grad + 1)` is a per-step
   ceiling derived under uniform-prior signal levels; tighter
   bounds are possible if the loss surface has reduced
   adversary-controllable directions (e.g. Hessian rank
   deficiency). Empirical measurement via #000034's probe
   could tighten C_B1 by 1-2 orders of magnitude on typical
   deployments. (Tracked under #000043.)
2. **C_B2 below 1.** Many LR choices map to similar
   trajectories; a deployment-specific empirical measurement
   of LR-trajectory diversity (1-Wasserstein distance between
   `(LR_1, LR_2, … LR_R)` final-checkpoint distributions)
   yields C_B2 < 1. (Tracked under #000043.)
3. **C_B3 closer to the random-shuffle baseline.** If the
   deployment's SGD is random-shuffle (most modern training is),
   the adversarial-order bound used here over-estimates by
   `O(√N_b)` factor. C_B3 → `O(1/√N_b)`. (Tracked under #000043;
   the cheapest of the three constant-tightening paths — needs
   only a DataLoader-config audit, no checkpoint.)
4. **Future B4-B5 control surfaces.** Adaptive optimizer state
   manipulation (momentum, second-moment estimates) is not in
   the §1 model. The framework here generalizes — add new B_i
   terms as new T3 control surfaces are documented.
5. **Empirical validation.** This bound has not been validated
   against an actual adversarial-training experiment. The
   acceptance criterion (§5 of the source ticket) explicitly
   marks empirical validation as out-of-scope; landing the
   doc establishes the framework operators can plan around.
   #000034's Phase 1b would feed directly into a future
   empirical-validation ticket.

### §10.1 dav1d-review changes landed 2026-05-11

Not "open" — already done (Tier-1 in `da62f80`, Option B / Tier-2
in the follow-up commit):

- **B1 model = `max_envelope` (Option B, applied in v1).** The
  default `b1_model` takes `max(fraction_channels, aggregate_bias)`
  — genuinely upper-bounding across both interpretations of `g`
  (§3.1). `effective_control_v1` / `fraction_channels` /
  `aggregate_bias` reachable via `--b1-model`. Every output reports
  all three concrete B1 variants + `b1_selected` + both SNR
  readings (`snr_grad`, `snr_per_channel`). `b1_model` is echoed in
  `inputs` so KAT replays are unambiguous. Applied by changing the
  v1 default rather than forking a v2 (per fox's direction):
  `CALCULATOR_VERSION` stays `t3-bound-v1-bottou-refinement` (the
  "bottou-refinement" descriptor names the unchanged B3 term).
- **KAT fixture regenerated + regen tooling.**
  `bench/fixtures/t3-bound/known-answer-tests.jsonl` (12 entries:
  §7 worked examples under `max_envelope`, explicit-mode pins for
  the other three models, a `g=0` edge case) is now produced by
  `scripts/generate_t3_bound_kat.py` — run it after any algorithm
  change, then bump `CALCULATOR_VERSION`.
  `test_t3_bound_known_answer_tests` now runs (no longer skips);
  it pins `b1_model`, `b1_selected`, `certification_status`, and
  the per-contribution numbers.
- Recommendation wording: "M2's single-window guarantee is
  broken" → "this conservative bound CANNOT CERTIFY M2's
  residual" (an upper bound exceeding 256 means we cannot
  certify, not that the adversary can steer 256 bits).
- Structured output fields: `b1_model`, `b1_selected`,
  `certification_status` ∈ {`CERTIFIED_BY_BOUND`,
  `NOT_CERTIFIED_BY_BOUND`}, `certification_threshold_bits`,
  `model_assumptions[]`, `B1_fraction_channels`,
  `B1_aggregate_bias`, `B1_effective_control_v1`, `snr_per_channel`
  — callers read a machine-readable status + the full B1 spread,
  not just prose.
- Input validation: bools rejected for both int and float fields
  (`isinstance(True, int)` is True in Python — a real leak risk
  for a security calculator); NaN / ±inf rejected for every
  numeric input and constant; invalid `b1_model` rejected.
- `gradient_fraction = 0` now accepted (no T2 surface; B1 = 0;
  T3's LR + batch-order channels still contribute) — improves
  component isolation.
- Tests: hard-coded `cwd="/home/fox/git/arborist"` replaced with
  `pathlib.Path(__file__).resolve().parents[1]` so the suite
  runs on any checkout. New bool/NaN/inf rejection tests, `g=0`
  acceptance test, `certification_status` field tests, per-model
  B1 hand-formula tests, `--b1-model` CLI test, invalid-`b1_model`
  rejection test. Suite count 53 → 83.

---

## §11. Calculator script

The closed-form bound from §6 lands as
`bench/scripts/t3_bound_calculator.py` for operator use:

```bash
$ python -m bench.scripts.t3_bound_calculator \
    --gradient-fraction 0.05 --gradient-norm-max 1.0 \
    --gradient-noise-stddev 0.1 --lr-decision-interval 100 \
    --lr-grid-size 8 --window-length 10000 \
    --batches-per-epoch 1024 --steps-per-epoch 1024
    # [--b1-model max_envelope]   ← the default
{
  "calculator_version": "t3-bound-v1-bottou-refinement",
  "b1_model": "max_envelope",
  "b1_selected": "aggregate_bias",
  "I_window_bits_upper_bound": 6183.0154,
  "B1_contribution": 5849.625,
  "B1_fraction_channels": 1729.7158,
  "B1_aggregate_bias": 5849.625,
  "B1_effective_control_v1": 292.4813,
  "B2_contribution": 300.0,
  "B3_contribution": 33.3904,
  "snr_grad": 0.5,
  "snr_per_channel": 10.0,
  "decisions_in_window": 100,
  "epochs_in_window": 10,
  "constants": {"C_B1": 1.0, "C_B2": 1.0, "C_B3": 1.0},
  "certification_status": "NOT_CERTIFIED_BY_BOUND",
  "certification_threshold_bits": 256,
  "model_assumptions": [
    "M2_nonce_per_window",
    "SHA256_random_oracle_baseline",
    "B1_model_max_envelope",
    "B3_gradient_noise_refinement"
  ],
  "inputs": { "...echoed input tuple incl. c_b1/c_b2/c_b3 + b1_model..." },
  "recommendation": "I_window upper bound ≈ 6183.0 bits/window
                     EXCEEDS the SHA-256 (256 bit) certification
                     threshold. This conservative bound CANNOT
                     CERTIFY M2's single-window residual at this W
                     — it does not prove the adversary can steer
                     256 bits, only that the bound is too loose to
                     certify safety. Reduce W (or reduce g / R /
                     increase K, or tighten C_B* empirically) until
                     the certified bound is < 256 bits/window."
}
```

The above shows the default `max_envelope` model: `B1 =
aggregate_bias` = 5849.6 bits (the larger of the two envelope
terms; `fraction_channels` = 1729.7) → total 6183.0 bits/window,
`NOT_CERTIFIED_BY_BOUND` at W=10000. All three B1 variants
(including `B1_effective_control_v1` = 292.5, what the older
risk-score model would have given) are reported regardless of
which `b1_model` is selected. Pass `--b1-model effective_control_v1`
(or `fraction_channels` / `aggregate_bias`) to switch the selected
term. Operators read the structured `certification_status` field,
not just the prose, and adjust W (or g, R, K) to tune — see §8.

---

## §12. References

- `docs/soft-hash-channel-analysis.md` — source analysis (#000018).
- Ticket #000036 — this document's spec.
- Ticket #000034 — φ_linear Hessian-alignment probe; informs
  the C_B1 tightening path.
- Ticket #000035 — φ_PRG construction; closes the random-oracle
  modeling gap independent of T3.
- Bottou & Bousquet (2008), "The Tradeoffs of Large Scale
  Learning" — gradient-noise / batch-order argument that
  **inspires** the §5 C_B3 model-bound (not a direct quotation;
  see §5's "model-bound, not theorem" note).
- Hardt, Recht & Singer (2016), "Train Faster, Generalize
  Better: Stability of Stochastic Gradient Descent" — shuffle-
  stability framework the §5 C_B3 random-shuffle reasoning draws on.
- dav1d review 2026-05-11 (`RESPONSE_1` + `RESPONSE_2`) — the
  B1-double-`g` finding (§3.1), the recommendation-wording
  correction, validation hardening, and the conservative
  `max_envelope` B1 model. All applied in v1 2026-05-11 (Tier-1 +
  Option B); see §3.1 + §10.1.
