Four things changed this week
Four threads carried the week: one boundary landed, one diagnosis was reversed in public, one everyday wait was explained down to its cost in memory, and one uncomfortable question about AI agents got a structural answer.
A peer reads the slice of your history you granted, and no more
A grant covers exactly the range you chose. Everything outside it is refused by default, decided at the moment the bytes would otherwise leave your machine.
A 37-second invitation was blamed on the wrong part of the system
The signing step was named as the cause and then cleared by measurement. A disk write running on the wrong thread had been holding everything else up.
Your vault password becomes a key that costs sixty-four megabytes
Every unlock fills sixty-four megabytes of memory and walks it three times. So does every guess a machine makes against you, which is the point of the expense.
Rules the agents are told are now also enforced where they cannot be skipped
An agent declares the one thing only it can know โ its own intent. The rest is checked on the server and refused there, whether it cooperates or not.
A grant that holds where the bytes actually leave

The feature: letting another person's device read part of your history โ one range of records and files, not all of them.
Before: access was a decision about the whole of your history. Now: it is a decision about a range within it. A peer reads exactly what you granted, and everything outside that range is refused by default rather than allowed by oversight. (Share a slice of your chain)
Denied by default is the only default that survives a system that keeps growing. Every permissive default is a bet that nobody will add a new kind of data later. That bet loses quietly: the new thing inherits the old permission, and nobody notices until it has already been read.
Most access bugs are bugs of location, not of logic
The check is usually correct and standing in the wrong place โ one layer above where the data actually moves, leaving a gap underneath it through which bytes can leave without ever passing the gate.
An application-layer check can be walked around by any path that reaches the bytes some other way. A check at the boundary cannot, because every path to the bytes goes through the boundary. That is the difference between a system that checks permissions and one where permission is a property of the read itself.
One question, asked on both planes
Your history is two things at once. There is the structured, queryable side โ the records and the links between them โ and there is the file side, the content stored separately and referred to by its fingerprint rather than carried along inside every record.
Partial access has to mean the same thing on both, or it means nothing. If a record can be refused while the file it points at is still fetchable by fingerprint, the first gate is theatre.
So there is now exactly one answer to "may this peer read this content, on this branch of this history," and both sides ask it.
The check is keyed on four things together: who is asking, whose history it is, which branch, and which specific piece of content. Absent an affirmative grant covering all four, the read is refused.
Default-deny here is not a banner on the front door โ it is the absence of a grant at the exact moment the bytes would otherwise move.
The streaming case is where it gets real
The hard version is a peer pulling content it does not hold locally yet. The system cannot ship the whole history and trust the reader to look away from the parts it should not see, so the decision is made during the fetch rather than once at the start of it.
That means the requester's identity is carried all the way down to the layer that hands over bytes, and the answer is worked out one piece of content at a time.
A peer entitled to one branch and not another, pulling from the same history, gets that branch's bytes and a refusal on the other โ decided at the fetch, fingerprint by fingerprint.
What it cost to prove
The proof is a two-device scenario: separate peers with separate grants, real requests across the network, asserting both that the granted read returns the bytes and that the ungranted read is refused. Not that a read happened โ that the right read happened and the wrong one did not.
Pairing those two is the non-negotiable part. A gate tested only in its refusing direction can be green because the whole path is broken and nobody is getting anything. The success twin is what proves it is a gate rather than a wall.
A test on one device can only show that the code intends to refuse. Two devices show that the refusal happens where it matters, on the far side of the link, which is the only place the guarantee is worth anything.
A second boundary moved the same way this week
Personal information is now scanned where data leaves rather than where it arrives. The scan runs at the point a shareable snapshot is built for export, not at the moment data first enters the machinery that generates it. (Outgoing, not incoming)
The reasoning is the same reasoning, arrived at from a different direction. Between the entrance and the finished artifact sit every transform, synthesis step and join, each of which can introduce or recombine personal data in a form that never existed at the door. Standing at the exit puts all of them upstream of the check.
There is a second reason, about which population is being checked at all. An entrance gate inspects your inputs, which you already control.
The risk is on your outputs โ the thing that crosses out of your hands and lands in someone else's. Checking inputs to protect outputs is checking the wrong population.
What the scan counts as personal
The definition was sharpened in both directions at once. Public identifiers that exist precisely to be published were dropped from the scan, because flagging something public by construction protects nobody and teaches people to ignore the alarm. The phone-number pattern was narrowed so it stops firing on digit sequences that merely resemble one.
Both directions are failures of the same classifier. Loosen it and real data slips out; tighten it carelessly and it becomes noise that people route around.
The check is also something a person can run on demand against a finished artifact, so "is this clean?" is a question you ask of the thing in your hand rather than a property you take on faith from a step that ran somewhere upstream.
A third boundary, sitting further down than either of those
The same question โ how far down does a limit have to sit before it is really underneath everything โ came up this week in the least glamorous place in the system: the pause after you type your vault password. (What your vault password becomes)
A password you can remember is a bad key. A key has to be a run of essentially unguessable material; a password is short, drawn from a small alphabet, and reused. You cannot take the letters someone typed and call them a key.
So they are put through a calculation whose defining property is that it is deliberately expensive. It costs sixty-four megabytes of memory, walked three times, in four lanes, and produces a thirty-two-byte key. Paid once, that is a pause. Paid for every guess, it is the whole defence.
The expense is aimed at a specific axis. Older schemes were expensive in time, and time is what an attacker buys most cheaply, since a graphics card runs thousands of guesses side by side.
Filling a large block of memory per attempt means a thousand simultaneous guesses cost a thousand blocks of memory, not merely more clock cycles.
Being blunt about what that buys: it is a multiplier on the price of each guess and nothing more. It makes a decent password expensive to attack. It cannot rescue a poor one.
When the cost of the calculation arrives as data
The interesting part is what happens when the three numbers are not chosen by the code at all.
Some callers read them back out of the stored record they are opening, so a device that never picked those numbers can still re-derive the same key from the same password. On that path, the cost of the calculation arrives as data.
Careful calling code is the wrong place to solve that, because a stored record is precisely the thing a careful caller cannot vouch for.
The answer sits below the callers instead, in the compiled core that both the desktop service and the phone runtime derive through, which refuses a memory cost below one megabyte or above a ceiling shipping at two hundred and fifty- six megabytes.
Its own note is blunt about the threat: someone who gets to choose the memory cost can exhaust the machine in a single call. And the browser build carries its own copy of those bounds rather than calling that core โ the same values today, and a standing reminder that "underneath everything" is a claim about a particular path.
A boundary that does not depend on the other side's goodwill
The standard we hold all three of those to came from somewhere, and we wrote down where this week. (An account you can actually carry)
The protocol behind Bluesky made leaving a host a right rather than a favour. It separates the key you sign with every day from the key that controls where your identity points, and you hold the second one. So you can move even if your old host would rather you did not.
That is the definition we took: portable has to mean portable over the other side's objection, guaranteed by something they never held. A boundary that holds only while the other party cooperates is a courtesy with good documentation.
Where our defaults invert theirs, we said so rather than implying they had fallen short. Their records are public by design and ours are private; theirs live on a host and ours on your own device; their identities mostly resolve through one shared directory and ours are built to need none. Different questions, answered clearly enough that we could choose.
What is still missing
The read gate has been proven between two cooperating devices, not against a peer that is trying rather than merely asking. The narrowed export scan publishes no false-negative rate, which is the number that would say what the narrowing cost.
The idea that large content should travel on its own path, addressed by what it is rather than by where it lives, is not ours; we took it from the neighbourhood and added an authorization plane our own commitments require (what others taught us about shipping the work).
The measurement that refuted our own diagnosis
The feature: creating an invitation from the command line, which has to finish inside a thirty-second deadline.
Before: it was taking about thirty-seven seconds, and we had already named the cause โ the signing step. Now: the numbers say otherwise. The delay was a blocking disk write on the main thread, and the signing step had been carrying the blame for it. (We were wrong about the signer)
A diagnosis that matches what you already believe is the one to measure first. Signing is cryptographic, it is the newest part of the path, and it is the part everyone finds interesting. All three make it a magnet for blame, and none of them is evidence.
How the path is meant to work
The command-line tool does not do the work itself. It hands the request to a long-running background service and waits for an answer over a connection that stays open in both directions, so the result can be pushed back the moment it exists.
That connection carries a deliberate thirty-second deadline. A deadline is not a failure mode; it is a promise that the tool will never hang on you forever, and thirty seconds was meant to be a wildly generous ceiling for work that should take a fraction of a second.
What the service produces is one entry appended to your own history โ a log where new records are added at the end and nothing already written is edited or removed. When we say the invitation was created, we mean exactly that: an entry landed, at a known position, durably.
Every entry is signed before it lands, and no single key can authorise anything on its own. The signing power is split into shares, a defined number of them have to cooperate to produce one valid signature, and the component that holds them runs as a separate process behind a narrow boundary โ deliberately, because that is the most sensitive code in the system.
Then the signed entries have to reach disk, and this is the step the whole story turns on. The service runs one thread that accepts and dispatches every request.
Anything occupying that thread occupies it for everyone. So writing to disk is explicitly designed to happen elsewhere: a separate worker takes a batch and writes it, and the main loop goes straight back to serving.
What the numbers actually said
The symptom was clean enough to be maddening. The invitation was genuinely created โ the entry landed, real and durable โ but roughly thirty-seven seconds after the call started, and the connection meant to carry the answer gives up at thirty. The system did the thing and then failed to tell anyone it had.
A batch of thirty operations had held the write path for about twenty-nine seconds. That much was visible from the start. The question was never whether the write path was starved; it was what held it.
Our candidate was the separate signing process, and we liked it. Thirty operations, thirty round-trips across a process boundary, twenty-eight seconds โ the story fits.
We had already reached for the matching fix: break the batch up by elapsed time so it yields between chunks and lets the invitation slip through.
The twenty-eight seconds is what broke the theory. Thirty round-trips would show up as thirty discrete waits. What the write path actually showed was one near-contiguous block of time, on the main thread, inside the step that writes a signed batch to disk. Not waiting on another process. Doing work.
The flag that spawns the writer worker was off. With no worker to hand the batch to, the write ran inline on the one thread everything else needed, and held it for the duration.
The fix was to spawn the worker โ the system arriving at its own specification rather than acquiring a new one, which is why the chunking we had been about to build was not merely unnecessary but actively wrong.
Why the wrong suspect was so attractive
A separate signing process behind a narrow boundary is exactly where an experienced engineer expects latency to hide. So the search went where the story was good rather than where the time was actually spent.
The disk write was invisible for the opposite set of reasons. It is old, it is boring, and it belongs to a layer nobody was looking at that week.
A blocking write on the main thread produces precisely the symptom we saw โ a fixed delay added to something unrelated โ without appearing anywhere in the story we had already constructed.
A good fix for the wrong bug is worse than no fix, because it convinces you that you are done.
The chunking would have shipped, might have helped a little at the margins, and would have left the real freeze exactly where it was: a worker still unspawned, the next batch still primed to starve the next request.
Publishing the reversal costs something and is worth it. A team that only publishes the diagnoses that turned out right teaches its readers that diagnoses are usually right, which is the least useful thing they could learn from us.
The habit meant to catch the next one
Since the twenty-fifth of May, closing a piece of work takes an extra pass whose stated job is to assume the tests are hiding something and prove it. (Hunting the gaps a green suite hides)
The method is deliberately mechanical. Write down, in plain language and separately from the tests, every behaviour the design promised. Then walk that list and demand the test that proves each item. Three outcomes are possible, and only one of them is comfortable.
Asserted and green, and you move on. Asserted weakly โ the test proves that something happened, not that the intended mechanism ran โ and it needs strengthening, because an outcome-only assertion passes even when the code took a completely different route than the design intended. Not asserted at all, and that is the bug.
The bar, stated honestly
The bar underneath it is stated honestly rather than as a victory number. Combined coverage should clear a real floor, and we hold eighty per cent, while saying plainly that eighty per cent over the wrong lines still hides the gap.
End-to-end tests must exercise every design intent, and a skipped one is treated as a critical gap rather than a minor one.
Every failure-mode test is paired with a test proving the good case succeeds. A lone failure test can pass for the wrong reason โ if the whole path is broken, of course the bad input fails.
The same week, the project's written rules were wired directly into how each agent starts, and the coverage report that came with it was published as it was: seven of nine files over the line bar, and the two that missed filed openly as follow-on work rather than rounded up or quietly dropped. That is the same instinct one level higher โ not letting "mostly covered" become "covered".
The same problem, one level up: what if the agent ignores the rule?
A test that certifies what it asserts and an agent that reports its own compliance are the same problem wearing different clothes. Both are a declaration standing in for a measurement. (Trust the agent, verify at the gate)
This system is built largely by AI agents working on their own, which makes the question unavoidable. If the whole governance story is that the agents were told the rules, then the day one of them does not follow a rule, the rule did not happen and the governance was theatre.
There is one thing only the agent can supply. When it decides it has finished researching and is moving to design, nobody else can read that transition out of the air; no server process can infer an intent from another party's reasoning. For anything hinging on intent, the declaration is the only available input.
Everything else is now checked where cooperation is not required. A gate runs at every attempt to write to the shared record and evaluates the matched rules against the actual event, blocking the write outright when a rule is serious enough.
A claim that a step is complete is validated against evidence that has to genuinely exist; no evidence, no advance.
Five declared levels, because rules differ
Each rule declares how seriously it is enforced, across five levels. The lowest simply notes that it matched. Higher ones surface guidance, or record that a different path was taken without blocking it. The top two block when their conditions match and refuse at both layers.
The spread exists because rules genuinely differ. "Leave things better than you found them" rests on a judgement โ is this bug in scope, or filed for later? โ that no server can evaluate, and its value comes almost entirely from an agent reading it and applying it.
A build check that aborts on failure needs no cooperation at all; surfacing it to the agent is a courtesy.
The trap this design exists to avoid was one the project fell into first. A shortcut answered for a handful of rules in fast custom code before the real engine ran. It looked efficient. It silently dropped every rule outside its handful, left no record of what it had refused, and fell back to crude text matching where false positives are guaranteed.
The fix was not a cleverer shortcut. It was deleting it and routing those rules through the one path, so they compose, emit a record, and can be reasoned about as a set.
What is still missing
The invitation is diagnosed, not fixed. Thirty-seven seconds against thirty, with the cause now known and no published measurement showing the path back inside the deadline.
What this means, in plain terms
Five general lessons this week's work paid for, each learned by getting something wrong first.
Denied by default, or the boundary drifts
A grant now covers one range of your history and refuses everything else, asked as one question on both the record side and the file side. A permissive default would have quietly extended itself to every kind of data added afterwards. A default that has to be revisited every time the system grows will not be revisited.
Measure the boring explanation first
An invitation was taking thirty-seven seconds against a thirty-second deadline, and the separate signing process was blamed because it was the newest and most interesting part of the path. The real cause was a disk write running inline on a thread everything else needed. Suspicion follows novelty and interest, neither of which is correlated with being the cause.
A passing test certifies what it asserts, not what you meant
A suite can be entirely green while a promised behaviour sits unbuilt, because nothing ever asked for it. Closing work now means listing the intents first and demanding the test that proves each, rather than reading the bar as an answer. A test that passes over a gap between the code and its design is itself a bug.
Guard the exit, not the entrance
Personal-information scanning moved from the moment data arrives to the moment a shareable artifact is built, with public identifiers dropped and the phone matcher narrowed. Data that never leaves needs no scan; data that leaves needs one at the door, in final form. Put the check where the risk is realised, not where it was easiest to instrument.
A rule you only told the agent about is not a rule
Governance here has two layers, because an agent forgets, mis-states its own state, or quietly routes around a check. It declares the one thing only it can know, and the server enforces the rest either way. A control that depends on the cooperation of the thing it constrains is one cooperative session from silent failure.
How much healthier is it than a week ago?
Read the 1,350. The larger figure is included because it exists and would otherwise be quoted at us, not because it is the better answer.
No net line-count headline appears either: the raw diff for the window is +2.2M and โ0.5M lines, and it is overwhelmingly generated bytes โ dataset packs and regenerated fixtures โ rather than written code.
Five honest notes
The invitation is diagnosed, not fixed. We know the thirty-seven seconds came from a blocking disk write on the main thread rather than from signing. Knowing is not the same as being inside the deadline, and no measurement published this week shows the path back under it.
Two of this week's threads are published positions, not shipped features. The study of portable accounts and the essay on the two ways an instrument stops serving you argue a design stance and record what we took from other people's work. Neither is something you can switch on.
Our own build-and-release machinery failed in a loop during the window and stopped the fleet's work while it did. That is the honest backdrop to a week spent reading how other projects coordinate the work that ships, and it is why that piece was written at all.
The rules landed in every agent with two files under the bar. Seven of nine cleared the coverage line and the two that did not were filed as follow-on work in the open. The report is honest; it is not a clean sweep.
The generated-bytes problem is getting worse, not better. A diff of +2.2M / โ0.5M cannot be read as effort at all. Every week this stays true, a whole class of ordinary progress metric is unavailable to us.
a peer can now read exactly the range of history you granted and nothing beyond it, a thirty-seven-second invitation turned out to be a disk write rather than the signer we had already blamed, the wait when you unlock your vault was explained down to its cost in memory, and the rules we tell our agents also became rules the server enforces without them.
What changed, area by area
Every area that moved this week. Per-area file counts are not available for this window, so the areas are listed by what landed rather than ranked by traffic.
The boundaries that moved
A peer can read exactly the range of your history you granted and nothing else.
One authorization question is asked on both the record side and the file side, keyed on who is asking, whose history it is, which branch and which piece of content; the decision is made inside the path that hands over bytes, including while a peer is streaming content it does not hold yet, and it is proven with a two-device scenario rather than a single-device assertion.
( Share a slice of your chain )
Personal information is scanned at the moment a shareable artifact is built rather than when data first arrives.
Identifiers that are public by construction were dropped from the scan, because flagging them protects nobody and trains people to ignore the alarm; the phone-number pattern was narrowed so it no longer fires on digit sequences that merely look like one; and the scan can be run on demand against a finished artifact.
( Outgoing, not incoming )
An invitation was completing in about thirty-seven seconds against a thirty-second deadline.
The signing step was blamed and then cleared by measurement: a batch of thirty operations was being written to disk inline on the one thread every other request needed, because the worker meant to take that work was never started. The reversal was published rather than quietly replaced with the right answer.
( We were wrong about the signer )
Typing your vault password turns it into a key by a calculation deliberately made to cost sixty-four megabytes of memory, walked three times, in four lanes, producing a thirty-two-byte key.
The expense is the design: it is trivial once for you and ruinous for a machine paying it again for every guess.
A random value stored per vault means two people who chose the same password get different keys, and a short version label glued to the password ties the key to this scheme rather than to the password alone. ( What your vault password becomes )
A wrong password makes the next attempt wait โ one second, then two, then four, doubling up to a minute โ counted on the device rather than only in memory.
The working buffers are overwritten with zeroes whether or not the key opens anything.
And because some callers read the cost out of a stored record rather than choosing it, the compiled core beneath them refuses a memory cost below one megabyte or above a ceiling that ships at two hundred and fifty-six megabytes, and reports that refusal with a fixed tag rather than free-form prose.
( What your vault password becomes )
The agents, and what holds them
Rules are now enforced in two layers rather than announced in one.
The agent declares what only it can know โ that it has finished one stage of work and is moving to the next โ and the server checks everything else against what actually exists, refusing outright where a rule is serious enough.
Each rule declares its own seriousness across five levels, from a quiet note that it matched up to a refusal at both layers, and a shortcut that had been answering for a handful of rules in fast custom code was deleted so all of them run through one path and leave a record.
( Trust the agent, verify at the gate )
A published essay names the two opposite ways an instrument stops serving you: accumulating until you cannot function without it, and quietly draining your attention and data while giving nothing back.
The answer argued there is structural rather than behavioural โ a delegation budget the agent cannot extend, a scope only you can widen, a root key held where no agent can reach it, and a signed record of every action โ with the question of whether an agent's correctability can ever be proven rather than continually re-checked left open on purpose.
( The hyperagent and the vampire )
Closing a piece of work now takes an adversarial pass that assumes the suite is hiding something.
Design intents are written down in plain language separately from the tests, each is matched to the assertion that proves it, weak outcome-only assertions are strengthened to prove the intended mechanism ran, and every failure-mode test is paired with a success twin so neither can pass for the wrong reason.
A skipped end-to-end intent counts as a critical gap. ( Hunting the gaps a green suite hides )
The project's written rules now load directly into each agent as it begins work, so there is one answer to what is allowed rather than one per agent.
The coverage report published alongside it says seven of nine files cleared the line bar and names the two that did not as open follow-on work. ( Hunting the gaps a green suite hides )
Published this week, rather than shipped
Two studies of other projects were published this week rather than any change to our own code.
One honours the protocol behind Bluesky for making account portability a right rather than a favour โ a separate key you hold, not your host, is what moves where your identity points, so you can leave over the host's objection โ and states plainly where our defaults invert theirs: private rather than public, on your device rather than on a host, identity that resolves without a shared directory, and discovery that follows trust rather than broadcasting to everyone who asks.
( An account you can actually carry )
A second study looks at three projects on the question of getting work to land: a transport that keeps itself honest about what it is and moves large content on its own addressed path, a system whose strength is refusing to over-specify its substrate at all, and a federated model that treats data shapes as named contracts.
It is written against a corpus of 117 project studies kept on disk, and it says out loud that our own build machinery failed in a loop that week and took the fleet's work down with it. ( What others taught us about shipping the work )
Elsewhere in the week
A second device can recover cleanly from a stale-key race, with the resend-request loop that closes it landing on 30 May.
The protocol is what shipped; the end-to-end two-device install behind it did not, and it stops at a cross-device replication problem this report can name and has not solved.
The plan-tree cockpit reached heavy keypress-level polish โ cursor movement, filtering, and a debounce for a storm of rapid enter presses.
It is being pushed toward release and is not released.