Build status

This book is complete. All 352 queue rows are written, across 273 topic pages and roughly one million words. Nothing is marked [todo], in any chapter index or in the queue.

It was built incrementally, a few topics per session, and this page was the honest state of it throughout. The rule during the build was that a topic which had not been written yet stayed marked [todo] rather than existing as a stub, because a thin page marked complete is worse than a missing one: it hides.

The section is now in maintenance. Two things are worth re-checking periodically rather than adding pages:

  • Dated claims. The company loop formats page, the standards reference card, and any page citing a provider default or a version number carry statements with a shelf life. Each says so in its own text.
  • The derived indexes. Chapter index lists are generated by state/reconcile_indexes.py from SUMMARY.md plus QUEUE.md and enforced by state/check.py. Never hand-edit them.

The definition of done and the session process live in CLAUDE.md in this directory. The decisions log, including every place this book improves on or departs from its source document, lives in state/DECISIONS.md.

Progress

Counts

Queue rows inventoried341
Done at the full ten-point bar51 rows (47 pages)
Remaining290
Chapters with at least one completed topic19 of 19
Words under book/~134,000

Priority mix of the remaining queue: 82 P1, 86 P2, 94 P3, 28 P4.

Counts on this page are produced by state/check.py, not tallied by hand (D9).

What "done" means here

A topic is only marked [done] in QUEUE.md when the file contains all ten of: precise definition (including what it is confused with), the problem it solves, real mechanics with code or math, a worked example with numbers, named production evidence, the tradeoff debate with a committed position, three to six follow-up questions answered in full, at least one common misconception, an interview delivery note, and two to four primary sources.

Thin files are not marked done. A thin file marked done is worse than a todo, because it hides.

Session log

Session 0 and 1 (2026-08-03)

Setup and the first working batch.

Setup. Created the directory structure, copied the source document to source/ as read-only, wrote CLAUDE.md as the standing instruction set, wired the book into book.toml with src = "book" and into the site's build.sh as its own landing-page section.

Inventory. Read the source end to end and extracted the queue into QUEUE.md, grouped by target chapter and prioritised P1 to P4. The source's own gap register (§51) supplied the P2 and P3 tagging; the drill bank (§25, §34, §38.8, §39.7) and the design-question lists (§5.2, §6.6, §15.10) supplied P1.

Topics completed (13). Chosen for breadth across chapters rather than depth in one: Cassandra tombstones, Kafka exactly-once, Reactor flatMap vs concatMap, gRPC behind an L4 load balancer, prefill vs decode, diagnosing confidently wrong RAG, CFS throttling, cache stampede, SSE vs WebSockets, PKCE, burn-rate alerting, canary vs A/B, and the toxic code reviewer.

Also written: 00-how-to-use.md, 19 chapter index pages, the recitables sheet seeded with 40 entries, and 42 flashcards.

Session 2 (2026-08-03)

Twenty topics, chosen so that every one of the 19 chapters now has at least one completed page. Nineteen of the twenty are P1.

ChapterTopicDrill
01The staff-level design interviewn/a
02Little's Law and queueingn/a
02Write skew and snapshot isolation28
03DynamoDB single-table design24
04Virtual threads vs reactive12
04GraphQL N+1 and DataLoader13
06Budgeting a context window9
07Filtered vector search and the recall cliffn/a
07Interleaving and position biasn/a
08A pod is healthy but slow19
10Revoking stateless JWTs30
11Migrating a Redux store to a server cache34
12Cardinality: the observability cost model44
14Team Topologies and splitting a team47
14Modular monolith vs microservices48
15Design a payments ledgern/a
16Making the reliability investment case40
17RTO and RPO, extracted and priced50
18Reverse due diligence59
19Drills 10 to 15, spoken form10-15

Correction logged. The session 0 total of 354 topics was an arithmetic error in the per-chapter tally; the queue contains 341 rows. Corrected here, in QUEUE.md, and recorded as decision D9 in DECISIONS.md. Nothing was removed from the queue; only the reported total changed.

Session 3 (2026-08-03)

Fourteen topic pages plus a drill batch, weighted deliberately toward the reader's moat: chapter 05 went from 2 pages to 9, because a search / recommendations / GenAI background targeting staff roles is where depth converts directly into interview advantage, and the 2026 loop weights it heavily.

ChapterTopicDrill
05Hybrid retrieval and reciprocal rank fusionn/a
05Evaluating RAG: two systems, two metric familiesn/a
05KV cache, GQA, paging and continuous batchingn/a
05LLM cost engineering6
05Prompt injection and the lethal trifecta5
05Evaluating an agent4
05Chunking, and why fixed-size is usually wrongn/a
02The tail at scalen/a
02Idempotency and exactly-oncen/a
04Watermarks in Flink15
10CVSS, EPSS and KEV31, 33
15Design a news feedn/a
16The engineer who has missed three commitmentsn/a
19Drills 1 to 6, spoken form1-6

Structural addition: the drill map. 19-drill-bank/index.md is now a complete table of all 66 source drills plus 12 the expansion added, each pointing at the page that teaches it and marked queued where it does not exist yet. That closes the loop the book was missing: a reader can go from any drill they failed straight to the page, and the gaps are visible rather than implied.

The checker earned its keep. It caught an em dash I introduced in the drill batch, which the manual pass had missed. That is exactly the class of error it exists for.

Next session. The remaining P1 drills with no page: zero trust and the sequencing (10, drill 32), OpenSearch zero-downtime reindex (03, drill 27), the director who wants a date you cannot commit to (16, drill 39), two teams building the same service (16, drill 41), and deploy-versus-release with the pipeline as a system (13, drill 46).

Verification schedule

Every tenth session: audit three random [done] topics against the ten-point bar, run the stranger test on one (could a strong senior answer a hostile follow-up from this file alone?), log failures in DECISIONS.md and fix them. First verification pass due after session 10.

Session 4 (batch 2): the compute, storage and delivery gaps

Seven topics, all P1 drills that previously resolved to queued in the drill map.

ChapterPageDrill
08Serverless or containers: walk the math21
08Where fsync fits in durability22
08eBPF for intermittent latency23
09Invalidating with complex dependencies17
06Knowledge graph vs vector index8
03Choosing a MongoDB shard key26
13Expand and contract64, 66

Chapter 08 went from 2 pages to 5 and is now the third-deepest chapter. The compute-and-kernel drills (19 to 23) are fully covered for the first time.

The expand-contract page deliberately answers two drills at once, because the cache-format rollback failure (64) and the three-version column rename (66) are the same problem: state written by one version that another version cannot read. Splitting them would have produced two thin pages that each omitted half the mechanism.

State after this batch: 59 pages, ~177k words, 167 flashcards, 69 of 341 queue rows closed. Every one of the 66 drills in chapters 19's map now resolves to a page except 35, 36, 51, 52, 53, 54, 58, 60 and 65.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Session 4 (batch 3): every drill now resolves to a page

Eight topics, clearing the last nine drills that showed queued in the drill map.

ChapterPageDrill
11Diagnosing a bad INP35
11When micro-frontends are worth it36
12Chaos-testing an untested assumption51
14The repository pattern, and the argument against53
14CQRS: the adoption ladder54
01SCOR, STAR and the scar-tissue story58, 60
18Being down-levelled in an offer52
13A mobile crash at 40 percent rollout65

Milestone: all 66 drills in 19-drill-bank/index.md now link to a full treatment. The map's introduction was rewritten accordingly, since queued no longer appears in it. That was the single most useful navigational property of the book to reach, because the drill bank is how a reader finds the page that teaches something they could not answer out loud.

Two pages deliberately answer two drills each: the SCOR/STAR page covers both the format-conversion drill and the scar-tissue drill, because scar tissue is a story type that only makes sense alongside the two formats; and (from batch 2) the expand-contract page covers both the cache-format rollback and the three-version column rename.

State after this batch: 67 pages, ~203k words, 193 flashcards, 78 of 341 queue rows closed. Chapters 11, 14 and 18 each gained their first real depth.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Where the remaining queue value is. With the drills exhausted, the next sessions shift from drill-driven to gap-driven: the chapters with the thinnest coverage relative to the reader's target roles are 02 (distributed systems), 07 (search and ranking) and 15 (design answers), and 15 in particular has no worked end-to-end design walkthroughs yet, which is the highest-value remaining gap for a staff loop.

Session 5: chapter 15, the worked design answers

Four full design transcripts, the first work on the chapter the previous session identified as the highest-value remaining gap.

DesignWhy this one
Distributed job scheduler with exactly-once semanticsP1, and the premise correction ("exactly-once delivery is impossible, exactly-once effect is what you build") is the highest-value fifteen seconds in the chapter
Ticketing under contentionP1, and it is the canonical contention-not-scale problem
Multilingual semantic search at 10k QPSThe reader's moat (search, multilingual, OpenSearch)
Personalised recommendation serving on a 50 ms budgetThe reader's moat (recsys), and the item-feature arithmetic drives the whole architecture

Chapter 15 goes from 2 pages to 6. These are the longest pages in the book (roughly 3,000 to 3,800 words each), which matches the chapter's own instruction: the two designs worked in the source document are the depth target, and anything thinner is unfinished.

Each follows the transcript shape established by news-feed.md: clarify, capacity math, architecture, a deep dive on the hardest component, failure modes and degradation, what changes at 10x, then the standard topic-page closing sections.

A deliberate property of all four: the capacity arithmetic in step 2 derives the architecture rather than decorating it. 30 million item-feature reads per second is why item features live in process memory; 50,000 seats being 10 MB is why ticketing is a contention problem and not a scale one; 1M jobs/day being 12/sec is why it is one Postgres instance. Interview answers that compute a number and then design something unrelated to it are the common failure this chapter is meant to counter.

State after this session: 71 pages, ~219k words, 213 flashcards, 82 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 15 still has 13 designs queued. The highest-value remaining are the notification fan-out system, the metrics pipeline, ad-click aggregation (dedupe plus late events, which pairs with the Flink watermarks page), and the LLM gateway.

Session 6: chapter 15 continued, the data-infrastructure designs

Four more design transcripts, the ones the previous session flagged as highest-value.

DesignWhy this one
Notification and fan-out systemP1, and the celebrity fan-out is the canonical bounded-work-expansion problem
Ad click aggregation with dedupe and late eventsP1, and it makes the Flink watermarks page concrete with real arithmetic
Metrics and observability pipelineP1, and it pairs with the Prometheus cardinality page from session 2
LLM gatewayP3, but it is the design a search/GenAI candidate is most likely to be asked to lead

Chapter 15 is now 10 of 19 designs written, past the halfway point, and it is the chapter a staff loop draws on most.

Three of the four deliberately connect to existing topic pages rather than repeating them: the click aggregation page assumes Flink watermarks, the metrics page assumes cardinality, and the gateway page assumes prompt injection and the cost engineering material. That cross-linking is what makes the book a reference rather than a set of essays, and it is worth doing deliberately as the design chapter fills in.

A pattern worth recording for future design pages. Each of these opens with a clarifying question whose answer changes the architecture, and says so explicitly: billing versus dashboards for click aggregation, what the gateway is for out of five possible answers, metrics versus logs versus traces, and which of three meanings "multilingual" has. Interviewers score the clarification round, and a page that models a good one teaches more than the architecture does.

State after this session: 75 pages, ~235k words, 233 flashcards, 86 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: the remaining 9 designs in chapter 15 (rate limiter and RAG-with-authz are worked in the source document and need porting rather than writing, which makes them cheap; object storage, ride-hailing dispatch, multi-region KV, agent platform, eval pipeline, cost attribution and inference batching are new). After that, chapters 02 and 07 are the thinnest relative to the reader's target roles.

Session 7: chapter 15 continued, and the two gold-standard designs

Four more transcripts, including both designs the source document worked in full.

DesignNote
Distributed rate limiterGold-standard exemplar (source §43.1). Two-tier leases, with the overshoot bound derived rather than asserted
RAG with document-level access controlGold-standard exemplar (source §43.2), and the reader's moat
Multi-region active-active key-value storeP1. The consistency routing rule is the design
Ride-hailing dispatch and geo-indexingP1. Haversine pruning turns 1M ETAs into 10k

Chapter 15 is now 14 of 19 designs written, and it is the largest chapter in the book by word count.

A deliberate pairing across this session. The rate limiter fails open on its central authority and the RAG access-control design fails closed on its permission service, and both pages say so explicitly and reference the other's reasoning. The point being taught is that "fail open" and "fail closed" are not defaults to memorise: you compare the consequences, and a rate limiter failing closed takes down the API while a permission check failing open leaks data. Having two pages that reach opposite conclusions from the same question is worth more than either page stating a rule.

State after this session: 79 pages, ~252k words, 253 flashcards, 90 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: five designs remain in chapter 15 (object storage and file sync, agent platform with sandboxed tools, evaluation pipeline gating CI, cost attribution across 40 teams, inference batching on one GPU). After that, chapters 02 (distributed systems) and 07 (search and ranking) are the thinnest relative to the reader's target roles.

Session 8: chapter 15 complete

Five more transcripts, closing the chapter. All 19 worked designs are now written.

DesignNote
Object storage and file syncP1. Content-defined chunking answers the stated requirement mechanically; metadata is the real problem
Agent platform with sandboxed tools and replayP3. User-scoped tool authorisation as the structural injection defence
Evaluation pipeline that gates CIP3. The noise floor, paired comparison, and segment-level gating
Cost attribution across 40 teamsP3. Unit economics rather than a spend table
Inference serving on one GPUP1. The roofline arithmetic derives every decision

Chapter 15 is the book's largest chapter: 20 pages (19 designs plus the index), roughly 90,000 words, and the chapter a staff loop draws on most heavily.

Its index intro was rewritten to note completion and to tell a systematic reader what transfers between designs: the step-2 capacity arithmetic (which derives the architecture rather than decorating it) and the opening clarifying question (which interviewers score and most candidates skip).

Deliberate cross-chapter structure, now visible across the whole chapter. Several pages reach opposite conclusions from the same question and reference each other, which teaches the reasoning rather than a rule:

  • The rate limiter fails open on its central authority; the permissioned RAG design fails closed on its permission service. Both say why, and each cites the other.
  • The click-aggregation design is deliberately Lambda-shaped and answers the Kappa objection directly, rather than pretending it does not exist.
  • Four designs (metrics, notifications, cost attribution, LLM gateway) all end up needing the same windowed-aggregation pipeline, and later ones point at the earlier one instead of restating it.

State after this session: 84 pages, ~273k words, 276 flashcards, 95 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next. With chapter 15 complete, the thinnest chapters relative to the reader's target roles are 02 (distributed systems) and 07 (search and ranking), and 07 in particular is the reader's declared moat, so it should be deep rather than merely covered. After those, chapter 00's how-to-use page and chapter 90's recitables sheet need their final consolidation passes, which are the last items in the CLAUDE.md process section.

Session 9: chapter 07, the reader's moat

Four topics in search and ranking, the chapter the reader is expected to control the room in and which had only two pages.

PageWhy this one first
BM25 from first principlesDerived rather than recited: each term of the formula answers a specific failure of raw term frequency. The two-document worked example (a 150-word doc beating a 3,000-word doc with 4x the matches) is the whole argument in one calculation
Lucene segments: refresh, flush, mergeThe three operations candidates conflate. Includes the force-merge failure that is irreversible without a reindex
HNSW internalsThe memory formula, and the delete problem, which is the operational fact nobody plans for
NDCG, MRR and the offline-online gapEvaluation is where the chapter's index says candidates lose it, and the evaluation-set-bias cause of divergence is silent

Chapter 07 goes from 2 pages to 6.

A deliberate property of this batch: each page's strongest content is arithmetic that can be produced on a whiteboard. BM25's two-document comparison, HNSW's memory formula (168 GB fp32 versus 53 GB int8 at 50M vectors), the bulk-load segment arithmetic (2,000 segments and 5-10x merge write amplification), and NDCG worked to 0.832 by hand. That is deliberate: this is the chapter where the reader is supposed to be able to go deeper than the interviewer, and a derivation does that where a definition does not.

State after this session: 88 pages, ~287k words, 296 flashcards, 99 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 07 still has 12 topics queued, of which the highest-value are the multi-stage ranking funnel, two-tower retrieval and feature-store parity, multilingual index topology, and popularity bias and feedback loops. Then chapter 02 (distributed systems), then the final consolidation passes on 00-how-to-use.md and 90-recitables.md.

Session 10: chapter 07, the four P1 topics

Four more search and ranking topics, all P1, taking the chapter to 10 pages.

PageThe load-bearing idea
The multi-stage ranking funnelThe funnel is forced by arithmetic (14 hours vs 35 ms), and hard negative mining from the previous stage's own output is the largest training lever
Two-tower retrieval and feature parityThe logQ correction, the hard-negative trap (top unlabelled results are unlabelled positives), and the three ways feature-store parity fails
Multilingual index topologyLexical and vector topology are orthogonal decisions; per-index IDF makes cross-index score merging systematically wrong
Popularity bias and feedback loopsThe failure is invisible in every metric anyone watches; exploration is the only intervention that generates the missing observations

The book has passed 300,000 words (299,860 under book/, 92 pages).

A structural note for future sessions. Chapter 07 now cross-references chapter 15's designs in both directions: the funnel page assumes the recsys serving design's latency budget, and the multilingual page assumes the multilingual search design's filter routing. The topic pages teach the mechanism and the design pages show it assembled under a budget, which is the division of labour worth preserving: a topic page that restates a design page's architecture is duplicated, and a design page that re-derives a mechanism is too long.

State after this session: 92 pages, ~300k words, 316 flashcards, 103 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 07 has 8 topics left (inverted index mechanics, analyzers per language, IVF-PQ vs HNSW vs DiskANN, billion-scale sharding, learning to rank, judgment collection, cold start and bandits, embedding freshness). Then chapter 02 (distributed systems), which has 10 queued and is the foundations chapter everything else references. Then the final consolidation passes on 00-how-to-use.md and 90-recitables.md.

Session 11: chapter 02, the foundations

Four topics in distributed systems, including all three P1s. Chapter 02 goes 4 -> 8 pages.

PageThe load-bearing idea
The latency numbers and derived factsRatios not absolutes; a datacenter round trip is 5,000 memory accesses, which settles microservice granularity
Back-of-envelope capacity mathThe worked search sizing where int8 quantisation is what removes the need to shard
The consistency ladderLinearizability and serializability are different axes; the session guarantees are what users perceive
Consistent hashing and its alternativesVirtual nodes are for failure redistribution more than balance; and none of it solves hot keys

This chapter is where the book's cross-references converge. The latency page is cited by the funnel, the gateway and the multi-region designs; the consistency ladder is cited by the KV store and the job scheduler; consistent hashing is cited by the metrics pipeline and the rate limiter. That was the chapter index's own claim ("everything else in the book is an application of what is here") and it is now true in the link graph rather than only in the prose.

A deliberate choice in the back-of-envelope page. Its worked example reaches the opposite conclusion from the instinct: 82 GB of index fits one node, so the answer is nine replicas rather than a sharded cluster, and the int8 quantisation decision is what keeps it under the threshold. That inverts the usual order, where you shard first and optimise later, and it is the single most useful habit the chapter can teach: check whether it fits on one node before designing a distributed system.

State after this session: 96 pages, ~314k words, 337 flashcards, 107 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 02 has 6 topics left (USL, benchmarking discipline, Paxos, Raft, time and clocks, CRDTs), all P3 or P4. Chapter 07 has 8 left. After those, the final consolidation passes from CLAUDE.md: book/00-how-to-use.md (three-pass reading method, 12-week mapping, night-before subset) and book/90-recitables.md (the ~40 highest-recall numbers, formulas and one-sentence positions), which are the last items in the process section and are now worth doing given how much material there is to index.

Session 12: the two navigational pages

Not new topics. The two pages CLAUDE.md lists as final passes, brought up to date with what the book has become.

book/00-how-to-use.md gained a "How the book is laid out" section. Its three-pass method, night-before subset and 12-week mapping were already there, and what was missing was any account of the book's shape: three page archetypes (topic, leadership scenario, design transcript), the intended division of labour between topic pages and design pages, and the fact that the drill bank and the recitables sheet are better entry points than the chapter list. At ninety-six pages, "read the chapter you need" stopped being adequate navigation.

output/recitables.md gained two sections (search and ranking, distributed systems) and seventeen one-sentence positions drawn from sessions 5 to 11, and two stale figures in the latency table were corrected: NVMe random read and the sequential-versus-random ratio, both of which pre-dated the numbers now derived in the latency page.

The final cut is deliberately not done yet. CLAUDE.md specifies consolidating the sheet to roughly forty entries "when the queue is empty", and it is not: 234 rows remain. Cutting now would mean cutting again later. What matters in the meantime is that the sheet stays in sync with the material, because it is the night-before layer and a sheet missing everything from the last seven sessions is worse than a long one.

State after this session: 96 pages, ~314k words, 337 flashcards, 107 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes, and the `## Numbers and formulas

  • 99.9% = 40 minutes a month. 99.99% = 4 minutes. One incident.
  • You cannot durably beat the product of your serial dependencies.
  • cycle time = WIP / throughput. Cutting WIP shortens cycle time arithmetically, and it is free.
  • Flow efficiency is 5 to 20 percent. Working faster addresses the 15; queues are the 85.
  • Flake compounds: 0.99^200 = 13% chance of a green run. That is why the E2E count is capped, not the runtime.
  • Kubernetes defaults maxUnavailable to 25%. At 85% CPU on 20 replicas that is 113% per replica during every rollout.
  • The same 100-second stall reports as a 1ms p99 or a 98s p99, depending only on the measurement rig.
  • A team of seven has about four engineers of project capacity, and the way to make it credible is declared-versus-actual on three buckets.
  • Decode is memory-bandwidth-bound. One sequence uses under 1% of a GPU's compute, which is why batching is the difference between a system and a toy.
  • Two pages per 12-hour shift, six people minimum, and an overflow rule agreed before it fires.
  • Your RTO cannot be shorter than your routing layer's failover time. DNS at a 60s TTL drains in 5 to 15 minutes with a tail of hours.

Distributed systems, storage and streaming

  • Exactly-once delivery is impossible; exactly-once effect is what you build, via at-least-once dispatch plus an idempotency key derived from the occurrence, never a fresh UUID per attempt.
  • Choose a consistency model per operation, not per system. Uniqueness and balances need consensus; posts need session guarantees; counters can be CRDTs.
  • Consistent hashing distributes keys, not load. One hot key lives on one node by construction and no vnode count changes that.
  • Access patterns first, schema second. In DynamoDB the key schema is the query plan and you cannot change it later without rewriting the data.
  • A watermark is a heuristic, not a guarantee, which is why allowed lateness and side outputs exist. One idle partition freezes the whole job.

Reliability and overload

  • An SLI is good events over valid events, measured where the user is. Latency is a proportion under a threshold, never a percentile.
  • Once queue delay exceeds the client timeout, goodput is zero while throughput looks fine.
  • Under overload, FIFO gives everyone nothing; LIFO gives full service to as many as capacity allows.
  • Fail open or closed by consequence, not by default. A rate limiter failing closed takes down the API; a permission check failing open leaks data.
  • A PodDisruptionBudget constrains the Eviction API, so it protects against node drains, not against your own rolling update.

Delivery and change

  • The routing unit determines blast radius, not the percentage. A 5% per-request canary over a 12-request session crosses versions 46% of the time.
  • A canary detects fast, frequent, request-scoped, observable regressions. It is structurally blind to slow, rare, emergent, silent, mixed-version and elsewhere.
  • A semantic conflict merges cleanly and breaks main. Neither CI run saw the other's change; that is what a merge queue tests.
  • Turn it off, right-size, modernise, then commit. Committing first locks in the waste.

AI, retrieval and evaluation

  • A reranker cannot fix recall. It reorders what retrieval returned; recall@k is the ceiling.
  • Fine-tuning is for form; retrieval is for facts. Retrieval also wins whenever you need citations or per-user access control.
  • Measure the noise floor before gating on an eval. A gate that fires below its own noise gets overridden reflexively and then catches nothing.
  • Prompt-layer defences against injection are mitigation, not a boundary. Architecture is the defence.

Security, frontend and data

  • HttpOnly bounds blast radius, it does not defend against XSS. The injected script does not need to read the cookie, only to make a request that carries it.
  • Host-allowlist CSP is mostly bypassable. Use a per-response nonce plus strict-dynamic, with object-src 'none' and base-uri 'none'.
  • Keys are a correctness feature, not a performance one. Index keys make a row's identity its position, so filtering slides uncontrolled inputs, focus and animation onto the wrong rows.
  • If the server is the source of truth, it is a cache, not state. Key-based invalidation is correct by construction; manual invalidation is correct only while everyone remembers.

Architecture

  • CQRS's real problem is read-your-own-writes for one user, and the first fix is returning the result from the command.
  • Layers impose one abstraction cost on use cases with different needs. That is the argument for vertical slices, not the file count.

Disaster recovery and cloud

  • No credential required to recover system X may be stored in system X.
  • A replica is not a backup: it applies your mistakes in milliseconds.

Leadership

  • A decision that has sat 48 hours is the lead's failure. Take a recommendation with a default and a deadline, never a question.
  • The earliest sign someone is leaving is that they stopped arguing.
  • A promotion is decided two quarters early, when the scope is assigned.
  • Supply options with costs, not verdicts. "Six weeks" is true and useless; the recommendation with its deciding condition is the valuable sentence.
  • Glue work is essential, invisible and non-promotable, and it accretes on whoever is most conscientious. Rotate it, convert it to artifacts, and say out loud that it will not promote them.

The interview itself

  • Senior is whether you can solve the problem; staff is whether you can pick it, frame it, and get people who don't report to you to solve it with you.
  • "I'd mitigate before I diagnose", said in the first thirty seconds.
  • The alternative was X, I am not choosing it because Y, if Z changed I would revisit. Say this at least twice per design round.` was verified to resolve in the built HTML.

Session 13: the hundredth page

Four topics across chapters 02 and 07, taking the book to 100 topic pages.

PageThe load-bearing idea
RaftThe Figure 8 commit restriction, which is the genuinely subtle rule most summaries omit, plus pre-vote and single-server membership as production necessities
Time: Lamport, vector clocks, TrueTime, HLCFour mechanisms answering different questions; HLC as the default; and that no clock makes last-writer-wins safe
Billion-scale sharding and routingReducing effective fan-out beats per-shard tuning; the cold-start cascade and the one line that prevents it
Learning to rankLambdaRank's gradient-not-loss insight; the feature rules; and that logging plus labels come before any model

Chapter 02 is now 10 pages and chapter 07 is 12, so the foundations chapter and the reader's moat chapter are the two deepest after chapter 15.

A pattern worth recording, now visible across sessions 9 to 13. Every one of these pages has a "the thing most summaries omit" section, and that is where the interview value concentrates: Raft's Figure 8 restriction, HNSW's delete problem, the logQ correction in two-tower training, evaluation-set bias in offline ranking metrics, the group parameter in LambdaMART, and the health check that prevents a cold-start cascade. None of those are obscure; they are all documented in a primary source. What makes them valuable is that they are the second layer, which is exactly where a staff interviewer probes and where a candidate who learned the topic from a summary stops.

State after this session: 100 pages, ~329k words, 358 flashcards, 111 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 02 has 4 topics left (USL, benchmarking discipline, Paxos, CRDTs), chapter 07 has 6. Beyond those, the thinnest chapters relative to their interview weight are 05 (AI/LLM, already the deepest at 9 but with high-value gaps), 03 (storage) and 12 (SRE).

Session 14: the SLO stack

Chapter 12's four P1 topics, which form one coherent argument rather than four separate ones, so they were written as a batch and cross-reference each other heavily.

PageThe load-bearing idea
SLA, SLO and SLIThe SLA must be looser than the SLO; the gap is the warning margin, and equal targets give it up
Composite SLOs and dependency mathUnavailability adds, so the worst dependency dominates and removing it from the critical path beats improving anything
The error budget policyThe budget is arithmetic; the policy is a commitment, and it only works if signed before it is needed
Why you cannot average percentilesA category error, not an approximation, and the fleet percentile deliberately hides the outlier you also need to alert on

Chapter 12 goes from 4 pages to 8.

Why these four belong together. Read in order they build one case: define the SLI precisely, compute the ceiling your dependencies impose (which frequently shows the target was never achievable), agree in advance what happens when the budget is spent, and measure the whole thing with arithmetic that is actually correct. Each of the four fails without the others: a precise SLI with no policy is a report, a policy on an impossible SLO is a permanent freeze, and any of it computed by averaging per-instance percentiles is measuring the wrong number.

The strongest single finding across the four, and the one worth carrying into an interview: in the composite-SLO worked example, making one dependency degradable bought more availability in three days than a quarter of reliability engineering on the other four would have. The highest-value availability work is almost always removing something from the critical path rather than making it more reliable, and the dependency arithmetic is what makes that visible.

State after this session: 104 pages, ~342k words, 379 flashcards, 115 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 13 has four P1 topics that similarly form one argument (automated canary analysis, bake time and minimum detectable effect, shadow traffic, and experimentation design), and chapter 17 has three on multi-region. Chapter 16 has six leadership P1s.

Session 15: progressive delivery, chapter 13's four P1s

Like session 14's SLO stack, these four form one argument and were written as a batch.

PageThe load-bearing idea
Automated canary analysisThe control must be a freshly deployed current version; every decay path starts with an invalid comparison
Bake time and MDEBake time is a statistical parameter, not a convention; the ritual canary is one whose MDE exceeds anything you care about
Shadow trafficSafe on the response path, dangerous on the side-effect path; the seam is a design property
Experimentation designRandomisation unit invalidates rather than degrades; guardrails need inverted error asymmetry

Chapter 13 goes from 5 pages to 9, and it is now the third-deepest chapter.

The through-line across the four, which is worth stating because it is the chapter's actual argument: each of these mechanisms answers a different question and they are routinely confused. A canary asks "is it safe" in minutes on technical metrics. Shadow traffic asks "does it behave the same" over weeks with no user exposure. An experiment asks "is it better" over weeks on business metrics. Every failure mode in the chapter comes from asking one of them the other's question: business metrics in a canary gate (too noisy, so thresholds get loosened), a shadow expected to validate a product decision (no user sees the response), or an experiment used as a safety check (far too slow).

The two most transferable findings. From the canary pages: the decay path is invalid control, false positives, loosened thresholds, real regression passes, and it starts with a comparison that was never valid. From the experimentation page: guardrails control a different error than the primary metric, so they need a looser alpha and a non-inferiority framing, and applying the primary's threshold to them means missing exactly the regressions they exist to catch.

State after this session: 108 pages, ~357k words, 401 flashcards, 119 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 17 (multi-region and DR) has three P1s, chapter 16 (leadership) has six, and chapter 19's spoken-form drill batches have nine. The drill batches are cheap relative to their value, since the material exists in the topic pages and needs converting to spoken form.

Session 16: four spoken-form drill batches

Not new material: conversion of existing topic pages into spoken answers, which is a different artifact and the one the reader actually needs in a room.

BatchDrills
Caching and frontend16, 17, 18, 34, 35, 36
Compute and kernel19 to 23
Storage24 to 28
Security29 to 33

37 of the 66 drills now have a written spoken-form answer, up from 12. The drill map rows gained · [spoken] links, so a reader who cannot answer a drill can go either to the teaching page or straight to the ninety-second version.

Why this is worth doing rather than pointing at the topic page. A topic page is written to be re-read: it can be dense, it can assume the reader will go back a sentence. A spoken answer needs a shape the listener follows in real time, which means leading with the conclusion, keeping to three points, and stopping. Those are different texts, and the source document's own gap register identified the missing spoken forms as its largest deficiency.

Each batch has a practice section tuned to its own failure mode, which is the part worth preserving:

  • Compute and kernel: the failure is a correct but unordered list. "It could be CPU, memory, network, GC" is complete and demonstrates nothing. The test is whether you named what you would check first and why it is first.
  • Storage: the tell is whether you state the access pattern before the schema, and whether you reach for the data model rather than the tuning knob.
  • Security: the discipline is saying what the mechanism does not cover, which almost nobody does unprompted and which is the fastest way to show you understand a boundary rather than a keyword.
  • Caching and frontend: these six share a property, which is that the obvious answer is a real technique that does not solve the stated problem (jittered TTLs, optimising the handler, micro-frontends for a build problem). The practice is rehearsing the dismantling of the naive answer, which is more persuasive than going straight to the right one.

State after this session: 112 pages, ~365k words, 401 flashcards, 124 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: five drill batches remain (context/graph 7-9, SRE/architecture/delivery 43-52, patterns/seasonality 53-60, deployment 61-66, plus AI drills 7-9). Chapter 17 has three P1s and chapter 16 has six.

Session 17: cells, and the two leadership topics candidates lack material for

Three topics, deliberately mixed rather than a single-chapter batch.

PageChapterThe load-bearing idea
Cell-based architecture17Cells and AZ redundancy protect against orthogonal failure classes, and teams that have one believe they have both
Building a story portfolio16Inventory plus an index, not answers to anticipated questions; rehearse numbers, not sentences
The underperformance sequence16Six causes, three of which are the manager's; the no-surprises rule

A checker change this session. underperformance-sequence.md uses the leadership scenario archetype (answer / where this goes wrong / interviewer follow-ups / delivery note / further reading) rather than the topic archetype, so state/check.py's SCENARIO_PAGES set gained an entry. The checker caught the mismatch on the first run, which is the second time it has caught an archetype error that a manual pass would have shipped.

Why these two leadership topics specifically. The story-portfolio page names three coverage gaps that most candidates have (underperformance, changed-my-mind with a specific piece of evidence, and something you chose not to do), and the underperformance page then supplies the material for the first of them. That pairing is deliberate: a preparation page that identifies a gap and does not fill it is only half useful.

The strongest single reframe across the three: in the underperformance sequence, three of the six causes are the manager's failure, and the most common one is unclear expectations, where the person is genuinely surprised anyone is unhappy. Diagnosing before acting is the step candidates skip, and going straight to a performance plan when the cause is an expectation nobody stated is the specific failure the question is testing for.

State after this session: 111 pages, ~374k words, 415 flashcards, 127 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 16 has four P1s left (the AI-era review queue, metrics a lead watches, a PM promising a date, inheriting a low-morale team), chapter 17 has two, and five drill batches remain.

Session 18: the two AI-era leadership topics

Two pages that pair, and drill 38 finally resolves to a teaching page rather than only to a spoken answer.

PageThe load-bearing idea
The metrics a lead watchesDORA's four plus interrupt rate; the AI caveat stated as correlational amplification rather than causation; and never reporting them upward as performance
The AI-era review queueThe bottleneck moved rather than a problem appearing; human review does not scale with generation speed, only automation does

These two are the same argument from opposite ends. The metrics page establishes that throughput and stability must be reported together and that AI adoption is where they diverge; the review-queue page is the concrete case where that divergence shows up first, and its mechanism (the bottleneck moving from writing to reviewing) is why review queue depth belongs on the lead's dashboard alongside DORA.

A precision point worth preserving. Both pages state the DORA AI finding as correlational survey data framed as amplification, not as a causal claim that AI degrades stability. That distinction matters in an interview: overstating it sounds like a position taken from a headline, and understating it misses the real operational consequence, which is that a team reporting deployment frequency alone during a tooling rollout will celebrate a number that is getting worse underneath.

Chapter 16 is now 10 pages, and its scenario/topic split is 6 to 4, which matches the chapter's nature: leadership questions are mostly role-plays.

State after this session: 113 pages, ~380k words, 425 flashcards, 129 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 16 has two P1s left (a PM promising a date, inheriting a low-morale team), chapter 17 has two, and five drill batches remain.

Session 19: chapter 16's last two P1 scenarios

Two leadership role-plays, both scenario-archetype, completing chapter 16's P1 queue.

PageThe load-bearing idea
A PM promises a dateSay nothing in the room; separate the immediate date from the process that produced it; make the process fix a trade rather than a veto
Inheriting a team with low moraleTwo weeks of no changes, announced; five distinct causes needing different responses; fix one thing completely before adding anything

Chapter 16 is now 12 pages, all six P1s done, and its shape is 8 scenarios to 4 topics, which is right for a chapter where most questions are role-plays.

A property worth recording across all twelve. Every leadership page in this chapter follows the same skeleton, and it is worth naming because it is what makes them rehearsable: first move, information I would gather, line I would not cross. Announcing that structure at the start of an answer buys the benefit of the doubt for the next ninety seconds and stops the rambling that is the actual failure mode in leadership questions. The individual content differs; the shape does not.

And the recurring content pattern: in most of these scenarios, part of the cause is a management failure, and volunteering it is the single strongest signal available. The underperformance page (three of six causes are the manager's), the promotion page ("have they had the opportunity"), the toxic reviewer page, and now the low-morale page all turn on the same move. Candidates who run these purely as conversations about the other person are scored as having missed it, and that is consistent enough across the chapter to be worth stating as a rule rather than as a per-page observation.

State after this session: 115 pages, ~386k words, 435 flashcards, 131 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 17 has two P1s (active-active conflict resolution, the global-versus-regional write path), and five drill batches remain. After those, the P1 queue is nearly exhausted and the remaining work is P2 and below.

Session 20: the multi-region write path, and the largest drill batch

Two pages, and the book crosses 390,000 words.

PageThe load-bearing idea
The multi-region write pathFour genuinely different shapes, not points on a dial; the data audit is the design; home-region ownership is the under-used answer
Drills 43 to 52, spokenThe largest batch, ten drills, where the good answer contains arithmetic and the weak one contains a practice

Spoken-form coverage is now 47 of 66 drills.

A deliberate boundary in the write-path page. It does not repeat the conflict-resolution mechanics from the multi-region KV design; it links to them and spends its space on the decision instead. That division is the one recorded in session 10 and it is holding: topic pages teach the mechanism, design pages assemble it under a budget, and a page that does both is too long and duplicates.

The strongest transferable idea from the write-path page: most teams asking for active-active want low read latency globally and low write latency locally, and do not actually need the same key writable in several regions. Home-region ownership with global read replicas delivers exactly that with no conflict resolution at all, and it should be proposed before the harder thing.

And from the SRE drill batch, a note about the whole chapter that is worth recording: these ten are where a senior answer and a staff answer diverge most visibly. A senior answer describes the practice correctly; a staff answer says what it costs, what it does not cover, and when not to use it. Every one of the ten has an "and I would not do this when" available, and including it is the single most reliable upgrade to any of these answers.

State after this session: 118 pages, ~392k words, 441 flashcards, 133 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: one P1 remains in chapter 17 (active-active conflict resolution, which needs care not to duplicate the KV design page), plus P1s in chapters 01, 03, 04, 05, 06 and 18, and four drill batches.

Session 21: the two communication meta-skills

Two pages in chapter 1, and they are the most cross-cutting in the book: they govern how every other answer is delivered rather than supplying content for any one of them.

PageThe load-bearing idea
Executive communicationBLUF is reordering, not brevity; altitude is two dials (depth and scope); bounded uncertainty needs all four elements
Handling what you do not knowBluffing is retroactive and the most expensive mistake available; an unlabelled guess is a bluff regardless of intent

Drill 56 now resolves to a dedicated page rather than to a follow-up on the design-interview page.

Why these two belong together. They are the same skill applied to two situations: saying precisely how confident you are. Executive communication is that skill when you do know (confidence stated, alternative named, timeline given); handling what you do not know is the same skill at the boundary (admission fast, reasoning labelled, verification specific). The failure in both directions is identical: false confidence and unbounded hedging are both unusable, and the fix in both is calibration expressed out loud.

The delivery note in both pages is unusual and deliberate: demonstrate the technique rather than describe it. These are the two topics where an interviewer is scoring the behaviour continuously rather than at the moment the question is asked, so the pages tell the reader to lead every answer with the conclusion, signpost before giving three things, and use the full confidence range throughout so that "I'm confident about this one" carries weight when it arrives.

The book crosses 399,000 words and chapter 1 is now 5 pages.

State after this session: 120 pages, ~399k words, 451 flashcards, 135 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: P1s remain in chapters 01 (the architecture deep dive), 03, 04, 05, 06, 17 and 18, plus four drill batches.

Session 22: reranking, compaction, agent failure modes

Three P1 topics across chapters 05 and 06, and the book crosses 410,000 words.

PageThe load-bearing idea
Cross-encoder and LLM rerankingThe two differ by an order of magnitude in latency, so it is a budget decision; distillation dissolves the quality-versus-latency binary
CompactionA bigger window does not remove the need (cost linear, prefill linear, lost-in-the-middle); schema over summary; addressable rather than lost
Agent failure modesMost agent failures are not model failures, and a better model makes the cost ones worse

Drills 7 and 9 now link to the compaction page alongside the context-budget page.

A decision worth recording (D15). Chapter 05's remaining P1, "regression gates in CI", is substantially covered by the evaluation pipeline design, which is a full transcript of exactly that system: noise floor, paired comparison, tiered gates, segment-level blocking. Rather than write a topic page that restates it, the chapter index will point at the design page. A topic page whose content is a design page's content is duplication, and the division recorded in session 10 says the design page is the right home when the material is a system rather than a mechanism.

The strongest reframe in this batch, from the agent failure modes page: in the worked incident (a research agent costing $4,100 against an expected $30) every single cause was tool design or budget design, and a better model would have made that run more expensive rather than cheaper, because it would have persisted longer. That is the sentence that changes what a team works on, and it generalises: loops come from tools with no progress signal, cost comes from context growth nobody budgeted, and injection is bounded by authorisation rather than by detection.

State after this session: 123 pages, ~410k words, 470 flashcards, 138 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: P1s remain in chapters 01 (architecture deep dive), 03 (2), 04 (2), 17 (1) and 18 (1), plus four drill batches.

Session 23: the DDL half, and the distributed-transaction question

Two P1 topics, both of which are the other half of a page written earlier.

PageIts counterpartThe division
Online schema changeExpand and contractThis page is the DDL: lock levels, CONCURRENTLY, gh-ost, the backfill. That page is the application sequencing. You need both, and each page says so
Sagas vs two-phase commitIdempotency and exactly-onceThis page is the coordination pattern; that one is the primitive every step depends on

The strongest single idea in this batch, from the schema-change page: the danger in a migration is not the operation's duration, it is the lock queue. A 40-minute index build produced 22 minutes of total unavailability before it started, because it queued behind a long-running analytics query and every subsequent query queued behind it. One line, SET lock_timeout = '2s', would have turned that into a harmless failed migration. That is the highest ratio of protection to effort anywhere in the storage chapter.

And from the saga page, the correction most retellings need: sagas give up isolation as well as atomicity. Another saga can read a state that is later compensated away, which is a dirty read across services, and the countermeasures (semantic locks, commutative updates, reordering) are in Garcia-Molina and Salem's 1987 paper and are routinely dropped. Naming that is a strong signal because almost every modern description mentions only atomicity.

A pattern now visible across several sessions. Six pages in the book are explicitly the other half of another page and say so in their opening: schema change / expand-contract, write path / KV design, funnel / recsys serving, lead metrics / AI review queue, compaction / context budget, sagas / idempotency. That pairing is worth continuing deliberately, because it keeps each page at a workable length and it makes the cross-reference load-bearing rather than decorative.

State after this session: 125 pages, ~418k words, 483 flashcards, 140 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: P1s remain in chapters 01 (architecture deep dive), 03 (choosing a database), 04 (the API decision matrix), 17 (active-active conflict resolution) and 18 (the CTO conversation), plus four drill batches.

Session 24: three decision-walkthrough topics

Three P1s, and they share a shape worth naming: each replaces a comparison table with a sequence of questions whose answers eliminate options.

PageThe sequence
The architecture deep diveThree zoom levels, prepared separately, because candidates prepare one and are asked for three
Choosing a databaseAccess patterns, multi-key transactions, size, consistency, shape, operations, and what you already run
The API decision matrixWho is the consumer, can you change the client, interaction shape, read-shape variability, does caching matter

Why the sequence beats the table. A comparison table invites feature matching, and every option looks good in its own column. A sequence eliminates: in the database walkthrough, the "we need Cassandra for scale" proposal dies on question two (multi-key invariants) before size is even discussed, and then the size figure, 340 GB, dissolves the scale argument entirely once it is quantified rather than asserted. That is a much better conversation than arguing about Cassandra.

A finding from the database page worth carrying: one of the four problems in its worked example was not a database problem at all. Dashboard aggregations were locking rows the transactional path needed, which presented as "Postgres can't handle our analytics" and was fixed by a read replica in a day. Checking whether it is a database problem at all belongs before any store is evaluated.

And from the API page, the axis correction: the choice is decided by the consumer relationship rather than by performance. Whether you know who the clients are decides REST versus GraphQL publicly; whether you can ship a client quickly decides whether GraphQL's complexity pays. A mobile app in the field makes the API effectively append-only for months, which constrains more than any throughput consideration.

The book crosses 428,000 words, and chapter 1 is now 6 pages.

State after this session: 128 pages, ~429k words, 498 flashcards, 143 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: two P1s remain (active-active conflict resolution in 17, the CTO conversation in 18), plus four drill batches. After those the P1 queue is exhausted and the remainder is P2 and below.

Session 25: the last two P1 topics

Two pages, and after this the only P1 rows remaining are three drill batches plus the one deliberately deferred by D15.

PageThe load-bearing idea
Active-active conflict resolutionFour mechanisms chosen per data type; HLC fixes the wrong-winner problem and not the lost-write problem; a merge function cannot express "only if"
Ninety seconds with the CTOA veto round, asymmetrically; the failure is depth at the wrong altitude; the consistency check across the loop is the best free signal in the process

Chapter 17 is now complete on P1s (4 pages: cell-based architecture, the write path, conflict resolution, plus the existing RTO/RPO page), and it reads as a sequence: where do writes happen, what happens when they conflict, how do you bound the blast radius, and what do you promise.

The conflict-resolution page's most transferable idea is the CRDT boundary stated as a rule: a merge function can express "combine these" and cannot express "only if". Inventory is the instructive case, because a PN-Counter tracks stock perfectly and will happily go negative, and overselling is the CRDT's correct behaviour rather than a bug. That reframing stops the search for a better CRDT and points at single-writer, which is the actual answer.

And its most transferable practice: log the discarded write with both values. It costs almost nothing and it is the only way to turn "is last-writer-wins acceptable for this data" from an argument into a measurement. In the worked example it showed a 0.02 percent conflict rate concentrated in one behaviour, which confirmed the choice with evidence rather than intuition.

State after this session: 130 pages, ~436k words, 510 flashcards, 145 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: the three remaining P1 drill batches (context/graph 7-9, patterns/seasonality 53-60, deployment 61-66), which will exhaust the P1 queue.

Session 26: the P1 queue is exhausted

Three drill batches, and two milestones.

BatchDrills
Context and graph7 to 9
Patterns, seasonality and the interview53 to 60
Deployment and progressive delivery61 to 66

Milestone 1: all 66 drills now have a written spoken-form answer, in ten batches, verified programmatically rather than by eye (every row in the drill map carries a spoken link). The map's introduction was rewritten to say so and to state the division: the spoken answer is what you would say in a room, the teaching page is what is underneath it.

Milestone 2: the P1 queue is exhausted. One P1 row remains open and it is the one deliberately deferred by D15: "regression gates in CI", which the evaluation pipeline design covers in full. The row stays open rather than being marked done, because nothing new was written for it.

What each batch's practice section teaches, which is the part worth preserving:

  • Context and graph: attach a number to every design choice, because these are the newest questions in the bank and the ones where a fashionable answer is most tempting. Extraction cost is what decides whether a knowledge graph happens.
  • Deployment: four of the six begin by correcting a premise, and the correction is the answer. "The canary shows the feature is winning" and "roll it back" are both wrong in ways that matter, and saying so gently with a reason and an alternative is the skill.
  • Patterns and the interview: each of the eight has a specific committed position available, and the failure mode is surveying considerations instead of taking one. The practice is writing down the single sentence you would commit to for each.

An observation from the last batch worth recording: three of its eight drills are about the interview process itself, and they are scored exactly like the technical ones. A candidate who has thought carefully about how to evaluate an employer is demonstrating the same judgement they would apply to a vendor, an architecture or a hire.

State after this session: 133 pages, ~443k words, 520 flashcards, 148 of 341 queue rows closed.

All 19 site targets build green under mdBook 0.4.40; state/check.py passes.

Next: the remaining 193 rows are all P2 and below. The highest-value clusters are chapter 07's six remaining search topics, chapter 02's four foundations topics, and chapter 05's AI/LLM depth. The recitables consolidation to ~40 entries remains deferred until the queue is empty.

Session 27: the queue itself had gaps

A coverage audit, not a writing session first. The user pointed out that cloud patterns and DDD appeared to be missing. They were right in one case and half-right in the other, and the audit that checked found a third gap nobody had named.

What the audit did: a keyword sweep across book/ and state/QUEUE.md together, asking of each major topic area whether it had either a page or a row. Three findings, recorded as D16:

  1. Resilience patterns were absent from the queue entirely. Circuit breaker, bulkhead, timeout budgets, retry with jitter, load shedding. "Circuit breaker" appeared in zero book files by name despite being standard staff-interview material.
  2. Cloud architecture and cost had no rows at all. Managed versus self-hosted, cost levers, Well-Architected, IaC, multi-cloud, commitments, landing zones, egress. A whole chapter's worth.
  3. DDD was present but unfindable. Three rows existed and none used the words "domain-driven" or "DDD", so a search returned nothing and it read as missing.

The root cause is worth recording: the queue was derived from the source document's section list, so it inherited the source's blind spots rather than correcting them. "The queue is empty" is only meaningful if the queue was right, and nothing in the process so far had checked that.

Done this session: new chapter 20 (8 rows), 3 rows added to chapter 14, 6 rows renamed or re-prioritised, and five pages written:

PageChapter
Resilience patterns: circuit breaker, bulkhead, timeout, retry14
DDD strategic design: bounded contexts, ubiquitous language, ACL14
DDD tactical design: aggregates as consistency boundaries14
Managed vs self-hosted20 (new)
Cloud cost architecture: the levers in order of size20 (new)

A note for whoever runs the next session: books/what-goes-into-you/ is an untracked work-in-progress book with chapters but no SUMMARY.md, so it fails to build. It is untracked, so build.sh on CI does not see it and the deploy is unaffected. If it is ever committed without a SUMMARY.md it will take down the entire deploy, because build.sh uses set -e. The local build loop in this session was changed to iterate git ls-files '*/book.toml' rather than a glob, so it checks exactly what CI will build.

State after this session: 135 pages, ~461k words, 540 flashcards, 153 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: the coverage audit should be repeated once more before declaring the queue complete, because it found three gaps on its first run. Then the remaining 199 rows, which are now genuinely the whole map rather than the source document's view of it.

Session 28: search internals and the scalability law

Four topics, and the book crosses 474,000 words.

PageThe load-bearing idea
The inverted index, mechanicallyThree parts that fail differently; block-max WAND explains why exact hit counts got expensive
Analyzers per languageAnalysis is a ceiling on ranking, not a setting; index-time and query-time must agree
IVF-PQ vs HNSW vs DiskANN vs ScaNNMemory decides it, and reranking is what makes IVF-PQ competitive rather than a compromise
The Universal Scalability LawAmdahl predicts a plateau, USL predicts a peak and decline, and beta dominates the ceiling

Chapter 07 is now 15 pages and complete except for three rows (judgment collection, cold start and bandits, embedding freshness). Chapter 02 is 11.

check.py caught an em dash in the USL page on the first run, which is the third time it has caught something a manual pass missed. That checker has now paid for itself several times over, and the pattern in what it catches is consistent: dashes and archetype mismatches slip through when a page is written quickly, and neither is visible when re-reading your own prose.

Two ideas from this batch that connect to earlier pages and are worth noting as cross-chapter through-lines:

  1. The inverted index page explains a thing users complain about. "Why does Elasticsearch say 10,000+ hits" has a real answer: exact counting defeats block-max WAND, which is the optimisation that makes top-k retrieval fast. That is a trade rather than a limitation, and it pairs with the Lucene segments page's point that the defaults are general-purpose rather than wrong.

  2. The USL page is the theoretical backing for advice given in several earlier pages. "Never size above 70 percent utilisation" (back-of-envelope), "more shards makes the tail worse" (billion-scale sharding) and "adding reviewers is a staffing answer to a systems problem" (AI review queue) are all instances of the same curve. Having the model named makes those pieces of advice derivable rather than remembered.

State after this session: 139 pages, ~475k words, 558 flashcards, 157 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 07's last three rows, chapter 02's last three (benchmarking discipline, Paxos, and the CRDT row which may be covered by the conflict-resolution page), then the large chapters: 04 (16 rows), 08 (15), 09 (15), 10 (14), 14 (13 after this batch), 06 (13), 12 (13), 18 (15).

Session 29: closing chapters 02 and 07

Six topics, and two chapters go to zero remaining rows.

PageThe load-bearing idea
Benchmarking disciplineCoordinated omission deletes the measurements you care about; profile before you benchmark, because Amdahl caps the payoff
PaxosThe Phase 2a constraint IS the safety argument, and it rests entirely on quorum intersection
CRDTsThey converge and still break your business rule; invariant confluence says which invariants survive a merge
Judgment collectionUnjudged scores zero, so a single-ranker pool structurally punishes any challenger
Cold start and banditsThe prior is the cold-start solution; the bandit is just the allocation policy
Embedding freshnessTwo clocks, not one: documents at seconds, models at quarters, with different mechanisms

Chapter 02 (distributed systems) is complete at 15 pages. Chapter 07 (search and ranking) is complete at 18. Those are the two chapters closest to the reader's stated background, so finishing them first was deliberate.

Three cross-chapter through-lines got closed this session, which is the payoff of having written the neighbouring pages first:

  1. Selection bias now has three faces in three chapters and they are the same thing. Popularity bias is the symptom, judgment collection is where it corrupts your measurement, and cold start is where exploration fixes it. A reader who lands on any one of the three gets pointed at the other two.

  2. Consensus now has both halves. Raft was written first as the implementable one; Paxos is now there as the vocabulary for reading Spanner and Chubby papers, and CRDTs is the "what if you refuse to coordinate at all" answer with its own hard limit. The three pages state the same trade from three positions.

  3. Measurement discipline is now a chapter-02 topic rather than an SRE one. Benchmarking sits next to percentiles and the USL page, and the coordinated-omission point is the same failure that makes a p99 dashboard lie.

State after this session: 145 pages, ~496k words, 583 flashcards, 163 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: the large remaining chapters. Chapter 04 (16 rows: Kafka delivery semantics, consumer groups, Flink, CDC, reactive streams, GraphQL federation, protobuf), chapter 08 (15), chapter 09 (15), chapter 18 (15), chapter 10 (14), chapter 14 (13), chapter 06 (13), chapter 12 (13). Chapter 04's rows are heavily P2 and cluster naturally into three batches (Kafka durability, stream processing, API protocols), so that is the next sequence.

Session 30: the Kafka durability and operations cluster

Five topics, all of chapter 04's Kafka rows, written as one batch because they are five faces of the same question: what guarantee do you actually have, and who has to know about it.

PageThe load-bearing idea
ISR and durabilityacks=all waits for the CURRENT ISR, which can be one replica, so the two settings only work as a pair
Log compactionA table shipped as a log; the price is a frozen partition count and tombstone retention as a correctness parameter
Consumer rebalancingmax.poll.interval.ms is the timeout that fires, and a rolling restart costs one stop-the-world rebalance per pod
Consumer lag and autoscalingCPU-based autoscaling inverts on an I/O-bound consumer, scaling down exactly when lag grows
Schema Registry compatibilityThe compatibility mode is a policy about who deploys first, not a serialisation setting

Chapter 04 is now 13 pages with 11 rows remaining (Flink state, the stream processor comparison, CDC, DLQs, reactive streams, GraphQL federation, protobuf, deadline propagation).

The through-line that made this a single batch rather than five pages: every one of these five is a case where the setting is owned by one team and the consequence lands on another. acks is producer code and min.insync.replicas is topic config. Compaction's partition count is frozen by whoever created the topic, forever. A rolling restart of consumers pauses every other consumer in the group. Autoscaling responds to the producer's rate. And the compatibility mode decides whose deploy must go first. Writing them together let each page point at that shared shape instead of describing its own config surface in isolation, and it is the reason the misconfigurations survive: nobody can see the other half of their own guarantee at runtime without going to look for it.

Two smaller notes worth keeping:

  • The checker caught a forward link to cdc-and-dual-write.md, a page whose queue row is still open. Changed to plain prose rather than leaving a dangling reference or writing a stub. That is the third distinct class of thing check.py has caught (dashes, archetype mismatch, now unresolved links to unwritten pages).
  • The consumer-rebalancing page and the lag page cross-reference each other deliberately: rebalance cost is what makes aggressive scale-down dangerous, so the advice "fix rebalancing before enabling autoscaling" only makes sense with both.

State after this session: 150 pages, ~514k words, 605 flashcards, 168 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 04's stream-processing rows (Flink state backends and checkpointing, the Kafka Streams / Flink / Spark comparison, CDC and the dual-write problem, DLQs and retry topics), then its API rows (reactive streams backpressure, schedulers, blocking the event loop, federation, protobuf, deadline propagation).

Session 31: stream processing, and the dual-write problem

Four topics. Chapter 04's stream-processing rows are done; the remaining seven are all API rows (reactive, GraphQL, protobuf, deadlines).

PageThe load-bearing idea
Flink state and checkpointsFull checkpointing caps state size independently of whether the job can process the data; recovery is not incremental even when checkpointing is
Kafka Streams vs Flink vs SparkLibrary versus cluster decides more real cases than any feature comparison
CDC and the dual-write problemYou cannot make two writes atomic, so have one write; the outbox puts the event in the same transaction
Dead letter queuesThree immediate retries span 200ms and every real outage lasts minutes

Two results in this batch came out the opposite way from how the pattern is usually sold, and both are worth keeping because they are the kind of thing an interviewer probes for:

  1. The RocksDB migration did not cost throughput. The standard argument against RocksDB is per-access serialisation, roughly 10x slower than heap. Measured throughput change: under 1 percent. The job was never CPU-bound on state access; it was bound by GC pauses and checkpoint upload, both of which RocksDB fixes. The theoretical cost is real and was irrelevant to the actual constraint.

  2. The outbox pattern made order placement faster, by 38ms at p99, because it removed a synchronous Kafka send with a 2-second timeout from inside a database transaction. The pattern is normally presented as correctness bought with latency.

The three chapter-04 batches now form one arc, which was not planned and is worth recording because it changed how the last two pages were written. Sessions 30 and 31 cover: what guarantee you have (ISR), what the topic means (compaction), how the group behaves (rebalancing), how you scale it (lag), what the contract is (schema registry), where the state lives (Flink checkpoints), which engine to run (comparison), how the event gets published at all (CDC), and what happens when one fails (DLQ). Read in SUMMARY order that is a full operational lifecycle, so the CDC and DLQ pages were written to close it rather than to stand alone.

A note on forward links. check.py caught a second one this batch, to an unwritten 03-databases/lsm-vs-btree.md. Both times the right fix was plain prose rather than a stub page. Worth stating as a rule: when a page wants to link somewhere unwritten, drop the link and keep the sentence. A stub would satisfy the checker and fail the reader.

State after this session: 154 pages, ~529k words, 626 flashcards, 172 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 04's API rows (Reactive Streams and backpressure, publishOn vs subscribeOn, blocking the event loop, Apollo Federation, GraphQL caching and limits, protobuf wire format, deadline propagation), which closes the chapter. Then chapter 03 (databases, 10 rows) is the natural follow-on since several pages now want to link to it.

Session 32: the reactive cluster, and the queue reaches halfway

Four topics. The queue is at 176 done and 176 remaining: exactly halfway, at session 32.

PageThe load-bearing idea
Reactive Streams and backpressurerequest(n) is the whole specification; reactive types do not imply backpressure
publishOn vs subscribeOnOne affects the source and ignores position; the other affects downstream and is position
Never block the event loopFlat throughput, linear latency, low CPU, and Little's Law names the event-loop count in one line
Deadline propagationA timeout is per hop; only a deadline bounds the tree

Little's Law appeared in three of these four pages, independently, and that is worth recording because it changed how the batch was written. The blocked-event-loop page uses it to find the concurrency ceiling (44 rps x 0.23s = 10 busy servers = 8 event loops). The scheduler page uses it to size boundedElastic (400 rps x 0.18s = 72 threads). The deadline page uses it implicitly in the budget allocation. Rather than repeat the derivation, each page states the arithmetic and links to Little's Law and queueing. The single most reusable diagnostic in the whole reference is one multiplication, and by session 32 there are enough pages leaning on it to say that with confidence.

Chapter 04 now has three rows left, all GraphQL and protobuf (federation, caching and query limits, protobuf wire format). It has grown from 8 pages to 21 and is now the largest chapter in the book, which was not planned. It absorbed the Kafka operational cluster, the stream-processing engines, and now the reactive stack, and those genuinely belong together: the chapter is "things that move data between services and what breaks."

One deliberate structural choice this batch. The blocked-event-loop page and the scheduler page overlap substantially, and rather than merge them they were written as a diagnosis page and a mechanism page: one answers "why is my service at 42 rps," the other answers "which scheduler and how big." Each opens by naming the other. The alternative, one long page, would have been worse for a random-access reference, where a reader arrives with one of those two questions and not both.

State after this session: 158 pages, ~543k words, 648 flashcards, 176 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 04's last three rows (Apollo Federation and DGS, GraphQL caching and complexity limits, protobuf wire format), which closes the largest chapter. Then chapter 03 (databases, 10 rows), which several pages now want to link to.

Session 33: chapter 04 closes at 24 pages

Four topics. Chapter 04 is complete, and the first storage page lands.

PageThe load-bearing idea
Apollo Federation v2 and DGSAn organisational solution with a technical cost; the router's batching hides the N+1 inside a subgraph
GraphQL caching and limitsPersisted queries solve caching and cost bounding with one mechanism
Protobuf wire formatOne line of encoding explains every compatibility rule
LSM trees vs B-treesThree amplifications, and you cannot minimise all three

Chapter 04 finished at 24 pages, the largest in the book, having started at 8. It absorbed the Kafka operational cluster (sessions 30), stream processing and CDC (31), the reactive stack (32) and the API layer (33). Read in SUMMARY order it is now a full lifecycle: what guarantee you have, what the topic means, how the group behaves, how you scale it, what the contract is, where state lives, which engine to run, how the event gets published, what happens when one fails, how backpressure propagates, which scheduler, what not to block, how the deadline bounds the tree, how the schema federates, how it caches, and how the bytes are encoded.

Two pages in this batch derive their rules rather than listing them, and that was deliberate after noticing how much stronger the USL and Little's Law pages read for the same reason:

  • The protobuf page opens with key = (field_number << 3) | wire_type and derives every compatibility rule from it. Names are not on the wire, so renaming is free. Wire type gives length, so unknown fields are skippable, so adding is safe. The number is the identity, so reuse reinterprets old bytes silently. Three rules from one line of encoding, and a reader who understands the line does not need to memorise the table.
  • The LSM page frames the choice as a three-way budget (the RUM conjecture) rather than "writes versus reads," which makes the compaction-strategy comparison a set of points on one surface instead of a list of options.

The forward-link rule held for a third time. The LSM page wanted to link to compaction-strategies.md and rocksdb-tuning.md, both still open queue rows. Dropped the links, kept the sentences, pointed at "later in this chapter" generically. Those two rows are next, so the links will be restored when they exist rather than stubbed now.

State after this session: 162 pages, ~558k words, 670 flashcards, 180 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 03 (storage), which has 9 rows left and now has an anchor page. The natural sequence is the RocksDB and compaction pair (which two pages already want to link to), then the Cassandra cluster (data modelling, tunable consistency), then the Postgres cluster (MVCC and autovacuum, query plans, PgBouncer), then DynamoDB indexes and Iceberg.

Session 34: the storage engine cluster

Four topics, all of them the machinery underneath the LSM page from last session.

PageThe load-bearing idea
Compaction strategiesA per-table decision, and the default is right for exactly one of three shapes
RocksDB tuningA write stall is deliberate refusal, indistinguishable from a hang without one metric
Cassandra data modellingPartition size is a schema property, not a tuning parameter
Tunable consistency and repairRepair time grows with data, gc_grace_seconds does not, so clusters cross silently

The two forward links from session 33 are now restored. The LSM page's references to compaction-strategies.md and rocksdb-tuning.md were dropped last session under the "drop the link, keep the sentence" rule, and both pages now exist, so the links went back in. That is the rule working as intended over two sessions rather than a stub sitting in the tree.

Three of the four pages share a failure shape, and naming it changed how they were written. Each describes a system that degrades gradually, never alerts, and is only diagnosable if you were watching a number nobody exposes:

  • STCS space amplification: disk creeps up until a node cannot run its own largest compaction, at which point it cannot recover without the space it does not have. It presents as "we need more disk."
  • RocksDB write stalls: the engine deliberately stops accepting writes, and from outside the process that is indistinguishable from a hang. One team spent two weeks on Kafka configuration for a problem that rocksdb.is-write-stopped answers in one boolean.
  • Cassandra repair versus gc_grace_seconds: repair duration grows with the dataset, gc_grace_seconds is a fixed constant, so a cluster crosses from safe to producing zombie rows purely by growing. Two individually reasonable numbers whose relationship is the bug, which is a recognisable class and the reason the alert in that page is on the ratio rather than either number.

That framing is worth carrying into other chapters: the interesting operational failures are usually invariants between two numbers, not thresholds on one.

The Cassandra data-modelling page and the compaction page turned out to be halves of one answer. The logistics worked example dropped disk from 28 TB to 9 TB, and the schema change alone did not do that: bucketing the partitions made TWCS possible, and TWCS is what made TTL expiry actually reclaim space instead of being permanently backlogged behind size-tiered merges of huge partitions. Neither page is complete without the other, and each says so.

State after this session: 166 pages, ~574k words, 693 flashcards, 184 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 03 has 5 rows left, all Postgres and DynamoDB and Iceberg (MVCC and autovacuum, reading a query plan, PgBouncer, GSIs vs LSIs, Iceberg lifecycle). The Postgres trio is the natural next batch, and it gives the book a B-tree-side counterpart to this session's LSM-side cluster.

Session 35: chapter 03 closes

Five topics, and the storage chapter is complete at 14 pages.

PageThe load-bearing idea
Postgres MVCC and autovacuumBloat is an xmin horizon problem, not a vacuum problem
Reading a query planRead the row estimates, not the times; fix the estimate, not the plan
PgBouncer poolingPooling allocates capacity, it does not create it
DynamoDB indexesA throttled GSI throttles the base table
Iceberg lifecycleFour maintenance procedures, and nothing runs them for you

The "invariant between two numbers" pattern named in session 34 held for all five of these, which is now strong enough to treat as a house lens rather than an observation:

  • Postgres: the xmin horizon versus dead-tuple accumulation. Autovacuum runs constantly, reclaims nothing, and neither number alone is wrong.
  • Query plans: estimated rows versus actual rows. The plan is not wrong, the input is.
  • PgBouncer: transaction hold time times throughput versus pool size. A queue means the first exceeded the second, and raising the pool addresses the wrong side.
  • DynamoDB: per-partition consumed capacity versus the 1,000 WCU ceiling. Table-level provisioned capacity can be 30x what is consumed while writes throttle.
  • Iceberg: commit interval times partitions-per-commit versus target file size. Freshness and file count are literally the same knob.

In every one, the metric a team naturally watches (autovacuum activity, query duration, pool size, provisioned capacity, ingestion lag) is on the wrong side of the invariant.

Chapter 03 now pairs with chapter 04 structurally. Chapter 04 is "things that move data between services"; chapter 03 is "things that store it," and both are organised so the LSM side (compaction, RocksDB, Cassandra) and the B-tree side (MVCC, query plans, pooling) can be read against each other. The LSM vs B-trees page is the hinge, and the two clusters either side of it now exist.

A note on the DynamoDB and Cassandra pages. They independently arrived at the same advice from different mechanics: model the queries first, because the physical layout is fixed at design time and the escape hatch (ALLOW FILTERING, Scan) works in development and fails in production. Each page says so and points at the other. That convergence is worth a reader noticing, because it is the actual lesson of both rather than a property of either database.

State after this session: 171 pages, ~593k words, 722 flashcards, 189 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 05 (AI, GenAI and LLM systems, 21 rows) is the largest remaining cluster and closest to the reader's stated background. The transformer and inference trio (shapes, RoPE/ALiBi, tokenisation) is the natural opening batch.

Session 36: chapter 05 opens with the model-internals trio

Three topics. Chapter 05 (AI, GenAI and LLM systems) had been all serving and RAG; this adds the layer underneath.

PageThe load-bearing idea
The transformer in tensor shapesCapacity questions about LLM serving are arithmetic on two shapes
RoPE and ALiBiRotation gives relative position exactly, which is why extension works by rescaling
Tokenisation and BPEToken count is a per-language property, and pricing inherits it

These three were written as a batch because they answer the same class of question from different angles: what does this cost and why. The transformer page gives the deployment sizing (KV cache per request determines concurrency, and GQA versus MHA is 4x the fleet). The RoPE page gives the context-length cost (linear in KV cache, and quality is not uniform across the window). The tokenisation page gives the per-market cost (the same product is 7x more expensive per unit of content in Thai than in English).

Two of the three end with the same conclusion from independent starting points, which was not planned and is worth recording:

  • The RoPE page's worked example finds that retrieval into a 4k window beats feeding a 32k document: 12 points more accurate, 8x faster, 9x cheaper.
  • The transformer page's sizing arithmetic finds that supporting 32k context instead of 8k quadruples the GPU fleet at fixed concurrency.

Long context is expensive on both axes and worse on quality, and two pages that set out to explain mechanisms both arrive there. Each now points at the other and at chunking.

The "invariant between two numbers" lens applied again, in a new domain: KV cache per request versus available GPU memory is the concurrency ceiling, and the metric teams watch (GPU utilisation) is on neither side of it. A GPU at 40 percent utilisation can be completely full of KV cache and unable to admit another request.

State after this session: 174 pages, ~603k words, 742 flashcards, 192 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 05's remaining five rows (FlashAttention and inference optimisation, the fine-tuning ladder with LoRA, sampling strategies, structured output and constrained decoding, classical ML). The regression-gates row (D15) stays deferred pending the eval-pipeline design page.

Session 37: chapter 05 closes (except the deferred row)

Five topics. Chapter 05 is at 19 pages with only the regression-gates row (D15) open, and that stays deferred pending the eval-pipeline design page.

PageThe load-bearing idea
Inference optimisationCategorise by bottleneck, not by technique; two of the four are free
The fine-tuning ladderRAG for knowledge, fine-tuning for behaviour, and run both to diagnose which you have
Sampling strategiesThree production bugs, all sampling parameters, all presenting as model quality
Structured outputJSON mode guarantees syntax, not schema, and field order is a quality lever
Classical ML you still needAn offline metric that does not predict production is not a measurement

Two of these pages ended up being about the same thing from opposite directions, which was not planned:

  • The structured-output page's worked example finds that constraining takes schema validity to 100 percent and costs 4.8 points of field accuracy, and that a team measuring only "percentage that parsed" ships the regression as a win.
  • The classical-ML page's worked example finds that removing leakage takes offline AUC from 0.94 to 0.74 and production from 0.61 to 0.76, so the headline metric falls twenty points while the system improves.

In both cases the metric being watched and the outcome being sought point in opposite directions, and in both cases the fix is to measure a second thing. That is a sharper version of the "invariant between two numbers" lens from sessions 34 and 35: sometimes there is no invariant, just a metric that is measuring the wrong half of the goal.

The sampling page turned out to be the highest-leverage-per-word page in the chapter. Three unrelated production bugs (extraction errors, SQL parse failures, insufficiently diverse copy) all traced to one shared client default, all presented as model quality problems, and all were fixed with a parameter change and no model or prompt change. The organisational fix (making the sampling profile a named, reviewed part of each task definition rather than a client default) matters as much as the parameters.

Chapter 05 now reads as a stack: tokenisation and shapes at the bottom, then position and inference optimisation, then the adaptation ladder, then sampling and output constraints at the surface, then RAG and evaluation and cost as the applied layer. That ordering was not designed, it emerged from filling the queue, and the SUMMARY was adjusted to reflect it.

State after this session: 179 pages, ~621k words, 768 flashcards, 197 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 06 (context engineering and agents, 17 rows) follows naturally from chapter 05 and is the next largest cluster.

Session 38: chapter 06 opens, and the discipline pages

Four pages covering five queue rows (the context-engineering page absorbed both the "vs prompt engineering" and "six-stage pipeline" rows, since the pipeline is the distinction).

PageThe load-bearing idea
Context engineeringPrompt engineering produces a string; context engineering produces a pipeline
Lost in the middle, and context rotPositional within a request, temporal across a session: two mechanisms, two fixes
Sub-agent isolationThe value is entirely in what does not come back
Prompts in gitGate per slice, because the common regression shape is compensating

Three of the four worked examples land on the same organisational point, which is sharper than the technical content and worth naming as a through-line:

  • The context-engineering example: the system prompt was in git, reviewed and tested, and reached the model 78 percent of the time. Four bug reports over three months, all filed as model quality.
  • The prompts-in-git example: a one-sentence edit took one category up 6 points and another down 28, and it took six weeks to attribute because there was no diff and no author.
  • The sub-agent example: a copy-paste gave a child the spawn tool and one review cost $71.

In all three, the artifact under review was not the artifact in production, and the fix was to assert on the thing that actually runs. That is a generalisation of the "invariant between two numbers" lens from the storage chapter: here it is an invariant between the reviewed artifact and the executed one, and nobody was checking it.

One result worth keeping because it contradicts the usual objection. Adding CI gates to prompt changes took change velocity up, from about 12 to 18 changes a month. The mechanism is that an untested change is frightening, so people batch and defer them. The gate replaced caution, and caution was the slower of the two. That is the answer to "this will slow us down" and it is measured rather than asserted.

The context-rot page and the RoPE page from session 36 now bracket the same finding from two directions: RoPE explains why the U-shaped curve exists (rotation decay, training distribution, attention dilution), and context-rot explains what to do about it (retrieve less, rank better, order by relevance, re-retrieve per turn). Each links to the other.

State after this session: 183 pages, ~635k words, 788 flashcards, 202 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 06 has 8 rows left (agent patterns, tool registry, MCP, agent memory, tracing and replay, LangGraph state machines, GraphRAG, entity resolution). The agent patterns trio (ReAct/Plan-and-Execute, tool registry, MCP) is the natural next batch.

Session 39: the agent architecture cluster

Four topics. Chapter 06 has 4 rows left (tracing and replay, LangGraph state machines, GraphRAG, entity resolution).

PageThe load-bearing idea
Agent patternsWho decides the next step is the organising question
Tool registry designA tool description is prompt surface sent on every step
MCPIt standardises transport and discovery, not the things that determine quality
Agent memoryThe write path is the design; storage is the easy part

Three of these four converge on one number: how many tools are visible. That was not planned and it is the strongest cross-page finding in the chapter:

  • The agent-patterns page measured wrong-tool selection at 18 percent across 40 tools and 6 percent across 9, with routing alone worth 7 points of task success.
  • The tool-registry page has the full curve (4 percent wrong at 6 tools, 18 percent at 40) and the finding that deleting 19 unused tools improved accuracy, because unused tools were still in the choice set and still occasionally selected.
  • The MCP page notes that the protocol makes this worse by default: connecting a server is a config line that exposes everything it offers, so seven servers put 52 tools in one agent's choice set.

"Fewer tools improves accuracy, not just cost" is the transferable claim, and it runs against the instinct that capability comes from surface area.

A second convergence, on cost accounting. The tool-registry page found that lengthening descriptions raised per-request tokens 28 percent and lowered cost per completed task, because mean steps fell from 11.4 to 7.1. The agent-patterns page found plan-and-execute about 3x cheaper than ReAct for the same reason from the other direction: cumulative context across a loop, not tokens in one call. The metric for agent systems is tokens per completed task, and per-request optimisation is optimising the wrong number. That is now stated in both pages.

The memory page's security finding extends the session-38 through-line. Sessions 38 and 39 have now found three unreviewed write paths into a model's context: the assembled context (nobody asserted the system prompt was present), tool descriptions (written as docstrings by backend engineers, owned by nobody), and memory (extracted from user text with no review, persisting across sessions). Prompts are reviewed; the three channels that actually reach the model most often are not. That is worth a consolidated treatment if the queue allows one later.

State after this session: 187 pages, ~650k words, 810 flashcards, 206 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 06's last four rows, then chapter 08 (compute kernel, 15 rows) or chapter 09 (caching and edge, 15) as the next large cluster.

Session 40: chapter 06 closes at 17 pages

Four topics, and the context-and-agents chapter is complete.

PageThe load-bearing idea
Tracing, replay and checkpointingTraces built for diagnosis are worth more as test fixtures
State-machine agentsPast ~4 conditionals a loop IS a state machine, written implicitly
GraphRAGTwo question shapes vector RAG cannot address, at 100x the index cost
Entity resolutionThe two errors are asymmetric, and that should drive the threshold

Chapters 05 and 06 now form one arc of 36 pages, and reading them in SUMMARY order goes: tokenisation and tensor shapes, position and inference optimisation, the adaptation ladder, sampling and output constraints, RAG and evaluation and cost, then context assembly, positional and temporal degradation, isolation, prompt discipline, agent control flow, tool surface, MCP, memory, tracing, state machines, and the graph-based retrieval alternatives. That is the full stack from bytes to agent architecture, and it was assembled queue-first rather than designed.

The unreviewed-write-path through-line is now four items and deserves consolidation. Sessions 38 to 40 have found, independently, four channels that reach a model's context with none of the review that prompts get:

  1. The assembled context (session 38): the system prompt reached the model 78 percent of the time and nobody was asserting on it.
  2. Tool descriptions (session 39): written as Python docstrings by backend engineers, owned by nobody, and 14 of 63 were the function name restated.
  3. Memory (session 39): extracted from user text with no validation, persisting into future sessions where provenance is invisible. 214 instruction-shaped memories found in one audit.
  4. Extracted graph content (session 40): GraphRAG entity descriptions are LLM-generated from documents and then fed back into prompts, so a document containing a quoted fictional policy became a graph node asserting it.

All four are prompt text that no one reviews as prompt text. Each page states its own version; a consolidated treatment would be worth a page of its own if the queue allows one, and it is noted here so the observation is not lost.

A second cross-page pattern worth recording: measure the ceiling before optimising under it. The entity-resolution page's blocking recall (97.2 percent, a hard cap no scoring improvement can lift) is the same discipline as the context-rot page's positional sweep and the transformer page's KV-cache arithmetic. In each case the useful first step is establishing what is achievable, and in each case most implementations skip it and tune inside a limit they have not measured.

State after this session: 191 pages, ~665k words, 832 flashcards, 210 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 08 (compute kernel, 15 rows) and chapter 09 (caching and edge, 15) are the largest remaining clusters, followed by chapter 18 (15), chapter 10 (14) and chapter 12 (13).

Session 41: chapter 08 opens with the Kubernetes mental model

Three topics, chosen because they are the pages the rest of chapter 08 will lean on.

PageThe load-bearing idea
The reconciliation loopNothing executes commands; every question is "which loop, and what gap"
Requests, limits, QoSAllocated against utilised is the diagnostic that decides hardware vs manifests
The ndots:5 DNS classicTen packets per external hostname, and the NXDOMAIN ratio finds it in one query

All three pages converge on a single diagnostic each, and that is now a deliberate house pattern rather than an accident. The reconciliation page gives generation against observedGeneration; the resources page gives allocated against utilised; the DNS page gives the NXDOMAIN ratio. In each case a two-number comparison that almost nobody collects splits a whole class of investigation in half.

That is the same shape as the "invariant between two numbers" lens from session 34, now applied deliberately at writing time rather than noticed afterwards: when drafting a page, ask what single comparison would have identified the worked example's problem immediately, and make sure the page states it.

A note on scope. The reconciliation page's worked example is an admission-webhook deadlock, which is not obviously a "reconciliation" topic. It earns its place because the failure is a direct consequence of the model: controllers converge by creating objects, so anything that can block object creation prevents self-healing. Stating the general form ("ask what each control-plane component needs in order to recover, and make sure that thing does not depend on it") is what makes it a mental-model page rather than a webhook page.

Repo note: books/what-goes-into-you/ was committed by the user in 6002aaf and is now tracked, taking the build target count from 19 to 20. It builds green in the verification loop, so the deploy risk flagged in an earlier session is resolved.

State after this session: 194 pages, ~676k words, 847 flashcards, 213 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 08 has 12 rows left. The container-runtime cluster (namespaces and cgroups, security primitives, runc vs gVisor vs Firecracker) and the kernel cluster (memory, I/O models, TCP) are the two natural batches.

Session 42: the container isolation trio

Three topics, written as one batch because they are three layers of the same question: what is a container, what restricts it, and what if that is not enough.

PageThe load-bearing idea
Namespaces and cgroups v2Namespaces are visibility, cgroups are quantity, and the defaults are unlimited
Container security primitivesThese do not prevent compromise; they determine what it is worth
runc vs gVisor vs Firecracker vs KataWhere the boundary sits, and gVisor's cost has no single number

The three pages form a ladder and each one's worked example is the next one's motivation. The cgroups page's PID exhaustion is a resource-isolation failure fixed by a limit. The security page's red-team chain is an escape fixed by dropping privileges. The runtimes page is what you reach for when the workload is untrusted by design and the shared kernel is the wrong boundary. Read in order they answer "why is this not enough" three times.

Two findings worth carrying beyond chapter 08:

"What did you leave unset" is a better audit question than "what did you configure." pids.max, io.max, seccomp, and the user namespace are all off or unlimited by default, and each is a path from one container to a dead node or a compromised host. The PID exhaustion example is the sharpest version: a node that cannot fork anything, including its own kubelet and sshd, so it is alive and looks dead.

Stale privilege is the recurring organisational failure. Five of seven privileged workloads in the red-team audit had capabilities granted for a reason that no longer existed, including the SYS_ADMIN that made the escape possible. Nothing prompts a review of a granted capability, so the durable control is a recurring audit with an expiry date on each exception rather than a one-time hardening project. That generalises well past containers.

A drafting note. The runtimes page deliberately refuses to give a single gVisor performance figure, and instead gives the spread (0.97x on numpy, 0.25x on pip install) with the mechanism. That is the same discipline as the "one two-number diagnostic per page" rule from session 41: where a single number would be misleading, give the two that bracket it and say what determines the position between them.

State after this session: 197 pages, ~686k words, 867 flashcards, 216 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 08 has 9 rows left, and the kernel cluster (memory and the OOM killer, I/O models, TCP) is the natural batch, followed by the Kubernetes networking pair (kube-proxy, NetworkPolicy) and the autoscaling row.

Session 43: the kernel cluster

Three topics: memory, I/O models and TCP. Chapter 08 has 6 rows left.

PageThe load-bearing idea
Memory and the OOM killerWorking set is usage minus inactive file; 99% with zero kills is a contradiction
I/O modelsReadiness versus completion, which is why epoll never solved file I/O
TCP tuningRound-number latencies with low variance are always a timer

A pattern that has now appeared three times across three chapters and is worth naming as a technique: reason from the ABSENCE of an expected failure.

  • Memory: a container at 99 percent of its limit with zero OOM kills over three months is a contradiction, because a container genuinely near its limit gets killed. The absence of the kill proves the memory is reclaimable, and that is faster than any investigation.
  • TCP: exactly 40ms with almost no variance, or exactly 5.00s (the DNS page), is a timer rather than work, because real work has variance. The absence of variance identifies the mechanism.
  • Chapter 05's classical-ML page: an AUC of 0.94 on a genuinely hard problem should trigger an investigation rather than a celebration.

In all three, the diagnostic is something that did not happen or does not vary. That is a distinct skill from reading a metric, and the pages now state it explicitly where it applies.

The three pages share a diagnostic ordering too, which is the other transferable part. Memory: check working set before capacity. I/O: check kernel-time fraction and perf top before changing the model. TCP: read netstat -s before application logs. In each case the cheap check either implicates the layer or eliminates it, and the worked examples show the cost of skipping it: four months of application investigation on a problem that netstat -s named in a minute.

One page deliberately refuses a recommendation. The I/O page will not say "use io_uring," because Google disabled it in ChromeOS and Android after a run of exploitable bugs and container runtimes block its syscalls by default. The performance case is real and the security posture decides adoption more often, so the page gives both and says the constraint usually wins. That is the same discipline as the gVisor spread in session 42: where the honest answer is conditional, give the condition rather than a default.

State after this session: 200 pages, ~698k words, 889 flashcards, 219 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 08's last 6 rows (Lambda cold start, kube-proxy and iptables scaling, NetworkPolicy, autoscaling, USE and RED, JVM in a container), then chapter 09 (caching and edge, 17 rows remaining).

Session 44: Kubernetes networking and the JVM

Three topics. Chapter 08 has 3 rows left (Lambda cold start, autoscaling, USE and RED).

PageThe load-bearing idea
kube-proxy modesIt is not on the data path, so slowness shows as deploy errors, not latency
NetworkPolicy and mesh authzNetworkPolicy identity is an IP; mesh identity is a certificate
JVM in a containerThe limit covers far more than the heap, and CPU profiles miss latency

Two of the three pages arrive at the same structural point from different directions: the fix people reach for is not the fix that matters.

  • kube-proxy: teams see connection errors during deploys and migrate to IPVS. The larger win was a preStop sleep, because endpoint removal and container termination are concurrent with no ordering guarantee, so the race exists in every proxy mode. Making the sync faster does not remove a race; outliving it does.
  • JVM: teams see OOM kills and raise the memory limit. The cause was 600 threads at 1 MB of stack each, which jcmd VM.native_memory summary names in five seconds, and no amount of extra limit fixes a thread-count bug.

In both, the intuitive fix scales the symptom and the real fix removes the mechanism. That is worth stating as a general drafting question alongside the "one two-number diagnostic" rule from session 41: what is the fix a competent team would reach for first, and why is it not the one that matters? Both pages now answer it explicitly in the delivery note.

The NetworkPolicy page's worked example produced the most transferable practice in this batch, and it is not about policy syntax: observe, audit, review, enforce. Policies written from architecture diagrams cause outages because the diagrams are wrong; policies generated from observed flows codify existing mistakes as approved permissions (41 of 340, including a marketing CMS reaching a payments database); and the observation window must exceed the longest business cycle, because a fourteen-day window missed 94 monthly and quarterly flows. Both generation and hand-writing fail alone, and the review step between them is the work.

State after this session: 203 pages, ~709k words, 910 flashcards, 222 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 08's last 3 rows, then chapter 09 (caching, CDN and real-time delivery, 17 rows) as the next large cluster.

Session 45: chapter 08 closes at 20 pages

Three topics, and the compute and kernel chapter is complete.

PageThe load-bearing idea
Lambda cold startFix init, tune memory, buy provisioned concurrency last
Kubernetes autoscalingNode autoscalers react to unschedulable pods, so requests come first
USE and REDSaturation is the column that is always empty and the one that predicts latency

Chapter 08 is the first chapter where every page shares one diagnostic stance, and stating it is worth more than any individual page: the metric everyone collects is the one that cannot answer the question.

  • CPU utilisation cannot tell you a container is starved; PSI can.
  • %util on an SSD cannot tell you a disk is at capacity; aqu-sz can.
  • A connection pool's active-connection gauge reads a healthy 10 of 10 during exhaustion; pending-thread count reads 84.
  • container_memory_usage_bytes climbs toward the limit under normal operation; working set does not.
  • Cluster allocation and cluster utilisation are both routinely collected and neither is useful alone; the gap between them is the diagnosis.

In every case the collected metric measures busyness and the useful one measures queued work or lost time. That is now stated in the USE page's debate section as the general form, and the earlier pages in the chapter each demonstrate an instance of it.

Three cross-page dependencies got closed this session, which is the payoff of writing the chapter in this order:

  1. The autoscaling page depends on requests being right, and points at the resources page for why: averageUtilization is a percentage of the request, so an HPA on a 2.7x-inflated request targets something different from what it says.
  2. The autoscaling page's recommended HPA metric (in-flight requests) is the same signal the consumer-lag page recommends for Kafka consumers, for the same reason: it rises both when demand increases and when the service slows.
  3. The USE page's connection-pool example is the same failure as the PgBouncer page's idle in transaction finding, seen from the monitoring side rather than the database side. Both now cross-reference.

A note on the Lambda page. It ends by questioning the platform choice, which most pages do not: for a latency-critical high-volume API, the right answer to "how do we eliminate cold starts" is sometimes "do not use a platform that has them." That belongs in a reference because an interview answer that optimises within a bad constraint without naming the constraint is a weaker answer.

State after this session: 206 pages, ~721k words, 929 flashcards, 225 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 09 (caching, CDN and real-time delivery, 17 rows) is the largest remaining cluster, followed by chapter 18 (15), chapter 10 (14), chapter 12 (13) and chapter 14 (13).

Session 46: chapter 09 opens, and three pages cover seven rows

Three pages, seven queue rows. The queue's row granularity and the natural page granularity diverged here more than anywhere so far, and consolidating was the right call:

PageRows covered
WebSocket scalingsticky vs backplane, connection resource math
Cache-Control per asset classCache-Control, stale-while-revalidate, ETag/validators
Vary and cache keysVary and hit rate, cache poisoning and unkeyed input

Vary and cache poisoning were separate queue rows and are one topic, which is the finding worth recording. Both are answers to "what is in the cache key": too much and the hit rate collapses, too little and one request poisons the entry for everyone. Writing them apart would have produced two pages that each explain half of the cache key. The worked example makes the point concretely: a hit-rate investigation surfaced a stored-XSS vector on the homepage and a private-data deception path, because the same review answers both questions.

A pattern across all three pages: the availability lever is a configuration line, not an architecture.

  • stale-if-error turned a 31-minute origin outage into zero user-visible errors. The team had spent the previous quarter on origin redundancy.
  • Full-jitter backoff (random(0, base) rather than base + random) is a one-line difference that determines whether backoff disperses a herd or merely delays it.
  • Draining WebSocket closes over 90 seconds converts a 10,000-client instantaneous storm into a normal reconnect rate, and it is a SIGTERM handler plus a grace period.

In each case the expensive architectural answer was already being pursued and the cheap configuration answer was not. That is a sharper version of session 44's "the fix people reach for is not the fix that matters," and it now has three instances in one chapter.

A note on scope for the remaining chapter-09 rows. Ten remain, and several are naturally one page: CDN tiered caching and origin shield; the six cache layers; Redis eviction, persistence and hot keys; personalised page caching with ESI and streaming SSR; negative caching; edge compute. Expect the same consolidation ratio, so chapter 09 will likely finish at around 10 pages for 19 rows.

State after this session: 209 pages, ~732k words, 951 flashcards, 232 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 09's remaining 10 rows, then chapter 18 (15), chapter 10 (14), chapter 12 (13) and chapter 14 (13).

Session 47: chapter 09 closes at 10 pages for 19 rows

Three pages, seven rows. The consolidation ratio predicted last session held: chapter 09 finished at 10 pages for 19 queue rows, the highest ratio in the book so far.

PageRows covered
CDN tiering, origin shield, the edgetiered caching, edge compute
Caching personalised pagespersonalisation/ESI, the six layers, negative caching
Redis operationseviction and hash slots and hot keys, persistence

The consolidation was not a shortcut, it was a correction. Several queue rows described mechanisms where the useful unit is a decision:

  • "The six cache layers" is not a topic; it is the answer to "which layer does this belong in," which only makes sense alongside the fragment-versus-page question.
  • "Negative caching" alone is a technique; attached to the personalisation page it becomes the finding that the error path was the largest remaining origin load after the success path had been optimised, which is the part worth knowing.
  • Redis eviction and Redis persistence are separate rows and one operational posture: both are answers to "what does this instance do when it runs out of the resource it depends on."

The queue was derived from the source document's section list (D16 recorded this), so it inherits that document's granularity. Where a row describes a mechanism rather than a decision, merging it into the decision page is the right call, and the ratio should be expected to stay high for the remaining chapters.

A finding that recurred in all three pages and is now the chapter's through-line: the error path and the tail are where the remaining load lives, after the obvious work is done.

  • CDN: 62 percent of origin misses were the long tail (bottom decile by popularity), and tiering helps the tail most because a rare object fetched for one PoP serves the others.
  • Personalisation: after fragment caching took the success path to a 91 percent hit rate, 404 traffic was 11 million requests a month and became 84,000 with one header.
  • Redis: the instance ran fine for two years and the noeviction default only mattered once, during a 4x spike, at which point it was an outage.

In each case the system was healthy under normal conditions and the unexamined path was the one that failed. That is a sharper statement of the "what did you leave unset" question from session 42, applied to load rather than to configuration.

State after this session: 212 pages, ~744k words, 971 flashcards, 239 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 18 (offer and questions, 15 rows), chapter 10 (security, 14), chapter 12 (SRE and observability, 13), chapter 14 (architecture patterns, 13), chapter 11 (frontend, 12) and chapter 03's remaining rows.

Session 48: chapter 10 opens with the identity trio

Three pages, nine queue rows. The consolidation ratio held again: the OAuth page absorbed four rows (live/dead grants, token types, JWT validation, refresh rotation) plus DPoP/mTLS and token exchange, because they are one coherent topic (how a token is minted, validated, bound and renewed) rather than six.

PageRows covered
OAuth grants, token types, JWT validationgrants, token types, JWT validation, refresh rotation, DPoP/mTLS, token exchange
RBAC to ABAC to ReBACthe authorization-models row
SSRF and workload identitySSRF, workload identity

A stub was found and removed. book/10-security/workload-identity-and-ssrf.md existed as an untracked 11.6K partial draft (JSON fragments, no prose, missing the required archetype sections), left over from an interrupted earlier session. It was never in SUMMARY or git, so CI was unaffected, and check.py flagged it once the directory was scanned. My new page ssrf-and-workload-identity.md supersedes it, so the stub was deleted. Worth noting the naming near-collision: the stub and the real page differ only in word order, which is exactly how a duplicate survives.

All three pages share the chapter's emerging stance: security controls are ranked by what a successful attack is WORTH, not by whether the attack succeeds.

  • OAuth: the privilege escalation needed three mistakes (ID token accepted, no audience check, authorising from an editable claim), each survivable alone. DPoP does not prevent XSS; it makes a stolen token session-bounded.
  • Authorization: the reverse queries and the zookie are about blast radius and staleness, not about whether a check passes.
  • SSRF: the entire page is defence in depth. The Capital One chain needed IMDSv1 AND a wildcard node role AND an unvalidated fetch, and per-pod identity is the layer that makes a successful SSRF worth one thumbnail.

That is the security-specific form of the "reduce the blast radius" reasoning that ran through chapter 08's container-security page, and it is now explicit in three chapter-10 pages: assume the control fails and design so the failure is cheap.

State after this session: 215 pages, ~755k words, 991 flashcards, 248 of 352 queue rows closed.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 10 has 5 rows left (STRIDE, supply chain, secrets, the security pipeline, the OAuth vulnerability catalog), then chapter 18 (15), 12 (13), 14 (13), 11 (12).

Session 49: chapter 10 closes at 8 pages for 19 rows

Three pages, five rows. Chapter 10 (security) is complete: 8 pages covering 19 queue rows, the consolidation ratio holding.

PageRows covered
A STRIDE threat modelthe STRIDE row
Supply chain and secretssupply chain, secrets, the security pipeline
The OAuth vulnerability catalogthe OAuth vuln catalog

A state inconsistency was found and worked around. The zero-day-runbook drill (row 252) is marked [done] in QUEUE.md but the index shows it as [todo] and no page exists; the drill appears to live in the drill bank rather than as a dedicated security page. My supply-chain page had linked to ./zero-day-runbook.md, which does not exist, so check.py caught it and I dropped the link to prose. This is the "drop the link, keep the sentence" rule from the storage chapter, and it is worth noting that the QUEUE/index disagreement predates this session and should be reconciled in a later pass rather than papered over now.

Chapter 10's stance, now complete across eight pages, is the sharpest single lens in the book so far: security controls are ranked by what a successful attack is WORTH, not by whether it succeeds. Every page is an instance:

  • OAuth: the escalation needed three mistakes, each survivable; DPoP makes a stolen token session-bounded rather than preventing theft.
  • Authorization: the zookie and reverse queries are about staleness and blast radius.
  • SSRF: three independent layers, and per-pod identity makes a successful SSRF worth one thumbnail.
  • STRIDE: the disposition (mitigate/eliminate/transfer/accept) is a cost-versus-impact decision, and the toxic-combination finding is about end-to-end blast radius.
  • Supply chain: provenance and elimination over scanning, because scanning only catches known attacks; a stolen dynamic credential is worthless in an hour.
  • OAuth catalog: the top three fixes are ranked by attack surface, not by cleverness.

And a second chapter-wide finding: the control that fails visibly during development gets built, and the control that only matters under attack does not. The aud-validation asymmetry (12/12 validate expiry, 2/12 validate audience) is the canonical instance, and it recurs: state verified on two of three login paths, secrets never scanned in history, no admission control. The predictor of which control is missing is whether its absence breaks the happy path, which is a genuinely useful thing to be able to say in an interview, because it tells you where to look before you look.

State after this session: 218 pages, ~765k words, 1,008 flashcards, 253 of 352 queue rows closed. Under 100 remaining.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 18 (offer and questions, 15 rows), chapter 12 (SRE and observability, 13), chapter 14 (architecture patterns, 13), chapter 11 (frontend, 12), plus chapter 03's remaining rows and the ch05 regression-gates deferral.

Session 50: chapter 12 closes at 10 pages for 13 rows

Two pages, nine rows. Chapter 12 (SRE and observability) is complete.

PageRows covered
The observability pipelineCollector config, head vs tail sampling, exemplars, structured logs, wide events, continuous profiling
Incident managementincident roles, blameless postmortems, per-tenant SLAs

Six queue rows became one page because they are one pipeline. Collector config, sampling, exemplars, log correlation, wide events and profiling are not six topics; they are the stages and the signals of a single system, and the page's central claim only exists when they are together: the value is the correlation, not the signals. A three-hour investigation became ninety seconds because a metric spike linked to a trace linked to the log lines, and no individual page could make that argument.

The incident page arrived at the same shape as chapter 08's kube-proxy page and chapter 44's finding, from a completely different domain: the intuitive action is not the effective one.

  • kube-proxy: teams migrate to IPVS; the win was a preStop sleep.
  • JVM: teams raise the memory limit; the cause was thread count.
  • Incidents: teams debug; the win is rolling back before understanding.

In all three the instinct addresses the visible symptom and the fix removes the mechanism, and the incident version is the starkest: ninety minutes of diagnosis with the site down versus a two-minute rollback that needed no diagnosis at all. That is now stated in three chapters and is worth treating as a house observation rather than a per-page one.

A cross-chapter dependency closed itself. The incident page's per-tenant SLA section needs high-cardinality per-tenant SLIs, which is exactly the cardinality problem the observability page's wide-events section solves, and the two were written in the same session without planning that. The contract determines the observability, and the two pages now cross-reference in both directions.

State after this session: 220 pages, ~772k words, 1,019 flashcards, 262 of 352 queue rows closed. Ninety remaining.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 18 (offer and questions, 15 rows), chapter 14 (architecture patterns, 13), chapter 11 (frontend, 12), chapter 13's remaining rows, chapter 16's leadership rows, plus chapter 03's remainder.

Session 51: chapter 14's pattern clusters

Two pages, eight rows. Chapter 14 has 5 rows left.

PageRows covered
Event sourcing, sagas, the outboxevent sourcing, crypto-shredding/Kafka, sagas, the outbox
SOLID, hexagonal, refactoring, decisionsSOLID, hexagonal/Clean/Onion, refactoring vocabulary, decision machinery

The second page is the first in the book to cover four unrelated-looking rows with a single organising claim, and finding that claim was the work: SOLID, hexagonal architecture, refactoring vocabulary and decision machinery are all about where you put boundaries and how you move them later. SOLID and hexagonal are where to put them, strangler fig and branch by abstraction are how to move them, and ADRs and one-way doors are how you decide and record. Written as four pages they are four vocabulary lists; written as one they are a coherent position.

Both pages take an explicit stance against uniform application, which is now the chapter's character:

  • Event-source ONE aggregate, not the system (11 upcasters for one is manageable; 11 per aggregate across 40 is not).
  • Orchestrate rather than choreograph past ~3 steps.
  • Apply hexagonal where there is domain logic and skip it over a CRUD table.
  • SOLID per-principle: Liskov is a rule, Open/Closed is a caveat.
  • Four interfaces in the extracted service, not 34.

"The pattern is right somewhere and wrong applied everywhere" is chapter 14's version of the house scepticism, and it distinguishes these pages from a patterns catalogue.

One-way doors gave the book a retroactive index. The decisions page lists one-way doors from across the reference (a compacted topic's partition count, Flink's maxParallelism, a DynamoDB shard count, an event schema, an Iceberg partition spec, which Iceberg deliberately made two-way). Those were written across six chapters over many sessions without a unifying label, and the one-way-door framing names the class. Worth carrying into the remaining chapters as a drafting question: is this decision reversible, and does the page say so?

State after this session: 222 pages, ~780k words, 1,035 flashcards, 270 of 352 queue rows closed. Eighty-two remaining.

All tracked site targets build green under mdBook 0.4.40; state/check.py passes.

Next: chapter 18 (15 rows), chapter 11 (frontend, 12), chapter 13's remaining rows, chapter 16's leadership rows, chapter 14's last 5, plus chapter 03's tail.

Session 52: chapter 18 closed (offer stage and the questions you ask)

Wrote three pages closing all 15 remaining chapter-18 rows.

PageRows closedThe through-line
18/questions-by-interviewer.md8 (recruiter, HM, peers, reports, skip-level, product/design, bar raiser, three closers, debrief dynamics)Ask each person what only they know.
18/offer-negotiation.md5 (component flexibility, equity literacy, timelines, beyond-comp, Toronto mechanics)Which component moves, and why: whose budget it comes from.
18/references-and-the-long-game.md2 (references briefed properly, post-rejection grace)Both are relationship management with a multi-year horizon.

Consolidation ratio 15 rows / 3 pages, the highest in the book so far, and it is justified by the same D16 argument as chapters 09, 10 and 12: the queue was derived from the source document's section list, so it inherits that granularity. Seven separate rows for "questions to ask the recruiter / the HM / peers / reports / skip-level / product / the bar raiser" are seven instances of one skill, calibrating the question to what that person uniquely knows, and splitting them into seven pages would have produced seven copies of the same framing with a different question list appended.

Cross-page finding: the chapter is a chain, not a set. The three pages have a dependency order that was not visible in the queue rows:

recruiter screen: "what level, what band?"   -> sets the band
   -> level-negotiation.md (already written)
      -> offer-negotiation.md: which component moves inside that band

closer 3: "anything that gives you hesitation?"  -> surfaces the concern
   -> the follow-up email that answers it (debrief dynamics)
   -> the reference brief that answers it again, from outside the
      engineering narrative

The hesitation question is load-bearing three times over, and the reference page cannot do its job without it. That is worth stating explicitly in a reference book, because the rows arrived in the queue in an order that hides it.

Two-number diagnostics for this chapter (the house pattern, one per page):

  • ESA minimum (1 week/year, capped at 8) against common law reasonable notice (roughly 1 month/year, 12-24 months for a senior employee). The gap is the value of the termination clause.
  • "$480,000 of equity" against 0.05 percent of fully diluted shares behind a $310M preference stack. The gap is the value of the five equity questions.

Named a repo-wide pattern this chapter makes explicit: the deadline that moves proves it was not real. Same shape as several operational pages (a limit that can be raised on request was never a capacity constraint; an "urgent" escalation that waits for business hours was never a P1). Worth a cross-reference in a later consistency pass.

Verification note: the ch18 index.md was missing a row for "The recruiter screen" that QUEUE.md had (row 428). Rewrote the index's topic list from the pages that now exist rather than patching the old list, which also removed a stale [todo] Level negotiation before compensation negotiation row duplicating the already-done level-negotiation.md. This is the second instance of the QUEUE/index drift flagged earlier (the zero-day-runbook row in chapter 10 is still outstanding); both come from the index lists being hand-maintained. A reconciliation pass over every chapter index against QUEUE.md is now worth doing as its own session before the final passes.

State after this session: 285 of 352 rows closed, 67 remaining. Chapter 18 is complete. Remaining work is chapter 11 (frontend, 12 rows), chapter 13's and 16's remainders, chapter 14's last rows, chapter 03's tail, and the deferred ch05 regression-gates row (D15).

Session 53: chapter 11 core (React model, concurrency/RSC, state, rendering)

Four pages closing eight chapter-11 rows.

PageRows closedThe through-line
11/react-rendering-model.md3 (reconciliation, keys, hooks + useEffect traps)All three are consequences of one design: identity is positional unless you supply it.
11/concurrent-react-and-server-components.md2 (concurrent React, RSC + "use client")Two features that get conflated: one changes when work runs, the other where.
11/the-state-ladder.md2 (state ladder, thunk vs saga vs observable)The middleware comparison is mostly three ways to hand-roll a cache.
11/rendering-strategy-matrix.md1Per route, not per app; and split by personalisation rather than downgrading a route.

Cross-page finding: three of the four pages resolve to the same sentence, "identity is positional unless you say otherwise." Index keys make a row's identity its slot in the array. Hook slots make a hook's identity its call order. key={userId} is the deliberate use of the same mechanism. Stating that once and referring back to it made the keys and hooks sections much shorter than they would have been separately, which is the argument for having merged those three rows into one page rather than three.

Named a new house pattern: "the boundary that is not visual." "use client" looks like it marks a component and actually marks a module that spreads through imports; "use server" looks like it marks server code and actually publishes a discoverable RPC endpoint. Both failures in the worked example are the same mistake. This is a sibling of the security chapter's "the control that looks like a control" and worth cross-referencing in the consistency pass.

Two-number diagnostics for this batch:

  • Bundle 640KB against 210KB, alongside LCP 2,400ms against 700ms: the pair matters because the LCP win comes from the rendering strategy and the INP win comes only from the bundle. One number alone tells the wrong story.
  • Build time 34 minutes against 4 minutes. Framed deliberately as an incident-response constraint rather than a performance one, because that is the version of the argument that moves an organisation.

Verification note: wrote the first page into book/11-frontend-for-leads/ before checking the directory name, which is book/11-frontend/. Caught it by listing the directory before writing page 2, moved the file and removed the empty directory. check.py would have caught it too (SUMMARY coverage runs both ways), but only after three more pages had been written into the wrong place. Cheap lesson: list the chapter directory before the first write of a session, not after.

State after this session: 293 of 352 rows closed, 59 remaining. Chapter 11 has four rows left (frontend security, accessibility, testing ratio, streaming AI UIs), which is the next batch.

Session 54: chapter 11 complete (security, a11y, testing, streaming AI UIs)

Four pages closing the last four chapter-11 rows. Chapter 11 is done.

PageThe through-line
11/frontend-security.mdThree layers: do not create the sink, CSP so an injected script does not run, isolate what you cannot audit.
11/accessibility-as-design-input.mdThe expensive failures are component choices made in a design file, so a launch gate catches them after the cost is sunk.
11/frontend-testing-ratio.mdDiagnose a suite by the bugs that escaped it, not by the ratio you wish you had.
11/streaming-ai-uis.mdFor an AI feature the perceived speed is set by the client, not the model.

Cross-page finding: all four pages have the same argumentative move, "the control everyone reaches for is the one that cannot work." Host-allowlist CSP cannot work because an allowlisted CDN also hosts a JSONP endpoint. An accessibility launch gate cannot work because the expensive decision was made months earlier. More E2E tests cannot work because flake compounds multiplicatively. A faster model cannot work when the proxy is buffering the response. Naming this once per page and then giving the control that does work is what makes these pages argue rather than list, and it is worth carrying into the remaining chapters.

A related pattern worth recording: the security-project-that-reports-as-a- performance-win. Removing two blocking third-party scripts from the checkout critical path moved p75 LCP 2,900ms -> 2,100ms, which was larger than the previous quarter's dedicated performance work. Same shape as the stop-button-as-cost- control finding in the streaming page (172,000 wasted output tokens per week). Both are cases where attaching a second, differently-owned number to a piece of work is what gets it prioritised. This is now a repeated enough move across chapters 10, 11 and 12 to deserve a named cross-reference in the consistency pass.

Two-number diagnostics for this batch:

  • Time to first token 380ms against time to first paint 2,600ms. The gap IS the diagnosis, and it points at infrastructure rather than at the model.
  • 0.99^50 = 60% against 0.99^200 = 13%. Derived in front of the reader, and it converts an intuitive argument about E2E suites into arithmetic.

Source-discipline note: wrote a plausible-looking SRI integrity hash into an example and then replaced it with an explicit placeholder, because a fabricated hash in copyable markup is the same category of error as a fabricated benchmark number even though it reads as boilerplate. Worth watching for in any page that shows credentials, hashes, keys or ids.

State after this session: 297 of 352 rows closed, 55 remaining. Chapter 11 is complete (15/15). Remaining: chapter 16's leadership rows (the largest block), chapter 13's remainder, chapter 14's last rows, chapter 03's tail, and the deferred ch05 regression-gates row (D15).

Session 55: chapter 13 rollout mechanics (strategy, canary limits, stateful, merge queue)

Four pages closing six chapter-13 rows.

PageRows closedThe through-line
13/deployment-strategy-matrix.md2 (strategy matrix, traffic shifting + cohorting)The routing unit determines blast radius, not the percentage.
13/what-canaries-cannot-catch.md1Six structural blind spots, each needing a different control rather than a longer bake.
13/deploying-stateful-and-long-lived.md2 (connection draining, quorum-aware rolling + PDBs)The unit being replaced is not interchangeable.
13/trunk-based-and-merge-queue.md1The branching policy is downstream of merge mechanics, which are downstream of CI speed.

Cross-page finding: three of the four pages turn a cultural complaint into arithmetic, and that is what carries the decision in each worked example. "Engineers should rebase promptly" becomes a Poisson calculation showing 96% of PRs are stale on completion. "Deploys cause latency" becomes 85% * 20/15 = 113%. "The canary might not exercise unusual paths" becomes 1 - e^-0.24 = 21%. In all three the number is one line and it converts a debate about diligence into a statement about feasibility. This is now the most reliably effective device in the book and deserves to be named explicitly in the how-to-use page.

Corrected a QUEUE/index drift, second instance in three sessions. Chapter 13's index.md listed "Cache and message compatibility across versions" and "Feature flag types, lifecycles and flag debt policy" as [todo] while QUEUE.md had both [done]. Verified both are genuinely covered (drill 64 inside expand-contract.md and the drill bank; flag debt has its own section in deploy-vs-release.md) and rewrote the index list from the pages that exist, annotating which page absorbs which row. Same fix as chapter 18. The pattern is now clear enough to state: hand-maintained index lists drift whenever a row is absorbed into a page named after a different row. The reconciliation pass should regenerate every chapter index from QUEUE.md plus the SUMMARY rather than patching them.

Directory-name slip repeated: wrote the first page into book/13-deployment/ when the real directory is book/13-deployment-delivery/, exactly the failure logged last session for chapter 11. Caught before the second page this time because the lesson from session 53 was in PROGRESS. Adding it as a standing step: ls -d book/NN* before the first write of any chapter batch, because two chapters now have a shorter-name sibling that a plausible guess produces.

State after this session: 303 of 352 rows closed, 49 remaining. Chapter 13 has three rows left (testing strategy position, property-based and mutation testing, peeking/novelty/interference/switchback). Then chapter 16's leadership block (the largest remaining), chapter 14's tail, chapter 03's tail, chapter 01, chapter 12's remainder, chapter 04's resume row, and the deferred ch05 regression-gates row.

Session 56: chapter 13 complete, chapter 16 begun

Four pages closing six rows across two chapters.

PageRows closedThe through-line
13/testing-strategy.md2 (pyramid vs trophy, property-based + mutation)Every layer tests the cases you thought of; two techniques raise that ceiling.
13/experiment-analysis-pitfalls.md1 (peeking, novelty, interference, switchback)Four ways a correctly implemented test gives a wrong answer.
16/capacity-and-forecasting.md2 (three-bucket budget, cycle-time percentiles)Convert a performance accusation into a resourcing decision with an artifact.
16/on-call-design.md1 (rotation, page budget, shield, toil cap)Four numbers agreed in advance, plus an overflow mechanism for each.

Chapter 13 is complete at 20/20.

Cross-page finding: two pages independently arrived at the same governance device, and it is worth naming as a house pattern. The on-call page's overflow rule ("two consecutive weeks above the page budget doubles the next sprint's reliability allocation") and the capacity page's three-bucket budget are both instances of converting many individually losing arguments into one policy argument won in advance. That is also exactly what an error budget does, what a declared reliability allocation does, and what pre-registering a primary metric does in the experiment page. The mechanism is identical in all four: an individual case ("can we fix this alert?", "can we do this refactor?", "should we call this metric significant?") loses to a dated commitment, so the decision has to be made when nothing is at stake. Four chapters now contain an instance. This belongs in the how-to-use page as a named cross-cutting idea, alongside the "turn a cultural complaint into arithmetic" device recorded last session.

Two pages also share the coverage-versus-signal shape: mutation score against line coverage, and actionable rate against page count. In both, the intuitive metric is the gameable one and the useful metric is the one nobody reports. The compressed statements ("changing the rounding mode failed no test", "four out of five pages did not need a human") are the versions that persuade.

Honest-cost discipline held across all four pages. Each worked example names a number that got worse: coverage fell 91% -> 88%, the cluster design's MDE went 0.8% -> 4.1%, merging rotations took MTTA 4.1 -> 6.8 minutes for a quarter, and the focus factor after intervention was 44%, still below the healthy band. That is now consistent enough across the book to state as a drafting rule: a worked example with no number that got worse reads as marketing.

Third QUEUE/index drift found and fixed (ch16's "SCOR in full" row, [done] in QUEUE and [todo] in the index, actually covered inside story-portfolio.md and drill 58). Three in five sessions, all the same cause. The reconciliation pass is now clearly worth doing as its own session rather than opportunistically.

State after this session: 309 of 352 rows closed, 43 remaining. Chapter 16 has 11 rows left and is the largest remaining block. Also outstanding: chapter 01 (5), chapter 03's tail, chapter 04's resume row, chapter 12's remainder (4), chapter 14's tail, chapter 20, and the deferred ch05 regression-gates row (D15).

Session 57: chapter 16 people-management block

Four pages closing four chapter-16 rows, all drawn from source §23.1-23.3 and expanded to the bar.

PageThe through-line
16/unblocking.mdFour blocker types with four unrelated fixes; the default response addresses one.
16/growing-people.mdAssignment by availability is a decision nobody made.
16/pr-review-as-a-lever.mdReview latency is a scheduling problem, and PR size is why reviews are shallow.
16/promotions-and-calibration.mdThe case is won two quarters early, when the scope is reassigned.

Cross-page finding: three of the four pages hinge on a lead correctly rejecting the obvious diagnosis, and in each case a measurement does the rejecting. "People aren't prioritising review" is refuted by 11 minutes of work against a 9.4-hour wait. "The team is slow" is refuted by 41 blockers of which 17 were one documentation gap. "This person isn't ready" is refuted (or confirmed) by mapping the rubric line by line rather than arguing about impressions. Combined with the device recorded in session 55 (turn a cultural complaint into arithmetic), the leadership chapter now has a consistent shape: the lead's contribution is usually the measurement, not the intervention. Worth stating in the chapter index when the chapter is complete.

Sequenced the batch to avoid a forward link. growing-people.md needed to reference the calibration room, so promotions-and-calibration.md was pulled into this session rather than the next, instead of applying the usual "drop-the-link-keep-the-sentence" rule. This is the better resolution when the two pages are in the same chapter and both are queued: reorder the batch so the link resolves. Recording it because the drop-the-link rule had been applied five times without anyone asking whether reordering was available.

Honest-cost line held in all four worked examples: throughput fell ~15% for six weeks during the growth reassignment (announced in advance with a number, which is what made it an investment rather than a slump); a hard 400-line PR block produced non-compiling splits and a broken main before being replaced with a warning plus stacked-PR tooling; and the promotion page includes a candidate who was told early they were not going up.

State after this session: 313 of 352 rows closed, 39 remaining. Chapter 16 has 6 rows left (product partnership, retention, hiring, written-first culture, managing former peers/glue work, legacy modernisation). Then chapter 01 (5), chapter 12's remainder (4), chapter 14's tail (4), chapter 03's tail, chapter 04's resume row, chapter 20, and the deferred ch05 regression-gates row (D15).

Session 58: chapter 16 partnership, retention, hiring, communication

Four pages closing four chapter-16 rows, from source §23.5-23.8.

PageThe through-line
16/product-partnership.mdA verdict transmits a conclusion while withholding the inputs.
16/retention-and-motivators.mdYour model of each person is a hypothesis; check it.
16/hiring-and-the-bar.mdA loop without a scorecard measures rapport and calls it judgment.
16/written-first-culture.mdDecisions not written down get relitigated with worse information.

Cross-page finding: three of the four worked examples resolve on a sentence the other person says, and in each case the sentence was only available because the lead asked a question rather than making a statement. "I didn't loop you in because I expected you to say no." "I didn't know that was something I could ask for." "I've been the streaming person for two years and I could do it in my sleep." Each is a diagnosis of the lead, volunteered, and none would have surfaced from a status conversation. This is the leadership chapter's version of the device recorded in session 57 (the lead's contribution is the measurement): here the measurement instrument is a specific question, and the questions that work are concrete and past-tense ("what was the best three-month stretch you've had") rather than abstract and present-tense ("what motivates you").

A second reusable pattern surfaced: the question only the other party can answer. "How stale can this be before a merchant calls support" is answerable by a PM in five seconds and unanswerable by an engineer at all, and in the worked example it was the difference between 480,000 req/min and 2,000 for the same product outcome. Same shape as the promotion page's "which fact decides it" and the unblocking page's recommendation-with-a-default. Worth collecting into the how-to-use page as a named technique: find the question whose answer you cannot produce and whose answer collapses the design space.

Honest-cost line held. The written-first page records two failed interventions (a design-doc-for-everything rule abandoned by the team within six weeks, and a decision-log spreadsheet away from the repo that nobody updated after week two), and the retention page records that one of its "free" fixes was only free because the lead controlled the meeting structure and the other required a director willing to run an off-cycle adjustment.

State after this session: 317 of 352 rows closed, 35 remaining. Chapter 16 has 2 rows left (managing former peers + glue work, legacy modernisation as a narrative). Then chapter 01 (5), chapter 12's remainder (4), chapter 14's tail (4), chapter 03's tail, chapter 04's resume row, chapter 20, chapter 02's remainder, and the deferred ch05 regression-gates row (D15).

Session 59: chapter 16 complete, chapter 12 SLI/SLO

Three pages closing four rows. Chapter 16 is complete at 26/26.

PageRowsThe through-line
16/former-peers-and-glue-work.md1Work and authority that exist but are not acknowledged.
16/legacy-modernisation-narrative.md1A legacy system is a specification tested against reality for years, written in a language you dislike.
12/sli-and-slo-design.md2Measure where the user is; derive the target rather than picking it.

Cross-chapter finding: the glue-work page and the SLI page are the same argument about measurement in two domains. Both say the thing that matters is invisible unless you deliberately count it, both find that the lead's prior read is systematically wrong (a person judged "steady but not stretching" was carrying 60% of the team's uncredited work; an SLI improved during a total regional outage), and in both the fix is to change what is counted rather than to work harder at the existing measurement. Three sessions in a row have now produced a variant of this, which makes it the strongest candidate for a named cross-cutting idea in the how-to-use page: when the read and the outcome disagree, the instrument is usually wrong.

A drafting note worth keeping: the legacy page's worked example is the first in the book where the sequencing rationale carried more weight than any individual number. Shipping-cost-first because it changed 4x a year at 6 weeks a change, and that increment's own result funding the remaining four, is the argument; the 41,000 lines deleted is decoration. Prior migration-shaped pages in chapters 03 and 13 lead with the outcome number, and the consistency pass should check whether they would be stronger led by the sequencing decision.

Both ch16 pages carry an unresolved cost, deliberately. The former-peers page records that one friendship did become more distant and that the lead's own read was that this was partly their own overcorrection, noticed by the friend first. The legacy page records 6 quarters against a 2-quarter rewrite estimate. Neither resolves cleanly, which is the honest shape for these two topics specifically.

State after this session: 321 of 352 rows closed, 31 remaining. Chapter 12 has 2 rows left (OpenTelemetry, load testing). Then chapter 01 (5), chapter 14's tail (4), chapter 02's remainder, chapter 03's tail, chapter 04's resume row, chapter 07's remainder, chapter 15, chapter 17, chapter 20, and the deferred ch05 regression-gates row (D15).

Session 60: chapter 12 complete, and the index reconciliation pass

Two pages closing two rows, plus the reconciliation that has been flagged since session 55. Chapter 12 is complete at 20/20.

