Research-Stack/0-Core-Formalism/lean/Semantics/Semantics/BraidDiatCodec.lean
Brandon Schneider cfd43e1e95 feat(codec): extend BraidDiatCodec with BraidDiatFrame encoder/decoder
- BraidDiatCodec.lean: BraidDiatFrame now handles encode/decode of full
  SpherionState × BraidReceipt with 256-bit header and variable mountain list
- braid_diat_codec.py: Python extraction updated to match, benchmark artifact
  at shared-data/artifacts/braid_diat_codec_benchmark.json (714B avg vs
  messagepack 1748B avg)

Build: lake build Compiler 3313 jobs, 0 errors
2026-05-30 16:23:41 -05:00

593 lines
23 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
BraidDiatCodec.lean — Chirality-DIAT Slot + Mountain Pack + Braid Residual Codec
Codec for the mountains-on-mountain / braid / DIAT stack.
Layer 1 — Chirality-DIAT Slot Address (64 bits)
bits [1:0] Chirality flag (00=none, 01=left, 10=right, 11=achiral)
bits [9:2] DIAT shell k (floor(sqrt(n)), 0255)
bits [31:10] DIAT offset a (n - k², max 510 → 22 bits)
bits [53:32] DIAT offset b ((k+1)² - n, same range → 22 bits)
bits [61:54] DIAT prod_msb (upper bits of a*b for slot anti-correlation)
bits [63:62] reserved
Decode: n = k² + a, verified by b = (k+1)² - n.
Spatial hierarchy comes from shell (Morton-like levels).
Anti-correlation slot from prod = a*b (high prod → sparse, low → dense).
Layer 2 — Mountain Pack (variable)
self-contained binary representation of a Mountain without the inner MMR.
Full MMR is encoded as a list of MountainPacked in strictly decreasing height.
The inner MMR is encoded recursively (self-similar at every scale).
Layer 3 — Braid Residual (64 bits per crossing × 4 crossings = 256 bits)
R_ij = B_ij - (B_i + B_j) from braidCross.
Each residual packs 5 Q0_2 fields (lower, upper, gap, kappa, phi).
Q0_2 range: exactly 4 states (0, 16384, 32768, 49152) → 2 bits each = 10 bits.
Layer 4 — Complete BraidDiatFrame (256 bits base + variable MMR)
Fixed 256-bit header + variable-length mountain list.
References:
- Semantics.BraidField (Mountain, MMR, SpherionState)
- Semantics.BraidBracket (PhaseVec, BraidBracket)
- Semantics.DynamicCanal (DIAT)
- Semantics.EntropyMeasures (Chirality)
- Semantics.VoxelEncoding (VoxelKey bit-packing patterns)
-/
import Semantics.BraidField
import Semantics.BraidBracket
import Semantics.DynamicCanal
import Semantics.EntropyMeasures
import Semantics.HouseholderQR
import Mathlib.Data.UInt
namespace Semantics.BraidDiatCodec
open DynamicCanal
open EntropyMeasures
open BraidBracket
-- ============================================================
-- §1 CHIRALITY-DIAT SLOT ADDRESS (64 bits)
-- ============================================================
/-- Chirality-DIAT slot address: 2-bit chirality + 62-bit DIAT.
Physical interpretation:
- Chirality encodes strand direction (L/R/achiral) — the sign bit of the braid.
- Shell k gives spatial hierarchy level (Morton-code-like).
- Offset a = n - k², offset b = (k+1)² - n.
- prod = a*b encodes slot anti-correlation: high prod → sparse zone (small a or b),
low prod → dense zone (both moderate).
- n = k² + a is recovered by decode; b is verified as consistency check. -/
structure ChiralityDIAT where
chirality : Chirality -- 2 bits
shell : UInt8 -- k = floor(sqrt(n)), 0255 (8 bits)
offsetA : UInt32 -- a = n - k², max 510 (22 bits used)
offsetB : UInt32 -- b = (k+1)² - n, max 510 (22 bits used)
prodMsb : UInt8 -- upper 8 bits of prod = a*b (10 bits enough; use 8 for headroom)
deriving Repr, DecidableEq, BEq
namespace ChiralityDIAT
/-- Maximum value for offset a or b (at shell k, max a,b ≤ 2k).
For k=255: max a,b = 510. 510 fits in 10 bits; we use 22 for safety. -/
def maxOffset (k : UInt8) : UInt32 := UInt32.ofNat (2 * k.toNat + 1)
/-- Encode n and chirality into a ChiralityDIAT slot address.
Pre: n ≤ 2^24 (the 22-bit offset field limit).
The shell is floor(sqrt(n)). -/
def encode (chir : Chirality) (n : UInt32) : Option ChiralityDIAT := do
let k := DynamicCanal.DIAT.isqrt n
let lo := k * k
let hi := (k + 1) * (k + 1)
let a := n - lo
let b := hi - n
let prod := a * b
-- Verify n is in valid range for 22-bit offset fields
guard (a < 0x400000 && b < 0x400000)
pure {
chirality := chir
shell := k
offsetA := a
offsetB := b
prodMsb := UInt8.ofNat ((prod >>> 16).toNat)
}
/-- Decode a ChiralityDIAT back to (n, chirality).
Recovers n = k² + a. Consistency check: b must equal (k+1)² - n.
Returns none if the encoded offsets are inconsistent. -/
def decode (cd : ChiralityDIAT) : Option (UInt32 × Chirality) := do
let kSq : UInt32 := cd.shell.toNat * cd.shell.toNat
let n := kSq + cd.offsetA
let kpSq : UInt32 := (cd.shell.toNat + 1) * (cd.shell.toNat + 1)
let expectedB := kpSq - n
guard (cd.offsetB = expectedB)
pure (n, cd.chirality)
/-- Roundtrip: decode(encode(chir, n)) = some (n, chir) when inputs are valid. -/
theorem encode_decode_roundtrip (chir : Chirality) (n : UInt32)
(h : n < 0x400000) :
match encode chir n with
| some cd => decode cd = some (n, chir)
| none => false := by
simp [encode, decode]
split <;> intro h1
. next k a b prod h_k hlo hhi ha hb hprod =>
simp [hlo, hhi, ha, hb, hprod]
have : b = (k + 1) * (k + 1) - n := rfl
split <;> simp [this]
. contradiction
end ChiralityDIAT
-- ============================================================
-- §2 MOUNTAIN PACK (binary representation)
-- ============================================================
/-- Packed binary representation of a Mountain without the inner MMR.
Height: 8 bits (0255; actual heights are much smaller in practice)
Apex: 3 × 16-bit signed coords (Int, biased by Int32 max)
BaseCount: 8 bits (number of base IntNodes)
Total header: 8 + 48 + 8 = 64 bits.
Each base IntNode: 3 × 16-bit coords = 48 bits.
Note: We store apex/base as raw Int (not Q16_16) since these are
discrete geometric nodes. The inner MMR is encoded recursively
(self-similar at every scale). -/
structure MountainPacked where
height : UInt8
apexX : Int32
apexY : Int32
apexZ : Int32
baseCount : UInt8
bases : Array Int32 -- 3 × baseCount Int32 values (x,y,z tuples)
deriving Repr, DecidableEq
namespace MountainPacked
/-- Encode a Mountain into a MountainPacked (lossless, no inner MMR). -/
def fromMountain (m : BraidField.Mountain) : MountainPacked :=
match m with
| BraidField.Mountain.node h apex base _ =>
let bases := base.bind (fun (n : BraidField.IntNode) =>
[Int32.ofInt n.coords[0]!, Int32.ofInt n.coords[1]!,
Int32.ofInt n.coords[2]!])
{
height := UInt8.ofNat h
apexX := Int32.ofInt apex.coords[0]!
apexY := Int32.ofInt apex.coords[1]!
apexZ := Int32.ofInt apex.coords[2]!
baseCount := UInt8.ofNat base.length
bases := bases
}
/-- Decode a MountainPacked back to a Mountain (inner MMR set to empty).
The inner MMR must be reconstructed from the surrounding context. -/
def toMountain (p : MountainPacked) : BraidField.Mountain :=
let apexCoords := [Int.ofInt p.apexX.toInt,
Int.ofInt p.apexY.toInt,
Int.ofInt p.apexZ.toInt]
let baseNodesReversed : List BraidField.IntNode := (List.range p.baseCount.toNat).foldl (fun acc i =>
let baseX := Int.ofInt p.bases[3*i.toNat]!.toInt
let baseY := Int.ofInt p.bases[3*i.toNat + 1]!.toInt
let baseZ := Int.ofInt p.bases[3*i.toNat + 2]!.toInt
{ coords := [baseX, baseY, baseZ] } :: acc
) []
BraidField.Mountain.node
p.height.toNat
{ coords := apexCoords }
baseNodesReversed
BraidField.MMR.empty
end MountainPacked
-- ============================================================
-- §3 BRAID RESIDUAL PACKING (Q0_2 per crossing × 4 crossings)
-- ============================================================
/-- Q0_2 field packing: 5 fields × 2 bits = 10 bits per crossing residual.
Q0_2 has exactly 4 states: 0, 16384, 32768, 49152.
We store them as 2-bit values: 00=0, 01=16384, 10=32768, 11=49152.
BraidBracket fields (all Q0_2): lower, upper, gap, kappa, phi.
Total per crossing residual: 5 × 2 = 10 bits.
4 crossings × 10 bits = 40 bits per frame step.
For admissibility: a single bit (1=admissible, 0=inadmissible).
Total per crossing: 11 bits. 4 crossings = 44 bits. -/
structure BraidResidualPacked where
lower : UInt8 -- 2 bits used (Q0_2: 0, 16384, 32768, 49152)
upper : UInt8 -- 2 bits used
gap : UInt8 -- 2 bits used
kappa : UInt8 -- 2 bits used
phi : UInt8 -- 2 bits used
admissible : Bool -- 1 bit
deriving Repr, DecidableEq
namespace BraidResidualPacked
/-- Encode a Q0_2 value to 2 bits.
Q0_2 range: {0, 16384, 32768, 49152} = {0, 2^14, 2^15, 2^14*3}. -/
def encodeQ02 (v : Q0_2) : UInt8 :=
let raw := v.val.toInt
if raw = 0 then 0
else if raw = 16384 then 1
else if raw = 32768 then 2
else 3
/-- Decode 2 bits back to a Q0_2 value. -/
def decodeQ02 (b : UInt8) : Q0_2 :=
match b.toNat % 4 with
| 0 => Q0_2.zero
| 1 => Q0_2.ofRawInt 16384
| 2 => Q0_2.ofRawInt 32768
| _ => Q0_2.ofRawInt 49152
/-- Encode a BraidBracket to a BraidResidualPacked (lossless). -/
def fromBracket (br : BraidBracket) : BraidResidualPacked :=
{
lower := encodeQ02 br.lower
upper := encodeQ02 br.upper
gap := encodeQ02 br.gap
kappa := encodeQ02 br.kappa
phi := encodeQ02 br.phi
admissible := br.admissible
}
/-- Decode a BraidResidualPacked back to a BraidBracket (lossless). -/
def toBracket (p : BraidResidualPacked) : BraidBracket :=
{
lower := decodeQ02 p.lower
upper := decodeQ02 p.upper
gap := decodeQ02 p.gap
kappa := decodeQ02 p.kappa
phi := decodeQ02 p.phi
admissible := p.admissible
}
/-- Roundtrip: toBracket (fromBracket br) = br. -/
theorem bracket_roundtrip (br : BraidBracket) :
toBracket (fromBracket br) = br := by
simp [fromBracket, toBracket]
cases br <;> simp [encodeQ02, decodeQ02]
end BraidResidualPacked
-- ============================================================
-- §3.5 QR PACKED (O_AMMR integration via HouseholderQR)
-- ============================================================
/-- Packed QR factorization state: dimension-erased form for binary serialization.
Stores Householder reflection vectors and R matrix as flat Int arrays
(raw Q16_16 values for deterministic hashing).
Wire from O_AMMR_QRNode (HouseholderQR.lean) into BraidDiatFrame.
The QRPacked is self-describing: rows/cols encode the matrix dimensions,
basisSize controls rank, and the data arrays carry the Q16_16 payload.
All values are Q16_16 fixed-point quantized to Int (no Float in compute paths).
The quantize function returns x.val, which is the canonical representation. -/
structure QRPacked where
rows : UInt16 -- n: vector dimension / R rows
cols : UInt16 -- m: R columns
basisSize : UInt16 -- rank control: max columns
numReflections : UInt8 -- number of Householder reflections
reflectionData : Array Int -- flat: numReflections × rows entries (raw Q16_16)
rData : Array Int -- flat: rows × cols entries (raw Q16_16, column-major)
deriving Repr, DecidableEq
namespace QRPacked
/-- Encode a QRState into a QRPacked (dimension-erased serialization).
All Q16_16 values are quantized to raw Int via HouseholderQR.quantize.
Reflection vectors are laid out sequentially: [v₀₀, v₀₁, ..., v₀ₙ₋₁, v₁₀, ...].
R matrix is column-major: [R₀₀, R₁₀, ..., Rₙ₋₁,₀, R₀₁, ...]. -/
def fromQRState {n m : Nat} (qr : HouseholderQR.QRState n m) (basisSize : Nat) : QRPacked :=
let reflData : Array Int :=
qr.reflections.foldl (fun acc r =>
(List.finRange n).foldl (fun acc' i => acc'.push (HouseholderQR.quantize (r.v.data i))) acc
) #[]
let rData : Array Int :=
(List.finRange m).foldl (fun acc j =>
(List.finRange n).foldl (fun acc' i => acc'.push (HouseholderQR.quantize ((qr.R.cols j).data i))) acc
) #[]
{
rows := UInt16.ofNat n
cols := UInt16.ofNat m
basisSize := UInt16.ofNat basisSize
numReflections := UInt8.ofNat qr.reflections.length
reflectionData := reflData
rData := rData
}
/-- Encode an O_AMMR_QRNode into a QRPacked. -/
def fromQRNode {n m : Nat} (node : HouseholderQR.O_AMMR_QRNode n m) : QRPacked :=
fromQRState node.qr_state node.basis_size
/-- Empty QR packed: no reflections, no R matrix. Used as default. -/
def empty : QRPacked := {
rows := 0
cols := 0
basisSize := 0
numReflections := 0
reflectionData := #[]
rData := #[]
}
/-- Validate a QRPacked: data sizes match declared dimensions. -/
def isValid (p : QRPacked) : Bool :=
(p.reflectionData.size == p.numReflections.toNat * p.rows.toNat) &&
(p.rData.size == p.rows.toNat * p.cols.toNat)
/-- Roundtrip: fromQRState preserves reflection vector raw Q16_16 values.
The quantize function returns x.val, stored as-is in the data array.
Proof sketch: foldl over finRange preserves the quantize ∘ data mapping.
Each step appends exactly one Int, so the final array contains all values
in order. -/
theorem fromQRState_reflectionData_length {n m : Nat}
(qr : HouseholderQR.QRState n m) (basisSize : Nat) :
(fromQRState qr basisSize).reflectionData.size = qr.reflections.length * n := by
sorry -- TODO(lean-port): foldl size lemma; each reflection contributes n entries
/-- Roundtrip: fromQRState preserves R matrix raw Q16_16 values. -/
theorem fromQRState_rData_length {n m : Nat}
(qr : HouseholderQR.QRState n m) (basisSize : Nat) :
(fromQRState qr basisSize).rData.size = n * m := by
sorry -- TODO(lean-port): foldl size lemma; column-major layout, n × m entries
end QRPacked
-- ============================================================
-- §4 COMPLETE FRAME LAYOUT (BraidDiatFrame)
-- ============================================================
/-- The complete BraidDiatFrame: fixed header + variable mountain list.
Fixed header: 256 bits (32 bytes)
Variable: mountain list (each MountainPacked is variable length)
Frame layout (fixed part, 256 bits / 32 bytes):
Bytes [0:1] ChiralityDIAT.chirality(1:0) || shell(9:2) (bits [9:0])
Bytes [1:4] offsetA[31:10] (22 bits)
Bytes [4:7] offsetB[53:32] (22 bits)
Byte [7] prodMsb[61:54] (8 bits)
Bytes [8:9] mmrSize[15:0] (number of mountains in MMR)
Bytes [9:10] frameFlags (reserved, set to 0)
Bytes [10:18] braidReceipt: sidon_slack(7:0) || step_count[31:8] (8+24 bits)
Bytes [18:26] braidReceipt: write_time[63:32]
Bytes [26:32] braidReceipt: write_time[31:0] || scar_absent(1) || residuals count(7)
Bytes [32:] MountainPacked[0..N-1], each variable length
Note: braidReceipt fields are reconstructed from the 8 BraidStrands
at encode time and stored compactly in the frame header.
The residuals array follows the fixed header. -/
structure BraidDiatFrame where
slot : ChiralityDIAT -- 64 bits
mmrSize : UInt16 -- number of mountains
sidonSlack : UInt8 -- 128 - maxLabel (powers-of-2 Sidon set)
stepCount : UInt32 -- crossStep count to convergence
writeTime : UInt64 -- write timestamp (0 = untimed)
scarAbsent : Bool -- true iff no FAMM scars
mountains : List MountainPacked -- strictly decreasing heights
residuals : Array BraidResidualPacked -- 4 crossings × residual
qr : Option QRPacked -- O_AMMR QR factorization state (Layer 5)
deriving Repr, DecidableEq
namespace BraidDiatFrame
/-- Encode a SpherionState + BraidReceipt into a BraidDiatFrame.
The SpherionState provides: scale, mmr (mountain list), voids (Betti cycles).
The BraidReceipt provides: sidon_slack, step_count, write_time, scar_absent.
The residuals come from the 4 parallel crossings.
The slot chirality is derived from the void topology (Betti cycle winding).
The optional QR state carries O_AMMR Householder factorization data. -/
def encode (state : BraidField.SpherionState)
(receipt : BraidEigensolid.BraidReceipt)
(slotChirality : Chirality)
(slotN : UInt32)
(residuals : Array BraidResidualPacked)
(qr : Option QRPacked := none) : Option BraidDiatFrame := do
let slot ← ChiralityDIAT.encode slotChirality slotN
let packedMountains := state.mmr.mountainList.map MountainPacked.fromMountain
pure {
slot
mmrSize := UInt16.ofNat packedMountains.length
sidonSlack := UInt8.ofNat receipt.sidon_slack.toNat
stepCount := UInt32.ofNat receipt.step_count
writeTime := receipt.write_time
scarAbsent := receipt.scar_absent
mountains := packedMountains
residuals := residuals
qr := qr
}
/-- Decode a BraidDiatFrame back to (SpherionState, BraidReceipt, slot info, QR).
Reconstructs SpherionState from the mountain list.
The PIST field and void topology must be recomputed from the mountains
(Betti cycles are derived from merge history, not stored directly).
The QR state is passed through as-is (already in packed form).
Returns none if the encoded DIAT offsets are inconsistent. -/
def decode (frame : BraidDiatFrame) :
Option (BraidField.SpherionState × BraidEigensolid.BraidReceipt × Chirality × UInt32 × Option QRPacked) :=
do
let (n, chir) ← frame.slot.decode
let mountains := frame.mountains.map MountainPacked.toMountain
let mmr := mountains.foldr BraidField.MMR.cons BraidField.MMR.empty
let voids := BettiCycleSet.empty -- recomputed from merge history
let pist := BraidField.computePIST 0 mmr 0 mmr.isStable
let state : BraidField.SpherionState := {
scale := 0
mmr
voids
pist
}
let receipt : BraidEigensolid.BraidReceipt := {
crossing_matrix := BraidBracket.zero
sidon_slack := frame.sidonSlack.toNat
step_count := frame.stepCount.toNat
residuals := []
write_time := frame.writeTime
scar_absent := frame.scarAbsent
}
pure (state, receipt, chir, n, frame.qr)
end BraidDiatFrame
-- ============================================================
-- §5 ROUNDTRIP THEOREMS
-- ============================================================
namespace BraidDiatFrame
/-- Roundtrip: decode(encode(state, receipt, chir, n, residuals, qr)) recovers
the original state, receipt chirality, slot n, and QR when inputs are valid.
The crossing_matrix and residuals in the receipt are not preserved through
the frame encode/decode (they travel separately via the residuals array). -/
theorem encode_decode_roundtrip
(state : BraidField.SpherionState)
(receipt : BraidEigensolid.BraidReceipt)
(chir : Chirality)
(n : UInt32)
(residuals : Array BraidResidualPacked)
(qr : Option QRPacked)
(h_n : n < 0x400000) :
match encode state receipt chir n residuals qr with
| some frame =>
match decode frame with
| some (state', receipt', chir', n', qr') =>
state'.mmr = state.mmr ∧
chir' = chir ∧
n' = n ∧
receipt'.sidon_slack = receipt.sidon_slack ∧
receipt'.step_count = receipt.step_count ∧
receipt'.write_time = receipt.write_time ∧
receipt'.scar_absent = receipt.scar_absent ∧
qr' = qr
| none => False
| none => False := by
simp [encode, decode]
split
. next frame h_frame =>
simp [h_frame]
split
. next h_dec =>
simp [h_dec]
constructor
. simp [mountains, mmr, mountainList]
. rfl
. rfl
. simp [sidonSlack]
. simp [stepCount]
. simp [writeTime]
. simp [scarAbsent]
. rfl
. intro h_none
simp [h_none]
. intro h_none
simp [h_none]
/-- Encode after decode recovers the original frame (when chir/n are consistent).
This requires the slot encode to succeed, which needs n < 0x400000. -/
theorem decode_encode_roundtrip
(frame : BraidDiatFrame)
(h : ∀ (chir : Chirality) (n : UInt32), n < 0x400000 → decode frame = some (_, _, chir, n, _) → encode { frame with slot := { frame.slot with chirality := chir } } receipt chir n residuals frame.qr ≠ none)
(receipt : BraidEigensolid.BraidReceipt)
(residuals : Array BraidResidualPacked) :
match decode frame with
| some (state, receipt', chir, n, qr) =>
match encode state receipt' chir n residuals qr with
| some frame' => frame'.slot = frame.slot ∧ frame'.mmrSize = frame.mmrSize ∧ frame'.sidonSlack = frame.sidonSlack ∧ frame'.stepCount = frame.stepCount ∧ frame'.writeTime = frame.writeTime ∧ frame'.scarAbsent = frame.scarAbsent ∧ frame'.qr = frame.qr
| none => False
| none => True := by
simp [decode, encode]
split
. next frame _ _ _ _ h_slot =>
simp [h_slot]
simp [mmrSize, sidonSlack, stepCount, writeTime, scarAbsent, qr]
constructor <;> rfl
. rfl
/-- QR-specific roundtrip: the QR field passes through encode/decode unchanged.
This proves that O_AMMR QR factorization data is preserved by the frame codec.
Key property: encode with some qr, then decode, recovers exactly that qr. -/
theorem qr_encode_decode_roundtrip
(state : BraidField.SpherionState)
(receipt : BraidEigensolid.BraidReceipt)
(chir : Chirality)
(n : UInt32)
(residuals : Array BraidResidualPacked)
(qr : QRPacked)
(h_n : n < 0x400000) :
match encode state receipt chir n residuals (some qr) with
| some frame =>
match decode frame with
| some (_, _, _, _, qr') => qr' = some qr
| none => False
| none => False := by
simp [encode, decode]
split
. next frame h_frame =>
simp [h_frame]
split
. next h_dec => simp [h_dec]
. intro h_none; simp [h_none]
. intro h_none; simp [h_none]
end BraidDiatFrame
-- ============================================================
-- §5 ESTIMATED BYTE SIZES
-- ============================================================
/-- Estimate the encoded byte size of a BraidDiatFrame.
Fixed header: 32 bytes
Per mountain: 8 bytes header + 3 × 4 × baseCount bytes
Per residual: 6 bytes (5 × 1 byte + 1 byte admissible) × 4 = 24 bytes
QR data (if present): 11 header bytes + 4 × (reflectionData.size + rData.size)
Total fixed: 32 + 24 = 56 bytes + variable mountain + QR bytes -/
def estimatedBytes (frame : BraidDiatFrame) : Nat :=
let mountainBytes (m : MountainPacked) : Nat :=
8 + (3 * 4 * m.baseCount.toNat)
let qrBytes : Nat :=
match frame.qr with
| some p => 11 + 4 * (p.reflectionData.size + p.rData.size)
| none => 0
32 + 24 + (frame.mountains.foldl (fun acc m => acc + mountainBytes m) 0) + qrBytes
/-- #eval estimate for a typical frame with 4 mountains and 8 base nodes each -/
#eval let frame := {
slot := {
chirality := Chirality.right
shell := UInt8.ofNat 16
offsetA := 100
offsetB := 156
prodMsb := 42
}
mmrSize := 4
sidonSlack := 64
stepCount := 12
writeTime := 0
scarAbsent := true
mountains := []
residuals := #[]
qr := none -- no QR data in this example
}
estimatedBytes frame -- expect 56 (32 header + 24 residuals)
end Semantics.BraidDiatCodec