Today's edition covers drawing consistency boundaries in the right place: narrower locks at GitHub, bounded deletes in Postgres, relaxed clocks in Spanner and signed provenance at Datadog.
Picked from 62 new articles across 34 sources · arrow keys for other days
Today in 30 seconds
30s left
At HPTS 2026, Dropbox reported that each new drive generation gives every stored byte less bandwidth. A downloadable Spanner showed it can keep external consistency without GPS clocks. story 1 ↓
PlanetScale argues against Postgres ON DELETE CASCADE at scale. One cascade held locks during an ALTER TABLE and blocked all writes. story 2 ↓
PlanetScale also found that logical replication plus cascades leaves orphaned rows and failed deletes, problems you only see in production. story 2 ↓
Datadog's Turnstile checks a chain of signed claims from commit to deploy against per-environment policies before any image ships, in a median 36 ms. story 4 ↓
1/4Murat Demirbas (Metadata)· Murat· Oct 21
HPTS 2026, day 1: hard-drive bandwidth limits and Spanner without atomic clocks
At the HPTS 2026 workshop, Dropbox said hard-drive capacity has grown 19x while bandwidth grew only 1.5x. Google said downloadable Spanner can keep its guarantees using ordinary clock sync, as long as clock uncertainty stays below one network round trip.
Why it matters · If you buy storage by capacity, Dropbox's numbers say each byte gets less bandwidth with every drive generation. The Spanner talk shows how loose clock sync can be before external consistency costs you latency.
Know this first
Context from the editor, not the article · 36 sec
1 · What HPTS is
High Performance Transaction Systems is a workshop Jim Gray founded 42 years ago. It meets every two years at Asilomar, California: about 100 invited people, one track, no published papers, and long breaks for discussion. Database and distributed-systems builders from industry and academia attend.
2 · Spanner and TrueTime
Spanner is Google's globally distributed SQL database. Its clock API, TrueTime, returns a time interval rather than a single instant. Before acknowledging a commit, Spanner waits out the clock uncertainty ("commit wait"). That wait is what makes transaction order match real-time order.
3 · Durability math for storage
2/4PlanetScale· Tom Pang· Oct 21
PlanetScale's case against Postgres ON DELETE CASCADE at scale
PlanetScale's Tom Pang argues that Postgres cascading deletes turn one statement into an unbounded transaction. These can block schema changes, flood replication and leave orphans on replicas. He recommends soft deletes and cleanup in small batches.
Why it matters · Cascades look like free correctness. This piece shows how they become unbounded transactions, and how that causes lock pile-ups and replication damage you only find in production.
Know this first
Context from the editor, not the article · 35 sec
1 · What ON DELETE CASCADE does
A foreign key links a child row to a parent row. With ON DELETE CASCADE, deleting the parent makes Postgres delete every matching child row automatically. If those children have cascading children of their own, those go too. It all happens inside the same transaction as the original DELETE.
2 · Postgres lock queues
Every statement takes table-level locks. Ordinary writes take RowExclusiveLock, and many writers can hold it at once. Most ALTER TABLE forms need AccessExclusiveLock, which conflicts with everything. Lock requests wait in a queue, so a waiting ALTER also blocks every later query on that table, even ones that would otherwise run.
3 · Logical replication basics
3/4GitHub Engineering· Eleanor White· Oct 21
GitHub replaces repository-wide write locks with per-branch locks to finish its Azure move
GitHub found that a cross-region round trip capped write throughput on its busiest Git repositories. It now locks each branch separately instead of the whole repository, and it is adding stateless replicas backed by Azure object storage.
Why it matters · It shows how narrowing a lock to the real consistency boundary can turn a latency problem into one that parallelism solves, a pattern that applies well beyond Git.
Know this first
Context from the editor, not the article · 35 sec
1 · Git references and objects
A Git repository holds immutable objects named by a hash of their contents, plus references: mutable names like branches and tags that point to a commit. Pushing writes new objects, then moves one or more references. Only the reference moves need careful ordering.
2 · Spokes, GitHub's replication layer
Spokes is GitHub's in-house system that keeps several full copies (replicas) of each repository on different servers. A reference update commits once a majority of replicas agree, which is called a quorum write. Spokes also routes reads to nearby replicas.
3 · Latency caps serialized throughput
4/4Datadog Engineering· Oct 20
How Datadog checks where an image came from before deploying it
Datadog built Turnstile, which checks signed records of each container image's commit, review, build and dependencies against per-environment rules before deployment. Caching keeps the median check at 36 ms.
Why it matters · It shows how to build a deploy gate that sits on every deployment's critical path. Its signed decisions can be reused by other systems and audited later, and caching keeps its added latency small.
Know this first
Context from the editor, not the article · 28 sec
1 · What image signing proves
Signing a container image cryptographically binds its digest (a content hash) to a trusted signer. Verifying at pull time proves the image wasn't altered after signing. It proves nothing about the code, dependencies or build machine that produced it.
2 · Software supply chain attacks
Attackers increasingly compromise the path to production rather than production itself: a malicious commit, a poisoned open source dependency, or a hijacked CI runner. The output looks like a normal build and gets signed normally.
3 · SLSA and in-toto
SLSA (Supply-chain Levels for Software Artifacts) is an industry framework describing source and build integrity threats. in-toto is an open format for signed statements recording which step happened to which artifact, and who performed it.
Blob stores estimate the chance of losing data from three inputs: how often drives fail per year, how fast lost fragments get rebuilt, and how much redundancy each object has, either full copies or erasure-coded fragments. The model assumes failures are independent and that the failure rates you plug in are right.
Image: Murat Demirbas (Metadata)
Murat Demirbas posted his notes from day 1 of 1 2026 (High Performance Transaction Systems). Jim Gray started this invitation-only workshop 42 years ago. It is still one track, about 100 people, and no published papers. Three of the day's four sessions were about AI coding agents, and their common theme was that specifications matter again. The systems talks are the more useful part for engineers.
Dropbox: drive capacity has outrun bandwidth
Dropbox moved off Amazon S3 ten years ago to Magic Pocket, its own blob store. It now holds about ten exabytes and trillions of blobs, with billions of deletes a day. Facundo Agriel's main point was that a durability model can't be better than the failure rates you feed it. The model's inputs are annual failure rate (2), repair speed, and redundancy (replication or 3).
Real failures broke the model's assumptions twice:
Heat raised failure rates for 30% of one drive population, but only that drive revision under those conditions. Dropbox built tooling to drain those drives early.
SSDs in the metadata tier were installed together and worn at the same rate, so they were heading for a correlated failure. The model assumes failures are independent.
The economics are changing too. Drives now hold 40 TB. Capacity grew 19x over the period measured, but bandwidth grew only 1.5x, so reading one drive end to end takes 36 hours. Cost per byte is now rising. Each new drive generation gives every stored byte less bandwidth, so operators will have to plan around I/O rather than capacity. Supply is tight as well: Western Digital is essentially sold out, and Seagate's 2028 nearline capacity is already allocated.
Spanner Omni: no atomic clocks needed
Google's Spanner Omni is a downloadable, licensed (not open-source) Spanner that runs on anything from a laptop to thousands of VMs. Version 1 shipped on September 30. Normally Spanner relies on three internal Google systems: Colossus (file system), 4 (lock service) and 5 (GPS- and atomic-clock-backed time). Omni replaces Colossus with only the parts Spanner needs and replaces Chubby with Omni-Chubby.
On clocks, Sebastian Kanthak argued as follows. Spanner's "6" only needs to cover clock uncertainty. A commit already pays about one network round trip to replicate, and if the wait fits inside that, it is effectively free. So uncertainty only needs to be smaller than one round trip. One central time reference, with a fallback in each region, is enough to get there.
Lightning talks
A Postgres redesign: 7 trees (write-optimized storage), a write-ahead log built on Raft (a consensus protocol), and cheap branching.
DBOS: durable workflows as a library inside your existing database.
MongoDB's William Schultz: run concurrency control on operation semantics, not reads and writes, to cut aborts under contention.
Size queues with 8 instead of guessing, to avoid 9.
Murat Demirbas, a distributed-systems and formal-methods researcher, posted his notes from the first day of 1 2026. HPTS (High Performance Transaction Systems) is the invitation-only workshop Jim Gray started 42 years ago. It still runs the same way at Asilomar: about 100 people, one track, no proceedings. Three of day 1's four sessions were about AI coding agents. Their shared conclusion, which Demirbas welcomed as a formal-methods person, was that specifications matter again. This write-up covers the systems content: Dropbox's storage lessons, how Google packaged Spanner to run outside its own infrastructure, and the lightning talks on databases and concurrency.
Ten years of Magic Pocket at Dropbox
Ten years ago Dropbox moved its data off Amazon S3 and onto Magic Pocket, its own on-premises blob store. Facundo Agriel described the system's current scale: about ten exabytes, trillions of blobs, and billions of deletes a day.
He framed reliability around the durability model. It takes three inputs:
2 (annual failure rate): the fraction of drives expected to fail in a year.
Repair rate: how fast fragments from a failed drive get rebuilt elsewhere.
Redundancy: replication or 3, which splits data into fragments plus parity so the original survives the loss of some fragments.
The model is only as good as the AFR you feed it. Agriel's lesson was that "failures don't care about your durability model." He gave two examples:
Heat. High temperature affected 30% of one drive population, and AFR rose sharply, but only for that drive revision under those conditions. A fleet-wide average would have hidden it. Dropbox built a system to drain those drives early.
SSDs wearing out together. The metadata tier was being written harder than the team realized. Those SSDs were installed together and wore at the same rate, so they were heading for a correlated failure. The durability math assumes independent failures, so this is exactly the case it misses.
He also stressed checksums and verifiers that keep confirming stored data is intact.
The I/O squeeze on hard drives
Demirbas found the drive economics the most interesting part. Drives now hold 40 TB. For a decade, higher density reliably lowered cost per byte. That trend is ending: cost is rising while density keeps climbing and I/O stays flat. Over the period Agriel measured, drive capacity grew 19x and bandwidth only 1.5x. Reading one drive end to end now takes 36 hours, which works out to roughly 300 MB/s on a 40 TB drive.
The consequence: if you buy a drive twice as large with the same bandwidth, each stored byte gets half the bandwidth. Buying capacity now buys less and less access to it, so operators will have to plan around I/O rather than capacity. Long full-drive reads also slow down rebuilding a failed drive, which feeds back into the repair-rate term of the durability model. That link is an inference, not something the notes state.
Supply is tight too. Agriel said Western Digital is essentially sold out, memory contract forecasts are up 3x, and Seagate's 2028 nearline capacity is already allocated.
Spanner Omni: Spanner without Google's infrastructure
Sebastian Kanthak presented Spanner Omni, a downloadable Spanner that runs on anything from one laptop to a multi-region cluster of thousands of VMs. Version 1 shipped on September 30, 2026. It is not open source and needs a paid license once the trial ends.
The engineering problem: Spanner depends on three internal Google systems that can't ship with it:
Colossus, Google's distributed file system. Omni includes only the part of Colossus that Spanner actually relies on, mainly moving files transparently.
4, Google's lock service. Omni ships its own replacement, Omni-Chubby, for leader election and cluster membership.
5, the clock API backed by GPS receivers and atomic clocks in every datacenter.
The clock was the question everyone cared about. Kanthak's argument went like this. Spanner's 6 only needs to cover the clock uncertainty. A commit already pays about one round trip (RTT) to replicate to a quorum. If the commit wait is about as long as that round trip, the two overlap and the wait costs almost nothing extra. So the uncertainty doesn't have to be tiny; it only has to be smaller than one RTT.
Illustrative numbers, not from the talk: suppose a quorum round trip is 40 ms and uncertainty is held to a few milliseconds. The commit wait finishes while replication is still in flight, so clients see no added latency. Push uncertainty past the RTT and the wait starts to dominate commit latency.
Getting under one RTT doesn't take hardware in every building. A single logically centralized time reference is enough if every node syncs to it. Each region keeps a fallback reference in case the central one becomes unreachable. The notes don't say how uncertainty bounds are computed or what happens if a region loses both references.
Lightning talks worth noting
The five-minute "Gong Show" talks got only brief notes:
The AI sessions, briefly
One AI talk was directly about database engineering. Todd Lipcon (Google) listed learned-systems projects that never shipped: learned B-tree indexes, ML cache eviction, Kepler query optimization, and an RL compaction scheme that gained 2%. His diagnosis was the "tax" of an embedded model: inference latency on every decision, plus permanent opacity and risk. His alternative: have the model write a C++ algorithm, review it, and ship the code. Google's cache-eviction work switched to this approach in 2024.
Several talks Demirbas attended aren't covered at all, including Salesforce's talk on logical corruption.
Remember
Durability models assume independent failures. Heat in one drive revision and SSDs wearing out together broke that assumption at Dropbox.
Hard-drive capacity grew 19x while bandwidth grew 1.5x; a 40 TB drive takes 36 hours to read end to end.
Spanner's commit wait costs almost nothing if clock uncertainty stays below one replication round trip, so GPS and atomic clocks aren't required.
Postgres logical replication streams row-level changes from a publisher database to subscribers. A publication defines which tables and which kinds of change are sent. On each subscriber, an apply worker process replays those changes.
Image: PlanetScale
Tom Pang of PlanetScale, a company that hosts Postgres and MySQL databases, argues against Postgres's ON DELETE CASCADE. This foreign-key option makes deleting a parent row automatically delete its child rows, and their children, in the same transaction. It's convenient. But one DELETE then becomes a transaction whose size depends on the customer's data, not the code.
How it causes an outage
Pang describes an incident pattern where writes to most tables time out. A cascading delete of a large customer holds RowExclusiveLock on every table it touches for the whole transaction. A routine migration, such as adding a nullable column, needs AccessExclusiveLock, so it waits. Postgres grants locks in queue order, so every later INSERT on that table queues behind the waiting ALTER. A millisecond migration becomes a write outage lasting as long as the delete. PlanetScale's fix in the moment was to cancel the transaction.
Setting a short lock_timeout on migrations and retrying them avoids the pile-up. It doesn't fix the cascade's other costs. Pang reports single transactions writing hundreds of gigabytes of 1 (the write-ahead log). Under 2, where commits wait for a standby to confirm, other transactions stall behind it. And if a foreign-key column has no index, deleting one parent row can trigger a full scan of the child table.
Replication surprises
With Postgres logical replication, which streams row changes from a publisher to subscribers, the subscriber skips foreign-key checks and cascades by default. That's because the publisher already sends the child deletes. A child table that exists only on the subscriber, or is left out of the publication, keeps orphaned rows, with no error. On the publisher, a cascade child that has no primary key (3) but is included in a publication that publishes deletes makes the parent delete fail outright. Pang's advice is to publish the whole foreign-key tree and run orphan checks.
What he recommends instead
Use a 4: UPDATE customer_organizations SET deleted_at = now() WHERE id = 42. This is one row, and it replicates as one change. Then a background job deletes the real rows later, perhaps after a 30-day retention window. It works in small batches during quiet hours and runs VACUUM afterwards. Each batch commits fast, so migrations wait only briefly. The costs: every read must filter on deleted_at, and you have to build the reaper job.
His general rule for OLTP (transactional) databases: keep transactions bounded. Start at hundreds to low thousands of rows per transaction, often fewer, and tune from there.
Tom Pang of PlanetScale, a company that hosts Postgres and MySQL databases, makes the case against Postgres's ON DELETE CASCADE. His argument is that the feature turns a one-line DELETE into a transaction of unknown size. That transaction interacts badly with schema migrations, with replication and with missing indexes. He recommends 1 followed by deletion in small batches.
Why cascades are tempting
The appeal is real. You declare a foreign key from customer_users.organization_id to customer_organizations.id with ON DELETE CASCADE. After that, DELETE FROM customer_organizations WHERE id = 42 removes the organization and every user in it, atomically and with integrity checked. Application code never needs to know the shape of the relationship tree.
As the application grows, more tables point at organizations, and further tables point at those, all cascading. Deleting one row becomes a convenient handle on an entire customer's data. That same convenience is the problem: the work behind one statement now grows with the size of the customer.
The outage: cascade plus migration
Pang describes the failure as one PlanetScale has seen. Writes to most tables start timing out. The cause is a large cascading delete running at the same time as an innocent migration, such as adding a nullable text column.
Here is the mechanism step by step:
The cascading DELETE runs as a single transaction. It deletes every matching row, which creates 2 (old row versions that wait for cleanup), updates indexes and writes 3. WAL is the write-ahead log, Postgres's durable record of changes. For the whole transaction, it holds RowExclusiveLock on every table it touches.
The migration's ALTER TABLE customer_users ... asks for AccessExclusiveLock. That lock conflicts with RowExclusiveLock, so the ALTER waits until the DELETE finishes.
Postgres grants locks in queue order, so the waiting ALTER also blocks new requests behind it. Every subsequent INSERT on customer_users queues behind the ALTER, which is queued behind the DELETE.
As an illustration (these numbers are not from the article), suppose a cascade takes four minutes to delete a large customer. A migration started one minute in turns that table into a three-minute write outage, even though the migration alone would finish in milliseconds. PlanetScale's fix in the incident was to cancel the offending transaction with its live-connections CLI.
The standard mitigation is a short lock_timeout on migration sessions, retried in a loop. The ALTER gives up quickly instead of sitting at the head of the queue, and succeeds once there is a gap. That protects the migration, but not the cascade's other costs. Pang reports that in larger environments a single transaction has written hundreds of gigabytes of WAL. With 4, where a commit waits until a standby confirms it received the WAL, other transactions end up waiting behind that flood.
PlanetScale has previously written about avoiding large deletes by dropping whole tables instead. Pang notes that cascade-driven deletion doesn't map easily onto that approach.
Unindexed foreign keys
Postgres doesn't automatically index the referencing column of a foreign key. When the column is indexed, the cascade uses that index to find children. When it isn't, deleting a single parent row can trigger a full sequential scan of the child table. Pang calls this confusing to diagnose, because the statement looks trivially cheap.
Cascades and logical replication
Built-in logical replication brings two more traps.
Orphans on the subscriber. On the publisher, deleting org 42 replicates as one transaction of ordinary row deletes: the org, then its users, then their children. The subscriber's apply worker runs with session_replication_role = replica. By default, that setting skips the internal triggers Postgres uses to check foreign keys and run cascades. This is deliberate, since the publisher already sent the child deletes. It breaks down when the subscriber has a child table the publisher doesn't know about. Pang's example is a subscriber-only user_activity_rollups table whose rows cascade from customer_users. When org 42 is deleted, its users disappear on the subscriber but their rollup rows stay, pointing at users that no longer exist. There is no error and no warning, only a violated foreign key. A publication with a hand-picked table list that omits a child table causes the same problem.
Failed deletes on the publisher. To publish deletes, a table needs a usable 5, which is how subscribers locate the row (by default, its primary key). Suppose user_sessions(user_id, token) is a cascade child of customer_users, has no primary key, and sits in a publication that includes deletes. Then deleting any org that has users fails with cannot delete from table "user_sessions" because it does not have a replica identity and publishes deletes. It fails even when those users have no sessions.
His guidance: if you cascade and replicate, publish the entire foreign-key tree. Use FOR ALL TABLES, or FOR TABLES IN SCHEMA (Postgres 15+) listing every relevant schema. Clean up subscriber-only children separately, and run orphan checks to catch what slips through.
The alternative: soft delete, then reap in batches
Pang argues that soft deletes are better in many ways for deleting customer data at scale. Deleting a customer becomes a single-row update:
UPDATE customer_organizations SET deleted_at = now() WHERE id = 42;
That replicates as one small change. Later, a background job "reaps" the real rows, perhaps after a retention window such as 30 days. It deletes in small batches during low-traffic periods and runs VACUUM afterwards so the freed space can be reused. Each batch commits quickly, so a pending ALTER TABLE, and the queries behind it, wait only briefly. A retention window also makes it possible to restore data after an accidental delete.
The costs are real, and Pang acknowledges them. Every read, including reads of child tables, must check deleted_at on the relevant rows. You also have to build and run the reaper. The article doesn't address how to enforce that filter reliably across a codebase. It also doesn't cover how soft-deleted rows affect unique constraints or index size.
The general rule
Pang presents all of this as a case of a broader OLTP (online transaction processing) principle: keep transactions short, small and bounded. As a starting point, he suggests a single transaction should touch hundreds to low thousands of rows, often far fewer, tuned to the workload. A cascade breaks that rule invisibly, because the number of rows it touches is set by the data rather than the code. That hidden size is the core of his objection.
Remember
A migration waiting on a lock blocks every query queued behind it, so long transactions plus ALTER TABLE can stop all writes.
On logical replication subscribers, cascades don't fire by default; child tables that exist only on the subscriber silently keep orphaned rows.
Postgres doesn't index foreign-key columns automatically; an unindexed one turns a single-row cascade into a full table scan.
When writes must happen one at a time, the most you can do per second is 1 divided by how long each write takes. If the network round trips get longer, throughput falls by the same factor. Adding hardware does not help, because the writes still wait on each other.
Image: GitHub Engineering
GitHub is moving its Git storage from its own data centers into Microsoft's 1 cloud. By its own count, 99.99999% of repositories now have copies in both places. A post by Eleanor White explains what has held back the last, busiest ones: a 25ms network round trip. It also covers the fix and the next step.
The bottleneck
Each repository usually has five replicas, full copies managed by 2, GitHub's system for replicating repositories and coordinating writes. A write commits once a majority agrees, but Spokes waits for every healthy replica to answer (up to a timeout). That means the slowest replica sets the latency of every write. Each write also holds a repository-wide lock until it commits, so only one write is in flight at a time.
An Azure replica is about 1,000 miles away, roughly 25ms per round trip, and a write needs several round trips. As an illustration (not GitHub's numbers): three round trips means at least 75ms per write, or about 13 writes per second for the whole repository. Busy repositories couldn't absorb that.
The fix: lock per 3
Git's consistency rule applies to each reference (a branch or tag) separately. Once an update to a branch is accepted, no one should see an older value for that branch. Updates to different branches are usually independent. So GitHub is narrowing the lock from the repository to the individual reference. Writes to the same branch still wait for each other, but pushes to separate branches run in parallel. Each write still pays the cross-region latency, but they no longer pay it one after another. In internal tests, writes to different references got 3–4x higher throughput at lower latency, enough to finish the migration.
Separating reads from writes
Repositories see 100 to 1,000 reads per write, yet reads and writes share the same machines. GitHub is adding 4, its object store, to the 5 as a "6." A process with no persistent state of its own streams writes into Blob Storage, so a write isn't acknowledged until it is durable there. It batches concurrent writes on different branches into one set of network calls. Read-only replicas can then be added on demand. They fill their caches from Blob Storage and reconcile in the background. GitHub's load-testing harness ran out of capacity before these replicas did.
Limits
Background reconciliation means read replicas can lag, so not every read can use them yet. Contention on a single busy branch is still serialized. The full-copy quorum still caps write throughput. GitHub's next step rests on the fact that Git objects are immutable and named by their contents, so only reference updates need ordering. Its final post will describe that design, which still includes a small consensus group.
GitHub is moving its Git storage from its own data centers into Microsoft's 1 cloud. By its own count, 99.99999% of repositories now have copies in both places. The ones left are among the busiest on the platform, and in a post by Eleanor White, GitHub explains what holds them back: a 25ms network round trip. The fix narrows the scope of Git write serialization from the whole repository to individual 2. The same change makes room for a second step: replicas that keep no persistent state of their own.
Why the migration had to be fast
GitHub says traffic has grown so quickly that it is running into a hard ceiling on power capacity in its data centers and their region, along with supply-chain limits on hardware. The capacity left was enough to migrate safely but not slowly. Changing the storage architecture and the hosting platform at the same time looked too risky, so the team chose an order: move the data first, then change the architecture.
Git operations are what GitHub calls 3, meaning nearly everything else depends on them. The first repository copy landed in Azure's Central US region in August 2025. Today most repositories have two of their five replicas in Azure, and Azure serves about half of Git traffic.
Traffic follows the data. 4, GitHub's system for replicating repositories and coordinating writes across copies, routes each read to a replica in the same region and 5 as the request. Each time a replica moves to Azure, Azure can serve a larger share of that repository's traffic. When the last replica moves, the old region stops getting requests.
The problem: the slowest replica sets the pace
Spokes commits a write once a majority of replicas agree. In practice, though, it waits for every healthy replica to answer, up to a timeout, before moving on. GitHub does this so slow replicas don't silently fall behind. The cost is that the slowest healthy replica sets the latency of every write.
The second ingredient is a lock. Each write holds a repository-wide lock until it commits, round trips included. That turns the 6 into one queue with a single write in flight at a time. An Azure replica sits about 1,000 miles from GitHub's data centers, so each round trip takes about 25ms, and a write needs several of them.
An illustrative calculation (not GitHub's figures): if a write needs three cross-region round trips, it holds the lock for at least 75ms. That caps the repository at about 13 writes per second, no matter how much hardware is behind it. A repository already near its old ceiling would fall further behind with every push, and its queue would keep growing.
The fix: serialize per reference
The key point is that Git's consistency guarantee applies to each reference separately. Once the server accepts an update to a branch, whether a fast-forward, a force push or a delete, no client should ever see an older value for that branch. Updates to different branches usually don't depend on each other.
So GitHub is shrinking the quorum's scope from the repository to the individual reference. Only writes that touch the same reference wait for each other. Each write still pays the cross-region latency, but writes to different branches can be in flight at once. Many developers and automated tools push to their own branches, so in practice most writes no longer queue behind one another.
Back to the illustrative numbers: with ten branches being pushed at once, the ceiling rises from about 13 to about 130 writes per second. GitHub describes the gain as roughly proportional to the number of references being written at once. In internal tests with realistic traffic, writes to different references got 3–4x higher throughput at lower latency. That is enough to move the last repositories to Azure.
Separating reads from writes
Most repositories see between 100 and 1,000 reads for every write. Today reads and writes hit the same replicas and compete for the same CPU and memory. For example, reads would benefit from far more in-memory cache, but that memory is also needed for 7. Compaction here means background reorganization of stored repository data; the article doesn't go into detail.
This is GitHub's second principle: separate storage from compute. The first step is to add 8, Azure's object store, to the quorum as a 9. A process with no persistent state of its own stands in for it. This virtual write replica streams incoming writes to object storage and serves no reads. Because it is a quorum member, a write isn't acknowledged until it is durable in Blob Storage.
That adds some latency to each write. As with the cross-region hop, per-reference serialization keeps it from limiting throughput. The virtual replica also batches transactions on different references into a single set of network I/O operations, so a busy repository pays one object-store round trip for many concurrent writes. For now it also runs compaction, and read replicas pick up the compacted state.
With that in place, GitHub can add as many virtual read replicas as a repository needs. Each one fills its cache from Blob Storage and starts serving reads without joining the quorum. It treats object storage as the source of truth and reconciles its local state against it in the background. GitHub's distributed load-testing harness routinely found limits in the current architecture. Against virtual read replicas, the harness hit its own limits first.
Trade-offs and open questions
Read freshness. Because read replicas reconcile in the background, they can lag, which suits only some read workloads. To serve every kind of read, reconciliation has to move in-line: before serving a request, the replica fetches only the reference state and data that changed since it last caught up. The article says this comes later.
Write ceiling. Per-reference locking helps only when writes touch different references. Heavy contention on one branch, such as a busy main, is still serialized. The full-copy quorum also remains the upper limit on write throughput.
Where this leads. GitHub argues that very little of a write needs ordering. Git objects are immutable and named by their contents, so they can be stored without any agreement step. Only the small set of reference updates needs ordering. The open problem is ordering that fast without moving the bottleneck somewhere else, and working out where durable reference state lives and how compaction and garbage collection scale. A final post promises the end state, which GitHub says still includes "a (small) consensus group."
Spokes itself stays. It now handles routing and load balancing, provides an internal API serving more than 100 billion operations a day, and runs "sweepers," background jobs that place, repair and rebalance repositories across storage nodes. GitHub says most of that carries over. The commit protocol does not: in GitHub's words, the protocol that reached a billion repositories won't reach the next billion.
Remember
When writes are serialized, adding latency cuts throughput directly; narrowing the lock scope turns that into a parallelism problem.
Git only needs ordering per reference, and objects are immutable and named by their contents, so most write coordination is optional.
Putting object storage in the quorum lets read replicas without local state scale independently of writes.
Overview: signed attestations checked against policies, with policies anchored to a root of trust and verdicts returned at enforcement points.1 / 2
Datadog has described Turnstile, an internal system that checks every container image before deployment. Datadog already signed images, which only proves an image wasn't altered after signing. Turnstile asks whether the evidence of how the image was made meets the rules for the environment it's going to. It handles tens of thousands of policy evaluations a day.
Why signing isn't enough
A malicious commit, a poisoned dependency, or a hijacked build runner all yield an image that is built and signed normally, so signature checks pass. The evidence that would catch them, such as PR approvals and build runner identity, sits in separate systems and is hard to link to the deployed image.
Signed, chained evidence
Turnstile records each life-cycle step as an 1: a signed claim about a specific artifact. The format is a modified version of 2, an open format for supply chain records. Types cover commit safety, source provenance, pull request approvals, build provenance, the 3 (the list of dependencies), vulnerabilities and deployment. Each attestation is keyed so it links to the next stage, letting you trace a running image back to the commit and its approvers.
A library called dd-attest signs these records with short-lived keys tied to workload identities such as CI jobs or Kubernetes service accounts, via 4 (OpenID Connect). No long-lived keys are handed out. If a CI job is compromised, every attestation it produced during that period can be revoked. Policies can also require that a claim come from a specific producer. Records live in a DynamoDB-backed store called AMS.
Policies and decisions
Policies are written in Rego and run on 5. An example rule: the code must come from an approved pull request on a protected branch, with no critical vulnerabilities in the SBOM. Rules are scoped per environment and start in audit mode before they block anything. Each evaluation produces a signed 6, a pass/fail record adapted from the SLSA supply-chain framework. Other systems can reuse it without re-running the checks. The policies themselves are distributed through 7, which uses offline root keys and signed metadata so clients reject tampered or stale policies.
Speed
Each process keeps an LRU (least recently used) cache of VSAs, keyed by artifact digest, policy and environment. Across about 1 million evaluations in August 2026:
the policy cache hit rate was 92.8%;
the per-artifact hit rate was 75%;
latency was 36 ms at P50 and 481 ms at P99.
Two questions go unanswered: whether deployments fail open or closed when AMS is unavailable, and how revocations reach VSAs that are already cached.
Datadog's engineering blog describes Turnstile, an internal system that decides whether a container image may be deployed. Before Turnstile, the check was whether the image was signed. Turnstile checks signed evidence of how the image was made. It evaluates every container image Datadog deploys, which comes to millions of 1 and tens of thousands of policy evaluations a day. The median evaluation takes 36 ms.
The gap image signing leaves
Datadog already signs images after they are built. A custom plugin for 2, the runtime that pulls and runs containers on each host, verifies the signature at pull time. That answers two questions: is this the same artifact that was signed, and was it signed by an identity we trust?
It cannot catch problems that happened earlier. A malicious commit, a poisoned dependency, or a compromised build runner that swaps the base image all produce an image that is built, pushed and signed normally, so verification passes. The evidence that would expose these problems is scattered across separate systems: who approved the pull request, which runner did the build, which packages went in. Linking that evidence to the digest that finally lands in production is hard. Turnstile changes the question to "does this artifact satisfy the requirements for this environment?"
Attestations that chain together
Turnstile is built on the attestation: a signed claim, tied to the identity of whoever made it, that something happened to or is true of a specific artifact. Datadog uses a modified version of 3, an open format for recording supply chain steps. Each attestation has:
a subject, an immutable identifier such as an image digest or a commit hash;
a predicateType saying what kind of claim it is, and a predicate holding the details;
a signature from a trusted producer, such as a CI job or platform service;
storage keyed by the artifact identifier, so anyone can fetch and verify it later.
The important part is how attestations link. Source control and build systems tend to drop the references between a commit, its pull request, the image built from it, and the deployment. Turnstile keys each stage's attestation so it points to the next. The attestation types are:
Here is how the chain works, using the article's example. A pull-request attestation's subject is a commit. Its predicate records that the commit merged into main through PR 42, with two approvals, and that the base branch was protected. A build-provenance attestation ties that same commit to a pipeline, a job and an image digest. Starting from a running image, you can walk back to the people who approved its code. Investigators can use the same trail after an incident.
Keyless signing
If every scanner, CI job and workflow had to manage long-lived private keys, both security and developer experience would suffer. Turnstile's client library, dd-attest, instead signs with short-lived keys bound to an existing workload identity: a CI job identity, a Kubernetes service account, or a service identity issued through 5 (OpenID Connect, a standard identity-token protocol). The library also stores attestations in the Attestation Metadata Store (AMS), which runs on DynamoDB, and verifies signatures and countersignatures.
The trust question shifts from "who holds this key?" to "which identity made this claim, and was it allowed to?" That fits a world where CI jobs move and services get renamed. It also makes revocation possible: if a CI job is compromised, every attestation it produced during the affected period can be invalidated. Policies can also demand a specific producer. An SBOM signed by anything other than the approved scanning pipeline does not count.
Policies and verification summaries
Policies are written in Rego and run on 6. Examples from the article: the source must chain back to a known repository; commits must be signed by employees; the commit must come from an approved PR on a protected branch; an SBOM from the approved scanner must exist and contain no package matching a critical-vulnerability rule. Policies are scoped per environment, so a regulated environment can be stricter than dev. New rules run in audit mode first, which surfaces pipeline gaps and false positives before anything is blocked.
At deployment, a library called policy-core takes the image digest or commit SHA. It fetches the artifact's attestations from AMS and checks that they are signed by trusted producers. It then runs the policies for the target scope and returns an audit, warn or block decision. The result is written back to AMS as a signed 7, adapted from the SLSA spec. The VSA records the artifact, the policy name and digest, the input attestations, the time, and PASSED or FAILED. Other systems can read it without re-running the evaluation, including deployment UIs, compliance reports, incident response, and verification at runtime.
Protecting the policies themselves
A tampered or stale policy could quietly approve bad artifacts or block good ones. Turnstile therefore distributes policy bundles, and the dd-attest and policy-core libraries, through 8. TUF is a design for secure software updates built on signed metadata, separation between signing roles, and threshold signatures. Offline root keys anchor trust. Clients check the metadata against that root and reject any policy that doesn't match. Root operations are managed with tuf-on-ci. Bundles ship as 9 from the same registry that already serves images and signatures, so the runtime gains no new dependency.
Scaling the hot path
Evaluations are mostly predictable key-value lookups, so Datadog chose DynamoDB for low latency, multi-availability-zone durability, and no manual sharding. The same artifact is often deployed to a service many times, so each process keeps an LRU (least recently used) cache of VSAs. The cache key combines the artifact digest, policy ID, software and control-plane versions, environment, and other input labels. On a miss, Turnstile loads the policy, fetches and verifies attestations, runs Rego, builds a VSA and caches it.
Across about 1 million evaluation traces in August 2026, the policy cache hit rate was 92.8% and the per-artifact hit rate was 75%. Evaluation latency was 36 ms at P50 and 481 ms at P99.
What the article leaves open
Outages. The article doesn't say whether deployments fail open or closed when AMS is unavailable.
Revocation and the cache. It doesn't explain how revoking a producer invalidates VSAs already in per-process caches.
The two hit rates. It doesn't define how they differ.
Tail latency. The roughly 13x gap between P50 and P99 presumably reflects cache misses, but it isn't broken down.
Interoperability. The changes to in-toto and VSA are not described, so it's unclear how well the records work with standard tooling.
Remember
Linking commit, pull request, build and deployment records turns separate audit logs into a chain you can trace from any running image.
Signing with workload identities rather than long-lived keys allows revoking everything a compromised CI job signed.
Caching signed pass/fail results per artifact, policy and environment kept a deploy-path security check at 36 ms median.
Postgres redesigned from scratch (Manish Jain): a forest of 7 trees (log-structured merge trees, which batch writes and merge them in the background), bitmaps, batched execution, physical replication rebuilt for an LSM, a write-ahead log built on Raft (a consensus protocol) plus hybrid logical clocks for read-your-writes high availability, and instant branching where you pay for what you change, not what you touch.
DBOS (Qian Li): durable execution (workflows, queues and events that survive crashes) as a library whose tables live in the database you already run, so there is no new system to operate. She sang it and co-won.
Multigres (Sugu Sougoumarane, Supabase): lessons from Vitess, focused on building consensus guarantees on top of native Postgres replication, starting from an informal statement of consensus.
Semantic concurrency control (William Schultz, MongoDB): conventional concurrency control works on reads and writes at the key-value layer and throws away application meaning. Moving it up to a shared intermediate representation of operations allows merging operations and smarter scheduling, which reduces aborts under heavy contention.
8 for queue sizing (Kiran Kumar Muniswamy Reddy, MongoDB): badly configured queue sizes often contribute to 9, where a system stays overloaded even after the trigger is gone. Reddy proposed computing queue size from Little's Law (items in system = arrival rate × time in system) instead of guessing.
Kyle Kingsbury of Jepsen, the database-correctness testing project, co-won with a fast talk saying LLMs aren't useful for his testing work.
commit safety: the commit was scanned for malicious content and signed with a trusted key;
source provenance: which repository the commit was merged into, and the state of that repository's protections at the time;
pull request: which PR merged the commit and who approved it;
build provenance: the pipeline, job, commit and image digest;
4: the list of dependencies;
vulnerability metadata: vulnerabilities found at build time;
deployment: the cluster and namespace the image went to.