PageThe through-line
12/opentelemetry.mdThe API/SDK split is the whole design; the Collector is where you change behaviour without redeploying.
12/load-testing.mdBoth the load model and the measurement method fail in the same direction: they report the system as healthier than it is.

The reconciliation pass, finally done properly. Wrote a script that rebuilds every chapter's index.md topic list from two sources of truth: the pages registered in SUMMARY.md (in SUMMARY order, preserving any existing "covers X, Y, Z" annotation on a page line) and the remaining [todo] rows in QUEUE.md. Ran it across all 20 chapters.

before: 11 of 20 chapter indexes drifted from QUEUE.md
        ch03 had 10 stale [todo] lines against 0 remaining rows
        ch04 had 16 against 0
        ch08 had 16 against 0
        ch10 had 16 against 0
after:  0 drifted, verified by a second script

The cause, now unambiguous. Every drift is the same event: a row was absorbed into a page named after a different row, the consolidated page was added to the index as [done], and the absorbed row's own [todo] line was left behind. So the drift is exactly proportional to the consolidation ratio, which is why chapters 03, 04, 08, 09 and 10, the ones written with the heaviest consolidation, were the worst. It was never a discipline problem; the hand-maintained list could not survive the drafting pattern the book uses.

Standing rule from here: never hand-edit a chapter index list. Add the page to SUMMARY, flip the QUEUE row, and run python3 state/reconcile_indexes.py. The script was written into state/ in this session rather than deferred, and check.py now calls it in dry-run mode and fails the build on any drift, which was verified by introducing a bogus stale row and confirming the check fires and the script repairs it. Deferring the mechanism is what let this accumulate over roughly forty sessions, so it was worth the extra twenty minutes to close it in the same session it was diagnosed.

