Last active
April 13, 2026 20:05
-
-
Save huitseeker/cc5e99ad466cae75bdfb4b447b5509ac to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>PR 2765 Analysis: Fixed-Layout Hashless MAST Serialization</title> | |
| <link | |
| rel="stylesheet" | |
| href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css" | |
| > | |
| <style> | |
| :root { | |
| --bg: #07111a; | |
| --bg-2: #0c1824; | |
| --bg-3: #102233; | |
| --panel: rgba(11, 22, 35, 0.88); | |
| --panel-2: rgba(17, 34, 51, 0.86); | |
| --panel-3: rgba(24, 45, 66, 0.8); | |
| --ink: #edf4fb; | |
| --muted: #94a9bf; | |
| --accent: #80e6c3; | |
| --accent-2: #73b6ff; | |
| --accent-3: #ffd17d; | |
| --danger: #ff8e8e; | |
| --line: rgba(158, 188, 219, 0.16); | |
| --line-strong: rgba(128, 230, 195, 0.28); | |
| --shadow: 0 24px 80px rgba(0, 0, 0, 0.34); | |
| --mono: "Berkeley Mono", "SFMono-Regular", "SF Mono", Menlo, Consolas, monospace; | |
| --sans: "Avenir Next", "Segoe UI", sans-serif; | |
| --serif: "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia, serif; | |
| --slide-pad: clamp(28px, 5vw, 72px); | |
| } | |
| * { | |
| box-sizing: border-box; | |
| } | |
| html { | |
| scroll-behavior: smooth; | |
| } | |
| body { | |
| margin: 0; | |
| color: var(--ink); | |
| font-family: var(--serif); | |
| background: | |
| radial-gradient(circle at 15% 10%, rgba(128, 230, 195, 0.14), transparent 22%), | |
| radial-gradient(circle at 85% 12%, rgba(115, 182, 255, 0.14), transparent 26%), | |
| radial-gradient(circle at 50% 100%, rgba(255, 209, 125, 0.09), transparent 24%), | |
| linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 52%, #08121b 100%); | |
| overflow-x: hidden; | |
| } | |
| body::before { | |
| content: ""; | |
| position: fixed; | |
| inset: 0; | |
| pointer-events: none; | |
| opacity: 0.18; | |
| background: | |
| linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px), | |
| linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px); | |
| background-size: 42px 42px; | |
| mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.65), transparent 88%); | |
| } | |
| a { | |
| color: var(--accent); | |
| text-decoration-color: rgba(128, 230, 195, 0.45); | |
| } | |
| .rail { | |
| position: fixed; | |
| top: 20px; | |
| left: 20px; | |
| bottom: 20px; | |
| width: min(290px, calc(100vw - 40px)); | |
| padding: 20px 18px; | |
| display: grid; | |
| grid-template-rows: auto auto 1fr auto; | |
| gap: 18px; | |
| z-index: 20; | |
| background: rgba(8, 18, 28, 0.78); | |
| border: 1px solid var(--line); | |
| border-radius: 24px; | |
| backdrop-filter: blur(18px); | |
| box-shadow: var(--shadow); | |
| } | |
| .rail-brand { | |
| display: grid; | |
| gap: 8px; | |
| } | |
| .eyebrow { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 8px; | |
| width: fit-content; | |
| padding: 8px 12px; | |
| border-radius: 999px; | |
| font: 700 0.78rem/1 var(--sans); | |
| letter-spacing: 0.16em; | |
| text-transform: uppercase; | |
| color: var(--accent); | |
| background: rgba(128, 230, 195, 0.08); | |
| border: 1px solid rgba(128, 230, 195, 0.22); | |
| } | |
| .rail h1 { | |
| margin: 0; | |
| font: 700 clamp(1.55rem, 2.3vw, 2rem)/0.94 var(--serif); | |
| letter-spacing: -0.04em; | |
| } | |
| .rail p { | |
| margin: 0; | |
| color: var(--muted); | |
| font-size: 0.98rem; | |
| line-height: 1.4; | |
| } | |
| .meta-grid { | |
| display: grid; | |
| grid-template-columns: repeat(2, minmax(0, 1fr)); | |
| gap: 10px; | |
| } | |
| .meta-card { | |
| padding: 12px 13px; | |
| border-radius: 16px; | |
| background: rgba(255, 255, 255, 0.04); | |
| border: 1px solid rgba(255, 255, 255, 0.06); | |
| } | |
| .meta-card .label { | |
| font: 700 0.72rem/1.1 var(--sans); | |
| letter-spacing: 0.12em; | |
| text-transform: uppercase; | |
| color: var(--muted); | |
| } | |
| .meta-card .value { | |
| margin-top: 6px; | |
| font: 700 1.08rem/1.1 var(--sans); | |
| color: var(--ink); | |
| } | |
| .agenda { | |
| display: grid; | |
| gap: 8px; | |
| align-content: start; | |
| min-height: 0; | |
| overflow: auto; | |
| padding-right: 4px; | |
| } | |
| .agenda a { | |
| display: grid; | |
| grid-template-columns: 30px 1fr; | |
| gap: 10px; | |
| padding: 11px 12px; | |
| border-radius: 16px; | |
| text-decoration: none; | |
| color: var(--ink); | |
| border: 1px solid transparent; | |
| background: rgba(255, 255, 255, 0.04); | |
| transition: transform 150ms ease, border-color 150ms ease, background 150ms ease; | |
| } | |
| .agenda a:hover, | |
| .agenda a.active { | |
| border-color: var(--line-strong); | |
| background: rgba(128, 230, 195, 0.08); | |
| transform: translateX(3px); | |
| } | |
| .agenda .index { | |
| font: 700 0.84rem/1 var(--sans); | |
| color: var(--accent-2); | |
| } | |
| .agenda .title { | |
| font: 600 0.96rem/1.25 var(--sans); | |
| } | |
| .rail-footer { | |
| display: flex; | |
| justify-content: space-between; | |
| gap: 12px; | |
| align-items: center; | |
| color: var(--muted); | |
| font: 600 0.82rem/1.2 var(--sans); | |
| } | |
| .progress { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| height: 4px; | |
| width: 100%; | |
| background: rgba(255, 255, 255, 0.05); | |
| z-index: 30; | |
| } | |
| .progress-bar { | |
| height: 100%; | |
| width: 0; | |
| background: linear-gradient(90deg, var(--accent), var(--accent-2)); | |
| box-shadow: 0 0 18px rgba(115, 182, 255, 0.45); | |
| transition: width 140ms linear; | |
| } | |
| .deck { | |
| margin-left: min(332px, calc(100vw - 8px)); | |
| } | |
| .slide { | |
| min-height: 100vh; | |
| padding: var(--slide-pad); | |
| display: grid; | |
| align-content: start; | |
| gap: 22px; | |
| border-bottom: 1px solid rgba(255, 255, 255, 0.06); | |
| scroll-snap-align: start; | |
| position: relative; | |
| } | |
| .slide::after { | |
| content: attr(data-slide); | |
| position: absolute; | |
| top: 22px; | |
| right: clamp(28px, 5vw, 72px); | |
| font: 700 0.9rem/1 var(--sans); | |
| color: rgba(255, 255, 255, 0.34); | |
| letter-spacing: 0.12em; | |
| text-transform: uppercase; | |
| } | |
| .slide-head { | |
| display: grid; | |
| gap: 14px; | |
| max-width: 78rem; | |
| } | |
| .slide-head h2 { | |
| margin: 0; | |
| font: 700 clamp(2.2rem, 4vw, 4.4rem)/0.94 var(--serif); | |
| letter-spacing: -0.045em; | |
| max-width: 15ch; | |
| } | |
| .slide-head .lede { | |
| margin: 0; | |
| max-width: 72rem; | |
| color: #dbe7f4; | |
| font-size: clamp(1.08rem, 1.4vw, 1.36rem); | |
| line-height: 1.48; | |
| } | |
| .grid { | |
| display: grid; | |
| gap: 18px; | |
| min-width: 0; | |
| } | |
| .grid.cols-2 { | |
| grid-template-columns: 1.02fr 0.98fr; | |
| } | |
| .grid.cols-3 { | |
| grid-template-columns: repeat(3, minmax(0, 1fr)); | |
| } | |
| .panel { | |
| min-width: 0; | |
| padding: 20px 22px; | |
| border-radius: 24px; | |
| border: 1px solid var(--line); | |
| background: | |
| linear-gradient(180deg, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0.02)), | |
| var(--panel); | |
| box-shadow: var(--shadow); | |
| backdrop-filter: blur(14px); | |
| } | |
| .panel.alt { | |
| background: | |
| linear-gradient(180deg, rgba(115, 182, 255, 0.06), rgba(255, 255, 255, 0.02)), | |
| var(--panel-2); | |
| } | |
| .panel.warm { | |
| background: | |
| linear-gradient(180deg, rgba(255, 209, 125, 0.07), rgba(255, 255, 255, 0.02)), | |
| var(--panel-3); | |
| } | |
| .panel h3 { | |
| margin: 0 0 12px; | |
| font: 700 0.95rem/1.15 var(--sans); | |
| letter-spacing: 0.11em; | |
| text-transform: uppercase; | |
| color: var(--accent); | |
| } | |
| .panel p, | |
| .panel li, | |
| .panel td, | |
| .panel th { | |
| font-size: 1.02rem; | |
| line-height: 1.48; | |
| } | |
| .panel p:last-child { | |
| margin-bottom: 0; | |
| } | |
| ul, | |
| ol { | |
| margin: 0; | |
| padding-left: 1.2rem; | |
| } | |
| li + li { | |
| margin-top: 0.48rem; | |
| } | |
| code, | |
| pre { | |
| font-family: var(--mono); | |
| } | |
| code:not(.hljs) { | |
| padding: 0.12rem 0.35rem; | |
| border-radius: 0.35rem; | |
| background: rgba(255, 255, 255, 0.08); | |
| font-size: 0.94em; | |
| } | |
| pre { | |
| margin: 0; | |
| border-radius: 20px; | |
| overflow: auto; | |
| border: 1px solid rgba(255, 255, 255, 0.08); | |
| box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03); | |
| } | |
| pre code.hljs { | |
| padding: 18px 20px 20px; | |
| font-size: 0.92rem; | |
| line-height: 1.48; | |
| background: #0a1520; | |
| } | |
| .stats { | |
| display: grid; | |
| grid-template-columns: repeat(4, minmax(0, 1fr)); | |
| gap: 12px; | |
| } | |
| .stat { | |
| padding: 15px 16px; | |
| border-radius: 18px; | |
| background: rgba(255, 255, 255, 0.04); | |
| border: 1px solid rgba(255, 255, 255, 0.07); | |
| } | |
| .stat .label { | |
| font: 700 0.73rem/1.1 var(--sans); | |
| letter-spacing: 0.11em; | |
| text-transform: uppercase; | |
| color: var(--muted); | |
| } | |
| .stat .value { | |
| margin-top: 8px; | |
| font: 700 clamp(1.25rem, 2vw, 2rem)/1 var(--sans); | |
| color: var(--ink); | |
| } | |
| .stat .detail { | |
| margin-top: 7px; | |
| color: var(--muted); | |
| font-size: 0.92rem; | |
| line-height: 1.35; | |
| } | |
| .compare { | |
| display: grid; | |
| gap: 12px; | |
| } | |
| .compare-card { | |
| padding: 16px 18px; | |
| border-radius: 18px; | |
| border: 1px solid rgba(255, 255, 255, 0.08); | |
| background: rgba(255, 255, 255, 0.04); | |
| } | |
| .compare-card .tag { | |
| display: inline-block; | |
| margin-bottom: 8px; | |
| padding: 5px 10px; | |
| border-radius: 999px; | |
| font: 700 0.72rem/1 var(--sans); | |
| letter-spacing: 0.12em; | |
| text-transform: uppercase; | |
| color: var(--accent-2); | |
| background: rgba(115, 182, 255, 0.11); | |
| } | |
| .quote { | |
| border-left: 4px solid var(--accent-2); | |
| padding: 14px 16px 14px 18px; | |
| border-radius: 0 18px 18px 0; | |
| background: rgba(115, 182, 255, 0.08); | |
| } | |
| .quote strong { | |
| color: var(--accent-3); | |
| } | |
| .timeline { | |
| display: grid; | |
| gap: 10px; | |
| } | |
| .timeline-item { | |
| display: grid; | |
| grid-template-columns: 112px 1fr; | |
| gap: 14px; | |
| padding: 14px 16px; | |
| border-radius: 18px; | |
| background: rgba(255, 255, 255, 0.04); | |
| border: 1px solid rgba(255, 255, 255, 0.08); | |
| } | |
| .timeline-item .date { | |
| color: var(--accent-2); | |
| font: 700 0.82rem/1.1 var(--sans); | |
| letter-spacing: 0.11em; | |
| text-transform: uppercase; | |
| } | |
| .timeline-item .entry { | |
| font-size: 1rem; | |
| line-height: 1.42; | |
| } | |
| .timeline-item code { | |
| font-size: 0.88em; | |
| } | |
| .callout { | |
| padding: 14px 16px; | |
| border-left: 4px solid var(--accent); | |
| border-radius: 0 18px 18px 0; | |
| background: rgba(128, 230, 195, 0.08); | |
| } | |
| .callout.warn { | |
| border-left-color: var(--accent-3); | |
| background: rgba(255, 209, 125, 0.1); | |
| } | |
| .callout.danger { | |
| border-left-color: var(--danger); | |
| background: rgba(255, 142, 142, 0.1); | |
| } | |
| .diagram { | |
| display: grid; | |
| gap: 12px; | |
| } | |
| .flow { | |
| display: grid; | |
| gap: 10px; | |
| } | |
| .flow-row { | |
| display: grid; | |
| grid-template-columns: repeat(5, minmax(0, 1fr)); | |
| gap: 10px; | |
| align-items: center; | |
| } | |
| .flow-node, | |
| .flow-arrow { | |
| padding: 16px 14px; | |
| border-radius: 18px; | |
| text-align: center; | |
| font-family: var(--sans); | |
| } | |
| .flow-node { | |
| border: 1px solid rgba(255, 255, 255, 0.08); | |
| background: rgba(255, 255, 255, 0.05); | |
| font-weight: 700; | |
| } | |
| .flow-arrow { | |
| color: var(--accent-2); | |
| background: rgba(115, 182, 255, 0.08); | |
| border: 1px solid rgba(115, 182, 255, 0.18); | |
| } | |
| table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| overflow: hidden; | |
| border-radius: 18px; | |
| } | |
| th, | |
| td { | |
| text-align: left; | |
| padding: 12px 14px; | |
| border-bottom: 1px solid rgba(255, 255, 255, 0.08); | |
| } | |
| th { | |
| font: 700 0.78rem/1.2 var(--sans); | |
| letter-spacing: 0.11em; | |
| text-transform: uppercase; | |
| color: var(--muted); | |
| background: rgba(255, 255, 255, 0.03); | |
| } | |
| tbody tr:last-child td { | |
| border-bottom: 0; | |
| } | |
| .refs { | |
| display: grid; | |
| gap: 12px; | |
| } | |
| .ref-card { | |
| padding: 15px 16px; | |
| border-radius: 18px; | |
| background: rgba(255, 255, 255, 0.04); | |
| border: 1px solid rgba(255, 255, 255, 0.07); | |
| } | |
| .ref-card strong { | |
| display: block; | |
| margin-bottom: 6px; | |
| font-family: var(--sans); | |
| } | |
| .kicker { | |
| display: inline-flex; | |
| padding: 7px 11px; | |
| border-radius: 999px; | |
| background: rgba(255, 255, 255, 0.05); | |
| border: 1px solid rgba(255, 255, 255, 0.08); | |
| color: var(--muted); | |
| font: 700 0.78rem/1 var(--sans); | |
| letter-spacing: 0.11em; | |
| text-transform: uppercase; | |
| } | |
| .caption { | |
| color: var(--muted); | |
| font-size: 0.92rem; | |
| line-height: 1.4; | |
| } | |
| .fade-up { | |
| opacity: 0; | |
| transform: translateY(24px); | |
| transition: opacity 520ms ease, transform 520ms ease; | |
| } | |
| .fade-up.visible { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| @media (max-width: 1100px) { | |
| .rail { | |
| position: static; | |
| width: auto; | |
| margin: 16px; | |
| } | |
| .deck { | |
| margin-left: 0; | |
| } | |
| .slide::after { | |
| right: 24px; | |
| } | |
| .grid.cols-2, | |
| .grid.cols-3, | |
| .flow-row, | |
| .stats { | |
| grid-template-columns: 1fr; | |
| } | |
| .timeline-item { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| @media (max-width: 720px) { | |
| .slide { | |
| padding: 26px 18px 34px; | |
| } | |
| .slide::after { | |
| position: static; | |
| margin-bottom: -8px; | |
| } | |
| .rail { | |
| margin: 10px; | |
| padding: 16px; | |
| } | |
| .meta-grid { | |
| grid-template-columns: 1fr 1fr; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="progress"><div class="progress-bar" id="progressBar"></div></div> | |
| <aside class="rail"> | |
| <div class="rail-brand"> | |
| <div class="eyebrow">Branch Diff</div> | |
| <h1>PR 2765: fixed-layout hashless MAST serialization</h1> | |
| <p> | |
| A deeper read of <code>next...HEAD</code> on <code>mast-serialization-squashed</code>: | |
| what changed on the wire, what changed in the trust model, and why the branch is mostly a | |
| serialization architecture rewrite rather than a feature sprinkle. | |
| </p> | |
| </div> | |
| <div class="meta-grid"> | |
| <div class="meta-card"> | |
| <div class="label">Commits</div> | |
| <div class="value">17</div> | |
| </div> | |
| <div class="meta-card"> | |
| <div class="label">Files</div> | |
| <div class="value">21</div> | |
| </div> | |
| <div class="meta-card"> | |
| <div class="label">Diff</div> | |
| <div class="value">+3326 / -713</div> | |
| </div> | |
| <div class="meta-card"> | |
| <div class="label">Format</div> | |
| <div class="value">v0.0.3</div> | |
| </div> | |
| </div> | |
| <nav class="agenda" id="agenda"> | |
| <a href="#cover"><span class="index">01</span><span class="title">Executive read</span></a> | |
| <a href="#format-shift"><span class="index">02</span><span class="title">Wire format shift</span></a> | |
| <a href="#commit-story"><span class="index">03</span><span class="title">Commit story</span></a> | |
| <a href="#architecture"><span class="index">04</span><span class="title">New architecture</span></a> | |
| <a href="#trust"><span class="index">05</span><span class="title">Trust boundary</span></a> | |
| <a href="#mechanics"><span class="index">06</span><span class="title">Mechanics and APIs</span></a> | |
| <a href="#hardening"><span class="index">07</span><span class="title">Hardening and evidence</span></a> | |
| <a href="#references"><span class="index">08</span><span class="title">References and takeaways</span></a> | |
| </nav> | |
| <div class="rail-footer"> | |
| <span>Keyboard: <code>J</code>/<code>K</code> or arrows</span> | |
| <span id="slideLabel">01 / 08</span> | |
| </div> | |
| </aside> | |
| <main class="deck" id="deck"> | |
| <section class="slide" id="cover" data-slide="01"> | |
| <div class="slide-head fade-up"> | |
| <span class="eyebrow">Executive Read</span> | |
| <h2>This branch turns MAST serialization into a layered system.</h2> | |
| <p class="lede"> | |
| Relative to <code>next</code>, the branch does three big things at once: | |
| it splits <code>MastNodeInfo</code> into structural <code>MastNodeEntry</code> plus | |
| separate digest sections, it introduces a zero-copy inspection API in | |
| <code>SerializedMastForest</code>, and it makes the trusted/untrusted split explicit so | |
| <code>HASHLESS</code> payloads are only usable through <code>UntrustedMastForest</code> | |
| or the structural view. | |
| </p> | |
| </div> | |
| <div class="stats fade-up"> | |
| <div class="stat"> | |
| <div class="label">Old core idea</div> | |
| <div class="value"><code>MastNodeInfo</code></div> | |
| <div class="detail">Each serialized node carried structure and digest together.</div> | |
| </div> | |
| <div class="stat"> | |
| <div class="label">New core idea</div> | |
| <div class="value"><code>ForestLayout</code></div> | |
| <div class="detail">One scanned layout drives both inspection and deserialization.</div> | |
| </div> | |
| <div class="stat"> | |
| <div class="label">New mode</div> | |
| <div class="value"><code>HASHLESS</code></div> | |
| <div class="detail">Internal hashes are omitted from the wire but rebuilt before use.</div> | |
| </div> | |
| <div class="stat"> | |
| <div class="label">Policy split</div> | |
| <div class="value">3 entry points</div> | |
| <div class="detail"><code>MastForest</code>, <code>SerializedMastForest</code>, and <code>UntrustedMastForest</code> now have different responsibilities.</div> | |
| </div> | |
| </div> | |
| <div class="grid cols-2"> | |
| <article class="panel alt fade-up"> | |
| <h3>What the diff is really about</h3> | |
| <ul> | |
| <li><code>core/src/mast/serialization/mod.rs</code> stops being a monolith and becomes the public policy layer.</li> | |
| <li><code>layout.rs</code> owns syntactic wire scanning and absolute section offsets.</li> | |
| <li><code>resolved.rs</code> owns digest lookup, lazy rebuilds, and materialization.</li> | |
| <li><code>info.rs</code> shrinks the fixed-width node representation down to <code>MastNodeEntry</code>.</li> | |
| <li><code>core/src/mast/mod.rs</code> rewires validation so structural checks and digest checks are no longer conflated.</li> | |
| </ul> | |
| </article> | |
| <article class="panel warm fade-up"> | |
| <h3>Short verdict</h3> | |
| <p> | |
| This is a format redesign with security policy cleanup around it. The most important | |
| semantic move is not “hashless serialization exists”, but “wire flags no longer imply | |
| trust semantics.” The payload says what was written. The caller chooses what can be | |
| trusted. | |
| </p> | |
| <div class="callout warn"> | |
| The branch is intentionally opinionated: <code>HASHLESS</code> implies | |
| <code>STRIPPED</code>, trusted reads reject it, and the untrusted path is allowed to | |
| accept overspecified payloads but then validate or ignore the extra parts. | |
| </div> | |
| </article> | |
| </div> | |
| </section> | |
| <section class="slide" id="format-shift" data-slide="02"> | |
| <div class="slide-head fade-up"> | |
| <span class="eyebrow">Wire Format</span> | |
| <h2>The key change is the move from “node info records” to “fixed entries + detached digests”.</h2> | |
| <p class="lede"> | |
| On <code>next</code>, the wire format still carried <code>decorator_count</code> and a | |
| flat <code>Vec<MastNodeInfo></code>. On this branch, the format becomes version | |
| <code>0.0.3</code>, drops the old decorator count, keeps node entries fixed-width, and | |
| peels digests into dedicated sections so hashless bytes can remove only the internal hash | |
| table without disturbing random access. | |
| </p> | |
| </div> | |
| <div class="grid cols-2"> | |
| <article class="panel fade-up"> | |
| <h3><code>next</code> format</h3> | |
| <pre><code class="language-rust">//! (Counts) | |
| //! - nodes count (`usize`) | |
| //! - decorators count (`usize`) | |
| //! ... | |
| //! (Node info section) | |
| //! - MAST node infos (`Vec<MastNodeInfo>`)</code></pre> | |
| <div class="quote" style="margin-top: 14px;"> | |
| <strong>Implication:</strong> every node's structure and digest travel together, so a | |
| hashless mode would either need empty digest placeholders or a second structural layout. | |
| </div> | |
| </article> | |
| <article class="panel alt fade-up"> | |
| <h3>Branch format</h3> | |
| <pre><code class="language-rust">//! (Node entries section) | |
| //! - fixed-width structural node entries (`Vec<MastNodeEntry>`) | |
| //! ... | |
| //! (External digest section) | |
| //! - digests for `External` nodes only | |
| //! ... | |
| //! (Node hash section - omitted if FLAGS bit 1 is set) | |
| //! - digests for all non-external nodes</code></pre> | |
| <div class="quote" style="margin-top: 14px;"> | |
| <strong>Implication:</strong> <code>MastNodeEntry</code> stays fixed-width at | |
| <code>8</code> bytes, while only the general node-hash section disappears in | |
| <code>HASHLESS</code> mode. | |
| </div> | |
| </article> | |
| </div> | |
| <div class="grid cols-3"> | |
| <article class="panel fade-up"> | |
| <h3>New invariants</h3> | |
| <ul> | |
| <li><code>FLAG_HASHLESS</code> is bit 1.</li> | |
| <li><code>FLAG_HASHLESS</code> requires <code>FLAG_STRIPPED</code>.</li> | |
| <li><code>FLAGS_RESERVED_MASK</code> tightens from <code>0xfe</code> to <code>0xfc</code>.</li> | |
| <li>Format version bumps from <code>0.0.2</code> to <code>0.0.3</code>.</li> | |
| </ul> | |
| </article> | |
| <article class="panel alt fade-up"> | |
| <h3>Why external digests remain</h3> | |
| <p> | |
| <code>External</code> nodes are explicitly treated as opaque. Their digests cannot be | |
| recovered from local structure, so they still occupy the external digest section even | |
| for hashless payloads. | |
| </p> | |
| </article> | |
| <article class="panel warm fade-up"> | |
| <h3>Space consequence</h3> | |
| <p> | |
| The PR's benchmark table reports that on the core library MAST, hashless saves | |
| <strong>26,240 bytes</strong> vs stripped and <strong>198,334 bytes</strong> vs full. | |
| The branch is aiming for the size win in issue <a href="https://github.com/0xMiden/miden-vm/issues/2628" target="_blank" rel="noreferrer">#2628</a> | |
| without inventing a totally new structural encoding. | |
| </p> | |
| </article> | |
| </div> | |
| </section> | |
| <section class="slide" id="commit-story" data-slide="03"> | |
| <div class="slide-head fade-up"> | |
| <span class="eyebrow">Commit Story</span> | |
| <h2>The history reads like a feature stack that first made the format possible, then made it safe.</h2> | |
| <p class="lede"> | |
| The branch history is not noise. It shows the implementation sequence: first add the new | |
| format concepts, then split responsibilities into <code>layout</code>/<code>resolved</code>, | |
| then tighten trust and budget behavior, then expand fuzzing and documentation. | |
| </p> | |
| </div> | |
| <div class="grid cols-2"> | |
| <article class="panel fade-up"> | |
| <h3>Phase map</h3> | |
| <div class="timeline"> | |
| <div class="timeline-item"> | |
| <div class="date">2026-03-19</div> | |
| <div class="entry"> | |
| <code>df1413cf2</code> adds hashless serialization and serialized views, then | |
| <code>5f2e365c6</code> physically splits node hashes away from node entries. | |
| </div> | |
| </div> | |
| <div class="timeline-item"> | |
| <div class="date">2026-03-19</div> | |
| <div class="entry"> | |
| <code>c35802c98</code> extracts <code>ForestLayout</code> and | |
| <code>ResolvedSerializedForest</code>, which is the architectural hinge point. | |
| </div> | |
| </div> | |
| <div class="timeline-item"> | |
| <div class="date">2026-03-19 → 2026-03-22</div> | |
| <div class="entry"> | |
| Follow-up commits simplify the type model, make digest access lazy, clarify rustdoc, | |
| and separate <code>MastForestView</code>. | |
| </div> | |
| </div> | |
| <div class="timeline-item"> | |
| <div class="date">2026-03-24</div> | |
| <div class="entry"> | |
| <code>427e3f4df</code> hardens untrusted allocation budgets; <code>5409f3b14</code> | |
| refreshes fuzzing to cover the new APIs. | |
| </div> | |
| </div> | |
| <div class="timeline-item"> | |
| <div class="date">2026-03-25</div> | |
| <div class="entry"> | |
| <code>2316d6595</code> lands the final trust-boundary clarification and makes the | |
| intended consumer split explicit. | |
| </div> | |
| </div> | |
| </div> | |
| </article> | |
| <article class="panel alt fade-up"> | |
| <h3>Commit stack, not just end state</h3> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Commit</th> | |
| <th>Meaning</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>df1413cf2</code></td> | |
| <td>Introduces hashless mode and the idea of serialized forest views.</td> | |
| </tr> | |
| <tr> | |
| <td><code>5f2e365c6</code></td> | |
| <td>Makes detached digest sections a real wire-format fact.</td> | |
| </tr> | |
| <tr> | |
| <td><code>c35802c98</code></td> | |
| <td>Refactors code structure so scanning and digest resolution are reusable layers.</td> | |
| </tr> | |
| <tr> | |
| <td><code>1b78806cc</code></td> | |
| <td>Stops the untrusted path from silently rewriting bad wire hashes.</td> | |
| </tr> | |
| <tr> | |
| <td><code>427e3f4df</code></td> | |
| <td>Adds second-stage budgeting for validation-side allocations.</td> | |
| </tr> | |
| <tr> | |
| <td><code>5409f3b14</code></td> | |
| <td>Aligns fuzz targets with the new public surfaces.</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p class="caption" style="margin-top: 12px;"> | |
| There is one slightly awkward narrative wrinkle: the branch is named | |
| <code>mast-serialization-squashed</code>, but the commit history is still a stacked, | |
| review-friendly evolution rather than a literal one-commit squash. | |
| </p> | |
| </article> | |
| </div> | |
| </section> | |
| <section class="slide" id="architecture" data-slide="04"> | |
| <div class="slide-head fade-up"> | |
| <span class="eyebrow">Architecture</span> | |
| <h2>The new design is a four-layer pipeline, and each layer now has a clean job.</h2> | |
| <p class="lede"> | |
| The branch's best improvement is conceptual compression. Instead of one deserializer doing | |
| everything, the code now separates structural scan, structural view, digest resolution, | |
| and full materialization. | |
| </p> | |
| </div> | |
| <div class="grid cols-2"> | |
| <article class="panel alt fade-up"> | |
| <h3>Pipeline</h3> | |
| <div class="flow"> | |
| <div class="flow-row"> | |
| <div class="flow-node"><code>wire bytes</code></div> | |
| <div class="flow-arrow">scan</div> | |
| <div class="flow-node"><code>ForestLayout</code></div> | |
| <div class="flow-arrow">view</div> | |
| <div class="flow-node"><code>SerializedMastForest</code></div> | |
| </div> | |
| <div class="flow-row"> | |
| <div class="flow-node"><code>UntrustedMastForest</code></div> | |
| <div class="flow-arrow">validate</div> | |
| <div class="flow-node"><code>ResolvedSerializedForest</code></div> | |
| <div class="flow-arrow">materialize</div> | |
| <div class="flow-node"><code>MastForest</code></div> | |
| </div> | |
| </div> | |
| <div class="callout" style="margin-top: 14px;"> | |
| <code>MastForestView</code> is the shared read API that lets | |
| <code>MastForest</code> and <code>SerializedMastForest</code> look alike to callers. | |
| </div> | |
| </article> | |
| <article class="panel fade-up"> | |
| <h3>Quoted entities that matter</h3> | |
| <ul> | |
| <li><code>ForestLayout</code> stores absolute offsets and section sizes, but is explicitly “not a trust marker”.</li> | |
| <li><code>TrackingReader</code> can record consumed bytes so untrusted validation can be deferred.</li> | |
| <li><code>ResolvedSerializedForest</code> chooses where digests come from: wire sections or a rebuilt table.</li> | |
| <li><code>MastForestView::node_info_at()</code> is now defined in terms of <code>node_entry_at()</code> + <code>node_digest_at()</code>.</li> | |
| <li><code>MastForest</code> itself implements <code>MastForestView</code>, so in-memory and serialized views line up.</li> | |
| </ul> | |
| </article> | |
| </div> | |
| <div class="grid cols-2"> | |
| <article class="panel fade-up"> | |
| <h3>Structural inspection path</h3> | |
| <pre><code class="language-rust">pub fn new(bytes: &'a [u8]) -> Result<Self, DeserializationError> { | |
| let mut reader = SliceReader::new(bytes); | |
| let mut scanner = TrackingReader::new(&mut reader); | |
| let (flags, layout) = read_header_and_scan_layout(&mut scanner, true)?; | |
| Ok(Self { bytes, flags, layout, resolved: OnceLockCompat::new() }) | |
| }</code></pre> | |
| <p class="caption" style="margin-top: 12px;"> | |
| <code>SerializedMastForest::new()</code> is intentionally cheap up front. It scans | |
| enough to support random access, but does not parse trailing <code>AdviceMap</code> or | |
| <code>DebugInfo</code>. | |
| </p> | |
| </article> | |
| <article class="panel warm fade-up"> | |
| <h3>Materialization path</h3> | |
| <pre><code class="language-rust">pub(super) fn materialize( | |
| &self, | |
| advice_map: AdviceMap, | |
| debug_info: DebugInfo, | |
| ) -> Result<MastForest, DeserializationError> { | |
| for index in 0..self.node_count() { | |
| let entry = self.node_entry_at(index)?; | |
| let digest = self.node_digest_for_entry(index, entry)?; | |
| let builder = entry.try_into_mast_node_builder(..., digest)?; | |
| builder.add_to_forest_relaxed(&mut mast_forest)?; | |
| } | |
| ... | |
| }</code></pre> | |
| <p class="caption" style="margin-top: 12px;"> | |
| The important consequence is that trusted materialization and untrusted validation now | |
| reuse the same resolved representation instead of each inventing their own parsing logic. | |
| </p> | |
| </article> | |
| </div> | |
| </section> | |
| <section class="slide" id="trust" data-slide="05"> | |
| <div class="slide-head fade-up"> | |
| <span class="eyebrow">Trust Boundary</span> | |
| <h2>The branch redraws the contract: flags describe the payload, not what the reader may trust.</h2> | |
| <p class="lede"> | |
| That is the branch's most repeated sentence in code and in the PR body, and it shows up in | |
| both API behavior and validation semantics. <code>MastForest::read_from_bytes()</code>, | |
| <code>SerializedMastForest::new()</code>, and <code>UntrustedMastForest</code> are now | |
| deliberately different products. | |
| </p> | |
| </div> | |
| <div class="grid cols-3"> | |
| <article class="panel fade-up"> | |
| <h3>Trusted path</h3> | |
| <p> | |
| <code>MastForest::read_from_bytes()</code> now goes through | |
| <code>decode_from_reader(..., false)</code> and therefore rejects | |
| <code>HASHLESS</code> before deeper parsing. | |
| </p> | |
| </article> | |
| <article class="panel alt fade-up"> | |
| <h3>Inspection path</h3> | |
| <p> | |
| <code>SerializedMastForest::new()</code> accepts full, stripped, and hashless bytes, but | |
| its rustdoc repeatedly says it is <strong>not</strong> an untrusted-validation API. | |
| </p> | |
| </article> | |
| <article class="panel warm fade-up"> | |
| <h3>Untrusted path</h3> | |
| <p> | |
| <code>UntrustedMastForest</code> holds raw bytes, a parsed layout, and deferred state. | |
| Validation materializes only after the caller opts in by calling <code>validate()</code>. | |
| </p> | |
| </article> | |
| </div> | |
| <div class="grid cols-2"> | |
| <article class="panel alt fade-up"> | |
| <h3>Validation no longer silently rewrites the wire</h3> | |
| <pre><code class="language-rust">pub fn validate(self) -> Result<MastForest, MastForestError> { | |
| let is_hashless = self.layout.is_hashless(); | |
| let forest = self.into_materialized() | |
| .map_err(MastForestError::Deserialization)?; | |
| if !is_hashless { | |
| forest.validate_node_hashes()?; | |
| } | |
| forest.validate()?; | |
| Ok(forest) | |
| }</code></pre> | |
| <div class="quote" style="margin-top: 14px;"> | |
| For non-hashless payloads, recomputation must match the serialized internal digests. | |
| For hashless payloads, recomputation becomes the source of truth. | |
| </div> | |
| </article> | |
| <article class="panel fade-up"> | |
| <h3>Intentional overspec acceptance</h3> | |
| <pre><code class="language-rust">if !flags.is_hashless() { | |
| log::error!("... includes wire node hashes ..."); | |
| } | |
| if !flags.is_stripped() { | |
| log::error!("... includes DebugInfo ..."); | |
| }</code></pre> | |
| <p class="caption" style="margin-top: 12px;"> | |
| This is subtle but important: the untrusted path is permissive at parse time. It does | |
| not reject full or stripped payloads outright; it logs that the caller supplied a richer | |
| artifact than expected, then validates the parts that matter. | |
| </p> | |
| <div class="callout warn"> | |
| The PR body says the untrusted path “expects hashless input” but still accepts | |
| overspecified bytes. The implementation matches that wording exactly. | |
| </div> | |
| </article> | |
| </div> | |
| </section> | |
| <section class="slide" id="mechanics" data-slide="06"> | |
| <div class="slide-head fade-up"> | |
| <span class="eyebrow">Mechanics</span> | |
| <h2>The diff adds two concrete mechanisms: dense-by-kind digest slots and lazy digest reconstruction.</h2> | |
| <p class="lede"> | |
| Those two mechanisms are what preserve random access while allowing hashless payloads to | |
| stay structurally identical. They are also why the branch adds both | |
| <code>ResolvedSerializedForest</code> and the <code>OnceLockCompat</code>-backed cache in | |
| <code>SerializedMastForest</code>. | |
| </p> | |
| </div> | |
| <div class="grid cols-2"> | |
| <article class="panel fade-up"> | |
| <h3><code>MastNodeEntry</code> replaces the structural half of <code>MastNodeInfo</code></h3> | |
| <pre><code class="language-rust">#[repr(u8)] | |
| pub enum MastNodeEntry { | |
| Join { left_child_id: u32, right_child_id: u32 } = JOIN, | |
| Split { if_branch_id: u32, else_branch_id: u32 } = SPLIT, | |
| Loop { body_id: u32 } = LOOP, | |
| Block { ops_offset: u32 } = BLOCK, | |
| Call { callee_id: u32 } = CALL, | |
| SysCall { callee_id: u32 } = SYSCALL, | |
| Dyn = DYN, | |
| Dyncall = DYNCALL, | |
| External = EXTERNAL, | |
| }</code></pre> | |
| <p class="caption" style="margin-top: 12px;"> | |
| This stays fixed-width at <code>8</code> bytes. It is the reason random access to node | |
| structure remains cheap even after digests move elsewhere. | |
| </p> | |
| </article> | |
| <article class="panel alt fade-up"> | |
| <h3>Slot-table lookup</h3> | |
| <pre><code class="language-rust">for index in 0..layout.node_count { | |
| let entry = layout.read_node_entry_at(bytes, index)?; | |
| if matches!(entry, MastNodeEntry::External) { | |
| slots.push(external_slot); | |
| external_slot += 1; | |
| } else { | |
| slots.push(node_hash_slot); | |
| node_hash_slot += 1; | |
| } | |
| }</code></pre> | |
| <p class="caption" style="margin-top: 12px;"> | |
| <code>slot_by_node</code> is the adapter between absolute node indices and the compact | |
| digest sections. Without it, detached digest sections would ruin index-based lookup. | |
| </p> | |
| </article> | |
| </div> | |
| <div class="grid cols-2"> | |
| <article class="panel warm fade-up"> | |
| <h3>Hashless view cost model</h3> | |
| <pre><code class="language-rust">pub fn node_digest_at(&self, index: usize) -> Result<Word, DeserializationError> { | |
| self.resolved()?.node_digest_at(index) | |
| } | |
| fn resolved(&self) -> Result<&ResolvedSerializedForest<'a>, DeserializationError> { | |
| self.resolved | |
| .get_or_init(|| ResolvedSerializedForest::new(self.bytes, self.layout)) | |
| .as_ref() | |
| .map_err(Clone::clone) | |
| }</code></pre> | |
| <div class="callout"> | |
| The structural operations stay cheap. The first digest-backed access in hashless mode is | |
| the expensive one because it rebuilds the digest cache. | |
| </div> | |
| </article> | |
| <article class="panel fade-up"> | |
| <h3>Caller-facing API changes</h3> | |
| <ul> | |
| <li><code>MastForest::write_hashless()</code> is added.</li> | |
| <li><code>MastForest::stripped_size_hint()</code> becomes exact for stripped bytes.</li> | |
| <li><code>read_from_bytes_with_flags()</code> and budgeted <code>..._and_flags()</code> variants appear on <code>UntrustedMastForest</code>.</li> | |
| <li><code>MastForestView</code> becomes public and shared.</li> | |
| </ul> | |
| <div class="callout warn"> | |
| One intentional tradeoff remains: <code>SerializedMastForest::new()</code> is a trusted | |
| tooling API, so its lazy digest rebuild is not bounded the way the untrusted path is. | |
| </div> | |
| </article> | |
| </div> | |
| </section> | |
| <section class="slide" id="hardening" data-slide="07"> | |
| <div class="slide-head fade-up"> | |
| <span class="eyebrow">Hardening</span> | |
| <h2>The back half of the branch is about closing validation gaps and proving the new surfaces hold up.</h2> | |
| <p class="lede"> | |
| The code changes would be incomplete without the tests and fuzzing. The branch adds new | |
| stress points for malformed hashes, malformed procedure-name digests, forward references, | |
| budget exhaustion, and serialized-view random access. | |
| </p> | |
| </div> | |
| <div class="grid cols-2"> | |
| <article class="panel alt fade-up"> | |
| <h3>Budget model</h3> | |
| <pre><code class="language-rust">const DEFAULT_UNTRUSTED_ALLOCATION_BUDGET_MULTIPLIER: usize = 7; | |
| pub(super) fn default_untrusted_allocation_budget(bytes_len: usize) -> usize { | |
| bytes_len.saturating_mul(DEFAULT_UNTRUSTED_ALLOCATION_BUDGET_MULTIPLIER) | |
| }</code></pre> | |
| <p class="caption" style="margin-top: 12px;"> | |
| The branch introduces a second budget beyond parsing: helper allocations for | |
| <code>slot_by_node</code>, rebuilt hash tables, and stripped debug scaffolding are | |
| charged explicitly. The multiplier is admitted in the docs to be a coarse bound, not a | |
| peak-memory proof. | |
| </p> | |
| </article> | |
| <article class="panel fade-up"> | |
| <h3>Tests that tell you what the author worried about</h3> | |
| <ul> | |
| <li><code>test_untrusted_forest_rejects_mismatched_wire_root_hash</code></li> | |
| <li><code>test_untrusted_forest_rejects_invalid_procedure_name_digest_without_remapping</code></li> | |
| <li><code>test_untrusted_forest_rejects_digest_collision_in_wire_hashes</code></li> | |
| <li><code>test_untrusted_hashless_validation_respects_custom_allocation_budget</code></li> | |
| <li><code>test_untrusted_forest_rejects_basic_block_indptr_that_breaks_push_immediate_commitment</code></li> | |
| </ul> | |
| <div class="callout danger"> | |
| That last test is the canary: the branch is explicitly defending against a commitment | |
| gap where batch metadata could alter semantics without changing the accepted digest. | |
| </div> | |
| </article> | |
| </div> | |
| <div class="grid cols-2"> | |
| <article class="panel warm fade-up"> | |
| <h3>Fuzzing and tooling</h3> | |
| <ul> | |
| <li>The <code>Makefile</code> adds <code>fuzz-mast-node-info</code> and <code>fuzz-serialized-mast-forest</code>.</li> | |
| <li><code>mast_forest_validate</code> now exercises parsing-only, parsing+validation, and flag-returning entry points.</li> | |
| <li><code>mast_node_info</code> now targets the serialized-view API instead of indirect full deserialization.</li> | |
| <li><code>serialized_mast_forest_new</code> is added specifically for the new structural inspection path.</li> | |
| </ul> | |
| </article> | |
| <article class="panel alt fade-up"> | |
| <h3>Benchmark story in the PR body</h3> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Mode</th> | |
| <th><code>origin/next</code></th> | |
| <th>Branch</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>Full bytes</td> | |
| <td>472,034</td> | |
| <td>472,066</td> | |
| </tr> | |
| <tr> | |
| <td>Stripped bytes</td> | |
| <td>299,972</td> | |
| <td>299,972</td> | |
| </tr> | |
| <tr> | |
| <td>Hashless bytes</td> | |
| <td>n/a</td> | |
| <td>273,732</td> | |
| </tr> | |
| <tr> | |
| <td>Trusted core-lib deserialize</td> | |
| <td>3.3250 ms</td> | |
| <td>3.1959 ms</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p class="caption" style="margin-top: 12px;"> | |
| The performance claim is disciplined: the PR body explicitly says the package-level | |
| benchmark does not measure hashless validation cost, only trusted deserialization. | |
| </p> | |
| </article> | |
| </div> | |
| </section> | |
| <section class="slide" id="references" data-slide="08"> | |
| <div class="slide-head fade-up"> | |
| <span class="eyebrow">References</span> | |
| <h2>The PR cites issues, benchmarks, and named techniques, but not academic papers.</h2> | |
| <p class="lede"> | |
| So the reference story is mostly internal design lineage: issue numbers, benchmark | |
| artifacts, and the vocabulary of the format itself. The named algorithmic ideas are still | |
| worth calling out because they frame the code: <code>MAST</code>, <code>CSR</code>, | |
| Merkle-style digest recomputation, and domain-separated hash merges via | |
| <code>hasher::merge_in_domain()</code>. | |
| </p> | |
| </div> | |
| <div class="grid cols-2"> | |
| <article class="panel fade-up"> | |
| <h3>References mentioned in the PR</h3> | |
| <div class="refs"> | |
| <div class="ref-card"> | |
| <strong>Primary PR</strong> | |
| <a href="https://github.com/0xMiden/miden-vm/pull/2765" target="_blank" rel="noreferrer">PR #2765: Refactor MAST forest serialization around fixed-layout hashless sections</a> | |
| </div> | |
| <div class="ref-card"> | |
| <strong>Issues called out as motivation</strong> | |
| <a href="https://github.com/0xMiden/miden-vm/issues/2726" target="_blank" rel="noreferrer">#2726</a>, | |
| <a href="https://github.com/0xMiden/miden-vm/issues/2504" target="_blank" rel="noreferrer">#2504</a>, | |
| <a href="https://github.com/0xMiden/miden-vm/issues/2628" target="_blank" rel="noreferrer">#2628</a>, | |
| <a href="https://github.com/0xMiden/miden-vm/issues/2863" target="_blank" rel="noreferrer">#2863</a> | |
| </div> | |
| <div class="ref-card"> | |
| <strong>Explainers linked from the PR</strong> | |
| <a href="https://gisthost.github.io/?cc5e99ad466cae75bdfb4b447b5509ac" target="_blank" rel="noreferrer">web explainer</a>, | |
| <a href="https://github.com/user-attachments/assets/8e7d4d45-4ecc-4a12-af59-8b2ded533598" target="_blank" rel="noreferrer">video explainer</a>, | |
| <a href="https://gist.github.com/huitseeker/dd70fc331cd954a4bed265968abd3f57" target="_blank" rel="noreferrer">standalone Criterion benchmark gist</a> | |
| </div> | |
| </div> | |
| </article> | |
| <article class="panel alt fade-up"> | |
| <h3>Named techniques and terms</h3> | |
| <ul> | |
| <li><code>MAST</code>: the Merkleized forest abstraction the whole wire format is encoding.</li> | |
| <li><code>CSR</code>: still used in debug/decorator metadata storage and cited in the format docs.</li> | |
| <li><code>Criterion</code>: benchmark harness referenced in the PR for size and timing measurements.</li> | |
| <li><code>hash_elements()</code> and <code>merge_in_domain()</code>: the concrete digest algorithms used during recomputation.</li> | |
| </ul> | |
| <div class="callout warn"> | |
| No academic paper is explicitly cited in the PR body. The branch is grounded in repo | |
| issues and implementation notes rather than outside literature. | |
| </div> | |
| </article> | |
| </div> | |
| <div class="grid cols-2"> | |
| <article class="panel warm fade-up"> | |
| <h3>Bottom line</h3> | |
| <p> | |
| If you want one sentence: this branch replaces an all-in-one serialized node format with | |
| a fixed-layout structural format that supports <code>HASHLESS</code> payloads, reuses a | |
| shared view layer, and makes the trust contract explicit at the API boundary. | |
| </p> | |
| <p> | |
| If you want the second sentence: the last third of the branch exists to make that design | |
| safe, by forcing hash rechecks, budgeting deferred allocations, and widening the | |
| fuzz/test matrix around the new entry points. | |
| </p> | |
| </article> | |
| <article class="panel fade-up"> | |
| <h3>What to watch in review</h3> | |
| <ul> | |
| <li>Whether the <code>* 7</code> default allocation multiplier is conservative enough for real untrusted workloads.</li> | |
| <li>Whether callers understand that <code>SerializedMastForest::new()</code> is intentionally not a security API.</li> | |
| <li>Whether future wire-format changes preserve the nice separation between <code>ForestLayout</code> and <code>ResolvedSerializedForest</code>.</li> | |
| </ul> | |
| <div class="kicker">Deck built from <code>next...HEAD</code> plus PR metadata</div> | |
| </article> | |
| </div> | |
| </section> | |
| </main> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/rust.min.js"></script> | |
| <script> | |
| const slides = [...document.querySelectorAll(".slide")]; | |
| const agendaLinks = [...document.querySelectorAll("#agenda a")]; | |
| const progressBar = document.getElementById("progressBar"); | |
| const slideLabel = document.getElementById("slideLabel"); | |
| if (window.hljs) { | |
| hljs.configure({ languages: ["rust"] }); | |
| document.querySelectorAll("pre code").forEach((block) => hljs.highlightElement(block)); | |
| } | |
| const updateProgress = () => { | |
| const maxScroll = document.documentElement.scrollHeight - window.innerHeight; | |
| const ratio = maxScroll > 0 ? window.scrollY / maxScroll : 0; | |
| progressBar.style.width = `${Math.max(0, Math.min(1, ratio)) * 100}%`; | |
| }; | |
| const setActiveSlide = (id) => { | |
| agendaLinks.forEach((link, index) => { | |
| const active = link.getAttribute("href") === `#${id}`; | |
| link.classList.toggle("active", active); | |
| if (active) { | |
| slideLabel.textContent = `${String(index + 1).padStart(2, "0")} / ${String(slides.length).padStart(2, "0")}`; | |
| } | |
| }); | |
| }; | |
| const observer = new IntersectionObserver((entries) => { | |
| entries.forEach((entry) => { | |
| if (entry.isIntersecting && entry.intersectionRatio >= 0.45) { | |
| setActiveSlide(entry.target.id); | |
| } | |
| if (entry.isIntersecting) { | |
| entry.target.querySelectorAll(".fade-up").forEach((item, index) => { | |
| setTimeout(() => item.classList.add("visible"), 55 * index); | |
| }); | |
| } | |
| }); | |
| }, { threshold: [0.45, 0.72] }); | |
| slides.forEach((slide) => observer.observe(slide)); | |
| const scrollToSlide = (delta) => { | |
| const anchor = slides.findIndex((slide) => { | |
| const rect = slide.getBoundingClientRect(); | |
| return rect.top >= -40 && rect.top < window.innerHeight * 0.6; | |
| }); | |
| const current = anchor === -1 ? 0 : anchor; | |
| const next = Math.max(0, Math.min(slides.length - 1, current + delta)); | |
| slides[next].scrollIntoView({ behavior: "smooth", block: "start" }); | |
| }; | |
| document.addEventListener("keydown", (event) => { | |
| if (["ArrowDown", "PageDown", "j", "J"].includes(event.key)) { | |
| event.preventDefault(); | |
| scrollToSlide(1); | |
| } | |
| if (["ArrowUp", "PageUp", "k", "K"].includes(event.key)) { | |
| event.preventDefault(); | |
| scrollToSlide(-1); | |
| } | |
| if (event.key === "Home") { | |
| event.preventDefault(); | |
| slides[0].scrollIntoView({ behavior: "smooth", block: "start" }); | |
| } | |
| if (event.key === "End") { | |
| event.preventDefault(); | |
| slides[slides.length - 1].scrollIntoView({ behavior: "smooth", block: "start" }); | |
| } | |
| }); | |
| window.addEventListener("scroll", updateProgress, { passive: true }); | |
| window.addEventListener("load", () => { | |
| slides[0].querySelectorAll(".fade-up").forEach((item, index) => { | |
| setTimeout(() => item.classList.add("visible"), 80 * index); | |
| }); | |
| setActiveSlide(slides[0].id); | |
| updateProgress(); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment