302 changes this week, and an unusual shape: instead of one project building one feature, six projects in two languages moved to a new revision of the same underlying protocol — 72 changes, landed in the same seven days. The new revision adds one rule that sounds mild and is not: two parties must be formally introduced before either will accept anything from the other, and an unintroduced message is dropped in silence. Nothing is refused, nothing is logged, nothing comes back. Most of the week was spent making that rule survivable — relationships that outlive a restart, a way to re-introduce yourself automatically, and an alarm on the one event nobody could previously see. Alongside it: post-quantum keys reached all the way from the key store to a signed credential, round two of the security review closed an information leak and five classes of gap in the identity-log host, and the community app made joining a community something a newcomer can actually walk through.
A protocol migration is the least glamorous kind of week and one of the most revealing, because a rule that changes everywhere at once finds every place that was quietly getting away with something. Nearly every fix below has the same shape: a limit that was configured and never charged, a gate that was correct and never called, a drop that was counted and never announced. The theme of the week is not new capability. It is saying something.
The secure-messaging protocol the stack rides on moved to revision 3 — and there is no partial path: the envelope, the encryption and all five message layouts change together, so a message is wholly old or wholly new. It landed the same week in the shared toolkit, the trust backbone, the community app, the identity-log host, the trust registry and the browser wallet's independent JavaScript implementation. The two implementations were then checked against the specification's own worked examples byte for byte, not field by field — which is the only version of that check that catches a disagreement about padding.
The new rule: an endpoint silently drops traffic from a party it holds no relationship with. Drop, not refuse — so the sender sees a service that accepts connections and never replies. Three separate bugs rode that rule into invisibility: introductions were received and never recorded, the record of who you knew was lost on restart, and one component could send but had no way to introduce itself. The fix is a full recovery mechanism — relationships that survive a restart, automatic re-introduction before a send, paced retries so a genuinely-down peer is not hammered, and idle cleanup — plus, finally, a counter on the drop itself.
Quantum-resistant signing stopped being a capability and became a path. Keys are now derived from the same seed chain as every other key and carry the algorithm they were minted with; an identity template declares which algorithms its keys use; the provisioning bundle can carry a second signing key; and a community's credential service signs with every key it holds, so one credential carries both a classical and a post-quantum signature. Three separate front doors had been shut the whole time — a command-line tool that matched three key names, a library dependency taken without the feature switched on, and a test suite that had never compiled.
Adding a new service to the stack should mean choosing an address and a message name. It did not: four components had each hand-rolled their own way of putting the same message on the wire, and a fifth would have been a fifth. There is now one outbound path, and it picks its carrier from what the recipient advertises rather than from what was compiled in. A service that speaks only the newer transport is now reachable; one that speaks plain web requests joins the same router rather than bypassing it.
Fourteen hardening changes in five projects. The identity-log host closed five classes at once — reading another tenant's records, exceeding a quota, replaying an old request, being pointed at an internal address, and acting without the right. The message hub's forwarding path was put behind a guard that refuses to dial any address on a private network, and now forces certificate checking on in real builds whatever the config says. And the agent stopped distinguishing "not yours" from "not there" — answering those separately had been quietly confirming which identifiers exist.
Forty changes on the one path a newcomer actually takes. You can now create the face you will be known by without leaving the flow, apply as a second persona, read a community's requirements from the endpoint it publishes rather than guessing, see every way in to a community at once instead of one, and abandon an application you no longer want. The small ones matter most here: telling apart the two different ways of having no invitation, and an oversized submission that now fails loudly instead of vanishing.
A service that refuses you is annoying. A service that accepts your connection, takes your message and silently discards it is far worse, because every party involved believes it is working. That is the failure mode the new protocol rule creates by design, and it is why so much of this week went on plumbing rather than features. The single most valuable change of the week is probably the smallest: a counter that increments when a message is dropped for having no relationship. It turns an invisible outage into an alert.
The hard cryptography for quantum-resistant signatures has been settled for a while and was already in the codebase. What stopped anyone using it was three unremarkable things: a tool that only recognised three key names, a library included without its optional feature enabled, and a set of tests that had silently never been compiled. Every one was found by trying to use the feature end to end rather than by reviewing the cryptography. Capability nobody can reach is not capability.
A delete confirmation listed the one thing you named. The delete itself removed that thing and everything underneath it. So a workspace with empty pockets of its own, sitting above children full of keys and identities, previewed as holding nothing — and every tool that asked "is this safe?" got the wrong answer. Two functions were answering different questions about the same act. The preview now walks the whole tree, reports what it could not remove from the servers that host it, and is the thing the confirmation is built from.
Imagine a members' club where the rule is that you may only speak to someone you have been formally introduced to. It is a good rule: it means nobody can walk in off the street and start making claims. The problem is how it is enforced. Speak to a stranger and they do not say "we haven't met" — they simply do not hear you. You keep talking; nothing happens; you have no way to tell whether they are ignoring you, whether the room is empty, or whether you are in the wrong building.
What changed. Revision 3 of the secure-messaging protocol replaces the encryption scheme, rewrites every message layout and moves the proof-of-sender into a different part of the message. There is no gradual migration available — a message is entirely old or entirely new — so every project that speaks it had to move together, and did: the shared toolkit, the trust backbone, the community app, the identity-log host, the trust registry, and the browser wallet's separate JavaScript implementation. Both implementations were then validated against the specification's published examples re-packed byte for byte, which is a materially stronger check than comparing the fields and is what catches two implementations that agree on meaning and disagree on encoding.
What it exposed. The introduction rule turned three latent bugs into invisible ones. Introductions arriving over the wire were unpacked as if they were ordinary traffic, so no relationship was ever recorded and every message afterwards was discarded. The record of who you knew lived only in memory, so a restart lost half of every relationship. And one component could send but had no way to introduce itself, so anything built on it went quiet after a restart with no way back. Each was fixed, and then generalised into a recovery mechanism: durable relationships, automatic re-introduction before sending, paced retry so a peer that really is down is not re-invited forever, a cap on how often an introduction can be accepted, and cleanup of relationships nobody has used in a week.
Two strands, and they met in the same week. One is forward-looking: making the stack's quantum-resistant signing usable by an operator rather than reachable only by a library author. The other is the second round of an external security review, which found the kind of things a first round does not — not missing locks, but locks that were installed and never engaged.
A derived key now carries the algorithm it was minted with rather than having it inferred, and quantum-resistant keys derive from the same seed chain as every other key — so one recovery phrase still recovers everything. An identity template declares which algorithms its key slots use, and the agent mints exactly what the template asks for.
A community's credential service now signs with every key it holds, so a credential can carry a classical signature and a quantum-resistant one side by side — verifiable today by everyone, and still verifiable later by those who need the stronger one. Every verification path was taught to read a document with more than one signature, which is the half that makes it useful.
The agent checked permission and existence separately and reported them separately — so the difference between the two answers told an outsider which identifiers were real. Both now return the same refusal. Eight documented error codes that the specification declared and the service had never emitted are now emitted.
The message hub's forwarding path now refuses any address on a private network — cloud metadata, internal ranges, loopback — checked at the point of the request and with the name re-resolved on the websocket path too, because a name can be pointed inwards a moment after it is checked. Certificate validation is forced on in real builds regardless of the configuration flag.
And two that were simply switched off. The message hub's per-identity rate limit had been built, garbage-collected and logged as enabled — and nothing ever called it, so it refused nothing. The traffic limiter in front of the agent trusted a forwarded-address header on a global on/off flag, which let an untrusted caller forge one to dodge its own limit while every client behind a legitimate proxy shared a single bucket; it now reads that header only from an explicit list of trusted proxy networks.
Counted the same way as the previous nine reports, across the same eight Rust projects. The browser wallet and the phone approver are written in TypeScript and Swift, so they contribute nothing to these greps — their changes are in the headline totals above, but the scoreboard stays a clean like-for-like.
In one line: a third of last week's volume, spent almost entirely on one protocol migration and the failures it uncovered — with the largest test-stand-in rise recorded here, and one measure that got worse for the second week running.
Three honest notes. First, 302 against last week's 463 is a genuine fall, not an artefact: the same ten projects, the same method. Last week was the busiest of the year and this is a normal-to-busy week. Second, unused-code markers rose again, by one. It is a small number and it is reported because it was explicitly on last week's list to fix; a measure named and then not moved is worth saying out loud. Third, the test-stand-in figure opens at 803 where the Week-37 page published 807 as its ending value. The identical scan points re-read on origin/main now give 803 — a measurement artefact of which copy of the code was read, not four stand-ins deleted. 803 is used here so the before and after are consistent with each other.
And one about the reading itself: six of the ten local copies were behind the published main line when this ran, one of them by 21 changes. Every figure on this page is read from origin/main, not from those copies.
The published report tracks around eleven projects; this page covers the ten held locally, so the totals here are a floor rather than the whole picture. Eight of the ten shipped something this week.
Take revision 3 to an outside implementation. The stack now has two independent implementations — Rust and JavaScript — validated byte for byte against the specification's own examples. That is a strong internal result and it is still internal. The next step is the same vectors against an implementation nobody here wrote. Wake the phone approver. It shipped nine changes last week after six quiet weeks and nothing this week, and the protocol underneath it has just changed; it is the standing risk on this page. Finish the post-quantum path at the verifier. Issuance now signs with every key; the credential is only as useful as the far end's willingness to read the stronger signature, and that is a cross-language piece of work. And reverse the measure that slipped. Unused-code markers rose again, by one, having been named last week as the thing to fix — small, but a stated intention that did not happen.