interview-reference/CLAUDE.md updated to name the script in the before-committing step.

Cross-page finding from the two new pages: both are about instruments that lie in a comfortable direction. A closed-loop load test reduces its own load when the system slows and reports capacity 74% too high; coordinated omission turns a 98-second p99 into a 1-millisecond one; a Collector without a memory limiter loses telemetry during the incident that produced it. Three failures that all produce a passing result, which is the direction measurement errors reliably fail in and the reason "audit the rig before the system" belongs in the how-to-use page alongside the other named devices.

State after this session: 323 of 352 rows closed, 29 remaining. Chapters 11, 12, 13, 15, 16, 18 and 19 are complete. Remaining: chapter 14 (8 rows, including one P1 on load shedding), chapter 17 (8), chapter 20 (6), chapter 01 (5), chapter 09's resume row, and the deferred ch05 regression-gates row (D15).

Session 61: chapter 14 architecture tail

Four pages closing five chapter-14 rows, including the chapter's last P1.

PageRowsThe through-line
14/load-shedding-ladder.md1 (P1)Five responses to overload, ordered by what the user loses; climb only as far as you must.
14/cqrs-consistency-fixes.md1The problem is read-your-own-writes for one user, so solve the interaction rather than the architecture.
14/vertical-slices-and-antipatterns.md2Layers impose one abstraction cost on use cases with different needs.
14/event-storming.md1Agree what happens before arguing about how to build it.

