What changed, and why

This is the first fix surfaced by the pedagogy loop (#5), run across all 23 lessons three times. The headline is the non-change: 22 of 23 lessons passed the teaching rubric 8/8 every pass. The collection teaches well. One majority-agreed gap remained — and it's a precise, small one.

cuckoo-filter was flagged on a single rubric item, "lands the transfer", by 2 of 3 independent evaluators. Their agreement was specific: the coda distills the cuckoo filter's own mechanism ("four moves: hash, place, evict, forget") and lists its neighbours, but never lifts one principle to carry to other problems — the thing a good close leaves you with. Both evaluators even named the same candidate the lesson had already built but not elevated: recovering a location by XOR instead of storing it.

The fix — one paragraph, in the lesson's voice

The change adds a single paragraph to the coda, right after "There is very little here. That is the point." It takes the XOR trick the lesson already taught — a fingerprint's alternate bucket is recomputed, i₂ = i₁ ⊕ hash(fp), never stored — and names the transferable idea inside it: derive what you can instead of keeping it. Nothing else moves; the style mirrors the existing body block (IBM Plex Serif, the same width and weight), with the formula in the family's JetBrains Mono.

The new paragraph sits between the 'very little here' close and the 'Where to go next' cards.

src/lessons/cuckoo-filter/components/Coda.jsx · 182 lines
src/lessons/cuckoo-filter/components/Coda.jsx182 lines · JSX
⋯ 49 lines hidden (lines 1–49)
1export function Coda() {
2 return (
3 <section style={{ marginTop: 160, marginBottom: 100 }}>
4 <div className="cf-page">
5 <div
6 style={{
7 maxWidth: 760,
8 margin: '0 auto',
9 textAlign: 'center',
10 padding: '60px 0',
11 borderTop: '1px solid var(--line)',
12 borderBottom: '1px solid var(--line)',
13 }}
14 >
15 <div className="cf-eyebrow cf-eyebrow-cuc" style={{ marginBottom: 28 }}>
16 Coda
17 </div>
18 
19 <h2
20 style={{
21 fontFamily: 'Fraunces',
22 fontWeight: 300,
23 fontStyle: 'italic',
24 fontSize: 'clamp(26px, 4.4vw, 56px)',
25 lineHeight: 1.18,
26 letterSpacing: '-0.02em',
27 margin: 0,
28 color: 'var(--text)',
29 fontVariationSettings: '"opsz" 144, "SOFT" 100',
30 }}
31 >
32 Four moves: <span style={{ color: 'var(--cuc)' }}>hash</span>, place, evict,{' '}
33 <span style={{ color: 'var(--cuc)' }}>forget</span>.
34 <br />
35 The rest is parameters.
36 </h2>
37 
38 <div
39 style={{
40 marginTop: 36,
41 maxWidth: 580,
42 margin: '36px auto 0',
43 fontFamily: 'IBM Plex Serif',
44 fontSize: 16.5,
45 lineHeight: 1.65,
46 color: 'var(--text-2)',
47 fontWeight: 300,
48 }}
49 >
50 The cuckoo filter is no larger than its description. A short hash, an XOR, a small
51 budget of kicks; eight bits per entry, three percent wrong, deletes for free. There is
52 very little here. That is the point.
53 </div>
54 
55 <div
56 style={{
57 maxWidth: 580,
58 margin: '22px auto 0',
59 fontFamily: 'IBM Plex Serif',
60 fontSize: 16.5,
61 lineHeight: 1.65,
62 color: 'var(--text-2)',
63 fontWeight: 300,
64 }}
65 >
66 And one of those moves travels. The filter never records where a fingerprints second
67 home is; it recomputes it,{' '}
68 <span style={{ fontFamily: 'JetBrains Mono', fontSize: 14, color: 'var(--text)' }}>
69 i = i hash(fp)
70 </span>
71 , so either bucket reaches the other with nothing stored between them.{' '}
72 <span style={{ fontStyle: 'italic', color: 'var(--text)' }}>
73 Derive what you can instead of keeping it.
74 </span>{' '}
75 That idea is older and wider than this filter, and it is the one to carry out.
76 </div>
77 
78 <div style={{ maxWidth: 620, margin: '56px auto 0', textAlign: 'left' }}>
⋯ 104 lines hidden (lines 79–182)
79 <div
80 className="cf-eyebrow"
81 style={{ marginBottom: 18, textAlign: 'center', letterSpacing: '0.28em' }}
82 >
83 Where to go next
84 </div>
85 <div className="cf-cols cf-cols-2">
86 {[
87 {
88 title: 'Bloom filters',
89 desc: 'The structure this one was built to beat. Pure bit arrays, smaller still, but no way to take a key back out.',
90 },
91 {
92 title: 'Counting Bloom filters',
93 desc: 'The other route to deletion: swap each bit for a small counter. It buys removal, but pays several times the space.',
94 },
95 {
96 title: 'Quotient filters',
97 desc: 'A cousin that also deletes, splitting each hash into a quotient and a remainder instead of kicking fingerprints between buckets.',
98 },
99 {
100 title: 'Cuckoo hashing',
101 desc: 'The table beneath the filter. Pagh and Rodler’s scheme, where the kick-and-rehome dance was born, before fingerprints ever entered.',
102 },
103 ].map((item) => (
104 <div
105 key={item.title}
106 style={{
107 padding: '18px 20px',
108 border: '1px solid var(--line)',
109 background: 'var(--bg-1)',
110 }}
111 >
112 <div
113 style={{
114 fontFamily: 'Fraunces',
115 fontSize: 19,
116 fontWeight: 400,
117 letterSpacing: '-0.012em',
118 color: 'var(--text)',
119 marginBottom: 8,
120 }}
121 >
122 {item.title}
123 </div>
124 <div className="cf-body" style={{ fontSize: 14, lineHeight: 1.55 }}>
125 {item.desc}
126 </div>
127 </div>
128 ))}
129 </div>
130 </div>
131 
132 <div
133 style={{
134 marginTop: 56,
135 display: 'flex',
136 alignItems: 'center',
137 justifyContent: 'center',
138 gap: 20,
139 }}
140 >
141 <div style={{ width: 40, height: 1, background: 'var(--line-strong)' }} />
142 <div
143 style={{
144 fontFamily: 'JetBrains Mono',
145 fontSize: 10.5,
146 letterSpacing: '0.32em',
147 color: 'var(--cuc)',
148 }}
149 >
150 END
151 </div>
152 <div style={{ width: 40, height: 1, background: 'var(--line-strong)' }} />
153 </div>
154 
155 <div
156 style={{
157 marginTop: 24,
158 fontFamily: 'IBM Plex Serif',
159 fontStyle: 'italic',
160 fontSize: 13,
161 color: 'var(--text-mute)',
162 letterSpacing: 0,
163 }}
164 >
165 Fan, Andersen, Kaminsky & Mitzenmacher. <br />
166 <span
167 className="cf-mono"
168 style={{
169 fontStyle: 'normal',
170 fontSize: 11,
171 letterSpacing: '0.06em',
172 color: 'var(--cf-label-faint)',
173 }}
174 >
175 "Cuckoo Filter: Practically Better Than Bloom" · CoNEXT 2014
176 </span>
177 </div>
178 </div>
179 </div>
180 </section>
181 );