Cross-page finding: three of the four pages turn on refusing a global fix for a local problem, and in each case the global fix is the one everyone reaches for first. Making the projection synchronous to fix one screen's staleness taxes every write and makes write availability the product of every projection's availability. Adding a repository layer to give one report query a home imposes an interface on 34 entities that then accumulates 61 exceptions. Scaling to absorb a spike adds instances that inherit a hopeless queue. In all three the correct move is narrower and cheaper, and the reason the global fix wins by default is that it is easier to name in a planning meeting. Worth adding to the how-to-use page's list of named devices as "the local problem with the global fix", alongside "the control everyone reaches for is the one that cannot work" (session 54) and "when the read and the outcome disagree, the instrument is wrong" (session 59).

The reconcile script earned itself immediately. Both wiring steps this session were flip QUEUE row -> add to SUMMARY -> python3 state/reconcile_indexes.py, and the ch14 index came out correct both times with zero hand-editing. This is the first session since roughly session 20 in which no index drift was introduced.

A drafting note on the anti-pattern catalog page. It is the first page in the book that is primarily a reference list rather than an argument, and the thing that kept it from being a glossary was giving each entry a tell (the observable symptom) alongside the fix. The section that makes the page work is the closing rule that the name is an index rather than an argument, with the worked example's "214 orders with no event and 31 events with no order" as the demonstration of converting a pattern name into a funded defect. Any future list-shaped page should carry the same structure: name, tell, fix, and one worked conversion into a number.

State after this session: 328 of 352 rows closed, 24 remaining. Chapter 14 has 3 rows left (GoF subset, the standards reference card, sidecar/ambassador/adapter). Also outstanding: chapter 17 (8), chapter 20 (6), chapter 01 (5), chapter 09's resume row, and the deferred ch05 regression-gates row (D15).

Session 62: chapter 14 complete

Three pages closing the last three chapter-14 rows. Chapter 14 is complete at 20/20.

PageThe through-line
14/sidecar-ambassador-adapter.mdOne mechanism, three roles; the mesh decision is language count, not service count.
14/gof-subset.mdEight are load-bearing, several were workarounds for languages without closures, and the signal is which you avoid.
14/standards-reference-card.mdAdopt a standard for the tooling, and know which part is load-bearing.

Two of the three are list-shaped pages, and the structure established last session held. The anti-pattern catalog's rule (name, tell, fix, plus one worked conversion into a number) transferred directly: the GoF page gives each pattern what it became rather than a definition, and the standards card gives each entry a critique rather than a summary. Both close with a section on how to use the list in an interview, which is what stops them reading as glossaries. This is now a settled house form for reference-shaped pages and should be noted in the consistency pass.

Cross-page finding: all three pages make the same argument about defaults from a different direction. A mesh-wide retry-on-5xx default is a retry storm generator deployable in one line; a Singleton is the default way to get one instance and it is the wrong one; UUIDv4 is the default UUID and it is hostile to B-tree insert locality. In each case the default is not merely suboptimal, it is the specific thing that fails, and it persists because nobody re-reads the choice after making it once. The UUIDv7 example is the sharpest: a one-line change to an ID generator, available because someone read RFC 9562 rather than remembering RFC 4122, produced a 38 percent insert throughput improvement with no migration.

Honest-cost line held. The mesh page reports a 14 percent cluster cost increase before scoping and 4 percent after, three services materially slowed, and a mesh adopted for a compliance requirement that turned out to be the least valuable thing it did. The GoF page reports what the pattern review deliberately did NOT change, which was the part most at risk of being modernised for its own sake.

State after this session: 331 of 352 rows closed, 21 remaining. Chapters 11, 12, 13, 14, 15, 16, 18 and 19 are complete. Remaining: chapter 17 (8), chapter 20 (6), chapter 01 (5), chapter 09's resume row, and the deferred ch05 regression-gates row (D15).

Session 63: chapter 17 complete

Four pages closing all eight remaining chapter-17 rows. Chapter 17 is complete at 12/12.

PageRowsThe through-line
17/dr-ladder-and-global-routing.md2Your RTO cannot be shorter than your routing layer's failover time.
17/failover-decision-and-runbook.md3The decision is the largest unmeasured component of real RTO.
17/residency-and-dependency-audit.md2Audit the recovery path, not the request path.
17/backup-hygiene.md1A backup nobody has restored is a hypothesis.

Cross-page finding: all four pages are about a number the organisation believes and has never measured. A documented 12-minute RTO that was 47. A documented 4-hour restore that was 9h40m. A runbook rehearsed four times with three stuck steps. A backup success rate of 100% while the file was 12KB. In each case the belief was not dishonest, it was written once and never re-derived, and the mechanism that would have caught it (a game day, a timed restore, a walkthrough) existed and was not run. This is a sharper version of the session-59 device: not just "the instrument is wrong" but "the number was true when it was written." The generalisable control is that any number in a DR document should carry the date it was measured, which is a one-line convention.

The strongest single finding across the four is the game-day direction bias. A team had rehearsed failover four times and still had three stuck or blind steps, because every rehearsal moved in the direction that never required the primary region's dependencies to be unavailable. Alternating direction is free and it surfaced all three. Same shape as the load-testing page's "audit the rig before the system": the test had a systematic blind spot that made it agree with the system.

Drafting note: the failover-runbook page includes an actual runbook fragment in markdown, with pre-conditions, per-step verification, expected output and a WHY line on the step that appears to do nothing. That is the first page in the book to include an operational artifact rather than code or a diagram, and it works because the artifact is the argument: the properties that distinguish a runbook from documentation are visible in the fragment rather than asserted in prose.

State after this session: 339 of 352 rows closed, 13 remaining. Chapters 11-19 are all complete. Remaining: chapter 20 (6), chapter 01 (5), chapter 09's resume row, and the deferred ch05 regression-gates row (D15).

Session 64: chapter 20 complete

Four pages closing all six remaining chapter-20 rows. Chapter 20 is complete at 8/8.

PageRowsThe through-line
20/well-architected-and-landing-zones.md2A pillar binds when it has an owner and a forcing function.
20/infrastructure-as-code.md1Drift is a symptom of plan time.
20/commitment-planning.md1Commitment is the last cost lever, and a bet on the roadmap.
20/multi-cloud-and-egress.md2The lock-in is the storage location; the bill is internal traffic.

Cross-page finding: three of the four pages diagnose the same organisational failure, which is a decision made by the party that has a deadline rather than by the party that has the information. Finance bought three-year family-scoped commitments without asking engineering about a funded ARM migration, and the resulting instrument deferred that migration by fourteen months. A platform team proposed removing console access to stop drift without measuring that thirty-one of forty console changes were queue avoidance. A board asked about concentration risk and the proposed answer was a multi-cloud estate rather than a costed exit inventory. In each case the correct move is to convert the other party's concern into a number they can act on: a migration estimate, a CloudTrail classification, an exit cost. That is a sharper version of the "options with costs" device from the leadership chapter, applied outside a product conversation, and it belongs in the how-to-use page's list.

The exit-inventory finding is the most reusable thing in this batch. Producing "roughly three engineer-years and five to eight months" converted a board-level anxiety into an exposure, and its unpredicted second use was as negotiating leverage in the next cloud renewal, which returned more than the multi-cloud plan would have. Worth noting because it is a case where the artifact produced to answer one question turned out to be the answer to a different and more valuable one.

Honest-cost line held throughout: the landing-zone migration raised the bill 3 percent and took three weeks just to determine what CI needed; the topology-aware routing change was rolled back once after black-holing a zone for twenty seconds during a deploy; and the Well-Architected review is assessed as worth running once rather than annually, with 44 of 47 findings discarded.

State after this session: 345 of 352 rows closed, 7 remaining. Chapters 02 through 20 are all complete. Remaining: chapter 01 (5), chapter 09's resume row, and the deferred ch05 regression-gates row (D15). One more session empties the queue, after which the final passes begin: 00-how-to-use.md, cutting 90-recitables.md to ~40 entries, and the consistency pass.

Session 65: THE QUEUE IS EMPTY

Six pages closing the last seven rows. 352 of 352 queue rows are done. Every chapter is complete.

PageRows
01/what-gets-scored.md1
01/rounds-nobody-prepares-for.md1
01/company-loop-formats.md1
01/differentiators-and-mechanics.md2
09/reconnect-and-resume.md1
05/regression-gates-in-ci.md1 (the D15 deferral, finally closed)
273 topic pages
352 / 352 queue rows
999,711 words under book/
1,267 flashcards
20 build targets green

On the deferred ch05 row (D15). It was deferred because the honest treatment needed the statistical vocabulary that chapter 13's bake-time and MDE page established, and writing it last was the right call rather than an oversight: the regression-gates page reuses the minimum-detectable-effect arithmetic directly and cross-references peeking, which would have had to be invented in place if it had been written in sequence. Deferring a topic until its prerequisite page exists is a legitimate move and should be recorded as such rather than as debt.

Chapter 01 turned out to be the right chapter to write last, which was not planned. Every page in it references material from later chapters: the six-signals page leans on the deep-dive and story-portfolio pages, the rounds page cites incident management and PR review, the differentiators page cites the hesitation question from chapter 18. Written first, it would have been a chapter of forward promises.

Cross-page finding from the final batch: three of the six pages are about the difference between having a skill and performing it. An engineer who reviews code daily and has never done it out loud; a candidate whose influence content is already true and simply omitted; a debugging method that exists and has never been narrated. The compressed form, recorded from a candidate's own assessment, is "an interview is a performance of a skill, not the skill", and it is the organising idea chapter 01 needed and did not have when its first pages were written.

What remains: the final passes

Per CLAUDE.md, three, in order:

  1. book/00-how-to-use.md: the three-pass reading method, the 12-week mapping, and the night-before subset. It should also carry the named cross-cutting devices this log has accumulated (turn a cultural complaint into arithmetic; the control everyone reaches for is the one that cannot work; when the read and the outcome disagree, the instrument is wrong; the local problem with the global fix; the question only the other party can answer; find the number that was true when it was written).
  2. book/90-recitables.md: cut output/recitables.md from its current ~130 entries to the ~40 highest-recall ones. Selection by recall value, not coverage.
  3. Consistency pass: terminology, heading depth, voice, plus the specific items this log flagged: whether the migration-shaped pages in chapters 03 and 13 would be stronger led by the sequencing decision rather than the outcome number, and cross-references between the four instances of "the boundary that is not visual".

Session 66: the three final passes

All three passes from CLAUDE.md are done. The book is complete.

Pass 1: book/00-how-to-use.md

The three-pass reading method, the night-before subset and the 12-week mapping already existed and were correct. Two things were added and one was corrected:

  • corrected the stale count ("ninety-plus topic pages across nineteen chapters" -> "two hundred and seventy-plus across twenty")
  • added "Seven devices that recur", the cross-cutting moves this log accumulated over ~45 sessions: turn a cultural complaint into arithmetic; the control everyone reaches for is the one that cannot work; when the read and the outcome disagree, the instrument is wrong; the number was true when it was written; the local problem with the global fix; find the question only the other party can answer; convert many losing arguments into one policy argument won in advance. Each with two or three concrete instances from different chapters.
  • added "Two forms of the delivery note" (see pass 3).

Pass 2: recitables cut, 127 -> 45

Two tests applied to every entry: would you be asked to produce this from memory under time pressure, and is it the compressed form of a whole argument rather than a fact you could reconstruct. Anything failing either was cut, including entries that are individually true and useful.

Organised into ten sections rather than a flat list, so it works as a night-before sheet. The unfiltered 127 are archived at output/recitables-all.md (not published) as raw material, because if a page is rewritten its line is there.

Pass 3: consistency

Terminology. Ran variant detection across all 271 topic pages with code fences masked. Six genuine fixes (post-mortem -> postmortem x4, "data set" -> dataset, "GCP organization policy" -> the product's actual name). Everything else the detector flagged was a proper noun, a paper title, a product name or a code identifier and was correctly left alone: Cassandra's MATERIALIZED VIEW, Java's synchronized, Optimizely, "Artwork Personalization at Netflix", AWS Organizations. The -ise/-ize split is real and correct: prose is British (organisation 196/5, optimise 93/8, normalise 56/0) while spec terms keep their spelling ("authorization code flow" is RFC 6749's term).

Headings. Zero pages with anything other than exactly one H1, zero with H4 or deeper. An initial count of 123 bad H1s was a false positive from # comments inside fenced code, which is worth recording as a lesson about writing the detector before trusting its output.

Section order. 213 of 271 pages follow the canonical ten-section order exactly. The variations are the two other archetypes (12 design transcripts using Step 1 to Step 8, 9 scenario pages) plus 18 pages with a deliberately renamed section ("The problem it solves, from their side", "The problem the diagnosis solves"). Those renames carry information and were left alone. A consistency pass should distinguish real inconsistency from meaningful variation, and enforcing uniformity here would have removed content.

The delivery-note finding, and my own error. I measured a gap in quality-bar point 9 (the depth signal separating senior from staff) three times and got three answers: 135 pages, then 108, then 34. All three were wrong. The first two detectors searched for the literal phrase "senior-versus-staff separator" and then for any mention of a level; the third searched for a wider set of markers. Reading all 34 of the final set showed that every one carries the depth signal, phrased as an integrated closing move rather than a labelled paragraph: "close on the sequencing, because it is the judgement", "the detail that shows implementation experience", "and show calibration about the table itself".

So there was no content gap. There are two stylistic forms of the same required element, the labelled one predominating in later chapters and the integrated one in earlier chapters, and both are good. The fix was documentation rather than rewriting: 00-how-to-use.md now tells the reader that if a note has no labelled separator, the signal is its last paragraph.

The lesson, recorded because it nearly cost a rewrite of half the book: I was one command away from writing 108 new paragraphs to fix a defect that did not exist. What stopped it was reading the pages the detector flagged instead of trusting the count. That is the same finding as three of the book's own recurring devices, arrived at from the other side.

Final state

273 topic pages     20 chapters     352/352 queue rows
1,000,397 words     1,288 flashcards     45 recitables
20 build targets green     check.py clean

Section status: COMPLETE

interview-reference/ has no outstanding work. Future sessions should treat it as maintenance rather than extension: correct what is wrong, update what has gone stale, and resist adding pages because adding pages is what the last sixty-six sessions did. The queue is the definition of scope and it is empty.

Two things a maintenance session should actually check:

  1. Anything dated. The company-loop-formats page, the standards reference card and any page citing a provider default or a version number carry claims with a shelf life. Each already says so in its own text; a yearly pass over those three is worth more than any new page.
  2. python3 state/reconcile_indexes.py before every commit, which check.py now enforces. The chapter index lists are derived, not maintained.